2013-01-25 66 views
0

我需要編寫一個命令行應用程序,例如shell。所以它會包含命令等等。事情是我不知道如何將參數傳遞給模塊中的函數。例如:Python - 在命令行應用程序中傳遞參數

用戶寫入:function1 folder1 程序現在應該將'folder1'參數傳遞給function1函數並運行它。但也有支持其他功能使用不同的參數例如:

用戶輸入:函數2文件夾2 --exampleparam

如何使這個工作?我的意思是,我只需要編寫一個模塊,將其導入到python中,然後使用python控制檯,但事實並非如此。我需要一個腳本,它接受命令輸入並運行它。

我試圖使用eval(),但是這並不能解決params問題。或者也許它確實存在,但我沒有看到它?

回答

6

問題的第一部分 - 解析命令行 - 可以用argparse來解決。

第二部分 - 將函數的字符串名稱轉換爲函數調用 - 可以使用exec或從字符串映射到函數對象的調度字典完成。

我會建議使用exec,因爲 允許用戶從命令行調用任意Python的功能可能是危險的。相反,要允許的功能,白名單:

import argparse 


def foo(path): 
    print('Running foo(%r)' % (path,)) 


def bar(path): 
    print('Running bar(%r)' % (path,)) 

dispatch = { 
    'foo': foo, 
    'bar': bar, 
} 

parser = argparse.ArgumentParser() 
parser.add_argument('function') 
parser.add_argument('arguments', nargs='*') 
args = parser.parse_args() 

dispatch[args.function](*args.arguments) 

% test.py foo 1 
Running foo('1') 
% test.py bar 2 
Running bar('2') 
% test.py baz 3 
KeyError: 'baz' 

上述工作當命令被鍵入到命令行本身。如果命令輸入到stdin,那麼我們需要做一些有點不同的事情。

一個簡單的方法是致電raw_inputstdin獲取字符串。然後,我們可以解析字符串以argparse,象我們上面那樣:

shmod.py

import argparse 


def foo(path): 
    print('Running foo(%r)' % (path,)) 


def bar(path): 
    print('Running bar(%r)' % (path,)) 

dispatch = { 
    'foo': foo, 
    'bar': bar, 
} 

def parse_args(cmd): 
    parser = argparse.ArgumentParser() 
    parser.add_argument('function') 
    parser.add_argument('arguments', nargs='*') 
    args = parser.parse_args(cmd.split()) 
    return args 

main.py

import shmod 

while True: 
    cmd = raw_input('> ') 
    args = shmod.parse_args(cmd) 
    try: 
     shmod.dispatch[args.function](*args.arguments) 
    except KeyError: 
     print('Invalid input: {!r}'.format(cmd)) 

另一個更處理這個問題的複雜方式是使用cmd module,如評論中提到的@chepner。

from cmd import Cmd 


class MyInterpreter(Cmd): 

    prompt = '> ' 

    def do_prompt(self, line): 
     "Change the interactive prompt" 
     self.prompt = line + ': ' 

    def do_EOF(self, line): 
     return True 

    def do_foo(self, line): 
     print('Running foo {l}'.format(l=line)) 

    def do_bar(self, line): 
     print('Running bar {l}'.format(l=line)) 

if __name__ == '__main__': 
    MyInterpreter().cmdloop() 

有關如何使用CMD模塊的更多信息,請參見Doug Hellman's excellent tutorial.


運行上述代碼產生這樣的結果:

% test.py 
> foo 1 
Running foo 1 
> foo 1 2 3 
Running foo 1 2 3 
> bar 2 
Running bar 2 
> baz 3 
*** Unknown syntax: baz 3 
+0

第二部分,請看'cmd'模塊。 – chepner

+0

這適用於我,但我仍然無法弄清楚如何從另一個腳本實際啓動命令。如果我把它放到模塊中的一個函數中,並像這樣調用它:module.function,什麼都不會發生。但是,如果我這樣做:module.function 1,我得到一個語法錯誤。由於該函數沒有任何參數,因此沒有必要使用參數module.function(param)調用它。 我是Python的新手,並且不幸的是還沒有真正掌握它。 –

+0

試試'import module; module.function()'調用'module'中定義的'function'。 – unutbu

0

看看optparse。這可以幫助將外殼樣式參數傳遞給python腳本。

更新: 顯然optparse已被棄用,argparse現在是解析命令行參數的首選選項。

0
import sys 

def main(arg): 
    return arg 

print main(sys.argv[1]) 

其中sys.argv中[0]是你正在運行的.py文件,以及所有的那些後,這將是每個參數。你可以檢查列表的長度,然後遍歷它,並根據需要解析它們,並將正確的東西傳遞給每個函數。

1

看看optparse模塊在Python中。這正是你所需要的東西:

http://docs.python.org/2/library/optparse.html 

也可以編寫自己的自定義選擇的解析器(簡約雖然)

def getopts(argv): 
    opts = {} 
    while argv: 
     if argv[0][0] == '-': # find "-name value" pairs 
     opts[argv[0]] = argv[1] # dict key is "-name" arg 
     argv = argv[2:] 
     else: 
     argv = argv[1:] 
    return opts 

if __name__ == '__main__': 
from sys import argv # example client code 
myargs = getopts(argv) 
# DO something based on your logic here 

但如果你的腳本需要在Python 3的運行,並超越,你需要考慮argparse模塊。\

希望有所幫助。

2

optparse因爲蟒2.7已被棄用無論如何,argparse更加靈活。 unutbu的方法是安全的,但如果你提供白名單,我建議你讓用戶知道哪些功能是接受

dispatch = { 
    'foo': foo,  
    'bar': bar, 
} 

parser = argparse.ArgumentParser() 
parser.add_argument('function', choices=dispatch.keys()) 

FYI:如果解析是不是太複雜,docopt貌似很不錯的軟件包