0

I'm creating a function that creates a class inside it and returns that...

    def create_object(**objects):
        # creates class, NewClass
        class NewClass:
            pass
        for key in objects.keys():
            # creating objects in NewClass
            exec("NewClass.%s = %s" % (key, objects[key]))
        return NewClass

and when we called this function,

new_object = create_object(first_name='Mayank', last_name='Tyagi')
new_object.first_name

this works fine and gives output

>>> 'Mayank'

but I want to create a function that will create a class with variable name. eg

    def object(class_name, **objects):
        # create a class where the value of class_name is the name of class
        exec("class %s:\n\tpass" % (class_name))
        for key in objects.keys():
            # creating new objects in this class
            exec("NewClass.%s = %s" % (key, objects[key]))

and after calling the function,

object('ClassName', first_name='Mayank', last_name='Tyagi')
ClassName.first_name

it should give the output,

>>>'Mayank'

How to make this?

-asking for help with a hope:)

martineau
  • 119,623
  • 25
  • 170
  • 301
  • In the last line of 4th code block, it is: exec("%s.%s = %s" % (class_name,key,objects[key])) – Mayank Tyagi Dec 31 '19 at 16:54
  • The second `exec` should be `exec("%s.%s = %s" % (class_name, key, objects[key]))`. Although, I don't really encourage this type of design. – Rahul Bharadwaj Dec 31 '19 at 16:57
  • 2
    Don't use `exec`, use [`type`](https://docs.python.org/3/library/functions.html#type): `cls = type(name, (object,), objects)`. – ekhumoro Dec 31 '19 at 17:00

1 Answers1

1

dont use exec unless you absolutely have to, which you don't.

use type

def __init__(self, first, last):
    self.first = first
    self.last = last

cls_ = type("Mayank", (object,), dict(__init__=__init__))

obj = cls_("Mayank","Tyagi")

print(obj, vars(obj))

out:

<__main__.Mayank object at 0x1028050b8> {'first': 'Mayank', 'last': 'Tyagi'}

edit: from Patrick's comment: whatever goes in that dictiory for the 3rd argument to type is a class-level attribute. I assume the OP wants to create an instance of a class with a first and lastname instance-level attribute into which they want to want to store names, at the instance level. Thus allowing different Mayank instances to have different names. Of course, they could mean a class with a first and name, set at the class level of Mayank/Tyagi. in which case those would be be passed into that dict directly, rather than providing an init function.

Subtlety: even a class-level first and last name allows instance-level overrides:

m1 = Mayank()
m2 = Mayank()
m3 = Mayank()

m1.last = "Foo"
m2.last = "Bar"

printing last names for m1,m2,m3 would print Foo, Bar, Mayank respectively as the assignment happens at the instance level, without altering the class.

JL Peyret
  • 10,917
  • 2
  • 54
  • 73
  • This answer is correct, but I think it could use an explanation of why you're passing the `__init__` function instead of the first and last names. – Patrick Haugh Dec 31 '19 at 17:06