2010-07-01 175 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