# 如果想要创建一个新形式的实例属性,可以以描述符类的形式定义其功能 # 所谓描述符就是以特殊方法__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重写