Python札记40_黑魔法

浏览: 1042

Python的类具有很多的特殊方法,__init__()__new__()__str__(),还有其他的一些特殊用法,称之为“黑魔法”

  • 优化内存
    • 通过__slots__属性进行内存优化
    • 增加属性只能通过类属性来实现
    • 加快属性加载速度
  • 属性拦截
    • getattr()
    • setattr()

优化内存

每个类都有一个特殊的属性:.__dict__,它包含了当前类的类属性。

class Foo:
name = "xiaoming"

>>Foo.__dict__

结果:

mappingproxy({'__module__': '__main__',
'name': 'xiaoming',
'__dict__': <attribute '__dict__' of 'Foo' objects>,
'__weakref__': <attribute '__weakref__' of 'Foo' objects>,
'__doc__': None})
>>Foo.name   # 直接通过类调用实例
'xiaoming'

>>a = Foo() # 调永类,建立实例
>>a.__dict__ # 查看实例的__dict__属性,为空
{}
>>a.age = 12 # 创建实例的属性
>>a.__dict__ # dict属性不再是空的
{'age': 12}

>>dir(Foo) # 查看类的所有属性

['__class__',
'__delattr__',
'__dict__',
'__dir__', # 重点关注
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__gt__',
'__hash__',
'__init__',
'__init_subclass__',
'__le__',
'__lt__',
'__module__',
'__ne__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__',
'__weakref__',
'name']

小结

  • 带有双下滑线的__dict__都是特殊属性
  • 每个类都有__dict__属性,表示类的所有类属性
  • 建立的实例也有__dict__属性,刚开始是空的
  • 说明类和实例的__dict__属性是有区别的
  • 一个类可以创建无数个实例,类是实例的工厂
  • 每创建一个实例就会产生一个新的__dict__,当实例多的时候,很占内存,特殊属性__slots__产生了。

image.png

class Spring:
__slots__ = ("tree", "flower") # 创建 __slots__属性

>>dir(Spring) # __dict__属性消失
['__class__',
'__delattr__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__gt__',
'__hash__',
'__init__',
'__init_subclass__',
'__le__',
'__lt__',
'__module__',
'__ne__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__slots__',
'__str__',
'__subclasshook__',
'flower', # 多出来的两个属性,属于普通属性
'tree']
>>Spring.__slots__    # 类属性只有两个
('tree', 'flower')

>>Spring.tree = "zhangshu"
>>Spring.tree
'zhangshu'
>>Spring.tree = "yinxingshu" # 通过类属性进行赋值和修改
>>Spring.tree
'yinxingshu'

实例化之后

>>t = Spring()
>>t.__slots__ # 也是两个属性值
('tree', 'flower')

>>f = Spring()
>>f.__slots__
('tree', 'flower')

>>id(t.__slots__)
>>id(f.__slots__)
1554379682696 # 不同实例的__slots__在内存中是同一个

image.png

小结

  • 实例的__slots__与类的完全一样,和__dict__不同
  • 不同实例的__slots__在内存中是同一个
  • 增加实例不增加__slots__属性
>>t.tree= "guangyulan"   # 不能通过实例修改属性的值

AttributeError Traceback (most recent call last)
<ipython-input-21-bf9f758ef89e> in <module>
----> 1 t.tree= "guangyulan"

AttributeError: 'Spring' object attribute 'tree' is read-only # 类属性是只读的
  • 对于实例属性,类的静态数据是只读的,不能修改
  • 只能通过类属性才可以修改
  • 尚未赋值的属性,能够通过实例进行赋值,看下面的例子:
>>t.flower = "juhua"
>>t.flower
'juhua'

>>Spring.flower # 实例属性的值并没有传到类属性中
<member 'flower' of 'Spring' objects>

>>Spring.flower = "zhizhihua" # 通过类属性赋值会影响实例属性的值:说明类属性对实例属性具有决定作用
>>t.flower
'zhizhihua'
  • 对于实例而言,通过类定义的属性都是只读的
  • 类的静态数据不能修改,只能通过类属性才可以进行修改
  • 类属性对实例具有决定作用

属性拦截

当访问某个类或者实例属性的时候,如果不存在,则会报错出现异常,出现异常就要处理。Python中具有属性拦截功能的方法(特殊方法,带上双下划线):

方法作用
setattr(self,name,value)给某个name赋值,进行调用
getattr(self,name)访问某个name,如果它不存在,调用此方法
getattribute(self,name)当name访问时候自动被调用,name存在与否,都要调用
delattr(self,name)如果删除name,调用这个方法

class A:
def __getattr__(self,name):
print("you use getattr")

def __setattr__(self,name,value):
print("you use setattr")
self.__dict__[name] = value

>>a = A()
>>a.x # a没有x属性,调用getattr方法
you use getattr

>>a.x = 5 # 此时属性x已经保存在__dict__中,可以进行调用
you use setattr

image.png

class NewRectangle:
def __init__(self): # 初始化函数
self.width = 0
self.length = 0

def __setattr__(self, name, value): # 给name属性赋值的时候进行调用
if name == "size": # r.size = 30, 40
self.width, self.length = value # value = (30, 40)
else:
self.__dict__[name] = value

def __getattr__(self,name): # 访问name属性,如果不存在则调用
if name == "size":
return self.width, self.length
else:
raise AttributeError

if __name__ == "__main__":
r = NewRectangle()
# size属性进行访问;不存在,调用__getattr__方法
r.width = 3 # 两个属性值
r.length = 4
print(r.size) # size属性不存在,调用__getattr__方法;返回的就是上面两个属性值
# 对size属性进行赋值,调用__setattr__方法
r.size = 30, 40
print(r.width)
print(r.length)

结果:
(3, 4)
30
40
推荐 0
本文由 皮大大 创作,采用 知识共享署名-相同方式共享 3.0 中国大陆许可协议 进行许可。
转载、引用前需联系作者,并署名作者且注明文章出处。
本站文章版权归原作者及原出处所有 。内容为作者个人观点, 并不代表本站赞同其观点和对其真实性负责。本站是一个个人学习交流的平台,并不用于任何商业目的,如果有任何问题,请及时联系我们,我们将根据著作权人的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。

0 个评论

要回复文章请先登录注册