Kiểm tra xem sys.argv [x] có được xác định không


Câu trả lời:


64

Cuối cùng, sự khác biệt giữa try, exceptvà thử nghiệm len(sys.argv)không phải là tất cả những gì đáng kể. Cả hai đều là một chút hackish so với argparse.

Tuy nhiên, điều này xảy ra với tôi - như một loại lập luận ngân sách thấp:

arg_names = ['command', 'x', 'y', 'operation', 'option']
args = dict(zip(arg_names, sys.argv))

Bạn thậm chí có thể sử dụng nó để tạo ra một namedtuplevới các giá trị mặc định None- tất cả trong bốn dòng!

Arg_list = collections.namedtuple('Arg_list', arg_names)
args = Arg_list(*(args.get(arg, None) for arg in arg_names))

Trong trường hợp bạn không quen thuộc namedtuple, nó chỉ là một tuple hoạt động giống như một đối tượng, cho phép bạn truy cập các giá trị của nó bằng cách sử dụng tup.attributecú pháp thay vì tup[0]cú pháp.

Vì vậy, dòng đầu tiên tạo một namedtuplekiểu mới với các giá trị cho mỗi giá trị trong arg_names. Dòng thứ hai chuyển các giá trị từ từ argsđiển, sử dụng getđể trả về giá trị mặc định khi tên đối số đã cho không có giá trị liên quan trong từ điển.


Tôi ngày càng yêu thích Python, tất cả là nhờ những câu trả lời như vậy và tất nhiên là Stack Overflow! Thật tệ là chúng tôi không có lời giải thích về hai dòng cuối cùng. Tôi tin rằng đối với người mới bắt đầu điều đó sẽ rất tuyệt.
Goujon

2
Yêu nó! Dễ dàng giải pháp tốt nhất mà tôi đã thấy cho vấn đề này. Đối với những người khác: Tôi không rõ ràng ngay lập tức (newb) rằng: 1) 'lệnh' sẽ chuyển làm đối số đầu tiên mỗi lần và 2) bạn có thể gọi kết quả bằng args [0], v.v.
Matt D

Điều này chắc chắn là thú vị, nhưng có gì khó khăn khi kiểm tra độ dài?
colorlace

1
@timwiz Tôi chỉ đang nói so với việc sử dụng argparse. Tuy nhiên, những ngày này, tôi luôn tự kích động bản thân mỗi khi quay lại một kịch bản cũ và thấy rằng mình không sử dụng argparse.
gửi

116

Kiểm tra độ dài của sys.argv:

if len(sys.argv) > 1:
    blah = sys.argv[1]
else:
    blah = 'blah'

Một số người thích cách tiếp cận dựa trên ngoại lệ mà bạn đã đề xuất (ví dụ try: blah = sys.argv[1]; except IndexError: blah = 'blah':), nhưng tôi không thích nó nhiều vì nó không "chia tỷ lệ" gần như độc đáo (ví dụ: khi bạn muốn chấp nhận hai hoặc ba đối số) và nó có thể ẩn các lỗi (ví dụ: nếu bạn đã sử dụng blah = foo(sys.argv[1]), nhưng foo(...)đã nêu ra IndexError, điều đó IndexErrorsẽ bị bỏ qua).


1
Miễn là bạn vẫn còn nguyên tử về nó, không có gì phải lo lắng về điều đó try, except. Chỉ cần đợi foođối số của bạn cho đến elsemệnh đề.
gửi

3
Ngoài ra, một khi bạn đang nghĩ đến việc mở rộng quy mô, đã đến lúc chuyển sang argparse.
gửi

1
+1 trên argparse. Tôi đã tham argparse.pygia tất cả các dự án dòng lệnh của mình.
David Wolever

2
@senderle: chắc chắn, nếu bạn siêng năng về nó thì tốt. Nhưng theo kinh nghiệm của tôi, hầu hết các lập trình viên không siêng năng và đặt tất cả logic trong trymệnh đề… Vì vậy, cho rằng nó không khó hơn (và, IMO, đẹp hơn một chút), tôi thích chỉ kiểm tra độ dài (ngoài ra, bạn tránh có những người la mắng bạn vì đã sử dụng các ngoại lệ để kiểm soát luồng).
David Wolever

2
@David, vâng, tôi hiểu ý của bạn. Tôi hơi theo chủ nghĩa xin lỗi try, tôi phải thừa nhận. Tôi chỉ cảm thấy rằng nó đôi khi thể hiện ý định của tôi rõ ràng hơn là một iftuyên bố.
gửi

22

Một cách khác mà tôi chưa thấy được liệt kê là đặt giá trị sentinel của bạn trước thời hạn. Phương pháp này tận dụng lợi thế của đánh giá lười biếng của Python, trong đó bạn không phải lúc nào cũng phải cung cấp một elsecâu lệnh. Thí dụ:

startingpoint = 'blah'
if len(sys.argv) >= 2:
  startingpoint = sys.argv[1]

Hoặc nếu bạn đang sử dụng cú pháp CRAZY, bạn có thể sử dụng toán tử bậc ba của Python :

startingpoint = sys.argv[1] if len(sys.argv) >= 2 else 'blah'

1
Câu trả lời của toán tử bậc ba đối với mắt tôi là đẹp nhất. Tôi đang ngồi đây lặng lẽ nguyền rủa thực tế là một số phần mềm mà tôi duy trì được gắn với Python 2.4, mà không có nó.
Richard Barrell

11

Tôi sử dụng cái này - nó không bao giờ lỗi:

startingpoint = 'blah'
if sys.argv[1:]:
   startingpoint = sys.argv[1]

Đó không phải là để kiểm tra nếu được xác định. Giống như xác định nếu tồn tại, mà không giống nhau. Tôi cũng đã sử dụng cách đó để đánh giá các biến dự phòng, nhưng không phải là câu trả lời cho câu hỏi hiện tại.
m3nda

@ erm3nda Tôi có thể xóa startingpointbiến khỏi ví dụ, nhưng câu hỏi đang chỉ định một biến dự phòng, vì vậy tôi chỉ thực hiện như vậy.
anatoly techtonik

1
Nếu bạn xóa nó, bạn sẽ gặp lỗi về biến không được xác định. Tôi đã đọc lại câu hỏi, và những gì anh ấy mong đợi là, một sự thay thế có thể thay thế :) nên nó ổn. Cảm ơn lời khuyên của bạn về cách ngắn gọn đó nếu sys.argv[1:]:. Điều này hoạt động với các đối số vị trí trong khi số đếm thì không.
m3nda

10

Đó là một danh sách Python bình thường. Ngoại lệ mà bạn sẽ bắt gặp cho điều này là IndexError, nhưng thay vào đó bạn nên kiểm tra độ dài.

if len(sys.argv) >= 2:
  startingpoint = sys.argv[1]
else:
  startingpoint = 'blah'

2

Một giải pháp làm việc với fonction tích hợp bản đồ!

arg_names = ['command' ,'operation', 'parameter']
args = map(None, arg_names, sys.argv)
args = {k:v for (k,v) in args}

Sau đó, bạn chỉ cần gọi các tham số của mình như sau:

if args['operation'] == "division":
    if not args['parameter']:
        ...
    if args['parameter'] == "euclidian":
        ...

1

Bạn có thể chỉ cần nối giá trị của argv [1] vào argv và sau đó kiểm tra xem argv [1] không bằng chuỗi bạn đã nhập vào Ví dụ:

from sys import argv
argv.append('SomeString')
if argv[1]!="SomeString":
            print(argv[1])

Đối với những người đã bỏ phiếu cho tôi, xấu hổ cho bạn, vì đã không làm rõ sai lầm.
Hassan Abdul-Kareem

Tôi đoán đó là bởi vì nó hackish. Điều gì sẽ xảy ra nếu ai đó chuyển SomeString làm đối số? Làm thế nào để sử dụng điều đó nếu bạn có thể chấp nhận cho phép nói 1 đến 5 đối số?
pbogut,

Tuyệt vời (nhưng vẫn khó hiểu) để đặt giá trị mặc định trong trường hợp người dùng không cung cấp đối số. Chỉ cần nối thêm và sau đó sử dụng argv [1].
Felizett

1

Khá gần với những gì người khởi tạo đang cố gắng làm. Đây là một chức năng tôi sử dụng:

def get_arg(index):
    try:
        sys.argv[index]
    except IndexError:
        return ''
    else:
        return sys.argv[index]

Vì vậy, cách sử dụng sẽ giống như:

if __name__ == "__main__":
    banner(get_arg(1),get_arg(2))
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.