类的实例是以函数形式调用类对象来创建的。这种方法将创建一个新实例,然后该实例传递给类的__init__()方法。__init__()方法的参数包括新创建的实例self和在调用对象是提供的参数
class MyClass: def __init__(self,name): self.name = name def say(self): print(self.name) #类的实例化 mc = MyClass("aa")
【1】__init__() "构造器"方法
当类被调用,实例化的第一步是创建实例对象。一旦对象创建了,Python 检查是否实现了 __init__()方法。默认情况下,如果没有定义(或覆盖)特殊方法__init__(),对实例不会施加任何特别的操作.任何所需的特定操作,都需要程序员实现__init__(),覆盖它的默认行为。如果 __init__()没有实现,则返回它的对象,实例化过程完毕。
然而,如果__init__()已经被实现,那么它将被调用,实例对象作为第一个参数(self)被传递去,像标准方法调用一样。调用类时,传进的任何参数都交给了__init__()。实际中,你可以想 像成这样:把创建实例的调用当成是对构造器的调用。
总之
1、你没有通过调用 new 来创建实例,你也没有定义一个构造器。是 Python 为你创建了对象; 2、__init__(),是在解释器为你创建一个实例后调用的第一个方法,在你开始使用它之前, 这一步可以让你做些准备工作。
__init__()是很多为类定义的特殊方法之一。其中一些特殊方法是预定义的,缺省情况下,不进行任何操作,比如__init__(),要定制,就必须对它进行重载,还有些方法,可能要按需要去实现。
class Student: def __init__(self): self.name = "学生" self.age = 18 def say(self): print(self.name) s1 = Student() print(s1.name) print(s1.age) #当创建Student对象后,在没有调用__init__()方法的前提下,s1就默认拥有了2个属性name和age,原因是__init__()方法是在创建对象后,就立刻被默认调用了
class Student: def __init__(self,name,age): self.name = name self.age = age def say(self): print(self.name) s1 = Student("学生",18) print(s1.name) print(s1.age) ''' __init__()方法,在创建一个对象时默认被调用,不需要手动调用 __init__(self)中,默认有1个参数名字为self,如果在创建对象时传递了2个实参,那么__init__(self)中出了self作为第一个形参外还需要2个形参,例如__init__(self,x,y) __init__(self)中的self参数,不需要开发者传递,python解释器会自动把当前的对象引用传递进去 '''
【2】__new__() "构造器"方法
class A: def __init__(self): print("__init__方法") def __new__(cls, *args, **kwargs): print("__new__方法") return object.__new__(cls) A()
总结
1、__new__
至少要有一个参数cls,代表要实例化的类,此参数在实例化时由Python解释器自动提供
2、__new__
必须要有返回值,返回实例化出来的实例,这点在自己实现__new__
时要特别注意,可以return父类__new__
出来的实例,或者直接是object的__new__
出来的实例
3、__init__
有一个参数self,就是这个__new__
返回的实例,__init__
在__new__
的基础上可以完成一些其它初始化的动作,__init__
不需要返回值
4、我们可以将类比作制造商,__new__
方法就是前期的原材料购买环节,__init__
方法就是在有原材料的基础上,加工,初始化商品环节
class A: def __init__(self): print(self) print("__init__方法") def __new__(cls, *args, **kwargs): print(id(cls)) print("__new__方法") re = object.__new__(cls) print(re) return re #print(id(A)) #4324822888 a = A() #__new__方法 #<test1.A object at 0x103f1f6d8> #<test1.A object at 0x103f1f6d8> #__init__方法
【3】__del__() "解构器"方法
由于 Python 具有 垃圾对象回收机制(靠引用计数),这个函数要直到该实例对象所有的引用都被清除掉后才会执行。 Python 中的解构器是在实例释放前提供特殊处理功能的方法,它们通常没有被实现,因为实例很少被显式释放
创建对象后,python解释器默认会调用__init__()方法;当删除一个对象时,python解释器也会默认调用一个方法,这个方法为__del__()方法
import time class Animal(object): # 初始化方法 # 创建完对象后会自动被调用 def __init__(self, name): print('__init__方法被调用') self.__name = name # j解构方法 # 当对象被删除时,会自动被调用 def __del__(self): print("__del__方法被调用") print("%s对象马上被干掉了..."%self.__name) # 创建对象 dog = Animal("哈皮狗") # 删除对象 del dog cat = Animal("波斯猫") cat2 = cat cat3 = cat print(id(cat),id(cat2),id(cat3)) print("---马上 删除cat对象") del cat print("---马上 删除cat2对象") del cat2 print("---马上 删除cat3对象") del cat3 print("程序2秒钟后结束") time.sleep(2) ''' __init__方法被调用 __del__方法被调用 哈皮狗对象马上被干掉了... __init__方法被调用 4369544752 4369544752 4369544752 ---马上 删除cat对象 ---马上 删除cat2对象 ---马上 删除cat3对象 __del__方法被调用 波斯猫对象马上被干掉了... 程序2秒钟后结束 '''
注意:
- 当有1个变量保存了对象的引用时,此对象的引用计数就会加1
- 当使用del删除变量指向的对象时,如果对象的引用计数不会1,比如3,那么此时只会让这个引用计数减1,即变为2,当再次调用del时,变为1,如果再调用1次del,此时会真的把对象进行删除
跟踪实例
Python 没有提供任何内部机制来跟踪一个类有多少个实例被创建了,或者记录这些实例是些什 么东西 。如果需要这些功能,你可以显式加入一些代码到类定义或者__init__()和__del__()中去。最好的方式是使用一个静态成员来记录实例的个数。靠保存它们的引用来跟踪实例对象是很危险的, 因为你必须合理管理这些引用,不然,你的引用可能没办法释放(因为还有其它的引用)!
class InstCt: count = 0 def __init__(self): InstCt.count += 1 def __del__(self): InstCt.count -= 1 def howMany(self): return InstCt.count a = InstCt() b = InstCt() print(b.howMany()) # 2 print(a.howMany()) #2 del b print(a.howMany()) # 1 del a print(InstCt.count) # 0 #此时引用已经为0,如果再使用a.howMany()方法的话,会报错