我正在开发一个基本上允许方法链接的类,用于为存储的不同字典设置一些属性。
语法如下:
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
这会起作用,如果没有,为什么?
答案 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)
但这很少有用。