Files
Python_CookBook_repo/8.类与对象/9.创建一种新形式的类属性或实例属性.py
2025-09-10 16:12:45 +08:00

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重写