What's your problem?

Sometime you want to implement this pattern in your code:


>>> MyClass.method("Antonio")  #1
or
>>> my_class = MyClass()
>>> my_class.method("Antonio")  #2

Basically a dual method acting as classmethod (#1) or a normal method (#2).

Approaches

One way to do is simply like this:

class MyClass:
    def method(self=None, name: str) -> None:
        ...

As opposed to this that cover only the #2:

class MyClass:
    @classmethod
    def method(cls, name: str) -> None:
        ...

Why the simple solutionw works, it's nice to have a way to "mark" the method as being special in the same way we use @classmethod and @staticmethod.

class MyClass:
    @specialmethod
    def method(self, name: str) -> None:
        ...

self in the case of a method is the class instance, in case of a classmethod use it will be None!!

Solution

This is a class that implements a neat decorator:

class specialmethod:
    def __init__(self, method):
        self.method = method

    def __get__(self, instance, owner):
        if instance is None:
            return self.wraps(None)
        return self.wraps(instance)

    def wraps(self, bind):
        @functools.wraps(self.method)
        def wrapper(*args, **kwargs):
            return self.method(bind, *args, **kwargs)
        return wrapper