How do I “open up” 3rd party libraries' __slots__ -based object instances for attribute assignment?
假设我想为第三方库返回的对象实例分配新的属性,第三方库使用槽返回实例。
(例如,为不打算写回数据库的数据在sqlachemy的rowproxy行上设置一些值。)
因为这个实例有
这就是我想到的,proxy2可以工作,但是有没有更优雅/更简单的东西?它断裂的风险是什么?它能在python 3上工作吗(我在2.7上,但最终计划升级到3.x)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | class Slotted(object): __slots__ = ("a","b") def hello(self): print("hello %s" % (self.a)) def __init__(self, a="1", b="2"): self.a = a self.b = b def test_it(f): fname = f.__name__ print(" test_it(%s)" % (fname)) instances = [Slotted(a=11), Slotted()] try: li_test = [f(obj) for obj in instances] except Exception, e: print("%s.failure at instance modification:%s" % (fname, str(e)[0:100])) return for cntr, tgt in enumerate(li_test): try: tgt.cntr = cntr print("tgt.cntr:%s" % (tgt.cntr)) #do I still have my function? tgt.hello() tgt.a = 100 except Exception, e: print("%s.failure:%s" % (fname, str(e)[0:100])) return #test that an attribute assignment to the slots actually went there... for ori in instances: try: assert ori.a == 100 except AssertionError: print("%s.failure:original instance should have its slot-based attribute set to 100, but is still %s" % (fname, ori.a)) break print"%s.success" % (fname) class Proxy2(object): """this works, can it be improved on?""" def __init__(self, obj): self.__dict__["_obj"] = obj def __setattr__(self, attrname, value): if attrname in self._obj.__slots__: setattr(self._obj, attrname, value) else: self.__dict__[attrname] = value def __getattr__(self, attrname): try: return getattr(self._obj, attrname) except AttributeError: raise #subclass Slotted class Opener(Slotted): """fails w Slotted' object layout differs from 'Opener'""" pass class Opener2(Slotted): """fails w Slotted' object layout differs from 'Opener2'""" __slots__ = Slotted.__slots__ + ("__dict__",) #functions to modify the original instances def proxy_instances(obj): #this works return Proxy2(obj) def do_nothing(obj): #fails, normal, this is the baseline slots behavior return obj def modify_class(obj): #change the instance's class to a subclass that has a __dict__ obj.__class__ = Opener def modify_class2(obj): #change the instance's class to a subclass to add __dict__ to the __slots__ obj.__class__ = Opener2 for func in [do_nothing, modify_class, modify_class2, proxy_instances]: test_it(func) |
输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | test_it(do_nothing) do_nothing.failure:'Slotted' object has no attribute 'cntr' test_it(modify_class) modify_class.failure at instance modification:__class__ assignment: 'Slotted' object layout differs from 'Opener' test_it(modify_class2) modify_class2.failure at instance modification:__class__ assignment: 'Slotted' object layout differs from 'Opener2' test_it(proxy_instances) tgt.cntr:0 hello 11 tgt.cntr:1 hello 1 proxy_instances.success |
号
我将获取从第三方库返回的结果,并将其与我要存储的其他数据一起存储在我自己的某种类型的容器对象(如类或字典)中。
这种方法将更加明确,直接,易于理解,不那么棘手。因为它不是以一种巧妙的方式修补第三方数据,所以它更可能避免神秘的错误。