获取静态变量值

时间:2015-03-29 13:44:35

标签: python static class-variables

我尝试创建一个静态变量,通过不同的类访问,为其赋值,并在需要时获取此值。我确实使用this way来实现这一目标,这导致我将以下属性包括在内:

class GetPartition(Partition):
    _i = 100
    def __init__(self):
        super(Partition,self).__init__("get")
    def get_i(self):
        return type(self)._i
    def set_i(self,val):
        type(self)._i = val
    i = property(get_i, set_i)

如果需要,这是课程Partition

class Partition(BaseCommand):
    def __init__(self,type):
        super(Partition,self).__init__("databaseTest")
        self.type = type

因此,当从另一个类别为i分配值时,我会直接指定它,如:

GetPartition.i = 5

并且在打印GetPartition.i时该类中,它给了我5,但是在尝试从另一个类中获取此值时:

partitionNum = GetPartition()
print(partitionNum.i) # 100
print(partitionNum.get_i()) # 100
print(GetPartition.i) # <property object at 0x12A938D0>
print(GetPartition._i) # 100

1 个答案:

答案 0 :(得分:1)

正如我在评论中所解释的那样,当您通过以下方式将{5}分配给i时会出现问题:

GetPartition.i = 5

使用这行代码,您覆盖属性&#34;绕过&#34; 属性设置器。我的意思是:当您从类中调用其属性名称​​时,属性设置器不会被称为;只有在从类实例调用其属性名称时才会调用它。

由于它已被覆盖,因此该属性不再存在,并且对i属性的所有引用(无论是来自类实例还是来自类本身)都是不同的。它们将不再检索相同的对象,而是检索不同的对象。

您可以通过执行以下操作来确认此问题:

gp = GetPartition()
print(GetPartition.i) # the property is returned
GetPartition.i = 5 # here the property is overwritten
print(GetPartition.i) # 5 ; the property is gone
print(gp.i) # 5 because gp instance doesn't have its own i
gp.i = 2 # now gp does have its own i
print(gp.i) # 2
print(GetPartition.i) # 5 ; i is not synced

如上所述,property getter和setter(以及一般描述符)仅适用于GetPartition的实例,而不适用于类本身。他们可以通过为您的类创建一个元类(类是类)来强制使用类本身;这被认为是&#34;深黑魔法&#34;许多人,如果你能避免,我不建议你去那条路。

我相信以下示例可能是实现您想要的行为的最简单方法。这种方法放弃了使用属性,而有利于直接覆盖属性getter和setter方法:

class Example():
    i = 1 # this is a "static variable"
    j = 3 # this is a regular class attribute
    #designate which of the class attributes are "static"
    statics = {'i'}
    def __getattribute__(self, attr):
        '''Overrides default attribute retrieval behavior.'''
        if attr in Example.statics:
            #use class version if attr is a static var
            return getattr(Example, attr)
        else:
            #default behavior if attr is not static var
            return super().__getattribute__(attr)
    def __setattr__(self, attr, value):
        '''Overrides default attribute setting behavior.'''
        if attr in Example.statics:
            #use class version if attr is a static var
            setattr(Example, attr, value)
        else:
            #default behavior if attr is not static var
            super().__setattr__(attr, value)

#testing
if __name__ == '__main__':
    print("\n\nBEGIN TESTING\n\n")

    e = Example()
    #confirm instance and class versions of i are the same
    test = "assert e.i is Example.i"
    exec(test)
    print(test)

    e.i = 5
    #confirm they remain the same after instance change
    test = "assert e.i is Example.i"
    exec(test)
    print(test)

    Example.i = 100
    #confirm they remain the same after class change
    test = "assert e.i is Example.i"
    exec(test)
    print(test)

    e.j = 12
    #confirm both versions of j are distinct
    test = "assert e.j is not Example.j"
    exec(test)
    print(test)

    print("\n\nTESTING COMPLETE\n\n")

如果您不熟悉__getattribute____setattr__,我应该告诉您,覆盖它们通常非常危险并且可能会导致很大问题(尤其是__getattribute__)。你会发现很多人只是说“不要这样做”;重新考虑你的问题,找到另一种解决方案&#34;。正确执行覆盖需要深入了解各种python主题。

我没有声称有这种深刻的理解(虽然我认为我有一个很好的理解),所以我不能100%确定我上面给出的覆盖不会导致你的其他问题。我相信它们是合理的,但请注意,python的这些特殊角落可能非常棘手。