4

How can I create classes dynamically in a class? As I tried below, I get a NameError: name 'Foo is not defined. I am quite new to Python, pls forgive me if it's obvious.

class Parent(object):
    name2class = {'foo' : Foo, 'bar' : Bar }

    def do(self,string):
        return name2class[string]()

class Foo(Parent):
    pass

class Bar(Parent):
    pass

if __name__ == '__main__':
    parent = Parent()
    instance = parent.do()
1

4 Answers 4

3

As you've written this, you need to define Foo and Bar above Parent since Parent references the other classes.

Edit: You just need to move those class references into the method:

class Parent(object):
    def do(self,string):
        name2class = {'foo' : Foo, 'bar' : Bar }
        return name2class[string]()

class Foo(Parent):
    pass

class Bar(Parent):
    pass

if __name__ == '__main__':
    parent = Parent()
    instance = parent.do('foo')

Edit2: Here's your factory version:

class Parent(object):
    # Add shared methods here
    pass

class Foo(Parent):
    # Add unique methods
    pass

class Bar(Parent):
    # Add unique methods
    pass

class ParentFactory(object):
    def __init__(self):
        self.name2class = {'foo' : Foo, 'bar' : Bar}

    def create(self, string):
        return self.name2class[string]()

if __name__ == '__main__':
    factory = ParentFactory()
    instance = factory.create('foo')
Sign up to request clarification or add additional context in comments.

11 Comments

In that case, he won't be able to inherit from Parent.
Btw, this really makes almost no sense as a construct. I was really just answering to show that in python, class definitions are expressions, so variable scoping rules apply. If you want to explain how you were trying to use this dynamic resolution (factory pattern?), I could help you find a better approach.
Thank you for your answers. My porblem is as it follows: I get a telgram from my client as a string. In this string, there is a section were there stands which kind of telgram it is ( there are a few and could get more in future) and in case of this information I want to create a class with its specific methods, inherited from parent, because the telegrams are often quite similar
@KevinStone: in Python class is actually a statement, not an expression.
@GrijeshChauhan Ultimately, it's because he/she was referencing classes that weren't defined yet in the scope. Class definitions are statements, so they are evaluated in order and variable scoping rules apply. Here's an an example: gist.github.com/kevinastone/7022045 . In that example, if x=1 was already defined in our scope, we'd get an error on the class definition of A (such as this example with x after the class definition): gist.github.com/kevinastone/7022068
|
1

The classes Foo and Bar were not defined by the time name2class dictionary instantiation needed them. The other bug was no parameter being passed to Parent.do()

class Parent(object):
    def __init__(self):
        self.name2class = {'foo' : Foo, 'bar' : Bar}

    def do(self, string):
        return self.name2class[string]()

class Foo(Parent):
    pass

class Bar(Parent):
    pass

if __name__ == '__main__':
    parent = Parent()
    instance = parent.do('foo')

1 Comment

I forgot to mention in my code, that the parent class gets arguments in __init__(self,telgram): self.telgram = telgram. Otherwise your solution would work fine ;)
1

You can use python type(name, bases, dict) functuion:...

Not Working


OK. Take a look here:

class Parent(object):

        childs = {}
        def somefunc(self):
                print "Hello from, %s"%self

        def do(self, string):

                return self.childs[string]()

class Foo(Parent):

        pass

class Bar(Parent):

        pass

parent = Parent()
parent.somefunc()
parent.childs["foo"] = Foo
parent.childs["bar"] = Bar
foo = parent.do("foo")
foo.somefunc()
bar = parent.do("bar")
bar.somefunc()

Which gives me:

Hello from, <__main__.Parent object at 0x...>
Hello from, <__main__.Foo object at 0x...>
Hello from, <__main__.Bar object at 0x...>

7 Comments

The new classes won't have the methods defined in class Foo then.
@drrtyrokka, check out my modified answer
Thanks but the factory solution is a better one for me, though this one works too.
@Vik2015: you obviously misunderstand type. First point, It's not ia function, it's a class. Second point: it's the default metaclass. IOW: it's main role is to create new classes, which is what it does the way you call it. In fact the class statement is mostly syntactic sugar for a call to type with name, bases and dict. To make a long story short: your first example doesn't instanciate the Foo or `Bar' subclasses, it creates new subclasses (with an empty namespace) and instanciate them.
@brunodesthuilliers, I understood this. Thats why I made second example
|
0

Defining a new child class should not impact the base class implementation. The appropriate design pattern here is the Factory. There are many ways to implement it, from a simple function to a dynamic registration mechanism. The simpler version:

class Parent(object):
   # your code here
   pass

class Child1(Parent):
   # XXX

class Child2(Parent):
   # XXX

class Child2(Parent):
   # XXX


CLSMAP = {
    "name1": Child1,
    "name2": Child2,    
    "name3": Child3,
    }   

def create(name, *args, **kw):
   return CLSMAP[name](*args, **kw)

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.