6
\$\begingroup\$

I want to allow anyone that has never coded to make classes depending on my template with little to no knowledge of Python.

These classes need to do 2 things:

  • Inherit from other classes similar to them.
  • Contain variables, updating values if they have been changed or keeping them if not.

For the sake of simplicity I don't want to have super() on these new classes, as I'm trying to not frighten newcomers with things they can't understand yet. Here's how I did it:

class Template(object):

    def __init__(self):
        self.value = "hello"
        self.other_value = "bonjour"
        self.constant_value = 42
        current_class = self.__class__
        inits = []
        while (current_class.__name__ != "Template"):
            inits.append(current_class.init)
            current_class = current_class.__bases__[0]
        for i in reversed(inits):
            i(self)

    def init(self):
        pass

    def info(self):
        print self.value
        print self.other_value
        print self.constant_value
        print ""

class Deep(Template):
    def init(self):
        self.value = "howdy"
        self.other_value = "salut"

class Deeep(Deep):
    def init(self):
        self.value = "hi"

class Deeeep(Deeep):
    def init(self):
        self.value = "'sup"

very_deep = Deeeep()
not_so_deep = Deep()
very_deep.info()
not_so_deep.info()

This outputs :

sup
salut
42

howdy
salut
42

Which is exactly what I want, but it looks really weird, obfuscated and non-Pythonic. Any ideas for improvements?

\$\endgroup\$
2
  • \$\begingroup\$ Could you please explain a little bit more how a novice is supposed to use the Template class? Should they create their own classes which inherit from Template, or should they simply make a copy of the code and modify it to their needs? In either case I don't understand how this is going to be easier for them than just learning to actually write their own class which does what they need. \$\endgroup\$
    – mkrieger1
    Dec 9, 2016 at 11:46
  • 1
    \$\begingroup\$ The output should really be 'sup, not sup. That has mistakenly been changed in rev. 2, but I can't fix it because it's only a single-character edit. \$\endgroup\$
    – mkrieger1
    Dec 9, 2016 at 11:52

2 Answers 2

1
\$\begingroup\$

Instead of managing the class hierarchy yourself, you should rely on Python's standardized way of doing it: the MRO. You can reach every class in the hierarchy using it without falling in the trap of forgetting some when dealing with multiple inheritance (which your code does):

class Template(object):
    def __init__(self):
        self.value = "hello"
        self.other_value = "bonjour"
        self.constant_value = 42

        for cls in reversed(self.__class__.mro()):
            if hasattr(cls, 'init'):
                cls.init(self)

However, if your plan is to make support for the call of super() on init without the user explicitly calling it, I would advise to put the initialization stuff in init as well:

class Template(object):
    def __init__(self):
        for cls in reversed(self.__class__.mro()):
            if hasattr(cls, 'init'):
                cls.init(self)

    def init(self):
        self.value = "hello"
        self.other_value = "bonjour"
        self.constant_value = 42
\$\endgroup\$
2
\$\begingroup\$

This:

...
while (current_class.__name__ != "Template"):
...

is weird. Do this:

...
while current_class != Template:
...

it does the same, except comparing classes instead of strings.


This is strange as well:

for i in reversed(inits):
     i(self)

i is used for iteration so it becomes obsucre, are you calling an int? This:

for init in reversed(inits):
    init(self)

is more explanatory.


I don't really know about this next part, but you could define a small lambda

extract_first = lambda x: x[0]

with an explanatory name, leaving that part of the code as this:

extract_first = lambda x: x[0]

while current_class != Template:
    inits.append(current_class.init)
    current_class = extract_first(current_class.__bases__)
for init in reversed(inits):
    init(self)

It leaves it with more words and text but less programming lingo. Might be good.


Now what I would do if this was for someone new to programming is relay on something else then abstraction of the init and abstract in something like biology:

class Exists(object):
    perceptible = True


class Alive(Exists):
    can_use_sustenance = True


class Vertebrate(Alive):
    can_move = True


class Mammal(Vertebrate):
    heat_generation = True


class Dog(Mammal):
    pass


class Cat(Mammal):
    pass

Tested on my significant other :-)

\$\endgroup\$

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.