Reputation: 11248
I have 2 classes:
class Parent(object):
def __init__(self, id, name):
self.id = id
self.name = name
self.__parent_vars = ['id', 'name'] # make a copy
def print_values(self):
res = {}
for el in self.__parent_vars:
res[el] = vars(self)[el]
return res
class Child(Parent):
def __init__(self, id, name, last_name, age):
Parent.__init__(self, id, name)
self.last_name = last_name
self.age = age
What I want to do - is to get from Child
parameters of Parent
class. I made it using additional variable and it works, but I need more elegant solution without additional variable. I need it for pickle class. If I create additional variable it breaks my Schemas in a big project.
I try to find something like this:
c = Child(12,"Foo","whatever",34)
vars(c.super())
with expected output:
{'id': 12, 'name': 'Foo'}
I found this question: Get attributibutes in only base class (Python) but it has significant difference of mine, so I can't use that solution.
Upvotes: 4
Views: 2993
Reputation: 11248
I found one more solution. It looks simplier, so I used it. It based on using Marshmallow Schemas. Also It is more usiful in my project because I already used marshmallow Schemas. The idea: I create 2 classes and 2 different Schemas. And can serialize bigger class (Child) using just Parent schema:
class Parent(object):
def __init__(self):
self.id = 'ID'
self.name = 'some_name'
class Child(Parent):
def __init__(self):
Parent.__init__(self)
self.last_name = 'last_name'
self.age = 15
from marshmallow import Schema, fields, EXCLUDE
class ParentSchema(Schema):
ba = Parent()
id = fields.Str(missing=ba.id)
name = fields.Str(missing=ba.name)
class ChildSchema(Schema):
ba = Child()
id = fields.Str(missing=ba.id)
name = fields.Str(missing=ba.name)
last_name = fields.Str(missing=ba.last_name)
age = fields.Int(missing=ba.age)
user_data = {'id':'IDIDID', 'name':'add_name', 'last_name':'FAMILIYA'}
res = ParentSchema().load(user_data, unknown=EXCLUDE)
# output:
res
{'name': 'add_name', 'id': 'IDIDID'}
Upvotes: 1
Reputation: 149185
I am afraid you cannot easily. In Python, classes only carry methods and static attributes. Non
static attributes are commonly stored in the __dict__
attribute of the objects. That means that except in special cases, you cannot easily know which attributes where assigned in a parent class method, in a child class method or even outside any method.
I can only imagine a meta_class that would instrument the __init__
method to store which attributes were changed during its call:
import collections
import functools
import inspect
class Meta_attr(type):
init_func = {}
attrs = collections.defaultdict(set)
def __new__(cls, name, bases, namespace, **kwds):
c = type.__new__(cls, name, bases, namespace, **kwds)
cls.init_func[c] = c.__init__
@functools.wraps(c.__init__)
def init(self, *args, **kwargs):
before = set(self.__dict__.keys())
cls.init_func[c](self, *args, **kwargs)
after = set(self.__dict__.keys())
cls.attrs[c].update(after.difference(before))
init.__signature__ = inspect.signature(c.__init__)
c.__init__ = init
return c
class Parent(object, metaclass=Meta_attr):
def __init__(self, id, name):
self.id = id
self.name = name
def print_values(self):
res = {}
for el in Meta_attr.attrs[Parent]:
res[el] = vars(self)[el]
return res
class Child(Parent):
def __init__(self, id, name, last_name, age):
Parent.__init__(self, id, name)
self.last_name = last_name
self.age = age
It gives:
>>> c = Child(1,"a","b", 20)
>>> c.print_values()
{'id': 1, 'name': 'a'}
BEWARE: if an attribute is set outside of the __init__
method, it will not be registered by this meta class...
Upvotes: 2