类的 __init__ (不是实例的 __init__)

8 投票
5 回答
647 浏览
提问于 2025-04-15 21:59

这里有一个我想解决的非常简单的例子:

class Test(object):
    some_dict = {Test: True}

问题是,在定义 Test 的时候,我无法引用它。

通常,我会这样做:

class Test(object):
    some_dict = {}
    def __init__(self):
        if self.__class__.some_dict == {}:
            self.__class__.some_dict = {Test: True}

但是我从来没有创建这个类的实例。这个类其实只是用来装一组相关的函数和数据(我有好几个这样的类,我会传递它们的引用,所以 Test 必须是一个独立的类)。

所以我的问题是,在定义 Test 的时候,我该如何引用它,或者有没有类似于 __init__ 的东西,可以在类定义完成后立即调用?如果可以的话,我希望 self.some_dict = {Test: True} 能留在类的定义里面。这是我目前知道的唯一方法:

class Test(object):
    @classmethod
    def class_init(cls):
        cls.some_dict = {Test: True}
Test.class_init()

5 个回答

1

我之前也尝试过这样使用类,结果很快就变得复杂了(比如,所有的方法都得是类方法或者静态方法,最后你可能会发现想定义一些特殊的方法,这时候就得开始用元类了)。如果你直接使用类的实例,事情会简单很多,基本上没有什么坏处。

还有一种(看起来有点奇怪的)替代方案:你可以使用 __new__

class Test(object):
    def __new__(cls):
        cls.some_dict = {cls: True}

Test()

你甚至可以让 __new__ 返回一个类的引用,然后用装饰器来调用它:

def instantiate(cls):
    return cls()

@instantiate
class Test(object):
    def __new__(cls):
        cls.some_dict = {cls: True}
        return cls
4

你可以在主类定义之后添加一些字典属性。

class Test(object):
  pass
Test.some_dict = {Test: True}
12

其实在定义一个类的时候,这个类并不存在。class这个语句的工作方式是,它的内容会作为一段代码在一个独立的命名空间中执行。执行结束后,这个命名空间会被传递给元类(比如type),然后元类会用这个命名空间来创建类,命名空间里的内容就成了类的属性。

根据你的描述,Test似乎并不一定要是一个类。听起来它更像是一个模块some_dict是一个全局变量——即使它是类的属性,程序里也只有一个这样的属性,所以它并不比全局变量更好。而你在类里定义的任何类方法其实都可以直接写成普通函数。

如果你真的想把它定义成一个类,你有三个选择:在定义类之后再设置字典:

class Test:
    some_dict = {}
Test.some_dict[Test] = True

使用类装饰器(在Python 2.6或更高版本):

def set_some_dict(cls):
    cls.some_dict[cls] = True

@set_some_dict
class Test:
    some_dict = {}

或者使用元类:

class SomeDictSetterType(type):
    def __init__(self, name, bases, attrs):
        self.some_dict[self] = True
        super(SomeDictSetterType, self).__init__(name, bases, attrs)

class Test(object):
    __metaclass__ = SomeDictSetterType
    some_dict = {}

撰写回答