Python类构造函数(静态)

时间:2017-08-04 11:25:30

标签: python class oop constructor

Python是否有类构造函数的机制,即每当首次引用类时调用的函数(与创建该对象的实例时相反)?我知道它存在于其他一些语言中,但我还没有在Python中遇到它。

基本上,我想在该函数中初始化一些静态属性。我在下面举了一个我期望的例子。当然,该示例返回None,但我希望它返回' foo'。

+www.example.com/*.gif
+www.example.com/*.jpg
+www.example.com/*.jpeg
+www.example.com/*.png
-www.example.com/*.html

为了避免混淆:我很清楚对象构造函数,但这不是我想要的,因为只有在创建第一个对象时才会调用它,而不是在之前:

class T:
    arg = None
    def __class_constructor__():
        T.arg = 'foo'

print(T.arg)  # returns None

3 个答案:

答案 0 :(得分:2)

您可以使用类装饰器:

def add_arg(cls):
    if not hasattr(cls, "arg"):
        cls.arg = 'foo'
    return cls

@add_arg
class T(object):
    pass

或自定义元类:

class WithArg(type):
    def __new__(meta, name, bases, attrs):
        cls = type.__new__(meta, name, bases, attrs)
        if not hasattr(cls, "arg"):
            cls.arg = "foo"
        return cls

# python 2
class T(object):
    __metaclass__ = WithArg

# python 3
class T(metaclass=WithArg):
    pass

但是正如其他人已经提到过的那样,除了在类声明中明确设置class属性之外,还有很多功能。

注意:如果你想在类本身上有一个计算属性,你必须将它设置为自定义元类的属性

 class WithProp(type):
     @property
     def arg(cls):
         return "foo"

 class T(object):
     __metaclass__ = WithProp

 T.arg
 => 'foo'

但是arg只能在类对象本身上使用,而不能在它的实例上使用:

T().arg
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'T' object has no attribute 'arg'

或编写自己的自定义描述符:

class ArgDescriptor(object):
    def __get__(self, obj, cls=None):
        return 42

class T(object):
    arg = ArgDescriptor()

T.arg
=> 42
T().arg
=> 42

答案 1 :(得分:1)

You simply have to initialise the class variable when declaring it within the class

class T:
    arg = 'foo' #this initialises the class instance

    def __init__(self):
        self.arg = 'bar' #this initialises the object instance

print(T.arg)  # class instance returns 'foo'
obj = T()
print(T.arg)  # class instance still returns 'foo'
print(obj.arg)  # object instance returns 'bar'

答案 2 :(得分:0)

我创建一个static_init装饰器,该装饰器将调用static_init类方法(如果存在)。这个static_init类方法将在评估类装饰器when the class is defined时运行-第一次引用该类时并不会如此-类似于Java等其他语言中的静态初始化。

这是装饰器,以及如何使用它来初始化枚举类的类变量的示例:

# pylint: disable=missing-docstring,no-member

import enum

def static_init(cls):
    if getattr(cls, "static_init", None):
        cls.static_init()
    return cls

@static_init
class SomeEnum(enum.Enum):
    VAL_A = enum.auto()
    VAL_B = enum.auto()
    VAL_C = enum.auto()
    VAL_D = enum.auto()

    @classmethod
    def static_init(cls):
        text_dict = {}
        setattr(cls, 'text_dict', text_dict)
        for value in cls:
            text_dict[value.name.lower().replace("_", " ").title()] = value

def test_static_init():
    assert SomeEnum.text_dict["Val A"] == SomeEnum.VAL_A
    assert SomeEnum.text_dict["Val B"] == SomeEnum.VAL_B
    assert SomeEnum.text_dict["Val C"] == SomeEnum.VAL_C
    assert SomeEnum.text_dict["Val D"] == SomeEnum.VAL_D