10

Suppose I have a class Foo, I want to define a function that receives the class constructor as a parameter:

def bar(class_name):
    local_class = None
    # TODO: if I call bar(Foo()), I want to get local_class = Foo()

How can I implement the function?

beaver
  • 550
  • 1
  • 9
  • 23
  • 3
    When you would call `bar(Foo())` , you would call `bar()` function with an instance of `Foo()` ,can't you directly use that instance? – Anand S Kumar Sep 22 '15 at 05:32
  • `Foo()` is not the class constructor. If you want to pass the class, you would pass `Foo`. – BrenBarn Sep 22 '15 at 05:35
  • Just past the class, `bar(Foo)`, then `local_class = class_name()` would create an instance of Foo. – AChampion Sep 22 '15 at 05:36
  • @AnandSKumar Inside the function, I want to get multiple independent instances of the class using the parameter ``class_name`` – beaver Sep 22 '15 at 05:38
  • @achampion What if ``Foo`` takes parameters? For example, ``bar(Foo(1,2,3))`` – beaver Sep 22 '15 at 05:39
  • @beaver `bar(functools.partial(Foo, 1, 2, 3))` – Huazuo Gao Sep 22 '15 at 05:40
  • @AnandSKumar I want to pass something that generally generates one object of a class, such as ``Foo(1,2,3)``, so that inside the function ``bar``, I can get multiple independent objects, all of which should be equivalent to be created as ``Foo(1,2,3)`` – beaver Sep 22 '15 at 05:46
  • @HuazuoGao I am sorry but it's a little inelegant to call the function. – beaver Sep 22 '15 at 05:49
  • Sounds like what you really want is `deepcopy` -- https://docs.python.org/3/library/copy.html#copy.deepcopy – Dunes Sep 22 '15 at 09:48

2 Answers2

12

The following bar function will work. Note, the first parameter will be a class itself and not the name of a class, so "class_name", which implies that it's a str, is misleading. args will be a tuple of args to initialize klass objects with, *-unpacked in the calls to klass. You said in a later comment that you wanted to "create multiple independent objects", all of the same class and initialized with the same args, so I've revised my answer to reflect that:

def bar(klass, *args):
    # Now you can create multiple independent objects of type klass,
    # all initialized with the same args
    obj1 = klass(*args)
    obj2 = klass(*args)
    # ...
    # do whatever you have in mind with the objs

Your "local_class" isn't a class at all, but rather an instance of klass, so that's a bad name; and anyway you want several of them.

Assuming Foo objects are initialized with three int arguments, and Baz objects with two strings, you can call bar like so:

bar(Foo, 1, 2, 3)
bar(Baz, 'Yo', 'bro')

etc.

Especially in a dynamically-typed language like Python, reasoning about code is more difficult when variables have misleading names.

BrianO
  • 1,496
  • 9
  • 12
1

When can pass the classname as an argument to your function, and then call class_name(). E.g., if you also want to pass arguments.

class Foo:
    def __init__(self, arg1, arg2):
        pass

def bar1(class_name):
    args = ("val1", "val2")
    local_class = class_name(*args)

or

def bar2(class_name):
    kwargs = {'arg1':'val1','arg2':'val2'}
    local_class = class_name(**kwargs)

You can call the functions like:

one = bar1(Foo)
two = bar2(Foo)

If you really want to call the class from a string read this post. I would suggest you use @Evan Fosmark's solution because use of eval and globals should be avoided

Community
  • 1
  • 1
MartyB
  • 135
  • 6