上一次我们讲了python类中的特殊成员,还有几个比较重要的忘记了
__new__方法是一个类方法,尽管它没有被classmethod装饰器修饰
单例模式
class A:
instance = None
def __init__(self):
print("A")
def __new__(cls, , *args, **kwargs):
print("A.__new__: ", cls)
if cls.instance is None:
cls.instance = super().__new__(cls)
return cls.instance
c = C()
#输出:
C.__new__: <class '__main__.C'>
C
定义一个instance类变量,然后重载__new__方法,这样就能确定此类只创建一个实例,但是返回值是一个实例对象,所以__init__每次还是会被调用。__new__重载方法的返回值有两种方式:
这两种方式有什么区别呢?看一下例子
class A:
a_inst = None
def __init__(self):
print("A")
self.name = "111"
def __new__(cls, *args, **kwargs):
print("A.__new__: ", cls)
if cls.a_inst is None:
cls.a_inst = super().__new__(cls)
return cls.a_inst
class B(A):
b_inst = None
def __init__(self):
super().__init__()
print("B")
self.name1 = 222
def __new__(cls, *args, **kwargs):
print("B.__new__: ", cls)
if cls.b_inst is None:
cls.b_inst = super().__new__(cls)
return cls.b_inst
b = B()
print(b.a_inst is b.b_inst)
print(b.name)
print(b.name1)
#输出:
B.__new__: <class '__main__.B'>
A.__new__: <class '__main__.B'>
A
B
True
111
222
可以看到A和B的__new__、__init__都会被调用,而且类变量a_inst和b_inst是同一个,name和name1均被正常初始化。A的__new__函数中打印的cls也是B,所以这就是super的原因了。如果把__new__中的super()换成object呢?
B.__new__: <class '__main__.B'>
A
B
False
111
222
只有B的__new__被执行了,__init__都被调用了,name和name1还是被初始化了,因为A的__new__没有被调用,所以a_inst变量没有初始化,还是None。知道了这种区别那么我们在使用当中就要根据场景去判断使用哪种方式,一般情况下super的方式其实就可以了。
class A:
def __init__(self):
self.name = "名称"
def __getattr__(self, item):
print("getattr: ", item)
return "没有属性:%s" % item
a = A()
print(a.name)
print(a.age)
#输出:
名称
getattr: age
没有属性:age
通过例子可以看到,name属性是存在的,在访问时没有调用__getattr__方法,但是age属性是不存在的,访问时调用了__getattr__方法。在多重继承时,可以在父类中定义此方法,这样就可以防止多继承时属性访问异常。
class A:
def __init__(self):
self.name = "名称"
def __getattribute__(self, item):
print("getattribute: ", item)
self.name = "新名称"
return super().__getattribute__(item)
a = A()
print(a.name)
#输出:
getattribute: name
新名称
这里可以看到,在访问正常属性时,会先调用__getattribute__,而且在此函数中重新设置name属性值后,访问到的属性也更改了,如果在此方法中固定返回一个值,那么所有的属性访问都是同样的值
from types import MethodType
class A:
pass
def func(self):
print("func")
a = A()
a.func = MethodType(func, a)
a.func() # 输出:func
这种方式绑定的方法,只在此对象中存在,其他对象是不存在的
class A:
pass
def test(self):
print("test")
a = A()
A.test = test
a.test() # 输出:test
这种绑定方式会给类增加一个方法,在此类所定义的所有对象中都可以调用,即使是在绑定方法之前所定义的对象也可以。注意:以上两种绑定方法只针对普通方法,并且普通方法第一个参数默认是self,所以这里定义的方法也必须有self参数
本文分享自 python爬虫实战之路 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!