有没有办法使用 __getattr__ 来确定方法和属性调用之间的区别?
即在:
class Bar(object):
def __getattr__(self, name):
if THIS_IS_A_METHOD_CALL:
# Handle method call
def method(**kwargs):
return 'foo'
return method
else:
# Handle attribute call
return 'bar'
foo=Bar()
print(foo.test_method()) # foo
print(foo.test_attribute) # bar
这些方法不是本地的,因此无法使用 getattr/callable 来确定它。我也明白方法是属性,并且可能没有解决方案。只希望有一个。
你根本无法知道一个对象将如何在
__getattr__
钩子中使用。例如,您可以访问方法而不调用它们,将它们存储在变量中,然后稍后调用它们。
返回一个带有
__call__
方法的对象,调用时会调用:
class CallableValue(object):
def __init__(self, name):
self.name = name
def __call__(self, *args, **kwargs):
print "Lo, {} was called!".format(self.name)
class Bar(object):
def __getattr__(self, name):
return CallableValue(name)
但是它的实例不会同时与字符串或列表相同。
演示:
>>> class CallableValue(object):
... def __init__(self, name):
... self.name = name
... def __call__(self, *args, **kwargs):
... print "Lo, {} was called!".format(self.name)
...
>>> class Bar(object):
... def __getattr__(self, name):
... return CallableValue(name)
...
>>> b = Bar()
>>> something = b.test_method
>>> something
<__main__.CallableValue object at 0x10ac3c290>
>>> something()
Lo, test_method was called!
__getattr__
调用某个属性,Martijn Pieters 对此进行了解释。
callable
可以知道某个属性是否可以被调用。另一种方法是使用 type
来跟踪各种对象,或制作属性名称列表。
class Foo(object):
bar_attribute = 'callable'
def __getattr__(self, name):
instanceOrValue = getattr(self, "bar_%s" %name)
if callable(instanceOrValue):
# Handle object that can be called
def wrap(**kwargs):
return "is %s" %instanceOrValue(**kwargs)
return wrap
# Handle object that can not be called
return 'not %s' %instanceOrValue
def bar_method(self, **kwargs):
return 'callable';
foo=Foo()
print(foo.method()) # is callable
print(foo.attribute) # not callable
__getattr__
只能跟踪某些事情,但在许多情况下它可能是正确的解决方案,因为更改调用(__call__
)对所有情况下的调用都有影响,而不仅仅是当 Foo 类是使用过。
简而言之,不,没有可靠的方法 - 问题是方法是 Python 中的属性 - 没有区别。它恰好是一个作为绑定方法的属性。
您可以检查该属性是否是一个方法,但不能保证这意味着它会被调用,例如:
class Test:
def test(self):
...
Test().test # This accesses the method, but doesn't call it!
访问函数的调用无法知道函数返回时是否会被调用 - 这是一个尚未处理的未来事件。
如果您愿意假设正在访问的方法是正在调用的方法,则可以通过如下检查确定它是正在访问的方法:
hasattr(value, "__self__") and value.__self__ is self
其中
value
是您要检查它是否是方法或其他属性的属性,self
是您要查看它是否是其方法的实例。
如果你需要在调用它时发生一些事情,你可以利用这个时刻来装饰该函数。
可以在here找到这方面的可靠代码示例。
稍微扩展一下Martijn的答案:
这并不适用于所有情况,但您可以返回其自身的另一个实例,以便对之后发生的情况有更多的控制。
这也允许链接属性和调用。
并且您可以实现比
__str__
更多的方法,以提供不同的表示。
class CallableValue():
name = None
called = False
args = []
kwargs = {}
def __init__(self, name = None, called=False, args=[], kwargs={}):
self.name = name or "default"
self.called = called
self.args = args
self.kwargs = kwargs
def __call__(self, *args, **kwargs):
return CallableValue(self.name, True, args, kwargs)
def __getattr__(self, name):
return CallableValue(name)
def __str__(self):
return self.name if not self.called else f"called {self.name} with {self.args} and {self.kwargs}"
t = CallableValue()
print(t)
print(t.attr)
print(t.something)
print(t.something1.something2.something3)
print(t.method())
print(t.other_method("value", key="value"))
print(t.something.method2("value"))
print(t.method1().method2().method3(key="value"))
结果:
default
attr
something
something3
called method with () and {}
called other_method with ('value',) and {'key': 'value'}
called method2 with ('value',) and {}
called method3 with () and {'key': 'value'}