reilic reilic - 3 months ago 7
Python Question

Is thre a better way to build it so it print all attributes from class/parent-class

I have a

Student
class extending
Person
class, both class implemented
__str__
to list out all attributes in both
Person
and
Student
class.

However, I am having issues with trying to do a print of
__str__
in the
__init__
function as below.

class Person(object):

def __init__(self, n):
self.name = n
print Person.__str__(self)

def __str__(self):
return "%15s%s\n" % ("Name: ", self.name)

class Student(Person):

def __init__(self, n, sid, d):
Person.__init__(self,n)
self.sid = sid
self.degree = d
print Student.__str__(self)

def __str__(self):
return Person.__str__(self) + "%15s%s\n%15s%s\n" % ("StudentID: ", self.sid, "Degree: ", self.degree)


When I execute the following

Jeff = Person("Jeff")
Cameron = Student('Cameron', 'U2314313', "Social Science")


it would produce something like:

Name: Jeff
Name: Cameron
Name: Cameron
StudentID:......
Degree:......


When initializing
Student
, it's calling
Student.__str__(self)
, and subsequently call
Person.__str__(self)
in order to bring back the name.

Just wondering if there's a better way to build the the structure so it's more usable and inline with the OO concept.

The result that I want is when I do the
__str__
for both
Student
or
Person
, it would list out all attributes, such as:

Name: Jeff
Name: Cameron
StudentID:......
Degree:......


and when I do something like
print Cameron
, it would still give me

Name: Cameron
StudentID:......
Degree:......


I know my code is duplicating it at the moment, but I can't figure out a way to make it work the way I intended... Help please.

Answer

You may use the getmembers function of inspect module to get the all the members of the class dynamically.

Generic function to return attributes based on passed class or class's object can be define as:

import inspect

def get_attributes(class_object):
    attributes = inspect.getmembers(class_object, lambda a:not(inspect.isroutine(a)))
    return [a for a in attributes if not(a[0].startswith('__') and a[0].endswith('__'))] 

Now the demonstration, on HOW this will work:

# Parent class
class MyClass(object):
    a = '12'
    b = '34'

# Child class
class MyChildClass(MyClass):
    c = '20'
    def __init__(self):
        self.x = 20

get_attributes(MyClass)  <-- Parent Class
# returns: [('a', '12'), ('b', '34')]
# Return all the class attributes of "MyClass"

get_attributes(MyChildClass)  <-- Child Class
# returns: [('a', '12'), ('b', '34'), ('c', '20')]
# Returns all the class attributes of "MyChildClass"

get_attributes(MyChildClass())  <-- Object Of Child Class
# returns: [('a', '12'), ('b', '34'), ('c', '20'), ('x', 20)]
# Returns all the class + object attributes of "MyChildClass's object"