2009-09-01 62 views
10

我有一組對象,我正在創建一個類,我想將每個對象存儲爲自己的文本文件。我真的很想把它作爲一個Python類定義來存儲,它定義了我創建的主類的子類。所以,我做了一些探索,並在effbot.org上找到了一個Python代碼生成器。我做了一些嘗試用它,這裏就是我想出了:Python生成Python

# 
# a Python code generator backend 
# 
# fredrik lundh, march 1998 
# 
# [email protected] 
# http://www.pythonware.com 
# 
# Code taken from http://effbot.org/zone/python-code-generator.htm 

import sys, string 

class CodeGeneratorBackend: 

    def begin(self, tab="\t"): 
     self.code = [] 
     self.tab = tab 
     self.level = 0 

    def end(self): 
     return string.join(self.code, "") 

    def write(self, string): 
     self.code.append(self.tab * self.level + string) 

    def indent(self): 
     self.level = self.level + 1 

    def dedent(self): 
     if self.level == 0: 
      raise SyntaxError, "internal error in code generator" 
     self.level = self.level - 1 

class Point(): 
    """Defines a Point. Has x and y.""" 
    def __init__(self, x, y): 
     self.x = x 
     self.y = y 

    def dump_self(self, filename): 
     self.c = CodeGeneratorBackend() 
     self.c.begin(tab=" ") 
     self.c.write("class {0}{1}Point()\n".format(self.x,self.y)) 
     self.c.indent() 
     self.c.write('"""Defines a Point. Has x and y"""\n') 
     self.c.write('def __init__(self, x={0}, y={1}):\n'.format(self.x, self.y)) 
     self.c.indent() 
     self.c.write('self.x = {0}\n'.format(self.x)) 
     self.c.write('self.y = {0}\n'.format(self.y)) 
     self.c.dedent() 
     self.c.dedent() 
     f = open(filename,'w') 
     f.write(self.c.end()) 
     f.close() 

if __name__ == "__main__": 
    p = Point(3,4) 
    p.dump_self('demo.py') 

,感覺真難看,有一個更清潔/更好/更Python的方式做到這一點?請注意,這不是我實際打算這樣做的班級,這是一個小班,我可以輕鬆地模擬出不太多的線路。另外,子類不需要在其中有生成函數,如果我再次需要,我可以從超類調用代碼生成器。

+0

不要使用製表符縮進蟒蛇,使用空格:) – 2009-09-01 22:02:21

+0

是的,它設置爲默認值,但我覆蓋該變量瓦特/ 4空間。 – Jonathanb 2009-09-01 22:56:40

回答

22

我們使用Jinja2來填寫模板。它更簡單。

該模板看起來很像Python代碼,其中有幾個{{something}}替代品。

+0

根據我對Anon的評論,我將只使用模板系統。我會密切關注Jinja,謝謝你的提示! – Jonathanb 2009-09-01 23:51:54

+2

有沒有這樣的例子? – KJW 2013-04-02 01:04:09

+0

這是一個很好的做法! – specialscope 2014-01-14 05:41:38

5

這是生成Python 源碼的最佳方法。但是,您也可以使用ast庫在運行時生成Python可執行代碼。 (我鏈接到Python 3版本,因爲它比2.x版本更強大)。您可以使用抽象語法樹構建代碼,然後將它傳遞給compile()以將其編譯爲可執行代碼。然後你可以使用eval來運行代碼。

我不確定是否有一種方便的方式來保存編譯後的代碼以供稍後使用(即在.pyc文件中)。

+0

好吧,我真的想要一些人類可讀的東西。可執行代碼往往不會。 – Jonathanb 2009-09-01 22:55:30

+0

夠公平的,我會在這裏留下這個答案,以防它對其他有類似問題的人有用。 – 2009-09-01 23:22:13

0

從我所瞭解的你想要做的事情中,我會考慮使用反射來在運行時動態檢查一個類,並根據它生成輸出。在http://diveintopython3.ep.io/有一個很好的反思教程(A.K.A. introspection)。

您可以使用dir()函數來獲取給定對象的屬性名稱列表。對象的文檔字符串可通過__doc__屬性訪問。也就是說,如果你想看看一個函數或類,你可以做以下的文檔字符串:

>>> def foo(): 
... """A doc string comment.""" 
... pass 
... 
>>> print foo.__doc__ 
A doc string comment. 
+0

我所擁有的是一堆行星,我想將它們存儲爲自己的文本文件。我並不特別強調將它們存儲爲python源代碼,但我附帶說明它們的可讀性。 – Jonathanb 2009-09-01 23:02:17

1

我不知道這是否是特別Python的,但你可以使用操作符重載:

class CodeGenerator: 
    def __init__(self, indentation='\t'): 
     self.indentation = indentation 
     self.level = 0 
     self.code = '' 

    def indent(self): 
     self.level += 1 

    def dedent(self): 
     if self.level > 0: 
      self.level -= 1 

    def __add__(self, value): 
     temp = CodeGenerator(indentation=self.indentation) 
     temp.level = self.level 
     temp.code = str(self) + ''.join([self.indentation for i in range(0, self.level)]) + str(value) 
     return temp 

    def __str__(self): 
     return str(self.code) 

a = CodeGenerator() 
a += 'for a in range(1, 3):\n' 
a.indent() 
a += 'for b in range(4, 6):\n' 
a.indent() 
a += 'print(a * b)\n' 
a.dedent() 
a += '# pointless comment\n' 
print(a) 

這當然比實例貴得多,而且我會對過多的元編程保持警惕,但這是一個有趣的練習。您可以根據需要擴展或使用它;怎麼樣:

  • 將寫入方法和重定向標準輸出到該對象直打印到一個腳本文件
  • 從它繼承自定義輸出
  • 添加屬性的getter和setter

會很高興聽到你隨隨便便:)

7

剛剛閱讀您的意見,以wintermute - 即:

我所擁有的是一堆行星 我想將它們各自存儲爲自己的文本 文件。我沒有特別附加 將它們存儲爲python源代碼, 但我附加到使它們可讀的 。

如果是這樣,那麼看起來你不應該需要子類,但應該能夠使用相同的類,並通過數據單獨區分行星。在這種情況下,爲什麼不直接將數據寫入文件,並且當您需要程序中的星球對象時,請讀入數據以初始化對象?

如果你需要像重寫方法那樣做東西,我可以看到寫出代碼 - 但是不應該只是使用不同的變量就可以爲所有行星使用相同的方法嗎?

只需寫出數據(它可以包括標籤類型信息以便在閱讀時跳過),這是因爲非Python程序員在閱讀時不會分心,您可以使用與其他語言相同的文件,如果有必要,等等。

+1

是的,我對這個想法有點太難,不是我。這可能是我會做的。謝謝! – Jonathanb 2009-09-01 23:50:45