【问题标题】:getattr on class objectsgetattr 对类对象
【发布时间】:2013-08-28 21:14:02
【问题描述】:
class A:
    def foo(self):
        print "foo()"

getattr(A, foo) # True
A.foo() # error

getattr(A(), foo) # True
A().foo() # prints "foo()"

话虽如此,这是我的问题:

我希望将测试用例元信息存储为测试用例类对象本身的属性,而不是它们的实例。
我有一个要提取的属性名称列表,但如果有同名的实例方法,那么getattr(class_obj, attr) 将返回 True,但getattr(class_obj, attr)() 会引发错误。

有没有办法告诉 getattr 不包含实例化类的属性而只包含类对象本身的属性?

编辑:我尝试直接访问class_obj.__dict__(我理解这是不好的做法),但它不包括一些属性,如__name__

编辑:改写问题。有没有办法区分 obj 类的方法和类实例的方法?

【问题讨论】:

  • "有没有办法告诉 getattr 不包含实例化类的属性,而只包含类对象本身的属性?"我不确定这意味着什么。 foo() 是一个(非静态)方法,因此名为 foo 的属性将同时存在于类及其实例上。 A.foo() 引发错误的原因是因为您不能在类对象上调用实例方法,但它仍然作为未绑定方法存在。我认为您可能会混淆属性和方法。 “没有属性”和“属性不可调用”是不同的东西。
  • 那么我想 getattr 不是我想要的。您是否知道仅在使用@classmethod 装饰时才获取属性的替代方法?
  • (而且,好吧,我很抱歉,如果这显得居高临下,但这似乎是在你运行之前先走的情况。你确定你应该在 Python 对象的怪癖之前进行元编程吗?模型是内部结构化的渗入?)
  • @waldol1 你想完成什么?区分类方法和实例方法?
  • @waldo1 使用“请求宽恕而不是许可”的方法怎么样?只需执行A.foo(),使用try..except 捕获错误,如果发生错误,就假装该属性不存在。

标签: python class-method getattr


【解决方案1】:

这够好吗?

import types
class Test(object):
    @staticmethod
    def foo():
        print 'foo'

    def bar(self):
        print 'bar'

结合:

>>>(isinstance(getattr(Test, 'foo'), types.FunctionType),
    isinstance(getattr(Test, 'bar'), types.FunctionType))
True, False

您也可以使用inspect 模块:

>>> inspect.isfunction(Test.foo)
True
>>> inspect.isfunction(Test.bar)
False

通过一些额外的工作,您甚至可以将类方法与实例方法和静态方法区分开来:

import inspect

def get_type(cls, attr):
    try:
        return [a.kind for a in inspect.classify_class_attrs(cls) if a.name == attr][0]
    except IndexError:
        return None

class Test(object):
    @classmethod
    def foo(cls):
        print 'foo'

    def bar(self):
        print 'bar'

    @staticmethod
    def baz():
        print 'baz'

您可以将其用作:

>>> get_type(Test, 'foo')
'class method'
>>> get_type(Test, 'bar')
'method'
>>> get_type(Test, 'baz')
'static method'
>>> get_type(Test, 'nonexistant')
None

【讨论】:

  • 仅供参考,今天,在 Python 3.9 isinstance(getattr(Test, 'foo'), types.FunctionType) isinstance(getattr(Test, 'bar'), types.FunctionType) 都返回 True 和不只是为了 foo。干杯
【解决方案2】:

您的结果来自 foo 的错误定义,而不是类属性的任何底层语义。默认情况下,在类中声明的函数是实例方法,它必须至少接受一个参数,即类的实例。按照惯例,它被称为self

class A:
    def foo(self):
        print "foo()"

通常,您会像这样调用这样的方法:

a = A()
a.foo()    # passes the object 'a' implicitly as the value of the parameter 'self'

但这也是合法的

a = A()
A.foo(a)   # pass the object 'a' explicitly as the value of the parameter 'self'

为了在不接受任何此类隐式参数的类中定义函数,您需要使用 @staticmethod 装饰器来装饰它:

class A:
    @staticmethod
    def foo():
        print "foo()"

现在,您可以像以前一样拨打foo

>>> A.foo()
foo()

【讨论】:

  • 我原本打算将self 作为foo 的参数包含在内。我已经编辑了我的问题。还是很高兴知道A.foo(a) 会起作用
【解决方案3】:

你想要这样的东西:

from inspect import ismethod
from collections import Callable
def can_i_call(func):
    if not isinstance(func, Callable):
        # not a callable at all
        return False

    if not ismethod(func):
        # regular function or class or whatever
        return True

    # func is a method
    return func.im_self is not None

注意:这只会测试调用尝试是否会出错,因为您正在调用没有self 的未绑定方法。它不保证func() 会成功,即不会因为任何其他原因而失败。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-13
    • 2015-09-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多