0

I'm making a decorator (using functools) and I need to know if the received function is a function, class method or instance method.

I tried to use type(function)(as said here) to decide at first if it's a function or a method, but I don't understand how Python classifies them: I found that setters and getters are functions, while it should be instance methods cause they receive the parameter self.

Question: How can I distinguish between function (external, static), class methods and instance methods?

Take an example with

  • External function
  • Static method
  • Class method
  • Instance method
  • Getter
  • Setter
import functools

def decorator_show_type(func):
    """Decorator to get the type of setter and getter"""
    @functools.wraps(func)
    def tell(*args, **kwargs):
        show_type(func)
        return func(*args, **kwargs)
    return tell

def show_type(function):
    print(type(function))

def exte():
    print("exte")

class Foo:
    def __init__(self):
        self.var = 0

    @staticmethod
    def stat():
        print("stat")

    @classmethod
    def clas(cls):
        print("clas")

    def inst(self):
        print("inst")

    @property
    @decorator_show_type
    def var(self):
        print("get var")

    @var.setter
    @decorator_show_type
    def var(self, newvar):
        print("set var")

Then, verifying the type of each function/method I get

show_type(exte)  # <class 'function'>
bar = Foo()  # <class 'function'>
             # set var
bar.var  # <class 'function'>
         # get var
show_type(Foo.__init__)  # <class 'function'> 
show_type(Foo.stat)  # <class 'function'>
show_type(Foo.clas)  # <class 'method'>
show_type(Foo.inst)  # <class 'function'>
show_type(bar.__init__)  # <class 'method'>
show_type(bar.stat)  # <class 'function'>
show_type(bar.clas)  # <class 'method'>
show_type(bar.inst)  # <class 'method'>

Motivation: The decorator I want to make verifies the input type of a function and raises error if it's the wrong type, like here. For external functions it works fine, but it fails for class/instance methods due the cls/self which doesn't need a type annotation. I tried to verify if 'method' in str(type(function)): ignore first argument, but getters and setters are <class 'function'> and have the parameter self.

Carlos Adir
  • 452
  • 3
  • 9
  • Getters and setters are ordinary functions... – metatoaster Nov 20 '22 at 21:25
  • 1
    It may help to read about the descriptor protocol to understand the mechanisms behind the handling of object and class attributes (which are functions and properties, too) better. Starting point: https://docs.python.org/3/glossary.html#term-descriptor – Michael Butscher Nov 20 '22 at 21:32
  • An instance method is a `function`-valued class attribute. A class method is a `classmethod`-valued class attribute. A static method is a `staticmethod`-valued class attribute. To see this, you need to access the attributes from the class's `__dict__` attribute, because attribute access invokes the descriptor protocol. – chepner Nov 20 '22 at 22:34

0 Answers0