1

I read here and here that Python methods can be aliased using =.

However, when I try it on the __init__ method, it doesn't seem to work.

class MyClass:
    def __init__(self):
        print("Hi mum!")
    
    new_name = __init__

a = MyClass()
b = MyClass.new_name()

The b = MyClass.new_name() causes this error:

TypeError: __init__() missing 1 required positional argument: 'self'

Why does this not work? And how should I alias __init__ correctly?

7
  • 1
    Make new_name static or class method that returns new MyClass object. Commented Dec 8, 2023 at 0:37
  • @AndrejKesely Yeah, that was also my first idea for a workaround. But I would still like to understand why my code above doesn't work. Commented Dec 8, 2023 at 0:44
  • 1
    The __init__ method expects the positional argument self, as you can see by it's definition. When you call the new_name method explicitly from the class, there is no positional argument passed, like there is implicitly when instantiating a new object Commented Dec 8, 2023 at 0:47
  • @schwartz721 Can I mimic this implicit behavior somehow? Making new_name a static method seems inconvenient because if the parameters of __init__ change, then I also have to update the parameters of new_name, and the arguments to MyClass(...) inside new_name. Commented Dec 8, 2023 at 0:52
  • You can call the __new__ method of a class to create an instance without it automatically calling the __init__ method. So you could do something like b = MyClass.new_name(MyClass.__new__(MyClass)). You'll have to modify the __init__ method to return self though, so that b points to the instance created Commented Dec 8, 2023 at 0:59

2 Answers 2

2

__init__ is not a constructor. __new__ is. __init__ is an instance method that performs initialization on an instance after it is constructed by the static method __new__. The reason why both __new__ and __init__ are called when you call the class with MyClass() is because it is what the __call__ method of the type, or metaclass, of MyClass, does.

So if you want to properly alias the constructor of a class you can alias the __call__ method of its metaclass:

class AliasedConstructor(type):
    new_name = type.__call__

class MyClass(metaclass=AliasedConstructor):
    def __init__(self):
        print("Hi mum!")

MyClass.new_name()

Alternatively, you can make the alias a classmethod descriptor that binds type.__call__ to the current class:

class MyClass:
    def __init__(self):
        print("Hi mum!")

    new_name = classmethod(type.__call__)

Both approaches would output:

Hi mum!
Sign up to request clarification or add additional context in comments.

4 Comments

Introducing a meta lass for this seems like overkill
Indeed the use of a metaclass was more of a demonstration of what happens when you call MyClass(), that the __call__ method of the metaclass is called. I've updated my answer to do away from a metaclass. +1 to your answer too.
Well, I'm not sure if my answer actually works. On the Metro right now...
It does work, though it feels weird indeed to modify a class after its definition.
1

The __init__ method was aliased. But __init__ is not a constructor to begin with.

You could probably do:

MyClass.new_name = MyClass.__call__

If you want things to "just work".

This is assuming your class doesn't define a __call__ method that would shadow type.__call__.

But this is rather weird to begin with, IMO. Just define a classmethod.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.