涉及知识点:容器方法、链表、描述器、类装饰器、反射
面向对象高阶业务运用二:将链表封装成容器,实现负向索引操作。
面向对象高阶业务运用三:自定义Property类,实现property功能。
需求分析
property是一个数据描述器。从类A的属性name被装饰的流程进行逻辑推导:
- 首先,
@property
装饰name -> 返回一个数据描述器property的实例,与标识符name绑定,原name方法成为property实例的一个动态属性; - 然后,
@name.setter
再次装饰第二个name,第一个name已经是property的实例了,装饰过后,第二个name方法再次成为property实例的第二个动态属性; - 最后,类A的name属性其实是被装饰两次后的一个数据描述器,这个数据描述器被动态绑定了访问和修改实例属性
_name
的两个方法。
class A:
def __init__(self, name):
self._name = name
@property # -> name=property(name)
def name(self):
print("I'm the property")
return self._name
@name.setter
def name(self, value):
self._name = value
@name.deleter
def name(self):
print('del name')
del self._name
if __name__ == '__main__':
a = A('Tom')
print(a.__dict__, a.__class__.__dict__)
print(a.name)
a.name = 'hah'
print(a.name)
print(a.__dict__)
del a.name
print(a.__dict__)
小结: 由上述分析可知,类A实例化后,通过a.name
访问实例属性_name
时,因为类属性name是一个数据描述器,自动触发__get__
方法,__get__
内部调用了动态绑定的访问实例属性_name
的第一个name方法;而通过a.name="Tom"
修改实例属性_name
时,触发__set__
方法,__set__
内部一定调用了被动态绑定的修改实例属性_name
的第二个name方法。
代码实现
由上述分析,自定义Property数据描述器,初步实现property类功能代码如下:
class Property:
def __init__(self, get_method):
self.get_method = get_method
self.set_method = None
def __set__(self, instance, value):
self.set_method(instance, value)
def __get__(self, instance, owner):
return self.get_method(instance)
def setter(self, method):
self.set_method = method
return self
class A:
def __init__(self, name, age):
self._name = name
self.__age = age
@Property
def age(self):
print("I'm the Property")
return self.__age
@age.setter
def age(self, value):
self.__age = value
if __name__ == '__main__':
a = A('Tom', 19)
print('~~~~~~~~~自定义Property类测试~~~~~~~~~~~~~~~~')
print(a.__dict__)
print(a.age)
a.age = 100
print(a.age)
print(a.__dict__)
执行结果:
{'_name': 'Tom', '_A__age': 19} I'm the Property 19 I'm the Property 100 {'_name': 'Tom', '_A__age': 100}
欢迎留言交流、讨论,觉得不错可以点波关注哦…