vincent
vincent

Reputation: 1390

Python class inheritance: dynamic attribute creation

I'm not sure if I'm asking this correctly, but I know you all are smart enough to figure it out :). I am having trouble condensing some repetitive code in a few python classes. Here is an example of what I mean...

class Parent:

    PATH_PROPERTIES = [ 'parent' ]

    def __init__(self, path):
        self.props = { 'parent': path }

    def getPath(self):
        return self.props['parent']


class Child(Parent):

    PATH_PROPERTIES = [ 'child' ]

    def __init__(self, path):
        self.props = { 'child': path }

    def getPath(self):
        return self.props['child']

Above, is the current situation, but I would like to reduce some of the duplication by doing something like...

class Parent:
    name = 'parent'

    PATH_PROPERTIES = [ name ]

    def __init__(self, path):
        self.props = ( name: path)

    def getPath(self):
        return self.props[name] 

The last bit of code obviously doesn't work. I can't find anything on Python being able to do C++-like macros. What is the best way to condense this code?

Upvotes: 1

Views: 153

Answers (2)

unutbu
unutbu

Reputation: 880677

You could use inheritance:

class Parent:

    PATH_PROPERTIES = [ 'parent' ]

    def __init__(self, path):
        self.props = { self.PATH_PROPERTIES[0]: path }

    def getPath(self):
        return self.props[self.PATH_PROPERTIES[0]]


class Child(Parent):

    PATH_PROPERTIES = [ 'child' ]    


c = Child('path')
print(c.getPath())

prints

path

Note that in Python it is usually preferable to use a property instead of a getter function:

class Parent:

    PATH_PROPERTIES = 'parent'

    def __init__(self, path):
        self.props = { self.PATH_PROPERTIES: path }

    @property
    def path(self):
        return self.props[self.PATH_PROPERTIES]


class Child(Parent):

    PATH_PROPERTIES = 'child'         

c = Child('path')
print(c.path)

also prints

path

Note that c.path looks like an attribute lookup, but since path is a property, it calls the function decorated with @property. The syntax looks nicer than c.getPath() and yet gives you the same functionality. There is a decorator to make setters too.

Upvotes: 2

kindall
kindall

Reputation: 184345

You should generally be able to do this with standard inheritance with a little redesign (as in unutbu's answer), but you could write a factory function to create your classes. This is probably the closest to what you'd do in C++ with macros:

def make_class(name, base=object):

    class Class(base):

        PATH_PROPERTIES = [name]

        def __init__(self, path):
            self.props = {name: path}

        @property
        def path(self):
            return self.props[name]

    Class.__name__ = name.title()
    return Class

Parent = make_class("parent")
Child  = make_class("child", Parent)

Upvotes: 1

Related Questions