有没有类似'__getattribute__'的方法适用于类变量而非实例变量?
我有一个叫做 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中更常见,所以我觉得这种方式对其他需要阅读你代码的人来说更容易理解。