如何在 super class 方法中访问 subcclass 属性,而不传入它们

How to access subcclass attributes in super class methods, without passing them in

如何在其基本 classes 方法中访问派生的 classes 属性(其他语言中的静态变量)? 即

class Base:
    @classmethod
    def get_list(cls):
        return [1, 2, cls.x]

class Derived(Base):
    x = 3
    foo = Base.get_list()    

Derived.foo # Hope to have it set to [1, 2, 3]

我不希望将 x 直接传递给基数 class,即 foo = Base.get_list(x),因为我有很多方法可以用相同的变量调用。

编辑

评论要求提供上下文。我试图做一个最小的可重现的例子来省去你们的细节。

这是完整的上下文:所以它实际上与 Django Admin 有关。 我有一个抽象模型。然后我有各种管理接口用于抽象模型的各种具体实现。正如您所猜到的,我创建了一个抽象管理模型来处理通用逻辑。处理公共管理逻辑的一部分,例如在派生管理模型上生成属性。

以列表显示为例,创建列表显示的逻辑如下:

class FactAdmin(admin.ModelAdmin):
    @classmethod
    def build_list_display(cls, *custom):
        return (
            'created_utc',
            *custom,
            'foo__bar__abbreviation',
            'foo__baz__name',
            'foo__caz__name',
            'foo__daz__description',
            'foo__eaz__code',
        )

@admin.register(FooEntry)
class FoopEntryAdmin(FactAdmin):
    fieldsets = FactAdmin.build_list_display('cannon_ball', 'pogo_stick')

因此在基础管理 class 中,它不断重复使用自定义字段、自定义模型和其他内容的列表。因此,与其每次都传递它们,对于每个 属性,将它们设置为静态属性似乎更 DRY。因此我希望将它们设置为派生 class 上的静态成员字段,并在基础 class.

中访问它们

如果你想让 super 访问派生 class 的 属性,可能是因为这个 属性 被所有派生的子 class 共享(你不无论如何都要检查派生的 class 类型)。在这种情况下,最合乎逻辑的做法是改为在 super 中实现 属性,这样就解决了问题:

class Base:
    x = 3
    @classmethod
    def get_foo():
        return [1, 2, self.x]

您不应该使用 class 属性和方法。您应该定义 class 创建实例并使用实例方法和属性的元素,以便正常的继承按照语言中预期的方式工作。

那么你需要利用实例方法可以被子classes覆盖的事实。这里,为了让parentclass到达childclass的x,你在[=32]中定义了一个get_x方法=] class 您希望在 child class 中覆盖。这就是 child class 的 x 被 parent 使用而没有传递给它的方式。

这是一个例子:

class Base:
    def set_foo(self):
        return [1, 2, self.get_x()]

    def get_x(self):
        return 0

class Sub(Base):

    def __init__(self):
        self.x = 3
        self.foo = super().set_foo()

    def get_x(self):
        return self.x

print(Sub().foo)

结果:

[1, 2, 3]

在 subclass 上调用的 superclass class 方法中访问 subclass 属性不是问题。这按预期工作:

class Base:
    @classmethod
    def get_list(cls):
        return [1, 2, cls.x]


class Derived(Base):
    x = 3


assert Derived.get_list() == [1, 2, 3]

但是,您不能轻易地在子class的class主体中调用那个class方法,因为当时class对象对于 DerivedDerived 这个名字确实还不存在。 (你可以在方法中调用它,classmethods 和 staticmathods,因为它们的主体在调用时被评估,而不是在它们被定义时已经评估。但这在这里没有帮助。)如果调用 Base,明显缺少x。 (并且作为 Python class 方法,get_list 必须明确地调用某些东西。我们不能像 Java 那样只进行不合格的调用。)

所以

class Derived(Base):
    x = 3
    foo = get_list()

结果 NameError: name 'get_list' is not defined

class Derived(Base):
    x = 3
    foo = Base.get_list()

结果 AttributeError: type object 'Base' has no attribute 'x'

class Derived(Base):
    x = 3
    foo = Derived.get_list()

结果 NameError: name 'Derived' is not defined

但并非一无所有。我们不要忘记 Python 允许我们从 class 外部创建和设置 class 属性。所以这有效:

class Base:
    @classmethod
    def get_list(cls):
        return [1, 2, cls.x]


class Derived(Base):
    x = 3


Derived.foo = Derived.get_list()


assert Derived.foo == [1, 2, 3]