Reputation: 4348
So classmethods can be used as an alternative "constructor" in python, they are bound to the class and not to an instance, pretty clear so far. But my question is, if it is mandatory to have the same number of arguments in the returned instance of the class method as in the __init__
. More exactly :
class MyClass(object):
def __init__(self,name):
self.name=name
@classmethod
def alternative_init(cls,name,surname):
return cls(name,surname)
And if I try to create an instance Myclass("alex")
works fine, but if I try to create an instance Myclass.alternative_init("alex","james")
I have a TypeError
, because I pass to many arguments, and init take only 2 . Am I missing something?
Upvotes: 18
Views: 32186
Reputation: 11
class MyClass(object):
def __init__(self,name):
self.name=name
@classmethod
def alternative_init(cls,name,surname):
return cls(name)
a = MyClass("alex")
MyClass.alternative_init("alex","james")
Upvotes: 1
Reputation: 597
In Python, the first argument Passed to a method is always the object itself. If you call now your method with a name, you will get self as first parameter and the name as second.
When you call now the init method from inside of your classmethod, python has no idea what it should do with the surname.
Upvotes: 2
Reputation: 133
Because Myclass.alternative_init("alex","james")
calls the cls(name, surname) which same as MyClass(name,surname)
which also same as __init__(self,name,surname)
but your __init__
function don't have surname
parameter. You can make surname
optional by __init__(self,name,surname=None)
class MyClass(object):
def __init__(self,name,surname=None):
self.name=name
self.surname=surname
@classmethod
def alternative_init(cls,name,surname):
return cls(name,surname)
Upvotes: 2
Reputation: 71461
__init__
only takes one parameter, the name. Thus, you can pass either name
or surname
to cls
, but not both. However, you can create a class instance in classmethod
, and add an additional paramter:
class MyClass(object):
def __init__(self,name):
self.name=name
def __setattr__(self, name, val):
self.__dict__[name] = val
@classmethod
def alternative_init(cls,name,surname):
v = cls(name)
v.surname = surname
return v
Upvotes: 14
Reputation: 24233
You could do what you want like this:
class MyClass(object):
def __init__(self,name):
self.name=name
@classmethod
def alternative_init(cls,name,surname):
new_instance = cls(name)
new_instance.surname = surname
return new_instance
a = MyClass.alternative_init('Bob', 'Spongy')
print(a.name, a.surname)
# Bob Spongy
Upvotes: 2