Dynamic creation of an object instance of a class by name

Discussion in 'Python' started by Andre Meyer, Apr 7, 2004.

  1. Andre Meyer

    Andre Meyer Guest

    Hi all

    I have been searching everywhere for this, but have not found a
    solution, yet.

    What I need is to create an object that is an instance of a class (NOT a
    class instance!) of which I only know the name as a string. This what I
    tried:

    class A:
    def __init__(self, id):
    self.id = id
    def getID(self):
    print self.id

    ca = new.classobj('A', (), {})
    oa1 = ca()
    oa2 = new.instance(ca)

    oa1
    <__main__.A instance at 0x007E8AF8>

    oa1.getID()
    Traceback (most recent call last):
    File "<stdin>", line 1, in ?
    AttributeError: A instance has no attribute 'getID'

    oa2
    <__main__.A instance at 0x007E8AF8>

    oa2.getID()
    Traceback (most recent call last):
    File "<stdin>", line 1, in ?
    AttributeError: A instance has no attribute 'getID'


    Thus, both ways only produce a class instance, but NOT an object of that
    class!!! How can I get a new object instance???
    What else needs to be filled in for base_classes and __dict__ in
    new.classobj?


    Any help is appreciated, this is driving me nuts!

    kind regards
    Andre
    Andre Meyer, Apr 7, 2004
    #1
    1. Advertising

  2. cn = 'A'
    inst = eval('%s()' % cn)

    --
    Regards,

    Diez B. Roggisch
    Diez B. Roggisch, Apr 7, 2004
    #2
    1. Advertising

  3. Andre Meyer

    Peter Otten Guest

    Andre Meyer wrote:

    > I have been searching everywhere for this, but have not found a
    > solution, yet.
    >
    > What I need is to create an object that is an instance of a class (NOT a
    > class instance!) of which I only know the name as a string. This what I
    > tried:
    >
    > class A:
    > def __init__(self, id):
    > self.id = id
    > def getID(self):
    > print self.id
    >
    > ca = new.classobj('A', (), {})
    > oa1 = ca()
    > oa2 = new.instance(ca)
    >
    > oa1
    > <__main__.A instance at 0x007E8AF8>
    >
    > oa1.getID()
    > Traceback (most recent call last):
    > File "<stdin>", line 1, in ?
    > AttributeError: A instance has no attribute 'getID'
    >
    > oa2
    > <__main__.A instance at 0x007E8AF8>
    >
    > oa2.getID()
    > Traceback (most recent call last):
    > File "<stdin>", line 1, in ?
    > AttributeError: A instance has no attribute 'getID'
    >
    >
    > Thus, both ways only produce a class instance, but NOT an object of that
    > class!!! How can I get a new object instance???
    > What else needs to be filled in for base_classes and __dict__ in
    > new.classobj?
    >
    >
    > Any help is appreciated, this is driving me nuts!
    >
    > kind regards
    > Andre


    Don't listen to the voices whispering "Use eval()" or "globals() are the way
    to go", make it clean and explicit with a dictionary containing all classes
    you want to expose:

    >>> class A: pass

    ....
    >>> class B: pass

    ....
    >>> class C: pass

    ....
    >>> exposed = dict(A=A, B=B, C=C)
    >>> exposed["A"]()


    :)

    Peter
    Peter Otten, Apr 7, 2004
    #3
  4. (Andre Meyer) writes:

    > Hi all
    >
    > I have been searching everywhere for this, but have not found a
    > solution, yet.
    >
    > What I need is to create an object that is an instance of a class (NOT a
    > class instance!)


    I'm sorry, I can't for the life of me figure out what the (semantic)
    difference is between "intsance of a class" and "class instance".

    > of which I only know the name as a string. This what I
    > tried:
    >
    > class A:
    > def __init__(self, id):
    > self.id = id
    > def getID(self):
    > print self.id
    >
    > ca = new.classobj('A', (), {})


    This creates a new class which will be called "A", displacing your
    original class by the same name.

    > oa1 = ca()
    > oa2 = new.instance(ca)
    >
    > oa1
    > <__main__.A instance at 0x007E8AF8>
    >
    > oa1.getID()
    > Traceback (most recent call last):
    > File "<stdin>", line 1, in ?
    > AttributeError: A instance has no attribute 'getID'
    >
    > oa2
    > <__main__.A instance at 0x007E8AF8>
    >
    > oa2.getID()
    > Traceback (most recent call last):
    > File "<stdin>", line 1, in ?
    > AttributeError: A instance has no attribute 'getID'
    >
    >
    > Thus, both ways only produce a class instance, but NOT an object of that
    > class!!!


    Yes, they produce an instance of your newly created class.

    > How can I get a new object instance???


    I think you mean to ask "How can I get a new instance of the class
    whose name I have in a string?". In other words, you should be asking
    yourself, "How can I get my hands on an object whose name[*] I have in a
    string?" (One possible approach is shown below.)

    > What else needs to be filled in for base_classes and __dict__ in
    > new.classobj?


    You can't do it that way ... that way you create a _new_ separate
    class called "A".

    Here's how you might achieve what you want:

    >>> class A:

    .... def __init__(self, id):
    .... self.id = id
    .... def getID(self):
    .... print self.id
    ....
    >>> oa1 = globals()['A'](12345)
    >>> oa1

    <__main__.A instance at 0x8190844>
    >>> oa1.getID()

    12345
    >>>



    [*] I'm a bit wary about using "name" here, because I don't really
    mean the name of the class, but the name of a variable that
    happens to refer to the class.

    For example, consider (in the context established above)

    >>> B = A
    >>> del A
    >>> B.__name__

    'A'
    >>> A.__name__

    Traceback (most recent call last):
    File "<stdin>", line 1, in ?
    NameError: name 'A' is not defined

    So, while the name of the class is still "A", it is no longer
    known by an identifier of that name.
    Jacek Generowicz, Apr 7, 2004
    #4
  5. > Don't listen to the voices whispering "Use eval()" or "globals() are the
    > way to go", make it clean and explicit with a dictionary containing all
    > classes you want to expose:


    Out of curiosity - why not to use eval? having a dict like yours makes
    things look like your average java factory pattern - some explicit
    structure, to which access has to be guaranteed and that requires a
    registration.

    Of course, if you know that you will always only select the class from a
    fixed num of classes, your approach ensures that no non-compliant classes
    can be selected - but hey, we're dynamic here ;) You never can be totally
    sure what you get....
    --
    Regards,

    Diez B. Roggisch
    Diez B. Roggisch, Apr 7, 2004
    #5
  6. Andre Meyer

    Peter Otten Guest

    Diez B. Roggisch wrote:

    >> Don't listen to the voices whispering "Use eval()" or "globals() are the
    >> way to go", make it clean and explicit with a dictionary containing all
    >> classes you want to expose:

    >
    > Out of curiosity - why not to use eval? having a dict like yours makes
    > things look like your average java factory pattern - some explicit
    > structure, to which access has to be guaranteed and that requires a
    > registration.
    >
    > Of course, if you know that you will always only select the class from a
    > fixed num of classes, your approach ensures that no non-compliant classes
    > can be selected - but hey, we're dynamic here ;) You never can be totally
    > sure what you get....


    It's probably a matter of taste, but most of the time the use of eval()
    suggests more freedom than there actually is. Let's suppose there are 3
    classes A, B, and C that will be used by your eval(), that limitation may
    then be enforced in various parts of your code or in the documentation,
    while I tend to see exposed = dict(...) as self-documenting. You can go to
    the implementation of one class in the list to look up the interface.

    To take an (almost) real-world example from the library, what would you
    suppose the following to do?

    klass = eval(klass, vars(logging))

    What would you do to make the above accept your special-purpose handler
    class? I think something like

    availableHandlers = {...}

    def registerHandler(name, klass, replace=False):
    if not replace and name in availableHandlers:
    raise NameClash
    availableHandlers[name] = klass

    formatterClass = availableHandlers[name]

    is much clearer.

    As a side note (not that I think this is important here), eval() is not the
    fastest of functions:

    $ timeit.py -s"class A: pass" -s"all=dict(A=A)" "all['A']"
    10000000 loops, best of 3: 0.147 usec per loop
    $ timeit.py -s"class A: pass" "eval('A')"
    10000 loops, best of 3: 19.7 usec per loop


    Peter
    Peter Otten, Apr 7, 2004
    #6
  7. Andre Meyer

    Andre Meyer Guest

    Right, ok, well, I do not assume to know what classes can be instantiated, thus
    anything like accessing globals() is not likely to help, sorry. The eval()
    version works pretty ok so far. I am develpoing a module of which other people
    can make use of by developing their own subclasses, but they need to be
    instantiated by my code. Eval() does the trick for me or is there a better way,
    assuming you do not need to know which class it might be beforehand?
    btw I LOVE dynamicity... ;-)

    kind regards
    Andre
    Andre Meyer, Apr 7, 2004
    #7
  8. Andre Meyer

    John Roth Guest

    "Andre Meyer" <> wrote in message
    news:...
    > Right, ok, well, I do not assume to know what classes can be instantiated,

    thus
    > anything like accessing globals() is not likely to help, sorry. The eval()
    > version works pretty ok so far. I am develpoing a module of which other

    people
    > can make use of by developing their own subclasses, but they need to be
    > instantiated by my code. Eval() does the trick for me or is there a better

    way,
    > assuming you do not need to know which class it might be beforehand?
    > btw I LOVE dynamicity... ;-)
    >
    > kind regards
    > Andre


    As long as you know where the class is (and I presume you do,
    since eval() is working), you can use getattr() to find the class,
    and then instantiate it the usual way. It's a good deal faster.

    The thing to remember is that eval() is not magic: it still needs
    to find the class you're referencing by the usual lookup path.

    For example, if you know it's in the current module, you
    could say:

    obj = getattr(globals(), "theClass")()

    If it's in another module, then the incantation
    becomes:

    obj = getattr(module, "theClass")()

    The moral of the story is that you do have to know where
    the class object resides.

    John Roth
    >
    >
    John Roth, Apr 8, 2004
    #8
  9. Andre Meyer

    Peter Otten Guest

    Andre Meyer wrote:

    > Right, ok, well, I do not assume to know what classes can be instantiated,
    > thus anything like accessing globals() is not likely to help, sorry. The
    > eval() version works pretty ok so far. I am develpoing a module of which
    > other people can make use of by developing their own subclasses, but they
    > need to be instantiated by my code. Eval() does the trick for me or is
    > there a better way, assuming you do not need to know which class it might
    > be beforehand? btw I LOVE dynamicity... ;-)


    You have to pass the name of the subclasses to your module somehow for your
    code to know what to instantiate. Why don't you pass the subclasses
    themselves instead?

    Peter
    Peter Otten, Apr 8, 2004
    #9
  10. Andre Meyer <> writes:

    > Right, ok, well, I do not assume to know what classes can be
    > instantiated,


    But you are assuming that you have a string which knows, right ...

    > thus anything like accessing globals() is not likely to help,
    > sorry. The eval() version works pretty ok so far.


    .... thus I fail to see a fundamental difference between the eval and
    globals approaches, in both cases you need the name of the class.

    > I am develpoing a module of which other people can make use of by
    > developing their own subclasses, but they need to be instantiated by
    > my code. Eval() does the trick for me or is there a better way,
    > assuming you do not need to know which class it might be beforehand?


    Why don't you just get your users to pass whatever class object they
    want, to your code ... which can then instantiate the class.

    Something like:

    # Your code
    class your_base:
    foo = 1

    def do_something_with_user_class_instance(user_class):
    uci = user_class()
    print uci
    print dir(uci)
    return uci

    # User code
    class user_derived(your_base):
    def __init__(self):
    self.bar = 2

    do_something_with_user_class_instance(user_derived)
    Jacek Generowicz, Apr 8, 2004
    #10
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Sridhar R
    Replies:
    14
    Views:
    1,398
    =?iso-8859-1?Q?Fran=E7ois?= Pinard
    Feb 10, 2004
  2. Andre Meyer
    Replies:
    1
    Views:
    582
    Peter Abel
    Apr 7, 2004
  3. Daniel Lipovetsky
    Replies:
    2
    Views:
    345
    Jordan Greenberg
    Mar 12, 2007
  4. dmitrey
    Replies:
    4
    Views:
    243
    dmitrey
    Oct 4, 2008
  5. Martin P. Hellwig
    Replies:
    1
    Views:
    374
    Martin P. Hellwig
    Mar 26, 2010
Loading...

Share This Page