首页 > 解决方案 > 内部类实例作为外部类方法的默认值

问题描述

我想使用一个内部类的实例(在这种情况下,namedtuple虽然用 定义的内部类会出现完全相同的症状class)作为外部类方法(在这种情况下是构造函数)的默认值。但是,当从不同的模块导入此代码时,似乎缺少外部类定义。

例子:

# mymodule.py

from typing import NamedTuple, Tuple

class IdSignal():
    Cfg = NamedTuple('IdSignalCfg', [
        ('nfft', int),
        ('limits', Tuple[float, float]),
        ('min_spacing', float),
        ('nmix', int)])
    Cfg.__new__.__defaults__ = (
        512,
        (1500, 7500),
        200,
        3
    )

    def __init__(self, cfg = IdSignal.Cfg()):
        self.cfg = cfg

现在执行import mymodule抛出:

Exception has occurred: NameError
name 'IdSignal' is not defined
  File "...", line 18, in IdSignal
    def __init__(self, cfg = IdSignal.Cfg()):
  File "...", line 5, in <module>
    class IdSignal():
  ...
    import mymodule

令人困惑的是,pylint 和 mypy 都无法识别上述代码中的任何错误。

这可以通过其他方式实现吗?

我知道我可以将None其用作默认值并IdSignal.Cfg 构造函数中实例化。如果这是唯一的解决方案,我想了解为什么上面的代码会失败?

标签: pythonpython-3.xoop

解决方案


__init__定义时,名称IdSignal尚未绑定到类。(直到整个语句体class被评估,并且评估的结果被传递给相关的元类时才会发生这种情况。)但是,Cfg它还不是类属性;它只是__init__定义在同一“范围”中的名称,因此您无需限定名称。

def __init__(self, cfg=Cfg()):
    self.cfg = cfg

像这样的class声明

class Foo:
    x = 3
    def __init__(self, y):
        self.y = y

大致相当于

# These names don't really matter, but I'm using different
# names than what the attributes will be just to emphasize
# the point that they really are distinct objects before
# the new class is ever created.

class_x = 3

def some_init(self, y):
    self.y = y

Foo = type('Foo', (object,), {'__init__': some_init, 'x': class_x})

请注意,名称Foo直到最后才出现。class语句不像模块或函数那样定义新的范围,但名称也不是在任何封闭范围的语句部分中定义的class;将它们视为创建类后丢弃的临时名称。


推荐阅读