2011-04-20 36 views
0

我正在讀取一些數據,我想創建類 - 這是在加載時完成的。這些類被分組到一個Special類中,該類只能使用運行時信息進行實例化。這些類依賴於這個類,因此它們只能在創建後纔有用。下面是一些簡單的代碼,表明我是多麼希望它的工作,使用random而不是實際運行時信息:我應該在這裏使用元類嗎?

import random 
def make_foo(param1, param2): 
    class Foo: 
     def __init__(self, special): 
      self.param1 = param1 
      self.param2 = param2 
      self.special = special 
     def do(self): 
      print "%s is doing" % self 
     def __str__(self): 
      return "Foo<%s,%s with %s>" % (self.param1, self.param2, 
              self.special) 

    return Foo 
def make_bar(foo): 
    class Bar: 
     def __init__(self, special): 
      self.foo = foo(special) 
     def do(self): 
      print "%s is doing" % (self,) 
     def __str__(self): 
      return "Bar<%s>" % self.foo 
    return Bar 

def make_grouper(foobars): 
    class Grouper: 
     def __init__(self, special): 
      self.foobars = [foobar(special) for foobar in foobars] 
    return Grouper 

def make_special(howtomake, groups): 
    class Special: 
     def __init__(self): 
      self.important = random.choice(howtomake) 
      self.groups = [group(self) for group in groups] 
     def __str__(self): 
      return "Special<%s>" % self.important 
    return Special 

Foo10_20 = make_foo(10, 20) 
Foo30_40 = make_foo(30, 40) 
Bar = make_bar(Foo10_20) 
Grouper1 = make_grouper([Foo10_20, Foo30_40]) 
Grouper2 = make_grouper([Bar, Bar]) 

Special = make_special("IMPORTANTINFO", [Grouper1, Grouper2]) 

s = Special() 
s.groups[0].foobars[0].do() 
s.groups[0].foobars[1].do() 
s.groups[1].foobars[0].do() 

s = Special() 
s.groups[0].foobars[0].do() 
s.groups[0].foobars[1].do() 
s.groups[1].foobars[0].do() 

輸出示例:

Foo<10,20 with Special<O>> is doing 
Foo<30,40 with Special<O>> is doing 
Bar<Foo<10,20 with Special<O>>> is doing 
Foo<10,20 with Special<I>> is doing 
Foo<30,40 with Special<I>> is doing 
Bar<Foo<10,20 with Special<I>>> is doing 

它可以概括爲不必創建一組類需要綁定到一個參數special(所以所有的構造函數,一旦完成了類,只需要一個special參數)。這可以使用元類更優雅地完成,還是這種代碼是正確的?

回答

3

因爲我通常更喜歡Python中的閉包類,所以我會在這裏使用工廠類,並避免全部使用動態創建的類。例如:

class Foo: 
    def __init__(self, param1, param2, special): 
     self.param1 = param1 
     self.param2 = param2 
     self.special = special 
    def do(self): 
     print "%s is doing" % self 
    def __str__(self): 
     return "Foo<%s,%s with %s>" % (self.param1, self.param2, 
             self.special) 

class FooFactory: 
    def __init__(self, param1, param2): 
     self.param1 = param1 
     self.param2 = param2 
    def __call__(self, special): 
     return Foo(self.param1, self.param2, special) 

foo_factory = FooFactory(1, 2) 
foo = foo_factory(3) 

FooFactory另一種方法是使用functools.partial()。如果Foo如上述定義,你可以做

FooSpecialised = functools.partial(Foo, param1, param2) 

,並通過使用

FooSpecialised(special) 
2

這不是嚴格意義上的答案(或者也許是),但我覺得這句話創建Foo實例(MarkLutz由蒂姆·彼得斯學習報價的蟒蛇4版)會感到很有趣:

要由經驗豐富藉由 comp.lang.python新聞組上報價Python的核心開發者蒂姆·彼得斯(誰 也是著名的 「進口這種」巨蟒格言的作者):

[元類]更深層次的魔法不是用戶的 99%應該永遠不用擔心。 如果你想知道你是否需要它們, 你不需要(實際上 需要他們的人肯定知道 他們需要他們,並且不需要關於爲什麼的 解釋)。

+0

我看過,但刷了它,但感謝提出。我覺得我需要一些東西......如果有什麼事情,我正在做的事情的概念是關閉的。但工廠的想法運作良好,我使用它 – Claudiu 2011-04-20 15:44:17

0

我最終作出了一個基類:

class Base(object): 
    @classmethod 
    def bind_init(cls, *args, **kwargs): 
     def init(special): 
      return cls(special, *args, **kwargs) 
     return init 

美孚等。人。是一個正常的前瞻性非動態類現在:

class Foo(Base): 
    def __init__(self, special, param1, param2): 
     self.param1 = param1 
     self.param2 = param2 
     self.special = special 
    def do(self): 
     print "%s is doing" % self 
    def __str__(self): 
     return "Foo<%s,%s with %s>" % (self.param1, self.param2, 
             self.special) 

,它們的用法如下:

Foo10_20 = Foo.bind_init(10, 20) 
Foo30_40 = Foo.bind_init(30, 40) 
Bar = Bar.bind_init(Foo10_20) 
Grouper1 = Grouper.bind_init([Foo10_20, Foo30_40]) 
Grouper2 = Grouper.bind_init([Bar, Bar]) 

Special = Special.bind_init("IMPORTANTINFO", [Grouper1, Grouper2]) 

這最大限度地減少重複代碼(不必使噸的工廠類的),我也比類工廠更像行話。

相關問題