上期回顾:Python:with上下文管理器:__enter__函数和__exit__函数
new() 是一种负责创建类实例的静态方法,它无需使用 staticmethod 装饰器修饰,且该方法会优先__init__() 初始化方法被调用。
一般情况下,覆写__new__() 的实现将会使用合适的参数调用其超类的 super().new(),并在返回之前修改实例。例如:
class demoClass:
instances_created = 0
def __new__(cls,*args,**kwargs):
print("__new__():",cls,args,kwargs)
instance = super().__new__(cls)
instance.number = cls.instances_created
cls.instances_created += 1
return instance
def __init__(self,attribute):
print("__init__():",self,attribute)
self.attribute = attribute
test1 = demoClass("abc")
test2 = demoClass("xyz")
print(test1.number,test1.instances_created)
print(test2.number,test2.instances_created)
输出结果:
__new__(): ('abc',) {}
__init__(): <__main__.demoClass object at 0x0000025650FACF28> abc
__new__(): ('xyz',) {}
__init__(): <__main__.demoClass object at 0x000002565FFC4CF8> xyz
0 2
1 2
new() 通常会返回该类的一个实例,但有时也可能会返回其他类的实例,如果发生了这种情况,则会跳过对__init__() 方法的调用。而在某些情况下(比如需要修改不可变类实例(Python 的某些内置类型)的创建行为),利用这一点会事半功倍。比如:
class nonZero(int):
def __new__(cls,value):
return super().__new__(cls,value) if value != 0 else None
def __init__(self,skipped_value):
#此例中会跳过此方法
print("__init__()")
super().__init__()
print(type(nonZero(-12)))
print(type(nonZero(0)))
输出结果:
__init__()
那么,什么情况下使用__new__() 呢?答案很简单,在 init() 不够用的时候。
例如,前面例子中对 Python 不可变的内置类型(如 int、str、float 等)进行了子类化,这是因为一旦创建了这样不可变的对象实例,就无法在__init__() 方法中对其进行修改。
有些读者可能会认为,new() 对执行重要的对象初始化很有用,如果用户忘记使用 super(),可能会漏掉这一初始化。虽然这听上去很合理,但有一个主要的缺点,即如果使用这样的方法,那么即便初始化过程已经是预期的行为,程序员明确跳过初始化步骤也会变得更加困难。不仅如此,它还破坏了__init__() 中执行所有初始化工作”的潜规则。
注意,由于__new__() 不限于返回同一个类的实例,所以很容易被滥用,不负责任地使用这种方法可能会对代码有害,所以要谨慎使用。一般来说,对于特定问题,最好搜索其他可用的解决方案,最好不要影响对象的创建过程,使其违背程序员的预期。比如说,前面提到的覆写不可变类型初始化的例子,完全可以用工厂方法(一种设计模式)来替代。
现在我也找了很多测试的朋友,做了一个分享技术的交流群,共享了很多我们收集的技术文档和视频教程。
如果你不想再体验自学时找不到资源,没人解答问题,坚持几天便放弃的感受
可以加入我们一起交流。而且还有很多在自动化,性能,安全,测试开发等等方面有一定建树的技术大牛
分享他们的经验,还会分享很多直播讲座和技术沙龙
可以免费学习!划重点!开源的!!!
qq群号:1150305204【暗号:csdn000】
所有类的超类object,有一个默认包含pass的__init__()实现,这个函数会在对象初始化的时候调用,我们可以选择实现,也可以选择不实现,一般建议是实现的,不实现对象属性就不会被初始化。
init() 方法可以包含多个参数,但必须包含一个名为 self 的参数,且必须作为第一个参数。也就是说,类的构造方法最少也要有一个 self 参数,仅包含 self 参数的__init__() 构造方法,又称为类的默认构造方法。例如,仍以 TheFirstDemo 类为例,添加构造方法的代码如下所示:
class TheFirstDemo:
'''这是一个学习Python定义的第一个类'''
# 构造方法
def __init__(self):
print("调用构造方法")
# 下面定义了一个类属性
add = 'http://c.biancheng.net'
# 下面定义了一个say方法
def say(self, content):
print(content)
if __name__ == "__main__":
result = TheFirstDemo()
输出结果:
调用构造方法
在创建 result 这个对象时,隐式调用了我们手动创建的 init() 构造方法。
不仅如此,在__init__() 构造方法中,除了 self 参数外,还可以自定义一些参数,参数之间使用逗号“,”进行分割。例如,下面的代码在创建__init__() 方法时,额外指定了 2 个参数:
class CLanguage:
'''这是一个学习Python定义的一个类'''
def __init__(self,name,add):
print(name,"的网址为:",add)
#创建 add 对象,并传递参数给构造函数
add = CLanguage("C语言中文网","http://c.biancheng.net")
输出结果:
C语言中文网 的网址为: http://c.biancheng.net
可以看到,虽然构造方法中有 self、name、add 3 个参数,但实际需要传参的仅有 name 和 add,也就是说,self 不需要手动传递参数。