15

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'

0

3 Answers 3

15

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.

Sign up to request clarification or add additional context in comments.

1 Comment

thank you. The way you explained that: > Also remember that Python never implicitely copy anything, so the code below: > WILL update Parent.attr. Cleared a lot of doubts in my mind!
5

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

Comments

4

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

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

4 Comments

Subclasses DO have their superclasse's attributes (well, superclasses attributes are accessible thru subclasses to be more exact), but not in the class statement block.
>>> class B: ... foo = 42 ... >>> class D(B): ... pass ... >>> B.__dict__ mappingproxy({'__module__': '__main__', 'foo': 42, '__dict__': <attribute '__dict__' of 'B' objects>, '__weakref__': <attribute '__weakref__' of 'B' objects>, '__doc__': None}) >>> D.__dict__ mappingproxy({'__module__': '__main__', '__doc__': None})
@brunodesthuilliers: Yes, and that's because Object.__getattribute__() climbs the MRO.foo is still never part of D.
Yes, that's what I said, and I do know how it works (been using python since the 1.5.2 days and had quite some fun with Python's object model since).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.