简体   繁体   中英

How to inherit and extend class attributes in Python?

I've made a lot of research on the net but I didn't find the correct way to extend "class" attributes dictionary with new values in a subclass. Most of the documentation are extending attributes inside methods.

I tried dictionary.update() but it doesn't work.

This is my example:

class Super(object):
    dictionary = {'one':1, 'two':2}

    def __init__(self, var):
        self.var = var

    def supermethod(self):
        pass

And I extended it to:

class Subclass(Super):
    dictionary.update({"zero":0})

    def __init__(self, var):
        super(Subclass, self).__init__(var)
        self.var = var

    def submethod(self):
        pass

If I override dictionary - it works fine. But If I try to extend, it gives me:

AttributeError: 'Subclass' object has no attribute 'dictionary'

In Python, class is an executable statement. When the interpreter finds a class statement, then first all the code in the class statement block is executed (in a special namespace), then all names defined in that block are used to build the class object (Python classes are objects), and finally the class name is bound to the class object in the current scope.

IOW, within the class statement's block, the class object doesn't exist yet and as a consequence it cannot be referenced, neither explicitly (by the class name) nor implicitly (Python overly flavors explicit over implicit anyway).

OTHO, the parent class object does exists at this point obviously (else you could not inherit from it), so you can explicitly reference it:

class Parent(object):
   attr = something()


class Child(Parent):
   attr = Parent.attr
   # do something with Parent.attr

Note that attributes defined in the class statement block (here attr ) are "class attributes", IOW attributes of the class object, and as such are shared amongst instances. When this attribute is a mutable object, mutating it from one instance will affect all instances.

Also remember that Python never implicitly copy anything, so the code below:

class Parent(object):
   attr = {"foo": "bar"}


class Child(Parent):
   attr = Parent.attr
   attr["baaz"] = "quux"
   # or attr.update(baaz="quux") etc

WILL update Parent.attr .

Subclasses never have their superclasses' attributes as their attributes, whether methods or not.

class Subclass(Super):
  dictionary = Super.dictionary
  dictionary.update({zero:0})

Subclasses do have their superclasses' attributes as their attributes. You can not use directionay.update({"zero":0}) because at that time class Subclass still not exist. If you do not do line1 & line2, you can still see line4 print {'one':1, 'two':2} which prove it.

But if you do line1 & line2, you had to add copy() , otherwise, you will see line3 & line4 both becomes {'zero': 0, 'two': 2, 'one': 1} , which means you want to extend parameters in subclass, but you also modify the parameters in superclass, it is not reasonable.

So following code will just output:

{'two': 2, 'one': 1}

{'zero': 0, 'two': 2, 'one': 1}

Which I think meet your requirements.

class Super(object):
    dictionary = {'one':1, 'two':2}

    def __init__(self, var):
        self.var = var

    def supermethod(self):
        pass

class Subclass(Super):
    dictionary = Super.dictionary.copy() # line1
    dictionary.update({"zero":0}) # line2

    def __init__(self, var):
        super(Subclass, self).__init__(var)
        self.var = var

    def submethod(self):
        pass

print(Super.dictionary) # line3
print(Subclass.dictionary) # line4

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