2010-09-24 54 views
3

我試圖把一個python類(在IronPython中)應用到一些數據並將其顯示在網格中。函數的結果成爲網格上的列,我希望函數的順序是列的順序。有沒有辦法根據它們在源代碼中聲明的順序來確定類的python函數的順序?我會接受使用IronPython或普通Python的答案。確定聲明Python/IronPython函數的順序

因此,舉例來說,如果我有一個類:

class foo: 
    def c(self): 
     return 3 
    def a(self): 
     return 2 
    def b(self): 
     return 1 

我想(不解析源代碼自己)回來的[c, a, b]列表。有任何想法嗎?

作爲一個告誡,IronPython用於保持函數的引用順序,他們聲明它們。在.NET 4中,他們改變了這種行爲來匹配python(它總是按字母順序列出)。

+0

我不知道爲什麼,這是標記C# – 2010-09-24 12:21:42

+0

我用的IronPython爲此在.NET 3.5,但他們在PythonType改變GetMemberNames方式()列出成員名稱以匹配.NET 4蟒蛇字典執行 – 2010-09-24 12:27:24

回答

2

在Python 2.X(IronPython目前在Python 2中),答案不幸的是沒有。 Python在創建類對象之前構建類成員的字典。一旦創建了課程,就沒有訂單的「記錄」。

在Python 3中,元類(用於創建類)得到了改進,您可以使用自定義對象而不是標準字典在構建類時收集類成員。這可以讓你知道訂單。

但是,對於IronPython來說,這可能會起作用。 Python字典本質上是無序的 - 即遍歷字典的成員以任意(但穩定)的順序返回它們。在IronPython中,使用就是這樣一種情況,作爲實現的一個意外,迭代會按照它們插入的順序返回成員。 (請注意,這可能不再是這種情況。)

你可以嘗試:

members = list(c.__dict__) # or c.__dict__.keys() 

您可能會發現,當你希望這是命令。不幸的是,在不同版本的IronPython(或Python的其他實現)下運行代碼可能會以不同的順序返回它們。

另一個(更好但更難)的方法是使用ast模塊(或IronPython解析器)並且走AST查找條目。不是很難,但更多的工作。

+0

你確定你可以使用這樣的元類嗎?我對他們並不擅長,但我認爲Python首先會將類定義解析爲字典,然後將其作爲構造的元類的參數傳遞給它。但我有興趣看到我錯了! – katrielalex 2010-09-24 12:56:46

+0

@katrielalex:在Python 3中,元類可以實現'__prepare__'函數,該函數將被調用以創建新類名稱空間的字典 - 請參閱http://www.python.org/dev/peps/pep-3115/ – 2010-09-24 13:13:08

+0

謝謝!我最終對IronPython的PythonWalker進行了分類,以瞭解該類的結構(重寫Walk()和PostWalk())。我現在這樣做,我可能會得到比我想要的更多的函數(在嵌套函數的情況下),但這並不影響我的特定應用程序。 – 2010-09-24 13:44:10

2

爲什麼你不能自己解析代碼?這很容易:

import inspect 
import ast 

class Foo: 
    def c(self): 
     pass 

    def a(self): 
     pass 

    def b(self): 
     pass 

code = ast.parse(inspect.getsource(Foo)) 

class FunctionVisitor(ast.NodeVisitor): 
    def visit_FunctionDef(self, node): 
     print(node.name) 

FunctionVisitor().visit(code) 

輸出

c 
a 
b 
+0

+1打我吧 – aaronasterling 2010-09-24 12:57:48

+0

這非常有幫助!我不想自己解析代碼,但是通過一個語法樹並不是一件壞事。 – 2010-09-24 13:45:09

1

另一種解決方案是使用一個裝飾將它們添加到列表中。

def make_registry(): 
    def register(f): 
     register.funcs.append(f) 
     return f 
    register.funcs = [] 
    return register 

register = make_registery() 

class Foo(object): 

    @register 
    def one(self): 
     pass 

    @register 
    def two(self): 
     pass 

    @register 
    def three(self): 
     pass 

    def utility_method_that_shouldnt_be_run_in_the_sequence(self): 
     pass 

print register.funcs