这是一个实验。我对支持这两种语法的API感兴趣:
obj.thing
- >返回默认值
obj.thing(2, 'a')
- >返回从* args和** kwargs
派生的值“thing
”在两种情况下都是相同的对象;我希望调用thing是可选的(或隐含的,如果之后没有(),那么。)
我试过覆盖__repr__,但这只是对象本身的直观表示,<em>实际返回的是包含对象的实例(这里是'obj')。所以,没有好处。
我认为在一个可调用的对象上会设置一个属性(不管它是一个实例,一个def,还是只是对象的__call__),它有足够的默认值:
class CallableDefault(object):
__call__(self, num=3, letter="z"):
return letter * num
class DumbObject(object):
foo = CallableDefault()
obj = DumbObject()
所以,理想情况下,单独执行obj
会返回“zzz”,但也可以执行obj(7,'a')
并获取'aaaaaaa'。
我认为装饰者可能是这样做的方式,但我对装饰者不太满意。可以覆盖包含类的getattr()调用,但这意味着它必须位于支持此功能的包含类中。
答案 0 :(得分:3)
您所描述的内容可行,但请注意,现在该属性的值被限制为CallableDefault
类的对象。这可能不会非常有用。
我强烈建议您不要尝试这样做。首先,你花了很多时间试图欺骗Python做一些它不想做的事情。另一方面,API的用户会感到困惑,因为它的行为与他们见过的所有其他Python代码的行为不同。他们会感到困惑。
编写一个在Python中自然运行的Python API。
答案 1 :(得分:3)
当你做任何一件事时会发生什么
obj.thing
或
obj.thing(2, 'a')
是Python在thing
上寻找obj
;一旦它有thing
,它就会返回它(上面的第一种情况),或者用参数调用它(第二种情况) - 关键点是调用直到之后才发生检索属性 - 并且包含的类无法知道它返回的东西是否会被调用。
你可以为这种方式使用的每种类型添加__call__
方法,但这种方式就是疯狂。
<强>更新强>
好吧,只要你对精神错乱感到满意,你就可以尝试这样的事情:
class CallableStr(str):
def __call__(self, num, letter):
return num*letter
class CallableInt(int):
def __call__(self, num, pow):
return num ** pow
class Tester(object):
wierd = CallableStr('zzz')
big = CallableInt(3)
t = Tester()
print repr(t.wierd)
print repr(t.wierd(7, 'a'))
print repr(t.big)
print repr(t.big(2, 16))
关于这个神奇物体的一个好处是,当你在计算(或调用)中使用它时,它会很快变为正常:
print type(t.big), type(t.big + 3), t.big + 3
print type(t.big), type(t.big(2, 3) + 9), t.big(2, 3) + 9
导致
<class '__main__.CallableInt'> <type 'int'> 6
<class '__main__.CallableInt'> <type 'int'> 17