[Python] Python @classmethod and @staticmethod decorators cause isinstance(…, FunctionType) to...

Discussão em 'Python' iniciado por Stack, Julho 8, 2025.

  1. Stack

    Stack Membro Participativo

    I am writing a Python metaclass that creates a special index of class members that meet certain criteria, one criterion being that those members should not be functions. I am checking this criterion with a call to isinstance for types.FunctionType:

    import types

    class MyMeta(type):
    def __new__(cls, clsname, bases, clsdict):
    field_names = [
    name for name, value in clsdict.items()
    # ...other conditions...
    and not isinstance(value, types.FunctionType)
    ]
    # ...


    This correctly omits most methods. However, I have discovered that this does not work for any methods with @classmethod or @staticmethod decorators, and isinstance(..., types.FunctionType) is always False for such methods:

    import types

    class MyMeta(type):
    def __new__(cls, clsname, bases, clsdict):
    print(clsname)
    for name, value in clsdict.items():
    print(f" {name} : {repr(value)}")
    print(f" FunctionType: {isinstance(value, types.FunctionType)}")
    print(f" classmethod: {isinstance(value, classmethod)}")
    print(f" staticmethod: {isinstance(value, staticmethod)}")
    print()

    # ...

    class MetaTest(metaclass=MyMeta):
    def normal_method(self):
    pass

    @classmethod
    def class_method(self):
    pass

    @staticmethod
    def static_method(self):
    pass


    class Test:
    def normal_method(self):
    pass

    @classmethod
    def class_method(self):
    pass

    @staticmethod
    def static_method(self):
    pass

    print(Test.__name__)
    for name, value in Test.__dict__.items():
    print(f" {name} : {repr(value)}")
    print(f" FunctionType: {isinstance(value, types.FunctionType)}")
    print(f" classmethod: {isinstance(value, classmethod)}")
    print(f" staticmethod: {isinstance(value, staticmethod)}")
    print()


    The above test code produces the following output:

    MetaTest
    __module__ : '__main__'
    FunctionType: False
    classmethod: False
    staticmethod: False
    __qualname__ : 'TestMeta'
    FunctionType: False
    classmethod: False
    staticmethod: False
    normal_method : <function TestMeta.normal_method at 0x7fbdbc47b760>
    FunctionType: True
    classmethod: False
    staticmethod: False
    class_method : <classmethod(<function TestMeta.class_method at 0x7fbdbc47b7f0>)>
    FunctionType: False
    classmethod: True
    staticmethod: False
    static_method : <staticmethod(<function TestMeta.static_method at 0x7fbdbc47b880>)>
    FunctionType: False
    classmethod: False
    staticmethod: True

    Test
    __module__ : '__main__'
    FunctionType: False
    classmethod: False
    staticmethod: False
    normal_method : <function Test.normal_method at 0x7fbdbc47b910>
    FunctionType: True
    classmethod: False
    staticmethod: False
    class_method : <classmethod(<function Test.class_method at 0x7fbdbc47b9a0>)>
    FunctionType: False
    classmethod: True
    staticmethod: False
    static_method : <staticmethod(<function Test.static_method at 0x7fbdbc47ba30>)>
    FunctionType: False
    classmethod: False
    staticmethod: True
    __dict__ : <attribute '__dict__' of 'Test' objects>
    FunctionType: False
    classmethod: False
    staticmethod: False
    __weakref__ : <attribute '__weakref__' of 'Test' objects>
    FunctionType: False
    classmethod: False
    staticmethod: False
    __doc__ : None
    FunctionType: False
    classmethod: False
    staticmethod: False


    isinstance(..., classmethod) and isinstance(..., staticmethod) both behave as expected, so one option is to replace

    and not isinstance(value, types.FunctionType)


    with

    and not isinstance(value (types.FunctionType, classmethod, staticmethod))


    which I have tested and verified that it does work. However, I find this kludgy and unmaintainable (am I supposed to exhaustively list every possible built-in decorator from now unto forever?). What I would like to know:

    1. Why are methods decorated with @classmethod and @staticmethod not considered children of types.FunctionType?
    2. Is there a clean way to check for functions, including methods decorated with @classmethod and @staticmethod, without exhaustively checking the return types of such decorators?

    Continue reading...

Compartilhe esta Página