2012-11-11 49 views
3

我有一些類的方法,我希望能夠添加到其他類可選。我最初的解決方案是使用混入,但是也會有點難看:Python(2.7):動態添加類方法

class Schedule(Enumerator, Humanizer, Inferer, ...): 
    ... 

所以我想,嘿,也許我可以使用類裝飾來達到同樣的效果。

@enumerator 
@humanizer 
@inferer 
class Schedule(object): 
    ... 

這裏是裝飾功能的示例:

import inspect 

def inferer(original_class): 
    from myproj.lib.inferer import Inferer 
    methods = inspect.getmembers(Inferer, predicate=inspect.ismethod) 
    for method in methods: 
     setattr(original_class, method[0], types.MethodTypes(method[1], original_class)) 
    return original_class 

...這似乎是適當的添加方法和classmethods到裝飾類。但是,當我在裝飾類上調用其中一種添加的方法(或類方法)時,出現一些錯誤。

對於方法:

>>> Schedule().humanize() 
TypeError: unbound method humanize() must be called with Humanizer instance as first argument (got type instance instead) 

...這似乎表明,這些被添加爲classmethods?

對於classmethods:

>>> schedule = Schedule.infer(foo) 
TypeError: infer() takes exactly 2 arguments (3 given) 

注推斷的定義:

class Inferer(object): 
    @classmethod 
    def infer(cls, dates): 
     ... 

我加了一些線infer顯示,它被稱爲當得到什麼樣的參數爲Schedule.infer()

cls: <class 'myproj.lib.inferer.Inferer'> 
dates: <class 'myproj.Schedule'> 

所以,我的問題:

裝飾器函數出現錯誤,導致這些添加的方法和類方法行爲奇怪?或者,更好地說,如何修改裝飾器函數以正確處理這些添加?

請讓我知道,如果我可以提供任何澄清任何一點。

+2

所以......你使用裝飾器的唯一原因是因爲傳統的語法看起來很醜陋?這聽起來像是大量的工作和額外的代碼脆弱性,僅僅爲了美學。 –

+0

我不知道爲什麼你認爲使用這樣的裝飾器會比使用mixin更難看(有問題)。這就是說你可能需要使用元類來完成你正在嘗試做的事情。幾年前,我回想起建立一個系統,可以從一組函數中隨時創建類,並且我使用了元類(現在不記得所有的細節,對不起)。 –

+0

我同意:mixins看起來更簡單,更清晰,而且它們實際上工作。爲什麼要去解決所有這些問題? –

回答

4

假設這是個好主意。這是您可能實現的一種方式。不過,我不能說我會提供建議。現在

def horrible_class_decorator_factory(mixin): 
    def decorator(cls): 
     d = cls.__dict__.copy() 
     bases = tuple([b for b in cls.__bases__ if b != object] + [mixin]) 
     return type(cls.__name__, bases, d) 
    return decorator 

你可以做這樣的事情:

class Inferer(object): 
    @classmethod 
    def foo(cls): 
     return "bar" + cls.__name__ 

inferer = horrible_class_decorator_factory(Inferer) 

@inferer 
class X(object): 
    pass 

X.foo() 
"barX" 

我與這一個評論者。只是因爲你可以做點什麼並不意味着你應該這樣做。

+0

有什麼理由?我從評論者那裏聽到的,從你那裏得知,這是一個可怕的想法,也很脆弱(感謝那裏指出的函數名稱)。特別有用。 – JEEND0

+0

Python的目的是易於閱讀和理解,一旦你開始搞亂最基本的語法的東西,你就開始介紹代碼脆弱和缺乏清晰的可能性。因爲你的美學感,做事可能是很有誘惑力的。請記住,設計該語言的人會對此進行很多思考。他們已經給了你很多內省和定製的力量,但它足以讓你自己堅持下去。 – BenTrofatter

+0

只是想到一個很好的例子,爲什麼這是不好的。假設你有一些mixin,也許你有他們由於某種原因從一個共同的基類繼承。我還沒有對基礎類進行任何類型的檢查。突然之間,我介紹了方法解決順序(MRO)問題。如果您希望看到有效完成此操作的示例,請查看Django Model基類。它很快變得非常複雜。 – BenTrofatter