2009-12-10 24 views
14

Tôi đã sử dụng optparse một lúc và muốn thêm khả năng tải đối số từ tệp cấu hình.Sử dụng tệp để lưu trữ đối số phân tách

Cho đến nay, tốt nhất tôi có thể nghĩ đến là một tập lệnh bó hàng loạt với các đối số được mã hóa ... dường như rất khó.

Cách thanh lịch nhất để làm điều này là gì?

Trả lời

22

Tôi đồng ý với ý tưởng sử dụng một tập tin cấu hình S. Lott, nhưng tôi khuyên bạn nên sử dụng các module tích hợp ConfigParser (configparser trong 3.0) để phân tích nó, chứ không phải là một giải pháp nhà ủ.

Dưới đây là một tập lệnh ngắn minh họa cho ConfigParser và optparse đang hoạt động.

import ConfigParser 
from optparse import OptionParser 

CONFIG_FILENAME = 'defaults.cfg' 

def main(): 
    config = ConfigParser.ConfigParser() 
    config.read(CONFIG_FILENAME) 

    parser = OptionParser() 
    parser.add_option("-l", 
         "--language", 
         dest="language", 
         help="The UI language", 
         default=config.get("Localization", "language")) 
    parser.add_option("-f", 
         "--flag", 
         dest="flag", 
         help="The country flag", 
         default=config.get("Localization", "flag")) 

    print parser.parse_args() 

if __name__ == "__main__": 
    main() 

Output:

(<Values at 0x2182c88: {'flag': 'japan.png', 'language': 'Japanese'}>, []) 

Run với "parser.py --language=French ":.

(<Values at 0x2215c60: {'flag': 'japan.png', 'language': 'French'}>, []) 

Giúp được xây dựng trong Run với" parser.py --help":

Usage: parser.py [options] 

Options: 
    -h, --help   show this help message and exit 
    -l LANGUAGE, --language=LANGUAGE 
         The UI language 
    -f FLAG, --flag=FLAG The country flag 

Các tập tin cấu hình:

[Localization] 
language=Japanese 
flag=japan.png 
3

Đó là chức năng của set_defaults. http://docs.python.org/library/optparse.html#optparse.OptionParser.set_defaults

Tạo tệp là từ điển của các giá trị mặc định.

{ 'arg1': 'this', 
'arg2': 'that' 
} 

Sau đó đọc tệp này, đánh giá nó để chuyển văn bản thành từ điển và cung cấp từ điển này làm đối số set_defaults.

Nếu bạn thực sự lo lắng về eval, sau đó sử dụng ký hiệu JSON (hoặc YAML) cho tệp này. Hoặc bạn thậm chí có thể tạo một tệp .INI trong số đó và sử dụng configparser để nhận các giá trị mặc định của mình.

Hoặc bạn có thể sử dụng danh sách câu lệnh chuyển nhượng đơn giản và exec.

Tệp cấu hình.

arg1 = 'this' 
arg2 = 'that' 

Đọc tệp cấu hình.

defaults= {} 
with open('defaults.py','r') as config 
    exec config in {}, defaults 
+0

Không có lý do gì để sử dụng eval tại đây - bạn chỉ có thể sử dụng nguyên soái. –

+1

@Nick Bastin: Đánh giá không phải là Ác ma, chỉ có những người dùng cuối sociopathic người luôn cố gắng để hack ứng dụng bằng cách khai thác việc sử dụng eval. –

+0

Đưa ngón tay của bạn vào kẻ tấn công lợi dụng chink trong áo giáp của bạn, không loại bỏ chink hay ngừng cuộc tấn công ... :) –

7

Bạn có thể sử dụng mô-đun argparse cho rằng:

>>> open('args.txt', 'w').write('-f\nbar') 
>>> parser = argparse.ArgumentParser(fromfile_prefix_chars='@') 
>>> parser.add_argument('-f') 
>>> parser.parse_args(['-f', 'foo', '@args.txt']) 
Namespace(f='bar') 

Nó có thể được bao gồm trong stdlib, xem pep 389.

+4

PEP 389 đã được phê duyệt và 'argparse' đã là một phần của Python 2.7 – sorin

4

Tôi gặp sự cố tương tự nhưng cũng muốn cụ thể tệp cấu hình làm đối số. Lấy cảm hứng từ câu trả lời của S. Lott, tôi đã đưa ra đoạn mã sau.

Ví dụ phiên cuối:

$ python defaultconf.py # use hard-coded defaults 
False 
$ python defaultconf.py --verbose # verbose on command line 
True 
$ python defaultconf.py --loadconfig blah # load config with 'verbose':True 
True 
$ python defaultconf.py --loadconfig blah --quiet # Override configured value 
False

Code:

#!/usr/bin/env python2.6 
import optparse 

def getParser(defaults): 
    """Create and return an OptionParser instance, with supplied defaults 
    """ 
    o = optparse.OptionParser() 
    o.set_defaults(**defaults) 
    o.add_option("--verbose", dest = "verbose", action="store_true") 
    o.add_option("--quiet", dest = "verbose", action="store_false") 

    o.add_option("--loadconfig", dest = "loadconfig") 

    return o 


def main(): 
    # Hard coded defaults (including non-command-line-argument options) 
    my_defaults = {'verbose': False, 'config_only_variable': 42} 

    # Initially parse arguments 
    opts, args = getParser(my_defaults).parse_args() 

    if opts.loadconfig is not None: 
     # Load config from disk, update the defaults dictionary, and reparse 
     # Could use ConfigParser, simplejson, yaml etc. 

     config_file_values = {'verbose': True} # the dict loaded from disk 

     my_defaults.update(config_file_values) 
     opts, args = getParser(my_defaults).parse_args() 

    print opts.verbose 

if __name__ == '__main__': 
    main() 

Một thực hiện thực tế có thể được tìm thấy trên Github: The defaults dictionary, the argument parserthe main function

+0

Thật tuyệt vời. Tôi đã mở rộng nó để hiển thị các giá trị mặc định từ tệp cấu hình trong --help: –

2

đọc các đối số trong các định dạng dòng lệnh tương tự từ một tệp ví dụ @commands, sau đó sử dụng trình phân tích cú pháp gốc của bạn để phân tích cú pháp chúng.

options, args = parser.parse_args() 

if args[0][0] == '@': # script.py @optfile 
    with open(args[0][1:]) as f: 
     fa = [l.strip() for l in f] 
    fa = fa + args[1:] # put back any other positional arguments 
    # Use your original parser to parse the new options 
    options, args = parser.parse_args(args=fa, values=options) 
0

Tôi đã tạo nhiều kịch bản với cờ và tùy chọn gần đây và tôi đã đưa ra giải pháp được mô tả here. Về cơ bản, tôi thể hiện một optionparser với một lá cờ đặc biệt cho phép thử và tải các tùy chọn từ một tập tin, vì vậy bạn có thể sử dụng bình thường kịch bản của bạn chỉ định các tùy chọn từ dòng lệnh hoặc cung cấp chúng (hoặc một tập hợp chúng) từ một tập tin.

Cập nhật: tôi có mã được chia sẻ trên GitHub

Các vấn đề liên quan