如何在Python 3.7中重新实现Python的__qualname__? (有一些细微的调整)

问题描述 投票:0回答:2

__qualname__
属性对我很有用,因为它使函数具有上下文关系;但是,我很难将其用于我的用例,因为:

  1. __qualname__
    返回一个字符串。对于我的用例,我需要引用父对象。

  2. __qualname__
    有时返回
    super
    类而不是引用的类。例如:

    class Parent():
    
        def __init__(self):
            pass
    
    
    class Child(Parent):
        pass
    
    
    print(Child.__init__.__qualname__)  # Prints: "Parent.__init__"
    
  3. 我正在开发的包需要强大,并且据我所知,

    __qualname__
    的边缘情况尚未记录

除了使用 ast

解析 Python 文件
之外,
__qualname__
可以通过检查在 Python3 中重新实现吗? Python如何实现
__qualname__
?在重新实现核心功能时,我想我将能够根据我的用例进行调整。


先前的研究:

我无法在Python源代码中找到qualname实现。

python python-3.x introspection
2个回答
6
投票

你不会得到你想要的。您希望

your_thing(Parent.__init__)
说一些关于
Parent
的事情,而
your_thing(Child.__init__)
说一些关于
Child
的事情,但是
Parent.__init__
Child.__init__
是同一个对象。

您已通过两种不同的方式访问该对象,但 Python 不保留任何记录。无论您实现什么,都只会收到一个函数对象,而没有您正在寻找的信息。

即使你做了一些可怕的堆栈检查来查看

your_thing(Child.__init__)
的源代码中写着“Child”的事实,这对于函数存储在变量中或通过变量传递的情况也不起作用。更多的函数调用层。它只会在一小部分情况下起作用,但不可靠,在这些情况下您不需要它,因为您在编写代码时已经拥有了所需的信息。


0
投票

如果您可以接受使用

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 实例)。

顺便说一句:欢迎对此方法提出任何意见或改进:-)

© www.soinside.com 2019 - 2024. All rights reserved.