最近项目 进行重构一些代码:
写代码过程中会遇到一个问题,我希望通过内置类型生成的对象 添加属性,但是添加总是失败.
obj = object() obj.name = 'frank'
报错如下:
Traceback (most recent call last):File input, line 2, in
AttributeError: 'object' object has no attribute 'name'
普通对象绑定属性
我们知道python 语言的动态性, 是允许可以直接在是一个实例添加属性的。
class Animal: def eat(self): pass def sleep(self): pass
在python console 里面运行,可以看到是可以正常添加属性name
>>> animal = Animal() >>> animal.name='dog' >>> animal.name 'dog'
对比这两个类的不同点:
class Animal(object): def __init__(self): # print(sorted(dir(self))) res = set(dir(self)) - set(dir(object)) print(res) print('########' * 10) res = set(dir(object)) - set(dir(self)) print(res) pass
结果如下
{'__module__', '__weakref__', '__dict__'} ################################################ set()
发现self 多了三个魔术方法。 我们来重点关注 __dict__ 方法,我们知道一个对象的属性,一般放在 这个属性上面的。 但是object 的实例 没有这个属性。
def main(): obj = object() try: print(obj.__dict__) except AttributeError as e: print("ERROR:", e) animal = Animal() print(animal.__dict__, type(animal.__dict__)) animal.name = 'animal' animal.age = 10 print(animal.__dict__)
结果如下:
在 animal 对象中, 属性已经存放在了 __dict__ 中。 而obj对象就没有 __dict__ 这个属性。
而我有一个大胆的想法,有没有办法可以直接在obj 实例上把 __dict__ 绑定到这个实例obj 上面呢?
在python console 里面尝试下
>>> obj = object() >>> >>> obj.__dict__ = dict() Traceback (most recent call last): File "", line 1, inAttributeError: 'object' object has no attribute '__dict__' >>> setattr(obj,'__dict__',dict()) Traceback (most recent call last): File "", line 1, in AttributeError: 'object' object has no attribute '__dict__'
发现并不能绑定成功,python 里面不允许这样绑定。
在python中 所有内置对象 list,dict,set ,object 等等,这些内置对象,不允许在里面添加 属性,方法等。
这样做是一个不好的行为,一旦你对内置对象做了修改,其他引用内置对象的代码,是否会受到影响呢 ? 这是一个不可预期的行为。
解决方法比较好的做法:想绑定一个属性 在一个对象上面。可以自定义一个类。然后绑定属性,而不是在内置类型生成的对象进行绑定。
class Object(object): pass >>> obj = Object() >>> obj.__dict__ {} >>> obj.name='frank' >>> obj.__dict__ {'name': 'frank'} >>> obj.name 'frank'
从网上找到一个解决方案在内置类型上面可以添加方法 ,但是记得不要在生产环境这样玩!
import ctypes class PyObject(ctypes.Structure): class PyType(ctypes.Structure): pass ssize = ctypes.c_int64 if ctypes.sizeof(ctypes.c_void_p) == 8 else ctypes.c_int32 _fields_ = [ ('ob_refcnt', ssize), ('ob_type', ctypes.POINTER(PyType)), ] def sign(klass, func_name): def _(function): class SlotsProxy(PyObject): _fields_ = [('dict', ctypes.POINTER(PyObject))] name, target = klass.__name__, klass.__dict__ proxy_dict = SlotsProxy.from_address(id(target)) namespace = {} ctypes.pythonapi.PyDict_SetItem( ctypes.py_object(namespace), ctypes.py_object(name), proxy_dict.dict, ) namespace[name][func_name] = function return _ # method-1 @sign(list, 'mean') def mean(l): return sum(l) / len(l) # # @sign(list, 'max') def mean(l): return max(l) # method-2 sign(list, 'mean')(lambda l: sum(l) / len(l)总结
不要在python内置对象上面添加方法和属性。因为这种行为是不可预期的,最好的做法继承内置对象,在派生子类中添加属性,方法等。
参考文档知乎解决方案
禁果
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)