Python API - 创建可选括号的模式?
我正在为一个Python库设计API,遇到了一些问题,感觉我的想法可能超出了Python的能力范围。
(如果有Python爱好者看到我设计中有点像Ruby的地方,我在这里先道个歉)
简单来说,我有一个类,里面有几个方法,每个方法都返回self
,这样就可以把它们连在一起使用。所以:
>>> a = MyKlass()
>>> b = a.method_one()
>>> c = b.method_two()
这和下面的写法是一样的:
>>> a = MyKlass()
>>> c = a.method_one().method_two()
我想问的是,能不能让括号变成可选的。我了解了一些关于使用__getattr__
和__call__
来处理可调用对象的知识,但还没能完全实现。目前,我的类中的__getattr__
会检查属性,然后判断name
是方法还是属性(更准确地说,是可调用的还是不可调用的)。
我的问题是,如果它是一个可调用的对象,我需要让__getattr__
做类似这样的事情:
>>> class MyKlass(object):
>>> def __getattr__(self, name):
>>> # pseudocode, you get the idea...
>>> if name is callable:
>>> def callme(*args, **kwds):
>>> # do stuff
>>> return callme
>>> else:
>>> # just return the attribute
这样它就返回了一个可调用的对象。不过,这样的话,我就无法让括号变成可选的,因为可调用对象会被返回,但永远不会被调用:
>>> a = MyKlass()
>>> c = a.method_one.method_two # AttributeError, since a bound function object does not have attribute "method_two"
我想到的唯一方法是能够“向前看”代码,判断name
后面是否跟着括号。如果name
是可调用的但没有被调用,我就可以返回调用name
时不带参数的结果,而不是返回一个可调用的对象。
我在想,这可能不太可行,但我还是想问问高手们的看法。
2 个回答
如果没有括号,你得到的是一个函数的引用;加上括号后,你得到的是函数执行后的结果。这是Python语法的一个基本部分(这种一致性是件好事!)。
你可以使用Python的property
函数(或者相关的装饰器)来让一个方法在后台作为属性的别名,这样就能实现你想要的效果。不过,这样做可能意味着你写的代码会有很多副作用,这样是不太好的。
像这样链式调用在jQuery中很流行,因为jQuery的主要目的是在DOM中引发副作用。但在其他地方通常不太合适,因为这样会让你的应用变得很难调试和测试。
我觉得你想这样做有点疯狂。你有什么理由呢?那那些需要参数的方法怎么办?(见下面的例子。)
如果你用 __getattribute__
而不是 __getattr__
,对于没有参数的方法似乎是可以工作的。
这里有个可以运行的例子:
class Test(object):
def __getattribute__(self, name):
attr = super(Test, self).__getattribute__(name)
if callable(attr):
return attr()
return attr
def f(self):
print 'f'
return self
def g(self):
print 'g'
return self
def h(self, x):
print x
return self
t = Test()
t.f.g # Works fine
t.f().g # Fails - the parens aren't optional, they must be left off now
t.f.g.h(1) # Fails - unable to provide an argument
为了绕过参数的问题,你可以检查一下这个函数,只有在它不需要任何参数(除了self)时才调用它。可以参考这个链接:http://docs.python.org/library/inspect.html
为了你好,还是别继续走这条路了。