对象属性的访问顺序
使用点操作符访问属性时,obj.value
等价于getattr(obj, 'value')
,其查找顺序为
- 实例属性,等价于使用
obj.__dict__[value]
- 类属性,等价于使用
type(obj).__dict__[value]
- 基类属性,遍历
type(obj)
的基类查找属性
-
obj
的类里重写了__getattr__(self, item)
方法,正常的属性访问找不到属性时会调用这个方法。 -
obj
的类里重写了__getattribute__(self, item)
方法,属性访问时无条件调用这个方法,一般不重写
class Animal(object):
num_animal = 0
class Cat(Animal):
num_cat = 1
def __init__(self):
self.name = 'cat'
def __getattr__(self, item):
print('function __getattr__ called')
return None
cat = Cat()
print(Cat.__dict__) # {'__module__': '__main__', 'num_cat': 1, '__init__': <function Cat.__init__ at 0x0000022E613C4730>, '__getattr__': <function Cat.__getattr__ at 0x0000022E613C47B8>, '__doc__': None}
print(cat.__dict__) # {'name': 'cat'}
print(cat.name) # cat
print(cat.num_animal) # 0
print(cat.num_cat) # 1
print(cat.age) # None
# function __getattr__ called
描述符
python描述符:某种特殊的类的实例作为另一个类的属性。描述符是可以实现大部分python类特性中的底层魔法,包括@classmethod
,@staticmethd
,@property
甚至是__slots__
属性
这种类需满足实现了以下至少一种特殊方法
__get__(self, instance, owner)
__set__(self, instance, value)
__delete__(self, instance)
描述符分类:
-
描述符:类内定义了上面三个方法的任意一个,类的实例就会被认为是一个描述符
-
数据描述符:类同时定义了
__get__()
和__set__()
方法 -
非数据描述符:类只定义
__get__()
方法 -
只读数据描述符:类中同时定义
__get__()
和__set__()
方法,且在__set__()
方法中抛出AttributeError
异常
数据和非数据描述符的区别:如果一个实例的字典有和数据描述符同名的属性,那么数据描述符会被优先使用;实例的字典实现了非数据描述符的定义,那么这个字典中的属性会被优先使用
class NameDescriptor(object):
def __init__(self):
self.name = 'cat1'
def __get__(self,instance,owner):
print("function __get__ called")
print('self:', self)
print('instance:', instance)
print('owner:', owner)
return self.name
def __set__(self,instance,value):
print("function __set__ called")
print('self:', self)
print('instance:', instance)
print('value:', value)
self.name = value
class Cat(object):
name= NameDescriptor() # 实例作为属性
cat=Cat()
print(cat.name) # cat1
# self: <__main__.NameDescriptor object at 0x0000026B738834A8>
# instance: <__main__.Cat object at 0x0000026B738834E0>
# owner: <class '__main__.Cat'>
cat.name='cat2'
# function __set__ called
# self: <__main__.NameDescriptor object at 0x0000026B738834A8>
# instance: <__main__.Cat object at 0x0000026B738834E0>
# value: cat2
print(cat.name) # cat2
描述符使用@
class Lazyproperty:
def __init__(self,func):
self.func=func
def __get__(self, instance, owner):
print('这是我们自己定制的静态属性,r1.area实际是要执行r1.area()')
if instance is None:
return self
return self.func(instance) #此时你应该明白,到底是谁在为你做自动传递self的事情
class Room:
def __init__(self,name,width,length):
self.name=name
self.width=width
self.length=length
@Lazyproperty # area=Lazyproperty(area) 相当于定义了一个类属性,即描述符
def area(self):
return self.width * self.length
r1=Room('alex',1,1)
print(r1.area)
参考
https://blog.csdn.net/weixin_38729390/article/details/86755682
https://www.cnblogs.com/ls-2018/p/8819740.html