class DeferredCall(object): """Call that is evaluated lazyly""" def __init__(self,func,*func_args,**func_kwargs): self.func = func self.func_args = func_args self.func_kwargs = func_kwargs def resolve(self): # called by JsON encoder return self.func(*self.func_args,**self.func_kwargs) a = DeferredCall(lambda: 1) a # gives <[module].DeferredCall at 0x1e99410> a.resolve() # gives 1
现在,功能强大的用户需要更多功率.即,直接对类进行 *** 作而不是它们所代表的值.根据python data model,这应该像实现魔术方法一样简单,例如__add __,__ len__等.
添加
def __add__(self,other): return self.resolve() + other
要么
def __add__(self,other): return self.resolve().__add__(other)
会正确地给我一个3 == 4.
但是,实施所有魔法方法有点过分了.所以我尝试使用__getattr__
def __getattr__(self,item): return getattr(self.resolve(),item)
这适用于.__ mul __(3)== 3但是对于* 3 == 3,其中包含TypeError:*不支持的 *** 作数类型*:’DeferredCall’和’int’.
那么还有其他方法可以将运算符转发给包含的值吗?理想情况下,没有冒险以编程方式编写代码或__getattribute__的麻烦.
解决方法 发布我的解决方案以防任何其他人需要它.大多数“内置” *** 作(如*或len)不会使用__getattr [ibute] __,按设计.我已经决定以编程方式创建方法
class DeferredCall(object): def __init__(self,**func_kwargs): self.func = func self.func_args = func_args self.func_kwargs = func_kwargs def resolve(self): return self.func(*self.func_args,**self.func_kwargs) # magic must be resolved explicitly # self other - resolve in reflected order to allow other to resolve as well for so_magic in [("lt","gt"),("le","ge"),("eq","eq"),("ne","ne"),("add","radd"),("sub","rsub"),("mul","rmul"),("div","rdiv"),("truediv","rtruediv"),("floordiv","rfloordiv"),("mod","rmod"),("divmod","rdivmod"),("pow","rpow"),("lshift","rlshift"),("rshift","rrshift"),("and","rand"),("xor","rxor"),("or","ror")]: for func_name,refl_name in [(so_magic[0],so_magic[1]),(so_magic[1],so_magic[0])]: exec("def __%(fname)s__(self,other):\n\ttry:\n\t\tres = other.__%(rname)s__(self.resolve())\n\t\tif res == NotImplemented:\n\t\t\traise AttributeError\n\texcept AttributeError:\n\t\tres = self.resolve().__%(fname)s__(other)\n\treturn res" % {"fname": func_name,"rname": refl_name}) # regular magic - immutable only for magic in ("str","nonzero","unicode","getattr","call","len","getitem","missing","iter","reversed","contains","getslice","neg","pos","abs","invert","complex","int","long","float","oct","hex","index"): exec("def __%(fname)s__(self,*args,**kwargs):\n\treturn self.resolve().__%(fname)s__(*args,**kwargs)" % {"fname": magic})
基本上,魔术方法必须分为两类:自足方法和上下文方法.
自包含的是直接创建的,解析调用并执行魔术方法.例如,len被解析为:
def __len__(self,**kwargs): return self.resolve().__len__(*args,**kwargs)
上下文必须反转呼叫,例如“大于”其他实际检查其他人是否“小于”自我.如果两个对象都是延迟调用,那么这是必需的,允许其他对象自行解析;否则,许多方法都会引发TypeError.直接评估仅在其他人没有倒置版本时使用.
def __gt__(self,other): try: res = other.__lt__(self.resolve()) if res == NotImplemented: raise AttributeError except AttributeError: res = self.resolve().__gt__(other) return res
有些调用可能会更有效地实现,因为python使用了一些技巧(这正是我的问题首先出现在哪里).例如,乘法可以利用交换性:
def __mul__(self,other): """self * other""" return other * self.resolve()总结
以上是内存溢出为你收集整理的python – 懒惰评估:将 *** 作转发到递延值全部内容,希望文章能够帮你解决python – 懒惰评估:将 *** 作转发到递延值所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)