【问题标题】:__getattr__ for static/class variables in python__getattr__ 用于 python 中的静态/类变量
【发布时间】:2010-07-01 06:09:07
【问题描述】:

我有这样的课程:

class MyClass:
     Foo = 1
     Bar = 2

每当调用MyClass.FooMyClass.Bar 时,我都需要在返回值之前调用自定义方法。在Python中可能吗?我知道如果我创建一个类的实例并且我可以定义我自己的__getattr__ 方法是可能的。但我的场景涉及使用此类而不创建它的任何实例。

我还需要在调用str(MyClass.Foo) 时调用自定义__str__ 方法。 Python 是否提供这样的选项?

【问题讨论】:

    标签: python class-method getattr


    【解决方案1】:

    __getattr__()__str__() 的对象可以在其类上找到,所以如果你想为一个类定制这些东西,你需要 class-of-a-class。一个元类。

    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
    
    # in python 3:
    # class MyClass(metaclass=FooType):
    #    pass
    
    
    print MyClass.Foo
    print MyClass.Bar
    print str(MyClass)
    

    印刷:

    foo!
    bar!
    custom str for MyClass
    

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

    【讨论】:

    • 感谢伊格纳西奥和马特。我想现在我了解类(而不是实例)创建是如何工作的,而且我认为所需的 str 行为很难实现。我认为元类应该足以满足我的要求。 :)
    • 如果你总是得到AttributeError 看看另一个答案,它有python3的语法(这个例子似乎是python2)
    【解决方案2】:

    (我知道这是一个老问题,但由于所有其他答案都使用元类......)

    您可以使用以下简单的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
    

    【讨论】:

    • 这只有在您事先知道您的属性名称时才会有所帮助。如果您从文件中读取它们并需要动态响应,这将不起作用。
    【解决方案3】:

    首先,您需要创建一个元类,并在其上定义__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 返回一个适当的类型。

    【讨论】:

    • 测试了这个例子,它只适用于我在 Python 2.x 中。将 print 更改为函数后,Python 3.2 给了我一个“AttributeError: type object 'MyClass' has no attribute 'Foo'”错误。有什么建议吗?
    • @Cyber​​ED: docs.python.org/py3k/reference/datamodel.html#metaclasses : "读取类定义时,如果在类定义中的基数之后传递可调用的 metaclass 关键字参数,则将调用给定的可调用对象而不是 @ 987654328@。”
    • 等不及了......经过一番谷歌搜索和测试:该示例适用于 Python 2.x。在 Python 3.x 中,您需要: class MyClass(metaclass=MyMetaclass): pass
    【解决方案4】:

    很惊讶没有人指出这一点:

    class FooType(type):
        @property
        def Foo(cls):
            return "foo!"
    
        @property
        def Bar(cls):
            return "bar!"
    
    class MyClass(metaclass=FooType):
        pass
    

    作品:

    >>> MyClass.Foo
    'foo!'
    >>> MyClass.Bar
    'bar!'
    

    (对于 Python 2.x,将 MyClass 的定义更改为:

    class MyClass(object):
        __metaclass__ = FooType
    

    )

    关于str 的其他答案对这个解决方案适用:它必须在实际返回的类型上实现。

    【讨论】:

    • 虽然我通常尽量避免发布“谢谢”,但我现在真的需要发布“谢谢”:谢谢!
    【解决方案5】:

    根据情况我使用这种模式

    class _TheRealClass:
        def __getattr__(self, attr):
           pass
    
    LooksLikeAClass = _TheRealClass()
    

    然后你导入并使用它。

    from foo import LooksLikeAClass
    LooksLikeAClass.some_attribute
    

    这避免使用元类,并处理一些用例。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-02
      • 1970-01-01
      • 2013-09-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多