马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?注册
x
原来Python懂魔法
一、 对象是怎么样的?魔法方法
(一)__init__(self[,…])能在对象初始化时候实现个性化定制。
(二)__new__(cls[,..])它是在__init__之前被调用的,事实上对象是由__new__方法创建的,所以我们看到了它的第一个参数是cls,是类,而不是self,对象诞生的流程是先调用__new__方法,创建一个类的实例,将其传递给__init__方法,再进行个性化定制。如果有人问:是哪种魔法方法创建了实例对象,或者说实例话对象中调用的第一个魔法方法是什么?那么答案必须是__new__,因为self就是它返回的,有了self才有这个对象,才有这个方法跟对象的绑定。
不过,需要重写__new__方法的情况较少,通常有两种情况,一种情况在原类中去定制类,原类是一个更高级的概念,是Python最难理解的概念之一被称之为魔法方法背后的魔法方法,这个后面会有讲解,这个情况这里按住不表。
另一种情况比较特殊,是在继承不可变数据类型的时候,如果我们想要从中作梗,就可通过重写__new__方法进行拦截。
Python 3.12.1 (tags/v3.12.1:2305ca5, Dec 7 2023, 22:03:25) [MSC v.1937 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license()" for more information.
class CapStr(str): (CapStr是继承自str这个字符串的)
def __new__(cls,string): (cls类,string实例化传进去的一个参数)
string = string.upper() (变成大写字母组成的形式)
return super().__new__(cls,string) (让父类去考虑是这个__new__怎么去构造对象的)
cs=CapStr("FishC")
cs (这里对不可变对象进行修改,是因为赶在实例对象被创建之前,就进行了拦截,然后才调用super().__new__去创建真正的实例。
由于CapStr类是继承自str字符串类的,字符串该有的方法,它也一并继承了下来,比如我们要把它变成小写或首字母大写:
'FISHC'
cs.lower()
'fishc'
cs.capitalize()
'Fishc'
当对象既将被销毁的时候,会调用一个魔法方法,叫做__del__(self).
(三)__del__(self)
class C:
def __init__(self): (构造方法)
print("我来了~") (当类被创建时,打印“我来了”)
def __del__(self):
print("我走了~") (当类被销毁时,打印“我走了”)
c = C() (实例化对象的时候)
我来了~
del c (调用del语句把它删除的时候,但是必须检测到一个对象没有任何引用的时候,才会将它销毁)
我走了~
c = C()
我来了~
d = c (做一个引用给d)
del c (此时,del c没有用)
del d (但是这个引用d被销毁,c才会被销毁)
我走了~
二、__del__是对象销毁前的最后拦截,有没有利用这个实现对象的重生,__del__方法可以通过创建一个该实例的新引用,来推迟其销毁,这也被称为对象的重生,虽然官方不建议,但它又告诉你可以实现,不妨尝试一下,虽然对象随着__del__语句删除了,这没错,但是如果能够在对象被销毁之前将self送出去,那么这个对象就算是得以重生了。
class D:
def __init__(self,name):
self.name = name
def __del__(self): (方法其实也是一个函数,只是多了一个对象绑定的操作和参数)
global x (创建一个全局变量x)
x = self (然后x=self)
d = D("小姐姐")
d
<__main__.D object at 0x000001EA934014F0>
d.name
'小姐姐'
del d
d
Traceback (most recent call last):
File "<pyshell#33>", line 1, in <module>
d
NameError: name 'd' is not defined. Did you mean: 'D'?
x
<__main__.D object at 0x000001EA934014F0>
x.name
'小姐姐'
我们在讲全局变量的时候,非迫不得已,尽量不要使用全局变量,因为它会污染命名空间,那么我们就要考虑,会不会有另一种方法:是不是可以在对象被销毁之前,让它去调用一个函数,然后通过参数传递的形式将self给传出去。所以还有一种方法:通过函数调用的形式,将这个对象,将这个self保存起来)
class E:
def __init__(self,name,func):
self.name = name
self.func = func
def __del__(self):
self.func(self)
def outter(): (定义一个闭包函数,)
x = 0
def inner(y=None):
nonlocal x
if y:
x = y
else:
return x
return inner
f = outter()
e = E("小姐姐",f)
e
<__main__.E object at 0x000001EA93401AF0>
e.name
'小姐姐'
del e
e
Traceback (most recent call last):
File "<pyshell#60>", line 1, in <module>
e
NameError: name 'e' is not defined. Did you mean: 'E'?
g = f()
g
<__main__.E object at 0x000001EA93401AF0>
g.name
'小姐姐' (小姐姐又复活了)
怎么实现的:这是我们定义为闭包函数的原因是为了让self保存在外部函数x变量,而内部函数的作用是用于窃取这个self对象,在del魔法方法中调用它的时候是带参数的,它就把这个(self.func(self))参数给存储起来,如果在外部调用这个函数,它(g=f())不带参数,就使用默认值None,它就返回刚刚拿到的self,这个就是刚刚发生的过程。
|