Python - 是否有可能获得链式函数的名称?

时间:2013-10-18 09:40:30

标签: python oop dictionary

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

语法如下:

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'"

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

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 

这会起作用,如果没有,为什么?

2 个答案:

答案 0 :(得分: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()。或者我查看了未绑定的方法并动态构建了一个绑定方法。或者......在每种情况下你想做什么?如果您有所有这些案例的答案,那么您可以计算出生成这些答案的规则,然后找出如何从字节码中获取答案。

答案 1 :(得分: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)

但这很少有用。