Python __init__ and classmethod, do they have to have the same number of args?

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)

__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

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