Python学习笔记(十四):类特殊成员

Python学习笔记(十四):类特殊成员

类的特殊属性和特殊方法

  • Python学习笔记(十四):类特殊成员
  • 一.类特殊成员
  • 二.__new__()
  • 三.__repr__()
  • 四.__del__()
    • Python的垃圾回收机制
  • 五.__dir__()
  • 六.__dict__属性

一.类特殊成员

以双下划线 "__" 开头和结尾命名的成员(属性和方法),都被称为类的特殊成员(特殊属性和特殊方法)

Python类中的特殊成员,不能在类的外部直接调用,可以用类中的普通方法调用和修改,可以对类的特殊方法进行重写,实现特殊的功能

二.new()

__new__() 是负责创建类实例的静态方法

无需使用 staticmethod 装饰器修饰,优先 __init__() 初始化方法被调用

覆写__new__()将会使用合适的参数调用其父类的super().__new__(),并在返回之前修改实例

__new__(*args, **kwargs)

Create and return a new object.  See help(type) for accurate signature.
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__(): <class '__main__.demoClass'> ('abc',) {
     }
__init__(): <__main__.demoClass object at 0x02519690> abc
__new__(): <class '__main__.demoClass'> ('xyz',) {
     }
__init__(): <__main__.demoClass object at 0x025196F0> xyz
0 2
1 2
__new__()通常会返回该类的一个实例,有时也可能会返回其他类的实例,如果发生了这种情况,会跳过对__init__()方法的调用

class nonZero(int):
    def __new__(cls,value):
        return super().__new__(cls,value) if value != 0 else None
    def __init__(self,skipped_value):
        print("__init__()")    #__new__方法返回None会跳过此方法
        super().__init__()
print(type(nonZero(-10)))
print(type(nonZero(0)))
__init__()
<class '__main__.nonZero'>
<class 'NoneType'>

如果__new__方法返回None,则__init__方法不会被执行,并且返回值只能调用父类中的__new__方法
__new__方法的第一个参数是这个类,其余的参数在调用成功后全部传递给__init__方法初始化

class A:
	pass
class B(A):
	def __new__(cls):
		print("__new__方法被执行")
		return super().__new__(cls)
	def __init__(self):
		print("__init__方法被执行")
b = B()

__new__方法是传入类(cls),__init__方法传入类的实例化对象(self)
__new__方法返回的值是一个实例化对象,如果__new__方法返回None,则__init__方法不会被执行,并且返回值只能调用父类中的__new__方法,而不能调用毫无关系的类的__new__方法
在__init__() 不够用的时候使用 __new__() 

__new__()不限于返回同一个类的实例,很容易被滥用,需谨慎使用

Python中大量使用 __new__() 方法且合理的,是 MetaClass 元类

关于MetaClass 元类见之前笔记
Python学习笔记(十二):类和对象

三.repr()

直接输出类的实例化对象

class test:
    pass
TEST = test()
print(TEST)
<__main__.test object at 0x02919670>

默认情况下,得到的信息只有“类名+object at+内存地址”,对了解该实例化对象帮助不大
当输出某个实例化对象时,调用的就是该对象的__repr__()方法,输出的是该方法的返回值

所以print(TEST) 等同于print(TEST.__repr__()),输出的内存地址可能不同

Python中的每个类都包含__repr__() 方法
因为object 类包含 __reper__() 方法,而Python中所有的类都直接或间接继承自 object 类
 
默认情况下,__repr__() 会返回和调用者有关的 “类名+object at+内存地址”信息,可以通过在类中重写这个方法,实现输出想要的信息
class test:
    def __init__(self):
        self.name = "youchanwill"
        self.add = "you.com"
    def __repr__(self):
        return "test[name="+ self.name +",add=" + self.add +"]"
TEST = test()
print(TEST)
test[name=youchanwill,add=you.com]

__repr__() 方法默认情况下会返回当前对象的“类名+object at+内存地址”,如果对该方法进行重写,可以为其制作自定义的描述信息

四.del()

__del__() 方法用来销毁实例化对象

之前创建的类实例化对象后续不再使用,最好在适当位置手动将其销毁,释放其占用的内存空间(垃圾回收,简称GC)

大多数情况下,不需要手动进行垃圾回收,Python有自动的垃圾回收机制,能自动将不需要使用的实例对象进行销毁
手动和自动都会调用 __del__() 方法

class test:
    def __init__(self):
        print("调用__init__() 方法构造对象")
    def __del__(self):
        print("调用__del__() 销毁对象,释放其空间")
TEST = test()
del TEST
调用__init__() 方法构造对象
调用__del__() 销毁对象,释放其空间

Python的垃圾回收机制

Python采用自动引用计数(ARC)的方式实现垃圾回收机制

1.每个Python对象都会配置一个计数器,初始实例对象的计数器值都为 0,如果有变量引用该实例对象,其计数器的值会加 1,依次类推

2.每当一个变量取消对该实例对象的引用,计数器会减 1

3.如果一个对象的的计数器值为 0,表明没有变量引用该对象,说明程序不再需要,自动调用 __del__() 方法将其回收
class test:
    def __init__(self):
        print("调用__init__() 方法构造对象")
    def __del__(self):
        print("调用__del__() 销毁对象,释放其空间")
TEST = test()
test1 = TEST   #添加一个引用TEST对象的实例对象
del TEST
print("****")
调用__init__() 方法构造对象
****

1.构建TEST实例对象时先用test()调用该类中的 __init__()方法构造出一个该类的对象(计数器为 02.用TEST这个变量作为所建实例对象的引用(计数器值+13.又有一个test1变量引用TEST(相当于引用 CLanguage()),此时计数器再+1 

4.调用del TEST语句,只会导致计数器减 1 ,因为计数器值不为 0,因此 不会执行 __del__() 方法

class test:
    def __init__(self):
        print("调用__init__() 方法构造对象")
    def __del__(self):
        print("调用__del__() 销毁对象,释放其空间")
TEST = test()
test1 = TEST   #添加一个引用TEST对象的实例对象
del TEST
print("****")
del test1
print("----")
调用__init__() 方法构造对象
****
调用__del__() 销毁对象,释放其空间
----

执行 del test1 语句时,计数器变为 0,对于计数器为 0 的实例对象,自动将其视为垃圾进行回收
如果重写子类的 __del__() 方法(父类为非 object 的类),必须显式调用父类的 __del__() 方法,这样才能保证回收子类对象时,其占用的资源能被彻底释放

class test:
    def __del__(self):
        print("调用父类__del__() 方法")
class test1(test):
    def __del__(self):
        print("调用子类__del__() 方法")
test2 = test1()
del test2
调用子类__del__() 方法

调用父类的 __del__()方法,保证回收子类对象时,其占用的资源能被彻底释放

test3 = test()
del test3
调用子类__del__() 方法
调用父类__del__() 方法

五.dir()

dir() 函数,返回一个包含有所有属性名和方法名的有序列表

通过 dir() 函数,不仅仅输出本类中新添加的属性名和方法,还会输出从父类继承得到的属性名和方法名

dir() 函数的内部实现,是在调用参数对象 __dir__() 方法的基础上,对该方法返回的属性名和方法名做了排序

class test:
    def __init__ (self,):
        self.name = "youchanwill"
        self.add = "you.com"
    def say():
        pass
TEST = test()
print(dir(TEST))

class test:
    def __init__ (self,):
        self.name = "youchanwill"
        self.add = "you.com"
    def say():
        pass
TEST = test()
print(TEST.__dir__())

使用 __dir__() 方法和 dir() 函数输出的数据相同,顺序不同

六.__dict__属性

在Python类的内部,类属性还是实例属性,都以字典的形式进行存储,其中属性名作为key,值作为该key对应的value

 __dict__ 属性可以用类名或者类的实例对象来调用
 
用类名直接调用 __dict__,会输出该由类中所有类属性组成的字典
用类的实例对象调用 __dict__,会输出由类中所有实例属性组成的字典
class test:
	a = 10
    b = 16
    def __init__ (self,):
        self.name = "youchanwill"
        self.add = "you.com"
print(test.__dict__)  #通过类名调用__dict__

{
     'a': 10, '__dict__': <attribute '__dict__' of 'test' objects>, '__module__': '__main__', '__init__': <function test.__init__ at 0x02A97270>, '__weakref__': <attribute '__weakref__' of 'test' objects>, 'b': 16, '__doc__': None}

TEST = test() #通过类的实例对象调用 __dict__ 
print(TEST.__dict__)

{
     'name': 'youchanwill', 'add': 'you.com'}
具有继承关系的父类和子类,父类有自己的 __dict__,子类也有自己的 __dict__,不会包含父类的 __dict__

由类的实例对象调用 __dict__ 属性获取的字典,可以使用字典的方式对其中实例属性的值进行修改

class test:
	a = 10
    b = 16
    def __init__ (self):
        self.name = "youchanwill"
        self.add = "you.com"

TEST = test() 
print(TEST.__dict__) #通过类实例对象调用 __dict__
TEST.__dict__['name'] = "chanwill"
print(TEST.name)
print(TEST.__dict__) 
{
     'name': 'youchanwill', 'add': 'you.com'}
chanwill
{
     'name': 'chanwill', 'add': 'you.com'}

无法通过类似的方式修改类变量的值

你可能感兴趣的:(Python,Note,python)