在python中,如果类实例具有__call__
方法,则它几乎可以像函数一样使用。我希望有一个类B
,其方法为A
,其中A
是具有__call__
方法的类的实例。为了进行比较,我还在"传统"中定义了另外两种方法foo
和bar
。方式(即使用def
)。这是代码:
class A(object):
def __call__(*args):
print args
def foo(*args):
print args
class B(object):
A = A()
foo = foo
def bar(*args):
print args
当我调用B
的任何方法时,它们被传递一个类实例作为隐式的第一个参数(通常称为self
)。
然而,我很惊讶地发现b.A()
传递了一个A
实例,我希望在那里B
实例。
In [13]: b = B()
In [14]: b.A()
(<__main__.A object at 0xb6251e0c>,)
In [15]: b.foo()
(<__main__.B object at 0xb6251c0c>,)
In [16]: b.bar()
(<__main__.B object at 0xb6251c0c>,)
是否有一种方法(可能是functools
技巧或类似方法)以A()
传递对b.A()
对象的引用的方式绑定b
? / p>
请注意,上述示例是为了说明我的问题而简化的。我没有就我的实际实施用例提出建议,这是不同的。
修改:如果我像这样定义我的班级B
,我会得到相同的输出:
class B(object):
def __init__(self):
self.A = A()
foo = foo
def bar(*args):
print args
答案 0 :(得分:1)
您的代码存在问题:
class B(object):
A = A()
类B
有一个名为A
的成员,它是A
的一个实例。当您执行B.A()
时,它会调用该__call__
实例的方法A
(这个实例容易混淆为A
);由于它始终是A
,而A
的方法,args
中的实际对象当然是A
。
你所追求的是descriptor;也就是说,A
应该有魔术方法__get__
; :
class A(object):
def __get__(self, cls, instance):
print(cls, instance)
return self
class B(object):
a = A()
b = B()
c = b.a
现在执行b.a
时,__get__
方法获得B
和b
作为cls
和instance
参数,无论它返回什么是属性查找的值(存储在c
中的值) - 它可以返回另一个实例,甚至是函数,或抛出AttributeError
- 由您自己决定。要有另一个知道B
和b
的函数;你可以这样做:
class A(object):
def __get__(self, cls, instance):
if instance is not None:
def wrapper():
print("I was called with", cls, "and", instance)
return wrapper
return self
class B(object):
a = A()
B.a()
代码输出:
I was called with <__main__.B object at 0x7f5d52a7b8> and <class '__main__.B'>
完成任务。