给出x = C.f
之后:
class C:
def f(self):
pass
我会在x
上呼叫哪些会返回C
?
我能做的最好的事情是exec
x.__qualname__
的解析部分,这很难看:
exec('d = ' + ".".join(x.__qualname__.split('.')[:-1]))
对于一个用例,假设我想要一个装饰器,它会对它应用的任何方法添加super
调用。那个只给出函数对象的装饰器怎样才能将类带到super
(下面的???
)?
def ensure_finished(iterator):
try:
next(iterator)
except StopIteration:
return
else:
raise RuntimeError
def derived_generator(method):
def new_method(self, *args, **kwargs):
x = method(self, *args, **kwargs)
y = getattr(super(???, self), method.__name__)\
(*args, **kwargs)
for a, b in zip(x, y):
assert a is None and b is None
yield
ensure_finished(x)
ensure_finished(y)
return new_method
答案 0 :(得分:4)
如果您的目标是摆脱exec
语句,但愿意使用the __qualname__
attribute,即使您仍然需要手动解析它,那么至少对于简单的情况,以下似乎工作:
x.__globals__[x.__qualname__.rsplit('.', 1)[0]]
或:
getattr(inspect.getmodule(x), x.__qualname__.rsplit('.', 1)[0])
我不是Python
专家,但我认为第二种解决方案更好,考虑以下文档摘录:
Python 3.3
的:
函数和类对象有一个新的
__qualname__
属性,表示从模块顶层到其定义的“路径”。对于全局函数和类,这与__name__
相同。对于其他函数和类,它提供了有关实际定义位置以及如何从全局范围访问它们的更好信息。
__qualname__
's description in PEP 3155的:
对于嵌套的分类,方法和嵌套函数,
__qualname__
属性包含从模块顶层通向对象的虚线路径。
编辑:
正如@eryksun的评论所述,解析__qualname__
这样的内容超出了预期用途,考虑__qualname__
反映closures的方式,它非常脆弱。更健壮的方法需要排除name.<locals>
形式的闭包命名空间。例如:
>>> class C:
... f = (lambda x: lambda s: x)(1)
...
>>> x = C.f
>>> x
<function C.<lambda>.<locals>.<lambda> at 0x7f13b58df730>
>>> x.__qualname__
'C.<lambda>.<locals>.<lambda>'
>>> getattr(inspect.getmodule(x), x.__qualname__.rsplit('.', 1)[0])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'C.<lambda>.<locals>'
可以通过以下方式处理此特定情况:
>>> getattr(inspect.getmodule(x),
... x.__qualname__.split('.<locals>', 1)[0].rsplit('.', 1)[0])
<class '__main__.C'>
尽管如此,目前尚不清楚现在存在哪些其他角落案件,或者未来版本中可能会出现这种情况。
正如@MichaelPetch的评论中所述,此答案仅适用于Python 3.3
以及the __qualname__
attribute was introduced之后的语言。
Python
版本的等效版本。有关处理绑定方法的完整解决方案,请参阅this answer。
答案 1 :(得分:1)
我将贡献一个选项,它依赖于 gc 模块向后跟踪引用。
它依赖于当然不能保证的实现细节,并且肯定不会适用于所有 Python 实现。尽管如此,某些应用程序可能会发现此选项比使用 MFMessageComposeViewController
更可取。
你实际上需要向后两跳,因为类在其中隐藏了一个字典,它保存了成员函数:
__qualname__