2012-11-02 28 views
5

i viết một tập lệnh có một hoặc nhiều tệp đầu vào. Tôi muốn có thể chỉ định các tùy chọn cho tập lệnh (A và B) và cho từng tệp đầu vào riêng biệt (C và D).Python argparse: các tùy chọn riêng biệt cho các đối số vị trí

Cách sử dụng nên hình như:

script.py [-A] [-B] [-C] [-D] file1 [[-C] [-D] file2] ... 

Làm thế nào nó có thể được thực hiện với argparse?

Cảm ơn bạn!

+0

Bạn có biết có bao nhiêu đầu vào tập tin bạn sẽ có? – mgilson

+0

Một hoặc nhiều :) :) – Roux

Trả lời

1

Như thường, câu hỏi dường như không chính xác những gì là cần thiết .. Xin lỗi. Đây là kết quả làm việc của tôi (lấy cảm hứng từ câu trả lời của unutbu) cho phép các tùy chọn cho mỗi tập tin với các đối số.

import argparse 

parser = argparse.ArgumentParser() 
parser.add_argument('-A', action = 'store_true') 
parser.add_argument('-B', action = 'store_true') 
args, unk = parser.parse_known_args() 

file_parser = argparse.ArgumentParser() 
file_parser.add_argument('-C', action = 'store_true') 
file_parser.add_argument('-D', action = 'store_true') 
file_parser.add_argument('-V', "--variable-list") 
file_parser.add_argument('file') 

fargs=[] 
n=len(unk) 
while True: 
     i=0 
     for i in range(n): # finding longest fully parsable tail 
      Parsed, unkf = file_parser.parse_known_args(unk[i:n]) 
      if not unkf: break 
     if i==n: # did not found parsable tail 
      file_parser.parse_args(unk[0:n]) # cause error 
     else: 
      fargs.append(Parsed) 
      n=i 
     if (n<=0): break 
fargs.reverse() 

print args 
for argl in fargs: 
     print argl 

Calling này với:

myscript.py -A -B -C -D file1 -C -V a,b,c file 

sản lượng:

Namespace(A=True, B=True) 
Namespace(C=True, D=True, file='file1', variable_list=None) 
Namespace(C=True, D=False, file='file2', variable_list='a,b,c') 
+0

Bây giờ, rắc rối duy nhất là cách sắp xếp việc sử dụng hợp lý và giúp thông điệp .... – Roux

4

Nếu có thể, hãy thử docopt. Nó dễ sử dụng hơn nhiều và có đủ ví dụ để bắt đầu.

+0

Cảm ơn! Cách tiếp cận ấn tượng. Tuy nhiên, kịch bản của tôi là nghĩa vụ phải làm việc tại một số máy tính với python khá cổ được cài đặt.Vì vậy, thật không may, các giải pháp tiêu chuẩn được ưa thích để tao nhã ... – Roux

1

tôi, câu trả lời này là phức tạp:

import sys 

#Unforunately, you can't split up positional arguments in a reasonable way if you 
#don't know about all of them... Count positional arguments (files) 

def how_many_files(lst): 
    return sum(1 for x in lst if not x.startswith('-')) 

args = sys.argv[1:] 
Nfiles = how_many_files(args) 

import argparse 

#Create our own NameSpace class so that we can have an easy handle on the 
#attributes that the namespace actually holds. 
class MyNameSpace(argparse.Namespace,dict): 
    def __init__(self): 
     argparse.Namespace.__init__(self) 
     dict.__init__(self) 

    def __setattr__(self,k,o): 
     argparse.Namespace.__setattr__(self,k,o) 
     self[k] = o 

class MyParser(argparse.ArgumentParser): 
    def __init__(self,*args,**kwargs): 
     self.my_parents = kwargs.get('parents',[]) 
     argparse.ArgumentParser.__init__(self,*args,**kwargs) 

class FooAction(argparse.Action): 
    def __call__(self,parser,namespace,value,option_string=None): 
     ref = namespace.pop('accumulated',{}) 
     try: 
      del namespace.accumulated 
     except AttributeError: 
      pass 

     #get a new namespace and populate it with the arguments we've picked up 
     #along the way   
     new_namespace = self.__default_namespace(parser) 
     for k,v in namespace.items(): 
      setattr(new_namespace,k,v) 
      delattr(namespace,k) #delete things from `namespace.__dict__` 

     namespace.clear() #also remove things from the dictionary side. 
     namespace.accumulated = ref 
     new_namespace.file = value 
     ref[value] = new_namespace 

    def __default_namespace(self,parser): 
     n = argparse.Namespace() 
     for parent in parser.my_parents: 
      parent.parse_args([],namespace=n) 
     return n 


parser = argparse.ArgumentParser() 
parser.add_argument('-A',action='store_true') 
parser.add_argument('-B',action='store_true') 
parser.add_argument('-C',action='store_true') 
parser.add_argument('-D',action='store_true') 


parser2 = MyParser(parents=[parser],conflict_handler='resolve') 
for i in range(Nfiles): 
    parser2.add_argument('files%d'%i,action=FooAction,default=argparse.SUPPRESS) 


n = parser2.parse_args(args,namespace = MyNameSpace()) 
for k,v in n.accumulated.items(): 
    print k,v 

Calling này với:

~ $ python test.py -A foo bar -A -B -C qux 

sản lượng:

qux Namespace(A=True, B=True, C=True, D=False, file='qux') 
foo Namespace(A=True, B=False, C=False, D=False, file='foo') 
bar Namespace(A=False, B=False, C=False, D=False, file='bar') 
4

Tôi đã muốn làm điều này trong một thời gian, nhưng không bao giờ mơ ước một trường hợp sử dụng. Bạn đã tìm thấy một: cảm ơn bạn!

Bạn có thể làm điều này với hai giai đoạn của argparsing. Trong giai đoạn đầu tiên, bạn chỉ tìm kiếm các tùy chọn -A hoặc -B.

Trong giai đoạn thứ hai, bạn chia tay các đối số còn lại thành các đoạn (trong trường hợp này bằng cách sử dụng chức năng máy phát điện) và gọi parse_args trên mảnh:

import argparse 

def fileargs(args): 
    result = [] 
    for arg in args: 
     result.append(arg) 
     if not arg.startswith('-'): 
      yield result 
      result = [] 

parser = argparse.ArgumentParser() 
parser.add_argument('-A', action = 'store_true') 
parser.add_argument('-B', action = 'store_true') 
args, unk = parser.parse_known_args() 
print(args) 

file_parser = argparse.ArgumentParser() 
file_parser.add_argument('-C', action = 'store_true') 
file_parser.add_argument('-D', action = 'store_true') 
file_parser.add_argument('file') 
for filearg in fileargs(unk): 
    fargs = file_parser.parse_args(filearg) 
    print(fargs) 

sau đó test.py -A -B -C -D file1 -C file2 mang

Namespace(A=True, B=True) 
Namespace(C=True, D=True, file='file1') 
Namespace(C=True, D=False, file='file2') 
+0

Cảm ơn bạn! Rõ ràng, đơn giản và chính xác giải quyết các câu hỏi được hỏi. Thật vậy tôi cũng cần sử dụng các đối số tùy chọn cho các tệp, nhưng bằng cách nào đó đã bỏ qua công thức câu hỏi. Lấy làm tiếc. Xin vui lòng xem thêm câu trả lời của tôi, được tìm thấy sau khi thử mã của bạn ... – Roux

0

Tùy chọn action=append có thể sẽ hữu ích. Điều này sẽ cho phép bạn chỉ định một tùy chọn nhiều lần và tất cả các đối số với một tùy chọn cụ thể sẽ được lưu trữ trong danh sách tương ứng của chúng.

... đây là một ví dụ, cho phép gọi nó là sample.py:

if __name__ == '__main__': 
    parser = argparse.ArgumentParser() 
    parser.add_argument("-c", "--cfilein", action="append") 
    parser.add_argument("-d", "--dfilein", action="append") 
    args = parser.parse_args() 
    print args.cfilein 
    print args.dfilein 

Execute: ./sample.py -c f1 -d f2 -c f3 -d f4 
Output: ['f1', 'f3'] 
     ['f2', 'f4'] 

Check-out: http://docs.python.org/2/library/argparse.html#action ... Hope this helps ...

+0

với các hành động tùy chỉnh, một cái gì đó như thế này có thể được thực hiện để làm việc khá dễ dàng, nhưng nó buộc bạn chỉ định một '-f' không cần thiết trước mỗi tệp. – mgilson

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