object.

    技术2022-07-10  179

    __new__

    __new__主要负责创建实例对象

    class Person(object): def __new__(cls, *args, **kw): return super().__new__(cls) def eat(self): print('eat something!') class Person(object): def eat(self): print('eat something!')

    1.为什么__new__的第一个参数是cls而不是self。因为调用__new__的时候,实例对象还没有被创建,__new__是一个静态方法。第一个参数cls表示当前的class 2.绝大多数时间不需要我们实现__new__方法,python已经帮我们实现:使用父类的__new__()方法来创建对象并返回。所以上述的代码是等价的。

    __new__与__init__的参数关系

    __new__方法如果返回cls的对象(return super().__new__(cls)),则对象的__init__方法将自动被调用,相同的参数*args和**kwargs将被传入__init__方法。也既是说__new__和__init__方法共享同名的参数,除了第一个从cls变成了self。 如果__new__没有返回实例对象,则__init__方法不会被调用。

    class Person(object): def __new__(cls, age): print(f"__new__:age:{age}") return super().__new__(cls) def __init__(self, age): print(f"__init__:age:{age}") self.age = age p = Person(100) __new__:age:100 __init__:age:100

    在调用Person(100)的时候,__new__中的age被赋值为100,__new__结束后会自动调用__init__,并把age传入给__init__。

    __new__比__init__参数多

    class Person(object): def __new__(cls, age): print(f"__new__:age:{age}") return super().__new__(cls) def __init__(self): print(f"__init__:age:{age}") self.age = age p = Person(100) __new__:age:100 Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: __init__() takes 1 positional argument but 2 were given

    如果我们在__new__中有传入age,而在__init__中没有传入age则会报错:__init__定义时只给了一个固定位置的参数self但是却给了两个参数。很显然是__new__方法直接调用了__init__方法,并将self,age作为参数。

    __new__比__init__参数少

    class Person(object): def __new__(cls, age): print(f"__new__:age:{age}") return super().__new__(cls) def __init__(self,age, name): print(f"__init__:age:{age}") self.age = age >>> p = Person(100) __new__:age:100 Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: __init__() missing 1 required positional argument: 'name'

    实例初始化本质是向__new__中传参

    class Person(object): def __new__(cls, age, name): print(f"__new__:age:{age}") return super().__new__(cls) def __init__(self,age): print(f"__init__:age:{age}") self.age = age >>> p = Person(100) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: __new__() missing 1 required positional argument: 'name'

    同样的道理,如果__init__有三个参数cls,age,name,而我们在初始化时(p = Person(100))只给了一个age参数,则会报错。所以没有打印print(f"__new__:age:{age}")。 这说明我们在初始化对象时Person(100)的参数,都会先经过__new__方法。

    只用__new__而不用__init__来实例化对象实例

    class Person(object): def __new__(cls, age): print('__new__() called.') obj = super().__new__(cls) obj.age = age return obj a = Person(100) a.age # 100

    当然这种方法是不建议的,我们通常使用以下方法:

    class Person(object): def __init__(self, age): self.age = age a = Person(100) a.age # 100

    这种既我们常用的定义类写的方法,其实完整的写法是:

    class Person(object): def __new__(cls, *args, **kwargs): return super().__new__(cls) def __init__(self, age): self.age = age a = Person(100) a.age # 100

    参考: https://www.codevoila.com/post/68/new-and-init-in-python

    super()

    class Person(object): def __new__(cls, age): # return object.__new__(cls) # return super(Person, cls).__new__(cls) return super().__new__(cls) def __init__(self, age): self.age = age Person(100)

    object.__new__(cls) 调用父类来创建对象实例 return super().__new__(cls) super()方法返回的既是object对象 return super(Person, cls).__new__(cls) super实际传入了两个参数,第一个是本类的类型(Person),第二个是类型(cls),cls既父类的类

    在类的继承中,__init__方法里,我们通常写的是super(类名,self),而这里是super(类名,cls),从self变成cls的原因是,要调用父类的__new__方法,这时还没有对象实例产生。

    应用

    在__new__中判断参数

    class Person(object): def __new__(cls, age): if age>100: return "年龄age需小于100,对象未创建" else: return super().__new__(cls) def __init__(self, age): self.age = age Person(200) '年龄age需小于100,年龄age需小于200,对象未创建'

    在__init__中判断参数

    class Person(object): def __new__(cls, age): print("对象已经创建") return super().__new__(cls) def __init__(self, age): if age>100: print("wrong age,参数初始化失败") else: self.age = age p = Person(200) 对象已经创建 wrong age,参数初始化失败 p.age Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'Person' object has no attribute 'age'

    使用__new__和__init__的区别是一个在创建对象之前判断,一个在创建对象之后判断

    参考: https://docs.python.org/3/reference/datamodel.html#object.new https://www.python.org/download/releases/2.2/descrintro/#cooperation

    object.__new__(cls[, ...]) 创建一个类的实例.

    class A(object): def __new__(cls): return object.__new__(cls)

    __init__有一个参数self,就是这个__new__返回的实例,__init__在__new__的基础上可以完成一些其它初始化的动作,__init__不需要返回值

    1.详解

    1.__new__()负责创建实例化对象,__init__()负责初始化(设置属性和方法) 2.__new__()始终是静态方法,即使没有加上静态方法装饰器

    默认调用父类的__new__()方法来创建实例,python中所有的类都继承object.不可调用自身的__new__方法,这样会造成死循环,因为会执行自己的__new__()方法 class Foo(object): def __new__(cls,*args,**kwagrs): # cls指代当前类 return super().__new__(cls,*args,**kwagrs) # 默认调用父类的__new__()方法 # return Foo.__new__(object,*agrs,**kwagrs) # 会再跳到第二行,死循环 # return 123 # print(Foo(),type(obj)) # 打印结果:123 <class 'int'>,返回的是什么就是构造了什么累

    1.1 如果父类中没有,则继续追溯到祖先类

    class A(object): pass class B(A): pass class C(B): def __new__(cls,*args,**kwargs): return super().__new__(cls, *args,**kwargs) # return B.__new__(cls, *args,**kwargs) 发现没有,则继续往上找A # return A.__new__(cls, *args,**kwargs) # 发现没有继续往上找object # return object.__new__(cls, *args,**kwargs) # object类中有

    1.3 通过__new()__可以返回其他类的实例

    class Foo(object): def __new__(cls,*args,**kwagrs): return object.__new__(cls,*args,**kwagrs) def __init__(self,name): self.name = name class Bar(object): def __new__(cls,*agrs,**kwagrs): return object.__new__(Foo,*agrs,**kwagrs) bar = Bar() print(type(bar)) #foo其实是Stranger类的实例。

    2.__new__()和__init__() 先执行__new__创建实例,再执行__init__()设置属性和方法

    class A: def __init__(self, name): print('执行 __init__') self.name = name def __new__(cls, *args, **kw): print('执行 __new__) return object.__new__(cls) # 这里和使用super()方法是一样的 a = A('wang')
    Processed: 0.014, SQL: 9