回顾实用属性的方法:
提倡使用getattr()
另一个使用实例的方法,用get、set的方式+property():
通过property()方法,使属性x和size挂钩
属性访问的魔法方法:
class C:
def __getattribute__(self, name):
print('getattribute')
# 使用 super() 调用 object 基类的 __getattribute__ 方法
return super().__getattribute__(name)
def __setattr__(self, name, value):
print('setattr')
super().__setattr__(name, value)
def __delattr__(self, name):
print('delattr')
super().__delattr__(name)
def __getattr__(self, name):
print('getattr')
使用上述类的举例:
注意调用的顺序:访问一个属性时,先访问__getattribute__(),如果没有找到,才调用__getattr__()
注意别陷入死循环:
举例:
写一个矩形类,默认有宽和高两个属性;
如果为一个叫square的属性赋值,那么说明这是一个正方形,值就是正方形的边长,此时宽和高都应该等于边长。
如果按图写法会出现死循环:原因实例化时,self.width=width调用__setattr__(),而其中else语句又调用了__setattr__()魔法方法
正确写法:
class Rectangle:
def __init__(self, width=0, height=0):
self.width = width
self.height = height
def __setattr__(self, name, value):
if name == 'square':
self.width = value
self.height = value
else:
self.__dict__[name] = value #或者调用基类的super()的__setattr__(name,value)方法,推荐这种方法。
def getArea(self):
return self.width * self.height
描述符(property的原理)
描述符就是将某种特殊类型的类的实例指派给另一个类的属性。
什么是特殊类型?至少实现以下3个方法之一:
__get__(self, instance, owner)
用于访问属性,它返回属性的值
__set__(self, instance, value)
将在属性分配操作中调用,不返回任何内容
__delete__(self, instance)
控制删除操作,不返回任何内容
class MyDescriptor:
def __get__(self, instance, owner):
print("getting...", self, instance, owner)
def __set__(self, instance, value):
print("setting...", self, instance, value)
def __delete__(self, instance):
print("deleting...", self, instance)
class Test:
x = MyDescriptor()
对以上定义的类进行测试:
注意观察每个魔法方法的返回值
再看一个演示:
class MyProperty: def __init__(self, fget=None, fset=None, fdel=None): self.fget = fget self.fset = fset self.fdel = fdel def __get__(self, instance, owner): return self.fget(instance) def __set__(self, instance, value): self.fset(instance, value) def __delete__(self, instance): self.fdel(instance) class C: def __init__(self): self._x = None def getX(self): return self._x def setX(self, value): self._x = value def delX(self): del self._x x = MyProperty(getX, setX, delX)
实例化调用:
举例:
先定义一个温度类,然后定义两个描述符类用于描述摄氏度和华氏度两个属性。
要求两个属性会自动进行转换,也就是说你可以给摄氏度这个属性赋值,然后打印的华氏度属性是自动转换后的结果。
class Celsius:
def __init__(self, value = 26.0):
self.value = float(value)
def __get__(self, instance, owner):
return self.value
def __set__(self, instance, value):
self.value = float(value)
class Fahrenheit:
def __get__(self, instance, owner):
return instance.cel * 1.8 + 32
def __set__(self, instance, value):
instance.cel = (float(value) - 32) / 1.8
class Temperature:
cel = Celsius()
fah = Fahrenheit()
实例化举例: