Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/python-2.7/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/jquery-ui/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
python中的方法委派_Python_Python 2.7_Reflection_Delegation_Message Passing - Fatal编程技术网

python中的方法委派

python中的方法委派,python,python-2.7,reflection,delegation,message-passing,Python,Python 2.7,Reflection,Delegation,Message Passing,我正在编写一个用于编排AWS集群的小框架,其中有一些常见的层次模式反复出现。其中一种模式是将实例集合收集到一个更大的对象中,然后将一些方法直接委托给所有实例。因此,我没有一次又一次地复制和粘贴相同的样板代码,而是使用以下模式对其进行了抽象: def __getattr__(self, item): if not item in self._allowed_items: raise NonDelegatableItem def delegator():

我正在编写一个用于编排AWS集群的小框架,其中有一些常见的层次模式反复出现。其中一种模式是将实例集合收集到一个更大的对象中,然后将一些方法直接委托给所有实例。因此,我没有一次又一次地复制和粘贴相同的样板代码,而是使用以下模式对其进行了抽象:

def __getattr__(self, item):
    if not item in self._allowed_items:
        raise NonDelegatableItem

    def delegator():
        for instance in self.all_instances:
            getattr(instance, item)()

    return delegator

是否有更好的方法或模式来完成委托?

\uuuu getattr\uuuu
在遍历整个类hirarchy且未找到属性时调用。因此,最好只生成一次方法并将其存储在类中。那么,下次找到该方法所需的时间就更少了

>>> X.a

Traceback (most recent call last):
  File "<pyshell#15>", line 1, in <module>
    X.a
AttributeError: class X has no attribute 'a'
>>> x.a
new delegator
<function delegator at 0x02937D30>
>>> x.a
<bound method X.delegator of <__main__.X instance at 0x028DBC60>>
>>> X.a
<unbound method X.delegator>

我一直在研究这个问题,发现了两个解决方案。使用decorator更改类并创建委托器,或者为委托器使用描述符。我从第一个开始,然后发展到我更喜欢的第二个,所以我将从它开始。两者都可以在这里找到:带doctests:)

--编辑--

对于任何感兴趣的人,我将此作为一个图书馆:

gist实现中存在bug,人们在github上对此做出了贡献,pypi项目已更新,gist未更新。我强烈建议您使用pypi版本

使用描述符 描述符是可以获取和设置的东西。在本例中,我们对描述符的可获取性感兴趣。委托描述符的定义如下

类委派给:
定义初始化(self、to、method=None):
self.to=to
self.method=方法
定义获取(self、obj、objecttype):
如果self.method不是None:
返回getattr(getattr(obj,self.to),self.method)
对于obj.\uuuuu类\uuuuu.\uuuuu dict\uuuuuuu.items()中的方法v:
如果v是self:
self.method=方法
返回getattr(getattr(obj,self.to),方法)
是这样使用的

Foo类:
上限=委托给('v')
__len_u;=被委派('l')
__iter_u_;=委托给('l')
定义初始值(self,v,l):
自我评价,自我评价
self.l=l
要调用描述符,只需调用方法
Foo('hello').upper()
。魔法方法也能工作
len(Foo(“”,[1,2,3,4])
返回4。上面的gist链接有一个更强大的实现,但基本原理是一样的

使用装饰器 每次您需要以重复的方式更改类行为时,装饰者都是候选对象。在这种情况下,装饰器将在类中调用
setattr
,以创建委托器

def委托(到,*方法):
def dec(klass):
def创建委托人(方法):
def授权人(自身、*args、**kwargs):
obj=getattr(自,至)
m=getattr(对象,方法)
返回m(*args,**kwargs)
返回授权人
对于m in方法:
setattr(klass,m,创建委托人(m))
返回克拉斯
返回十二月
用法也很简单,只需根据需要多次装饰课堂即可。decorator将就地修改类,以便返回相同的类

这里有一个用法

@delegate('v'、'upper'、'lower')
Foo类:
定义初始值(self,v):
自我评价,自我评价
委托方法的调用也是透明的
Foo('hello').upper()
。我更喜欢第二个,因为它对我来说更地道。decorator在支持多个方法方面具有优势,但这也可以在描述符表单上实现

再一次,我真的建议您看看要点:docstring中有大量的示例。只需修改它们并执行脚本即可

--编辑--

对于任何感兴趣的人,我都会制作一个pip包

--编辑--

gist实现中存在bug,人们在github上对此做出了贡献,pypi项目已更新,gist未更新。我强烈建议您使用pypi版本


关于

在中使用
而不是
,这是惯用的用法。我想说的是
方法
。很好。我没有想到在这一过程中也会分配这个方法。很好。
\uuuu getattr\uuuu
检查方法\u name\u是\u delegator
的调用是否应该省略,这样就不会再次查找不可删除的属性(毕竟,有人可以通过
除了AttributeError
之外的
捕获
不可删除的项
)?第二个调用可以放在
delegator
之外,并带有一个
非可删除项:def delegator(self,*args,**kw):raise NonDelegatableItem(…
所以可委派性只检查一次。@TobiasKienzler听起来很合理。你可以用它创建一个新的答案。我们可以在以后讨论。@User Hm,StackOverflow应该有一个github式的“fork answer”选项;)实际上我很快就和你谈过了:你的
setattr(cls,方法名称,delegator)
已经负责防止再次调用
\uuuuuuGetAttr\uuuuuuuuuu
(我把它和总是调用的
\uuuuuuuuuGetAttribute\uuuuuuuuuuuuuuuuuu
混淆了),通过拆分
检查方法\u name\u is\u delegator
-签入
定义delegator
,可以取消动态修改
\u允许的\u项的选项
。因此,唯一剩下的建议是省略
检查方法\u name\u is\u delegator的调用,尽管这会略微增加非授权人的绩效。。。
class NonDelegatableItem(AttributeError):
    pass

class X:
    def __getattr__(self, method_name):
        self.check_method_name_is_delegator(method_name)
        return self.create_delegator(method_name)

    def check_method_name_is_delegator(self, method_name):
        if method_name not in self._allowed_items:
            raise NonDelegatableItem('{} can not be delegated'.format(method_name))

    @classmethod
    def create_delegator(cls, method_name):
        print 'new delegator'
        def delegator(self, *args, **kw):
            self.check_method_name_is_delegator(method_name)
            for instance in self.all_instances:
                getattr(instance, method_name)(*args, **kw)
        setattr(cls, method_name, delegator)
        return delegator


x = X()

x._allowed_items = ['a', 'b']