Python:检查方法是否是静态的

发布于 2024-12-24 16:33:22 字数 308 浏览 2 评论 0原文

假设以下类定义:

class A:
  def f(self):
    return 'this is f'

  @staticmethod
  def g():
    return 'this is g'

a = A() 

因此 f 是普通方法,g 是静态方法。

现在,我如何检查函数对象 af 和 ag 是否是静态的? Python 中有“isstatic”函数吗?

我必须知道这一点,因为我有包含许多不同函数(方法)对象的列表,并且要调用它们,我必须知道它们是否期望“self”作为参数。

assume following class definition:

class A:
  def f(self):
    return 'this is f'

  @staticmethod
  def g():
    return 'this is g'

a = A() 

So f is a normal method and g is a static method.

Now, how can I check if the funcion objects a.f and a.g are static or not? Is there a "isstatic" funcion in Python?

I have to know this because I have lists containing many different function (method) objects, and to call them I have to know if they are expecting "self" as a parameter or not.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

贱人配狗天长地久 2024-12-31 16:33:22

让我们尝试一下:

>>> import types
>>> class A:
...   def f(self):
...     return 'this is f'
...   @staticmethod
...   def g():
...     return 'this is g'
...
>>> a = A()
>>> a.f
<bound method A.f of <__main__.A instance at 0x800f21320>>
>>> a.g
<function g at 0x800eb28c0>
>>> isinstance(a.g, types.FunctionType)
True
>>> isinstance(a.f, types.FunctionType)
False

看起来您可以使用 types.FunctionType 来区分静态方法。

Lets experiment a bit:

>>> import types
>>> class A:
...   def f(self):
...     return 'this is f'
...   @staticmethod
...   def g():
...     return 'this is g'
...
>>> a = A()
>>> a.f
<bound method A.f of <__main__.A instance at 0x800f21320>>
>>> a.g
<function g at 0x800eb28c0>
>>> isinstance(a.g, types.FunctionType)
True
>>> isinstance(a.f, types.FunctionType)
False

So it looks like you can use types.FunctionType to distinguish static methods.

櫻之舞 2024-12-31 16:33:22

你的方法对我来说似乎有点缺陷,但你可以检查类属性:(

在Python 2.7中):

>>> type(A.f)
<type 'instancemethod'>
>>> type(A.g)
<type 'function'>

或在Python 3.x中检查实例属性

>>> a = A()
>>> type(a.f)
<type 'method'>
>>> type(a.g)
<type 'function'>

Your approach seems a bit flawed to me, but you can check class attributes:

(in Python 2.7):

>>> type(A.f)
<type 'instancemethod'>
>>> type(A.g)
<type 'function'>

or instance attributes in Python 3.x

>>> a = A()
>>> type(a.f)
<type 'method'>
>>> type(a.g)
<type 'function'>
羅雙樹 2024-12-31 16:33:22

为了补充这里的答案,在 Python 3 中最好的方法如下:

import inspect

class Test:
    @staticmethod
    def test(): pass

isstatic = isinstance(inspect.getattr_static(Test, "test"), staticmethod)

我们使用 getattr_static 而不是 getattr,因为 getattr 将检索绑定方法或函数,而不是 staticmethod 类对象。您可以对 classmethod 类型和 property 进行类似的检查(例如使用 @property 装饰器定义的属性)

从技术上讲,任何方法都可以用作“静态”方法,只要它们在类本身上调用,所以请记住这一点。例如,这将工作得很好:

class Test:
    def test():
        print("works!")

Test.test()

该示例不适用于 Test实例,因为该方法将绑定到实例并被称为 Test。改为测试(自我)

在某些情况下,实例和类方法也可以用作静态方法,只要正确处理第一个参数即可。

class Test:
    def test(self):
        print("works!")

Test.test(None)

也许另一种罕见的情况是静态方法也绑定到类或实例。例如:

class Test:
    @classmethod
    def test(cls): pass

Test.static_test = staticmethod(Test.test)

虽然从技术上讲它是一个静态方法,但它的行为实际上就像一个类方法。因此,在您的自省中,您可以考虑检查 __self__ (在 __func__ 上递归)以查看该方法是否绑定到类或实例。

对于那些进行更深入内省的人来说,另一个最后的警告是静态方法可以在不同的类中定义。 __qualname__ 将显示静态方法是否在其附加的类中定义。

To supplement the answers here, in Python 3 the best way is like so:

import inspect

class Test:
    @staticmethod
    def test(): pass

isstatic = isinstance(inspect.getattr_static(Test, "test"), staticmethod)

We use getattr_static rather than getattr, since getattr will retrieve the bound method or function, not the staticmethod class object. You can do a similar check for classmethod types and property's (e.g. attributes defined using the @property decorator)

Technically, any method can be used as "static" methods, so long as they are called on the class itself, so just keep that in mind. For example, this will work perfectly fine:

class Test:
    def test():
        print("works!")

Test.test()

That example will not work with instances of Test, since the method will be bound to the instance and called as Test.test(self) instead.

Instance and class methods can be used as static methods as well in some cases, so long as the first arg is handled properly.

class Test:
    def test(self):
        print("works!")

Test.test(None)

Perhaps another rare case is a staticmethod that is also bound to a class or instance. For example:

class Test:
    @classmethod
    def test(cls): pass

Test.static_test = staticmethod(Test.test)

Though technically it is a staticmethod, it is really behaving like a classmethod. So in your introspection, you may consider checking the __self__ (recursively on __func__) to see if the method is bound to a class or instance.

Another final caution for those doing more in depth introspection is that a staticmethod could be defined in a different class. The __qualname__ will reveal whether the static method was defined in the class it is attached to or not.

海夕 2024-12-31 16:33:22

我碰巧有一个模块可以解决这个问题。它是Python2/3 兼容解决方案。并且它允许使用从父类继承的方法进行测试。

另外,该模块还可以测试:

  1. 常规属性
  2. 属性样式方法
  3. 常规方法
  4. 静态方法
  5. 类方法

例如:

class Base(object):
    attribute = "attribute"

    @property
    def property_method(self):
        return "property_method"

    def regular_method(self):
        return "regular_method"

    @staticmethod
    def static_method():
        return "static_method"

    @classmethod
    def class_method(cls):
        return "class_method"

class MyClass(Base):
    pass

以下是仅静态方法的解决方案。但我建议使用该模块发布在这里

import inspect

def is_static_method(klass, attr, value=None):
    """Test if a value of a class is static method.

    example::

        class MyClass(object):
            @staticmethod
            def method():
                ...

    :param klass: the class
    :param attr: attribute name
    :param value: attribute value
    """
    if value is None:
        value = getattr(klass, attr)
    assert getattr(klass, attr) == value

    for cls in inspect.getmro(klass):
        if inspect.isroutine(value):
            if attr in cls.__dict__:
                bound_value = cls.__dict__[attr]
                if isinstance(bound_value, staticmethod):
                    return True
    return False

I happens to have a module to solve this. And it's Python2/3 compatible solution. And it allows to test with method inherit from parent class.

Plus, this module can also test:

  1. regular attribute
  2. property style method
  3. regular method
  4. staticmethod
  5. classmethod

For example:

class Base(object):
    attribute = "attribute"

    @property
    def property_method(self):
        return "property_method"

    def regular_method(self):
        return "regular_method"

    @staticmethod
    def static_method():
        return "static_method"

    @classmethod
    def class_method(cls):
        return "class_method"

class MyClass(Base):
    pass

Here's the solution for staticmethod only. But I recommend to use the module posted here.

import inspect

def is_static_method(klass, attr, value=None):
    """Test if a value of a class is static method.

    example::

        class MyClass(object):
            @staticmethod
            def method():
                ...

    :param klass: the class
    :param attr: attribute name
    :param value: attribute value
    """
    if value is None:
        value = getattr(klass, attr)
    assert getattr(klass, attr) == value

    for cls in inspect.getmro(klass):
        if inspect.isroutine(value):
            if attr in cls.__dict__:
                bound_value = cls.__dict__[attr]
                if isinstance(bound_value, staticmethod):
                    return True
    return False
冰雪梦之恋 2024-12-31 16:33:22

何苦呢?您可以像调用 f 一样调用 g:

a = A()
a.f()
a.g()

Why bother? You can just call g like you call f:

a = A()
a.f()
a.g()
囍孤女 2024-12-31 16:33:22

python 中无法检查方法是否是静态的,只能通过方法对象来检查。这是我的实现。

def isStaticmethod_withClass(classObj, methodName):
    return isinstance(inspect.getattr_static(classObj, methodName), staticmethod)


def isStaticmethod_onlyByStringDefinition(method):
    if not isinstance(method, types.FunctionType):
        return False

    return inspect.getsource(method).strip().startswith('@staticmethod')


def isStaticmethod(method):
    if isStaticmethod_onlyByStringDefinition(
            method):  # check being static method with it's string definition
        staticmethod_actualClass = getStaticmethod_actualClass(method)  # gets class object
        return isStaticmethod_withClass(staticmethod_actualClass, method.__name__)
    return False


def getStaticmethod_actualClass(method):
    if not isStaticmethod_onlyByStringDefinition(method):
        return None
    className = method.__qualname__.split('.')[0]
    moduleName = method.__module__
    actualClass = getattr(sys.modules[moduleName], className)
    return actualClass


def isClassMethod(method):
    bound_to = getattr(method, '__self__', None)
    if not isinstance(bound_to, type):
        # must be bound to a class
        return False
    name = method.__name__
    for cls in bound_to.__mro__:
        descriptor = vars(cls).get(name)
        if descriptor is not None:
            return isinstance(descriptor, classmethod)
    return False
    ```
    function `isStaticmethod` can get if the object is a static method or not. also you may get the actual class of that method with `getStaticmethod_actualClass`.

the `isStaticmethod_withClass` is from @Azmisov 's code here.

There is no way in python to check if the method is static or not, only with having the method object. this is my implementation.

def isStaticmethod_withClass(classObj, methodName):
    return isinstance(inspect.getattr_static(classObj, methodName), staticmethod)


def isStaticmethod_onlyByStringDefinition(method):
    if not isinstance(method, types.FunctionType):
        return False

    return inspect.getsource(method).strip().startswith('@staticmethod')


def isStaticmethod(method):
    if isStaticmethod_onlyByStringDefinition(
            method):  # check being static method with it's string definition
        staticmethod_actualClass = getStaticmethod_actualClass(method)  # gets class object
        return isStaticmethod_withClass(staticmethod_actualClass, method.__name__)
    return False


def getStaticmethod_actualClass(method):
    if not isStaticmethod_onlyByStringDefinition(method):
        return None
    className = method.__qualname__.split('.')[0]
    moduleName = method.__module__
    actualClass = getattr(sys.modules[moduleName], className)
    return actualClass


def isClassMethod(method):
    bound_to = getattr(method, '__self__', None)
    if not isinstance(bound_to, type):
        # must be bound to a class
        return False
    name = method.__name__
    for cls in bound_to.__mro__:
        descriptor = vars(cls).get(name)
        if descriptor is not None:
            return isinstance(descriptor, classmethod)
    return False
    ```
    function `isStaticmethod` can get if the object is a static method or not. also you may get the actual class of that method with `getStaticmethod_actualClass`.

the `isStaticmethod_withClass` is from @Azmisov 's code here.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文