__qualname__
属性对我很有用,因为它使函数具有上下文关系;但是,我很难将其用于我的用例,因为:
__qualname__
返回一个字符串。对于我的用例,我需要引用父对象。
__qualname__
有时返回 super
类而不是引用的类。例如:
class Parent():
def __init__(self):
pass
class Child(Parent):
pass
print(Child.__init__.__qualname__) # Prints: "Parent.__init__"
我正在开发的包需要强大,并且据我所知,
__qualname__
的边缘情况尚未记录。
除了使用 ast
解析 Python 文件之外,
__qualname__
可以通过检查在 Python3 中重新实现吗? Python如何实现__qualname__
?在重新实现核心功能时,我想我将能够根据我的用例进行调整。
先前的研究:
qualname
实现:https://github.com/wbolster/qualname/blob/master/qualname.py__qualname__
获取引用:获取Python 3中未绑定方法对象的定义类__qualname__
stackoverflow:在早期 Python 中重现 Python 3.3 __qualname__ 的效果我无法在Python源代码中找到qualname实现。
你不会得到你想要的。您希望
your_thing(Parent.__init__)
说一些关于 Parent
的事情,而 your_thing(Child.__init__)
说一些关于 Child
的事情,但是 Parent.__init__
和 Child.__init__
是同一个对象。
您已通过两种不同的方式访问该对象,但 Python 不保留任何记录。无论您实现什么,都只会收到一个函数对象,而没有您正在寻找的信息。
即使你做了一些可怕的堆栈检查来查看
your_thing(Child.__init__)
的源代码中写着“Child”的事实,这对于函数存储在变量中或通过变量传递的情况也不起作用。更多的函数调用层。它只会在一小部分情况下起作用,但不可靠,在这些情况下您不需要它,因为您在编写代码时已经拥有了所需的信息。
如果您可以接受使用
BaseNode
类中每个属性的子类进行非常规(或繁琐)的类创建
class A(BaseNode):
class a(BaseNode):
pass
a = a()
class B(BaseNode):
class a1(A):
pass
a1 = a1()
class a2(A):
pass
a2 = a2()
class C(B):
class c(BaseNode):
pass
c = c()
然后每个属性都知道他在类层次结构中的路径名。 (可以使用
__init_subclass__()
或装饰器来简化类的创建。)
c = C()
assert c._pathname == 'C'
assert c.c._pathname == 'C.c'
assert c.a1._pathname == 'C.a1'
assert c.a1.a._pathname == 'C.a1.a'
assert c.a2._pathname == 'C.a2'
assert c.a2.a._pathname == 'C.a2.a'
每个属性实例都是根据需求创建的,您可以在
print
输出中看到
*** <__main__.C object at 0x7fca81558190> creates 'c' from <class '__main__.C.c'>
*** <__main__.C object at 0x7fca81558190> creates 'a1' from <class '__main__.B.a1'>
*** <__main__.B.a1 object at 0x7fca8155b760> creates 'a' from <class '__main__.A.a'>
*** <__main__.C object at 0x7fca81558190> creates 'a2' from <class '__main__.B.a2'>
*** <__main__.B.a2 object at 0x7fca8155b490> creates 'a' from <class '__main__.A.a'>
BaseNode
类使用self._parent
来跟踪父对象(=父类的实例)。
class BaseNode:
def __init__(self, parent=None):
self._parent = parent
@property
def _path(self):
path = []
obj = self
while obj:
path.append(obj)
obj = obj._parent
return path[::-1]
@property
def _pathname(self):
return '.'.join(node.__class__.__name__ for node in self._path)
def __get__(self, obj, cls=None):
if obj is None:
return self
name = self.__class__.__name__
try:
inst = obj.__dict__[name]
except KeyError:
print(f'*** {obj} creates {name!r} from {self.__class__}')
inst = self.__class__(obj)
obj.__dict__[name] = inst
return inst
描述符方法
__get__()
根据需要动态创建属性(= BaseNode 实例)。
顺便说一句:欢迎对此方法提出任何意见或改进:-)