2

我正在研究一个基本上允许方法链接的类,用于为存储的不同字典设置一些属性。

语法如下:

d = Test()
d.connect().setAttrbutes(Message=Blah, Circle=True, Key=True)

但也可能有其他情况,例如:

d = Test()
d.initialise().setAttrbutes(Message=Blah)

现在我相信我可以覆盖“setattrbutes”函数;我只是不想为每个字典创建一个函数。相反,我想捕获前一个链接函数的名称。所以在上面的例子中,我会得到“connect”和“initialise”,这样我就知道在哪个字典里存储它们了。

我希望这是有道理的。任何想法将不胜感激:)

编辑:

这个工作/成为解决上述问题的好方法:

使用方法重载,我可以有以下方法:

def setAttrbutes(self, Name="Foo", Message="", Circle=False):
    print "Attrbutes method called for 'Foo'"

def setAttrbutes(self, Name="Boo", Message=""):
    print "Attrbutes method called for 'Boo'"

因此,我可以说调用哪个方法取决于使用的名称。例如,在主要情况下,如果我有以下内容:

d.setAttrbutes(Name="Foo", Message="Hello world", Circle=True) # this will call the first
d.setAttrbutes(Name="Boo", Message="Hello world") # this will call the second 

这会奏效吗?如果没有,为什么?

4

2 回答 2

0

这几乎可以肯定是一个坏主意……但它是可行的,以几种不同的方式。


最简单的是,您可以让每个函数将其名称保存在对象中,例如:

def stash_name(func):
    @functools.wraps(func)
    def wrapper(self, *args, **kwargs):
        self._stashed_name = func.__name__
        return func(self, *args, **kwargs)
    return wrapper

class Test(object):
    @stash_name
    def foo(self, x):
        print x
    @stash_name
    def bar(self):
        print

现在,调用后d.connect()d._stashed_name将是"connect"


在相反的极端,如果你想变得非常 hacky,你可以在没有上述方法的任何合作的情况下做到这一点。只需使用sys._getframe(1)查找您的调用上下文,然后您可以检查框架f_code以查看您是如何被调用的。

您可以使用该dis模块查看真实的字节码。但基本上,它看起来像这样的伪字节码:

LOAD_NAME d
LOAD_ATTR connect
<possibly other ops to prepare arguments>
CALL_FUNCTION 1 (or any other CALL_FUNCTION_* variant)
LOAD_ATTR setAttributes
<various other ops to prepare arguments>
CALL_FUNCTION 0

在这种情况下,您可以从 中获取属性名称LOAD_ATTR,或者获取推送的并查看其im_func.__name__,这取决于您想要的。

当然也会有其他看起来不像这样的情况。例如,假设我将其称为getattr(d, ''.join('con', 'next'))()而不是d.connect(). 或者我查找了未绑定的方法并动态构建了一个绑定的方法。或者……在每种情况下你想做什么?如果您对所有此类情况都有答案,那么您可以制定生成这些答案的规则,然后找出如何从字节码中获取答案。

于 2013-10-18T09:52:20.557 回答
0

由于您提出了第二个完全不同的问题,因此这是第二个答案。

这个工作/成为解决上述问题的好方法:

使用方法重载,我可以有以下方法:

不,你不能。Python 没有方法重载。如果您def的方法与以前的方法同名,它只会完全替换第一个方法。

有一些方法可以通过在方法主体内手动分派参数值来模拟方法重载。例如:

def _setAttrbutes_impl1(self, Name, Message, Circle):
    pass

def _setAttrbutes_impl2(self, Name, Message):
    pass

def setAttrbutes(self, Name=None, Message="", Circle=None):
    if Circle is None:
        return _setAttrbutes_impl2("Boo" if Name is None else Name, Message)
    else:
        return _setAttrbutes_impl1("Foo" if Name is None else Name, Message, Circle)

但这很少有用。

于 2013-10-18T10:37:18.957 回答