__getattr__ 用于静态/类变量

79 投票
5 回答
42750 浏览
提问于 2025-04-16 00:39

我有一个这样的类:

class MyClass:
     Foo = 1
     Bar = 2

每当调用 MyClass.FooMyClass.Bar 时,我希望在返回值之前能调用一个自定义的方法。Python能做到这一点吗?我知道如果我创建这个类的实例,就可以定义自己的 __getattr__ 方法。但我的情况是我想直接使用这个类,而不创建任何实例。

另外,当调用 str(MyClass.Foo) 时,我也需要一个自定义的 __str__ 方法被调用。Python有这样的选项吗?

5 个回答

13

首先,你需要创建一个元类,并在这个元类上定义 __getattr__() 方法。

class MyMetaclass(type):
  def __getattr__(self, name):
    return '%s result' % name

class MyClass(object):
  __metaclass__ = MyMetaclass

print MyClass.Foo

其次,不可以。调用 str(MyClass.Foo) 会触发 MyClass.Foo.__str__() 方法,所以你需要为 MyClass.Foo 返回一个合适的类型。

23

(我知道这个问题比较老,但其他答案都用到了一个元类...)

你可以使用下面这个简单的 classproperty 描述符:

class classproperty(object):
    """ @classmethod+@property """
    def __init__(self, f):
        self.f = classmethod(f)
    def __get__(self, *a):
        return self.f.__get__(*a)()

使用方法如下:

class MyClass(object):

     @classproperty
     def Foo(cls):
        do_something()
        return 1

     @classproperty
     def Bar(cls):
        do_something_else()
        return 2
100

__getattr__()__str__() 是对象的特殊方法,它们是在对象的类里面定义的。所以,如果你想要为一个类自定义这些方法,你需要用到一个叫做元类的东西。

class FooType(type):
    def _foo_func(cls):
        return 'foo!'

    def _bar_func(cls):
        return 'bar!'

    def __getattr__(cls, key):
        if key == 'Foo':
            return cls._foo_func()
        elif key == 'Bar':
            return cls._bar_func()
        raise AttributeError(key)

    def __str__(cls):
        return 'custom str for %s' % (cls.__name__,)

class MyClass(metaclass=FooType):
    pass

# # in python 2:
# class MyClass:
#    __metaclass__ = FooType


print(MyClass.Foo)
print(MyClass.Bar)
print(str(MyClass))

打印输出:

foo!
bar!
custom str for MyClass

而且,不,对象不能拦截对其某个属性进行字符串化的请求。返回的属性对象必须自己定义 __str__() 的行为。

更新 2023-02-20,适用于 Python 3.x 的默认实现(Python 2 的内容作为注释)。

撰写回答