1

I am trying to call the constructor of a class object in python. I managed to get it to work using the following few lines:

obj = cls.__new__(cls)
n = (List of attribute names)
v = (List of attribute values)

for s in n:
    setattr(obj, s, v[s])

I was wondering if there is a way to directly insert the attribute value + name pairs into the constructor, cause the arguments are just ignored if i call the following:

obj = cls.__new__(cls, v)

p.s.: I am using python3

The class looks similar to this:

class InheritingClass(BaseClass):
    def __init__(self, basic_attribute, another_attribute=None):
        super().__init__(basic_attribute=basic_attribute)
        self.another_attribute= another_attribute

class BaseClass:
    def __init__(self, basic_attribute=1):
       self.basic_attribute= basic_attribute

So nothing special there

Rittel
  • 579
  • 5
  • 21
  • What is the class you are trying to instantiate? – Karin Aug 24 '16 at 06:39
  • 3
    `cls(s, v)` calls your constructor. `__new__` creates the instance, `__init__` initialises it; both are called by `Foo(s, v)`. If you do `cls = Foo`, `cls(s, v)` does the exact same thing. – Amadan Aug 24 '16 at 06:41
  • @Amadan thanks, that is what i was looking for – Rittel Aug 24 '16 at 06:47
  • If you are aiming the object instances `obj` in your case it is better to use the `__init__` for that instead of `__new__`. – prosti Jun 04 '19 at 08:53

4 Answers4

1

I was wondering if there is a way to directly insert the attribute value + name pairs into the constructor

Please don't do that. This would be the anti pattern. Instead, use the __init__ method to set the values. The __new__ method should be the memory space allocation that returns the object instance, obj in your case.

So you should probable better do this inside your __init__:

k = ['a', 'b', 'c']
v = [1, 2, 3]
d = dict(zip(k, v))

class C:
    def __init__(self, d):                
        for _ in d:            
            setattr(self, _, d[_])

ci=C(d)
print(ci.a) # 1

I used the dict as __init__ parameter, where I used the zip method to create one.

prosti
  • 42,291
  • 14
  • 186
  • 151
0

__init__ is the constructor of Python class instead of __new__. Refer Pythons use of new and init for more information.

Community
  • 1
  • 1
Moinuddin Quadri
  • 46,825
  • 13
  • 96
  • 126
0

To add, if you want to store arbitrary attributes to your class, you can use dict.update like so:

class BaseClass:
    def __init__(self, basic_attribute=1, **kw):
        self.basic_attribute = basic_attribute
        self.__dict__.update(**kw)


class InheritingClass(BaseClass):
    def __init__(self, basic_attribute, another_attribute=None, **kw):
        super().__init__(basic_attribute=basic_attribute, **kw)
        self.another_attribute = another_attribute

Then:

ic = InheritingClass('hi', a=1, b=20)
print(ic.a, ic.b)  # prints 1, 20
bananafish
  • 2,877
  • 20
  • 29
0

To answer the question "How do you call the constructor on a class object?" you need to look at the comments from Amadan way back on Aug 24, 2016 at 6:41.

The answer:

new_obj = cls()

Here's some example code that illustrates the point:

class C:
    @classmethod
    def c(cls):
        return cls()
    
c = C.c()
print(c) # displays <__main__.C object at 0x10ef16a90>

class D(C):
    pass
d = D.c()
print(d) # displays <__main__.D object at 0x10ef16370>

And so we see that you can instantiate an object from the cls object.

Now if we combine Amadan's comment with prosti's cool code for setting attributes, we get this:

class ObjectFactory:
    @classmethod
    def new(cls,**kwargs):
        return cls(**kwargs)

    def __init__( self, **kwargs ):
      for _ in kwargs:
        setattr( self, _ , kwargs[ _ ] )

class Person(ObjectFactory):

    pass

person = Person.new( first = "John", last = "Doe" )

print(person)            # <__main__.Person object at 0x10fe49ff0>
print(person.__dict__)   # {'first': 'John', 'last': 'Doe'}
Mark
  • 4,249
  • 1
  • 18
  • 27