簡體   English   中英

在 Python 中可以使用 instance() 來檢測 class 方法嗎?

[英]In Python can instance() be used to detect a class method?

如何確定 object 是否是 class 方法? 使用 instance() 不是最佳實踐嗎?如何讓它發揮作用?

    class Foo:
        class_var = 0

        @classmethod
        def bar(cls):
            cls.class_var += 1
            print("class variable value:", cls.class_var)


    def wrapper(wrapped: classmethod):
        """
        Call the wrapped method.

        :param wrapped (classmethod, required)
        """
        wrapped()


    Foo.bar()
    wrapper(Foo.bar)
    print("the type is:", type(Foo.bar))
    print("instance check success:", isinstance(Foo.bar, classmethod))

Output:

class variable value: 1
class variable value: 2
the type is: <class 'method'>
instance check success: False

Process finished with exit code 0

As you know Python fills the first parameter of the classmethod s with a reference to the class itself and it doesn't matter if you call that method from the class or the instance of the class. 方法 object 是一個 function,它綁定了一個 object。

object 可以通過.__self__屬性檢索。 因此,您可以簡單地檢查.__self__屬性是否為 class 。 如果是 class,class 是type

一種方法:

class Foo:

    @classmethod
    def fn1(cls):
        pass

    def fn2(self):
        pass


def is_classmethod(m):
    first_parameter = getattr(m, '__self__', None)
    if not first_parameter:
        return False

    type_ = type(first_parameter)
    return type_ is type


print(is_classmethod(Foo.fn1))
print(is_classmethod(Foo().fn1))
print("-----------------------------------")
print(is_classmethod(Foo.fn2))
print(is_classmethod(Foo().fn2))

output:

True
True
-----------------------------------
False
False

檢查模塊中有一個ismethod專門檢查 object 是否是綁定方法。 您也可以在檢查第一個參數的類型之前使用它。

解決方案2:

您的isinstance解決方案不起作用,因為classmethod是一個描述符。 如果你想獲取實際的類方法實例,你應該檢查 Foo 的命名空間並從那里獲取方法。

class Foo:

    @classmethod
    def fn1(cls):
        pass

    def fn2(self):
        pass


def is_classmethod(cls, m):
    return isinstance(cls.__dict__[m.__name__], classmethod)


print(is_classmethod(Foo, Foo.fn1))
print(is_classmethod(Foo, Foo().fn1))
print("-----------------------------------")
print(is_classmethod(Foo, Foo.fn2))
print(is_classmethod(Foo, Foo().fn2))

如果您只想告訴 class 方法與常規方法和 static 方法不同,那么您可以使用inspect.ismethod(f)進行檢查。

class A:
    def method(self): pass
    @classmethod
    def class_method(self): pass
    @staticmethod
    def static_method(): pass

在 REPL 中:

>>> from inspect import ismethod
>>> ismethod(A.method)
False
>>> ismethod(A.class_method)
True
>>> ismethod(A.static_method)
False

如果您更喜歡使用isinstance執行此操作,則可以使用typing.types.MethodType

>>> from typing import types
>>> isinstance(A.method, types.MethodType)
False
>>> isinstance(A.class_method, types.MethodType)
True
>>> isinstance(A.static_method, types.MethodType)
False

請注意,這些測試將錯誤地識別例如A().method ,因為實際上我們只是在測試綁定方法,而不是未綁定的 function。 因此,上述解決方案僅在您檢查A.something ,其中A是 class 並且something是常規方法、class 方法或 static 方法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM