I have a Parent class and a inherited child class, I would like to know how to access the child class variable in my Parent class..
I tried this and it fails -
class Parent(object):
    def __init__(self):
        print x
class Child(Parent):
    x = 1;            
x = Child();
Error:-
NameError: global name 'x' is not defined
This question is in relation to Django forms where we inherit the form class and declare some class variables.
For example:-
My form looks like this
from django import forms
class EmployeeForm(forms.Form):
      fname = forms.CharField(max_length=100)
      lname = forms.CharField(max_length=100)
I believe the form fields are considered as class variable and somehow passed to the parent class..
Django does this with metaclasses. (Relevant Django source)
Here's a distilled example of the relevant code:
class Field(object):
    def __init__(self, *args):
        self.args = args
    def __repr__(self): 
        return "Form(%s)" % (', '.join(map(repr, self.args)),)
class Meta(type):
    def __new__(mcs, name, bases, attrs):
        field_list = []
        for k,v in attrs.items():
            if isinstance(v, Field):
                field_list.append(v)
        cls = type.__new__(mcs, name, bases, attrs)
        cls.fields = field_list
        return cls
class Form(object):
    __metaclass__ = Meta
class MyForm(Form):
    fe1 = Field("Field1", "Vars1")
    fe2 = Field("Field2", "Vars2")
    x = "This won't appear"
form_fields = MyForm.fields
print(form_fields)
There are many questions on here about Python metaclasses (example), so I won't try to re-explain the concept.
In this case, when you create the class MyForm, each of the class attributes are checked for being instances of Field.  If they are, they're added to a list (field_list).
The class is created, then an attribute .fields is added to the class, which is field_list, the list of Field elements.
You can then access the form fields through <FormSubclass>.fields or in the case of this example, MyForm.fields.
Edit:
It's worth noting that you can accomplish very similar functionality, without the metaclass syntactic sugar with something like:
class Field(object):
    def __init__(self, *args):
        self.args = args
    def __repr__(self): 
        return "Form(%s)" % (', '.join(map(repr, self.args)),)
class Form(object):
    def __init__(self):
        self._fields = None
    def fields(self):
        if self._fields is None:            
            field_list = []
            for k in dir(self):
                v = getattr(self, k)
                if isinstance(v, Field):
                    field_list.append(v)
            self._fields = field_list
        return self._fields
class MyForm(Form):
    def __init__(self):
        Form.__init__(self)
        self.fe1 = Field("Field1", "Vars1")
        self.fe2 = Field("Field2", "Vars2")
        self.x = "This won't appear"
form_fields = MyForm().fields()
print(form_fields)  # [Form('Field1', 'Vars1'), Form('Field2', 'Vars2')]
                        You need to refer to self.x to access Child class variables:
class Parent(object):
    def __init__(self):
        print(self.x)
class Child(Parent):
    x = 1
if __name__ == '__main__':
    child_instance = Child()
                        Short answer : you dont access subclasse's attributes from a parent class - because the parent class can not know what attributes a child class might have.
Long answer : ... unless the parent class defines a protocol allowing subclasses to let the parent class knows about at least part of it's own attributes.
Django's form framework (as well as django's orm FWIW) use such a protocol: the base Form class has a custom metaclass that collects the form.fields declared in a subclass - and do quite some black magic. FWIW, Django is oss so you could have answered the question yourself just reading the source code: https://github.com/django/django/blob/master/django/forms/forms.py
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With