有没有类似'__getattribute__'的方法适用于类变量而非实例变量?

8 投票
3 回答
2547 浏览
提问于 2025-04-17 17:56

我有一个叫做 sysprops 的类,我想在里面定义一些常量。不过,我希望这些常量的值是从数据库中获取的,所以我想要在每次访问这些类常量的时候,有一种机制可以触发(类似于实例变量的 getattribute 方法)。

class sysprops(object):
    SOME_CONSTANT = 'SOME_VALUE'

sysprops.SOME_CONSTANT  # this statement would not return 'SOME_VALUE' but instead a dynamic value pulled from the database.

3 个回答

0

sysprops.SOME_CONSTANT 可以是一个函数的返回值,前提是 SOME_CONSTANT 是在 type(sysprops) 上定义的一个属性。

换句话说,如果 sysprops 是一个实例而不是一个类,你说的这种情况是很常见的。

但这里有个关键点——类是元类的实例。所以你用类来控制实例行为的所有知识,同样也适用于用元类来控制类的行为。

通常情况下,元类是 type,但你可以通过继承 type 来定义其他元类。如果你在元类中放置一个属性 SOME_CONSTANT,那么这个元类的实例,比如 sysprops,在 Python 评估 sysprops.SOME_CONSTANT 时就会有你想要的行为。


class MetaSysProps(type):
    @property
    def SOME_CONSTANT(cls):
        return 'SOME_VALUE'

class SysProps(object):
    __metaclass__ = MetaSysProps


print(SysProps.SOME_CONSTANT)

会得到

SOME_VALUE
3

虽然我觉得这样做是个非常糟糕的主意,但实际上是可以做到的:

class GetAttributeMetaClass(type):
    def __getattribute__(self, key):
        print 'Getting attribute', key

class sysprops(object):
    __metaclass__ = GetAttributeMetaClass
2

虽然其他两个回答的方法也很有效,但我更喜欢一种“最少魔法”的方式。

你可以用一种类似于元类的方法,但其实不需要用到元类。只需要使用一个装饰器就可以了。

def instancer(cls):
    return cls()

@instancer
class SysProps(object):
    def __getattribute__(self, key):
        return key # dummy

这样做会创建一个 SysProps 的实例,然后把它重新赋值给 SysProps 这个名字。这样就有效地覆盖了实际的类定义,并且允许使用一个常量实例。

因为装饰器在Python中更常见,所以我觉得这种方式对其他需要阅读你代码的人来说更容易理解。

撰写回答