2010-07-01 128 views
42

静态/类变量我有一个类,如:__getattr__在蟒蛇

class MyClass: 
    Foo = 1 
    Bar = 2 

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

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

回答

48

__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 


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

打印:

foo! 
bar! 
custom str for MyClass 

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

+0

Thanks Ignacio and Matt。我想现在我明白了类(不是实例)的创建是如何工作的,而且我认为所需的__str__行为很难实现。我认为元类应该足够满足我的要求。 :) – Tuxdude 2010-07-01 06:49:03

+0

如果你总是得到'AttributeError'检查出其他的答案,其中有python3的语法(这个例子似乎是python2) – Chris 2017-06-21 09:03:26

8

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

+0

测试过这个例子,它只适用于Python 2.x.将打印改为函数后,Python 3.2给了我一个“AttributeError:类型对象'MyClass'没有属性'Foo'”的错误。有什么建议么? – CyberFonic 2011-11-17 07:44:17

+1

@Cyber​​ED:http://docs.python.org/py3k/reference/datamodel.html#metaclasses:“当读取类定义时,如果在类定义中的基类之后传递了可调用的'metaclass'关键字参数,可调用的给定将被调用而不是'type()'。“ – 2011-11-17 07:51:05

+3

等不及了....经过一番谷歌搜索和测试: 这个例子是针对Python 2.x的。在Python 3.x中,您需要: class MyClass(metaclass = MyMetaclass): pass – CyberFonic 2011-11-17 08:00:07

5

惊讶没有人指出这一个:

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的其他解答也适用于此解决方案:它必须在实际返回的类型上实现。

+2

虽然我通常会尽量避免发布“谢谢”,但我真的需要立即发布“谢谢”:谢谢! – Chris 2017-06-21 09:11:00

11

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

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

class classproperty(object): 
    """ @[email protected] """ 
    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 
+0

如果您事先知道属性的名称,这只会有所帮助。如果你从文件中读取它们并需要动态反应,这将不起作用。 – Chris 2017-06-21 09:02:33