【问题标题】:Pass the name of the class to a function, assign to a class attribute, outside of a method将类的名称传递给函数,分配给方法之外的类属性
【发布时间】:2019-04-16 17:02:38
【问题描述】:

Python 3.7:

我有一个类定义,其中类属性根据类名分配一个值,该值用于类内的装饰器中。

我正在寻找“当前正在定义的类”的代词。

这是一个例子:

class MyClass:

    # NameError: name '__class__' is not defined
    class_logger = find_logger(__class__.__name__)

    # __init__ is not important
    def __init__(self):
        # This works!
        self.logger = find_logger(__class__.__name__)

    @mydecorator(class_logger)
    # mymethod is not important
    def mymethod(self):
        return 1

“当前正在定义的类”的合适代词是什么?

(这类似于How to get the current Python class name in __init__ regardless of the class of "self"?,但那里的问题是“在 init 的定义中”,当时是针对 2.7。Python 3.x 解决了这个问题。)

【问题讨论】:

  • 有趣的问题。我认为不一定保证类对象存在于某种部分初始化的状态,而类块尚未完全执行。所以可能没有任何等价的__class__。不过,获取名称并且仅获取名称可能更有可能......
  • 执行类块时类不存在。没有可引用的类对象

标签: python class python-3.7


【解决方案1】:

当类定义尚未完成评估时,不能保证类对象存在并且用户可以访问。即使它是可访问的,它也可能没有被初始化到你可以用它做任何有用的事情的程度。

也就是说,您也许可以得到班级的名称。 __qualname__ 是一个属性,它保存了类/函数/方法/描述符/生成器实例的qualified name。您应该能够从类的定义中访问它。

class Fred:
    print("Fred's qualname:", __qualname__)
    class Barney:
        print("Barney's qualname:", __qualname__)

结果:

Fred's qualname: Fred
Barney's qualname: Fred.Barney

如果您的类未在文件级别定义,您可能需要进行一些字符串操作以将其名称与路径的其余部分分开。例如,将上面的示例更改为 print("Barney's qualname:", __qualname__.rpartition(".")[-1]) 以获取“Barney”而不是“Fred.Barney”。


尽管我尽了最大努力,但我找不到明确确认__qualname__ 在作为常规名称而不是作为属性访问时具有合理值的文档。我不完全相信这是定义明确的行为,所以我认为我不能毫无保留地认可它用于生产质量代码。

【讨论】:

  • class MyClass():(给定的工作代码)之后快速检查dirs(),表明__qualname__ 是那里定义的唯一有用的变量。由于__qualname__ 将具有虚线类层次结构(例如,“One.Two.Three”),我已将它与 split 一起使用来获取叶类。此外,__qualname__ 似乎在 3.7.3、docs.python.org/3/library/stdtypes.html#definition.__qualname__ 中有详细记录。我可以看到它存在于 3.6.8,但不是 3.5。
  • 我将docs.python.org/3/library/stdtypes.html#definition.__qualname__ 解释为仅引用可通过类对象上的属性访问访问的__qualname__,例如Fred.__qualname__。如果该段落暗示该名称 also 在类块的本地名称空间中可用,那么我很困惑为什么 __name__ 不能以相同的方式工作。它是可用的,但它的值是__main__ 而不是Fred,所以它似乎属于模块对象而不是类。这种不一致让我相信这是特定于实现的行为。
  • 我同意您对文档的分析。我也很失望,就是这样。我更希望 Python 文档承认这种区别。同样令人沮丧的是,我不能轻松地将类名传递给类中定义的方法装饰器,但我必须跳过箍间接地做到这一点。
【解决方案2】:

要在定义期间使用类名,您还可以使用带有__prepare__ 方法的元类:

def find_logger(name):
    return name + '_logger'


class PrepareClassLogger(type):
    def __prepare__(name, bases, **kwargs):
        return {'class_logger': find_logger(name)}


class MyClass(metaclass=PrepareClassLogger):
    pass

print(MyClass.class_logger)  # MyClass_logger

【讨论】:

    猜你喜欢
    • 2021-11-30
    • 1970-01-01
    • 1970-01-01
    • 2014-08-23
    • 1970-01-01
    • 1970-01-01
    • 2019-10-11
    • 2021-07-07
    • 1970-01-01
    相关资源
    最近更新 更多