本章来探讨一下Python类的self作用,以及__init__,__new__。
为什么是探讨,不是学习,因为菜🐎;
先看个例子:
class Example: def animal(self): self.dog = "大黄" def Dog(self): print(self.dog) if __name__ == "__main__": example = Example() example.Dog()
❝运行报错:AttributeError: 'Example' object has no attribute 'dog'
❞
这个报错是告诉你,Example类没有这个属性。
先来看看self
self是一个惯用的命名约定,它代表类的实例对象自身。在类的方法中,self作为第一个参数传递,并用于引用该实例对象的属性和方法。
❝注意了,这里说到了实例对象
❞
当定义一个类并创建该类的实例时,每个实例都有自己的状态(即属性)和行为(即方法)。在方法中,可以使用self来引用当前实例对象的属性和方法。
❝也就是上述代码中的self.dog。
❞
白话文一点就是我在这个类中定义了创建了一个该类的实例后,我就可以全局使用。不论定义多少个方法,都可以使用这个实例。
如何解决,找不到属性的问题?
❝1、返回self.dog这个值
2、写一个方法中可以规避这个问题 3、写到__init__中
4、动态添加
❞
1、2不说了,看__init__。以及动态加载
写到__init__中
class Example: def __init__(self) -> None: self.dog = "大黄" def Dog(self): print(self.dog) if __name__ == "__main__": example = Example() example.Dog()
这样就没啥问题了。但是还有一种写法。
class Example: def __init__(self, dog) -> None: self.dog = dog def Dog(self): print(self.dog) if __name__ == "__main__": example = Example("大黄") example.Dog()
这样也是OK的,二者有什么区别?
def __init__(self, dog)
这种写法有一个形参。所以在实例化的时候必须要传参。
动态加载
class Example: def set_name(self, dog): self.dog = dog def Dog(self): print(self.dog) if __name__ == "__main__": example = Example() example.set_name("大黄") example.Dog()
__init__方法用于初始化实例的属性,也叫初始化方法。
在使用过程中,我们只知道__init__用于初始化。如果没有在__init__中定义的属性,就不能在其他方法中被使用。
❝实例化分为两阶段:
○ 构造实力过程,实例化 先调__new__
○ 初始化过程,初始化 再调__init__
❞
这里提到了__new__。
再来看看实例对象。
前面说了self的作用。那么它什么时候作为第一个参数传递?
class Person: def __init__(self, name): self.name = name def say_hello(self): print(f"Hello, my name is {self.name}.") person = Person('清安') # 相当于Person.say_hello(person) person.say_hello()
❝person.say_hello()相当于调用Person类的say_hello方法,并把person实例对象自动作为第一个参数传递给该方法。也就是说,self在say_hello方法中会接收到person对象的引用,从而可以访问person对象的属性和方法。这个过程中,person对象被传递给了self。
❞
所以
class Person: def __init__(self, name, age=18): print('__init__ id is ',id(self)) self.name = name self.age = age def show(self): # self永远指向当前实例自身,this print(f"show id is {id(self)}") print(f"{self.name} is {self.age} yeas old!") pe = Person('拾贰', 20) # 实例化 pe.show() # 相当于show(pe) 解释器会把pe赋值给self print(f"id is {id(pe)}")
❝__init__ id is 2064008937088 show id is 2064008937088
拾贰 is 20 yeas old!
id is 2064008937088
❞
好了,已经知道self的由来了
__init__小结
❝__init__方法中初始化了self.属性名,使其成为实例的属性。
❞ ❝self在Python类中是一个引用,用于指代实例对象本身。通过self,您可以在类的方法中访问和操作实例对象的属性和方法。
❞
最后来个错误的例子再次熟悉熟悉
class Person: def __init__(self, age=18): self.age = age def show(self): return 1 pe = Person('清安', 20).show() print(pe)
TypeError: __init__() takes from 1 to 2 positional arguments but 3 were given 类型错误:__init__()接受1到2个位置参数,但给定了3个
再来看看__new__
__init__方法在创建实例对象时自动调用,且在该方法中定义的属性会被添加到实例对象中。
前面也提到了几个注意点,结合这里的自动调用,我们就很有必要看看__new__了。
❝_new__方法在类实例化时起到了重要的作用,它负责创建并返回类的实例对象。在创建实例对象之前,__new__方法被调用,它接收类作为第一个参数,并返回一个新的实例对象。
❞
当你不手动创建的时候,它就自动,但你手动的时候,那就看看下面的例子。
class Example: def __new__(cls): instance = super().__new__(cls) instance.name = "清安" # 手动创建实例属性name return instance def print_name(self): print(f"Name: {self.name}") example = Example() example.print_name() # Name: 清安
❝cls参数代表的是类本身也就是Example
❞ ❝当调用Example()时,实际上是调用了Example类的构造方法__new__,它会创建一个Example类的实例对象,并把这个实例对象的引用返回。
❞
上述中return了instance,所以,我们在self的时候其实就是example实例对象的引用。这也就是self其实也就是一个参数,仅此而已。
在代码中我们instance.name = "清安",也就等价于在__init__中写了self.name = '清安'。
而代码中是super(),super()函数用于获取当前类的父类,并返回一个代理对象,可以调用父类的方法和属性。在这个例子中,super().__new__方法,并传递当前类cls作为参数。
来复刻一下object has no attribute。
class Example: def __new__(cls): instance = super().__new__(cls) instance.name = "清安" # 手动创建实例属性name return instance def print_name(self): print(f"Name: {self.name}") # def print_age(self): # print(f"Age: {self.age}") # 尝试访问未定义的属性age example = Example() example.print_name() example.print_age() # 报错:AttributeError: 'Example' object has no attribute 'age'
__new__与__init__区别
__new__方法和__init__方法在类实例化时起到不同的作用。__new__方法负责创建并返回实例对象,而__init__方法负责对实例对象进行初始化。
个题外话的例子
class ClassA: def __new__(cls): instance_b = ClassB() # 在__new__方法中创建ClassB的实例 instance_a = super().__new__(cls) instance_a.class_b = instance_b # 将ClassB的实例赋值给当前类的属性 return instance_a def __init__(self): pass class ClassB: def __init__(self): self.name = "B" def __str__(self): return self.name obj_a = ClassA() print(obj_a.class_b) # 输出:B
❝此处没啥说的
❞
class Example: def __init__(self,age=0) -> None: self.age = age def print_name(self): self.age += 1 return self example = Example().print_name() print(example.age)
❝上述代码注释return self,运行即AttributeError: 'NoneType' object has no attribute 'age'
❞