简体   繁体   中英

Prevent sharing of class variables with base class in Python

I have the following situation in Python 3:

class A:
    d = {}

class B(A):  pass
class C(A):  pass

I work with the classes only, no instances get created. When I access Bd I will get a shared reference to Ad . That's not what I want. I would like to have each class which inherits A have its own d which is set to a dictionary. d is an implementation detail to A . All access to d is done in the code of A . Just B 's d should not be identical to A 's d .

With instances, I would create that dictionary in the __init__() function. But in my case I work with the classes only.

Is there a standard way to achieve this (EDIT: without changing the implementation of the subclasses B and C )? Is there something analog to __init__() which gets called for (or in) each derived class at the time of deriving?

I found a solution myself using a metaclass:

class M(type):
  def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self.d = {}

class A(metaclass=M): pass

Then one can create subclasses of A which all have their own d attribute:

class B(A): pass

B.d is A.d
False

Simply testing @meissner_ comment: you can easily replace the d inside your subcalsses by other ones.

class BaseA():
    """Provides basic initialization for dicts used in A() and deriveds."""
    @classmethod
    def InitDefaults(cls):
        return { 1: "this", 2:"are", 3:"some", 4:"defaults"}

class A():
    d = BaseA.InitDefaults()

class B(A):
    d = BaseA.InitDefaults()

class C(A):
    d = BaseA.InitDefaults()


print(A.d)
print(B.d)
print(C.d)

print("\n")
B.d[99] = "Not a default"
C.d[42] = "Not THE answer"

print(A.d)
print(B.d)
print(C.d)

Output:

{1: 'this', 2: 'are', 3: 'some', 4: 'defaults'}
{1: 'this', 2: 'are', 3: 'some', 4: 'defaults'}
{1: 'this', 2: 'are', 3: 'some', 4: 'defaults'}


{1: 'this', 2: 'are', 3: 'some', 4: 'defaults'}
{1: 'this', 2: 'are', 3: 'some', 4: 'defaults', 99: 'Not a default'}
{1: 'this', 2: 'are', 3: 'some', 4: 'defaults', 42: 'Not THE answer'}

This is kinda ugly but would work. You have a central place for code modifying the "base-default" and A,B,C get distinct dicts - initted the same - that can develop into different directions.

Probably better would be to use Instances and init () though ...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM