66 lines
2.4 KiB
Python
66 lines
2.4 KiB
Python
# 如果想要创建一个新形式的实例属性,可以以描述符类的形式定义其功能
|
|
# 所谓描述符就是以特殊方法__get__; __set__; __delete__的形式实现了三个核心属性的访问操作
|
|
class Integer:
|
|
# 存储名称
|
|
def __init__(self,name):
|
|
self.name = name
|
|
|
|
# 如果没有输入目标对象,就返回自身,如果输入了获取目标对象的__dict__属性里key是name的条目
|
|
def __get__(self, instance, cls):
|
|
# 这里的描述比较复杂
|
|
# ,如果instance是空的,说明访问的是类,那么我们就要返回类本身
|
|
# 如果instance不是空的,那说明是实例对象,需要返回实例的字段
|
|
if instance is None:
|
|
return self
|
|
else:
|
|
return instance.__dict__[self.name]
|
|
|
|
# 如果设置输入不是整数,就报错.否则往目标对象的__dict__属性中写入{name: value}
|
|
def __set__(self, instance, value):
|
|
if not isinstance(value, int):
|
|
raise TypeError('value must be an integer')
|
|
print("Set {} to {}".format(self.name, value))
|
|
instance.__dict__[self.name] = value
|
|
|
|
# 将key为name的属性从目标对象的__dict__中移除
|
|
def __delete__(self, instance):
|
|
del instance.__dict__[self.name]
|
|
|
|
class Point:
|
|
# 先设置x和y(其实是初始化self.x和self.y)
|
|
x = Integer('x')
|
|
y = Integer('y')
|
|
|
|
# 实例化的时候调用
|
|
def __init__(self,x,y):
|
|
# 调用Integer的__set__方法来给元素赋值
|
|
self.x = x
|
|
self.y = y
|
|
|
|
p = Point(2,3)
|
|
p.x
|
|
p.y
|
|
# 很明显,如果我首先初始化一个b,然后对b使用__set__方法指定p作为插入对象,那这个类就有麻烦了
|
|
b = Integer('b')
|
|
print("\n{:-^18}".format("这里有脏东西"))
|
|
b.__set__(p, 3)
|
|
print("{:-^18}\n".format("这里有脏东西"))
|
|
# 这说明一件事,如果对实例的__dict__属性进行操作,那么我们就可以搞到一个动态类
|
|
|
|
# 初始化一定要在实例化之前进行,否则就只能用拙劣的__set__方法了,这就比较丑陋了
|
|
class Point:
|
|
# 实例化的时候调用
|
|
def __init__(self, x, y):
|
|
# 先设置x和y
|
|
self.x = Integer('x')
|
|
self.y = Integer('y')
|
|
# 调用Integer的__set__方法来给元素赋值
|
|
self.x.__set__(self, x)
|
|
self.y.__set__(self, y)
|
|
|
|
p = Point(2,3)
|
|
p.x
|
|
p.y
|
|
|
|
# 当然,这样做会很爽,但如果你只需要给某个特定类中的一种属性加东西,最好还是使用property重写
|