如何创建不在子类间共享的类变量?

2 投票
1 回答
824 浏览
提问于 2025-04-18 08:26

我需要使用一些变量,这些变量在一个类的不同实例之间是共享的。所以,类变量看起来很合适。但是,这些类变量在子类之间也是共享的,这一点我希望避免。

问题是这样的:

class Parent(object):
    a=[]

class Child(Parent):
    pass

print(Child.a is Parent.a) # => True # Need to avoid this

这是我尝试解决的方法:

  1. 可以通过在子类中重新声明父类的类变量来“遮蔽”它,但这样做仍然可能会删除子类的“a”变量,这样子类的“a”又会指向父类的“a”。

    class Parent(object):
        a=[]
    
    class Child(Parent):
        a=[] # Works, but delete-able.
    
    print(Child.a is Parent.a) # => False # Works
    del Child.a
    print(Child.a is Parent.a) # => True # Breaks again
    
  2. 和之前的方法类似,但通过元类添加“a”,这样看起来更好。

    class meta(type):
        def __new__(cls, name, base, clsdict):
                temp_class = type.__new__(cls, name, base, clsdict)
                temp_class.a=[]
                return temp_class
    class Parent(object):
        __metaclass__=meta
    
    class Child(Parent):
        pass
    
    print(Child.a is Parent.a) # => False # Works
    del Child.a
    print(Child.a is Parent.a) # => True # Breaks again
    

但是这些方法都没有解决“可能删除子类的类变量”的问题。

有没有办法为类变量设置某种描述符,使得删除变得不可能?如果没有,解决这个问题的好方法是什么呢?

1 个回答

2

要让一个类的属性只对这个类自己可用,而不让子类访问,可以在属性前面加上两个下划线“__”。这就叫做“类私有成员”或者“类私有引用”。

在下面的例子中,__update 是在 Mapping 类里面的,但在子类里是找不到的。

class Mapping:
    def __init__(self, iterable):
        self.items_list = []
        self.__update(iterable)

    def update(self, iterable):
        for item in iterable:
            self.items_list.append(item)

    __update = update   # private copy of original update() method

class MappingSubclass(Mapping):

    def update(self, keys, values):
        # provides new signature for update()
        # but does not break __init__()
        for item in zip(keys, values):
            self.items_list.append(item)

来源: Python 类文档

这里是原始代码。注意,Child 类并没有继承父类的 __a 属性。

还要注意,Child实例对象 也没有继承 __a 属性。这个 __a 属性是父类和它的实例的私有属性,子类是无法继承的。

源代码

class Parent(object):
    __a = []

class Child(Parent):
    def check(self):
        print self.__a  # raises exception, __a is in Parent only, not in self

try:
    print(Child.__a is Parent.__a)
except AttributeError as exc:
    print exc
print
try:
    Child().check()
except AttributeError as exc:
    print exc

输出结果

type object 'Child' has no attribute '__a'

'Child' object has no attribute '_Child__a'

撰写回答