Python: thử câu lệnh trong một dòng


89

Có cách nào trong python để biến thử / ngoại trừ thành một dòng duy nhất không?

cái gì đó như...

b = 'some variable'
a = c | b #try statement goes here

Trong trường hợp blà một biến khai báo và ckhông phải là ... do đó csẽ ném ra một lỗi và asẽ trở thành b...

Câu trả lời:


60

Không có cách nào để nén a try/ exceptblock vào một dòng duy nhất trong Python.

Ngoài ra, thật tệ là không biết liệu một biến có tồn tại trong Python hay không, giống như bạn làm trong một số ngôn ngữ động khác. Cách an toàn hơn (và là phong cách thịnh hành) là đặt tất cả các biến thành một cái gì đó. Nếu chúng có thể không được đặt, hãy đặt chúng thành Nonetrước (hoặc 0hoặc ''hoặc cái gì đó nếu nó phù hợp hơn.)


Nếu bạn làm assign tất cả các tên bạn đang quan tâm đến việc đầu tiên, bạn có các tùy chọn.

  • Tùy chọn tốt nhất là câu lệnh if.

    c = None
    b = [1, 2]
    
    if c is None:
        a = b
    else:
        a = c
    
  • Tùy chọn một lớp lót là một biểu thức điều kiện.

    c = None
    b = [1, 2]
    a = c if c is not None else b
    
  • Một số người lạm dụng hành vi đoản mạch orđể làm điều này. Đây là lỗi dễ xảy ra, vì vậy tôi không bao giờ sử dụng nó.

    c = None
    b = [1, 2]
    a = c or b
    

    Hãy xem xét trường hợp sau:

    c = []
    b = [1, 2]
    a = c or b
    

    Trong trường hợp này, acó lẽ nên được [], nhưng nó là [1, 2]bởi vì []là sai trong một bối cảnh boolean. Vì có rất nhiều giá trị có thể sai nên tôi không sử dụng orthủ thuật này. (Đây cũng là vấn đề mà mọi người gặp phải khi họ nói if foo:khi họ muốn nói if foo is not None:.)


Cảm ơn. Vấn đề là nó thực sự là một truy vấn django model.objects.get mà tôi đang cố gắng kiểm tra. các .get trả về một lỗi nếu không có dữ liệu được tìm thấy ... nó không trả lại None (mà làm phiền tôi)
Brant

@Brant, Được rồi, tình huống đó hơi khác so với việc kiểm tra xem một biến có được đặt hay không (không có biến nào được khai báo bằng Python). Phong cách điển hình trong Python là thích nâng cao ngoại lệ để trả về lỗi dưới dạng giá trị, điều mà nhiều người trong chúng ta thực sự yêu thích. Phải kiểm tra mã trả về của một hoạt động mọi lúc và gặp khó khăn khi theo dõi lỗi nếu không là điều tôi chắc chắn không bỏ lỡ về C khi viết Python. Trong mọi trường hợp, mặc dù nó đã được thảo luận, không có cú pháp một dòng cho khối try/ except. May mắn thay, các dòng rẻ, vì vậy giải pháp 4 dòng sẽ phù hợp với bạn. ;-)
Mike Graham

Nó là một phần của một tập hợp lớn của các bộ trong một dict ... Tôi chỉ cố gắng để rút ngắn mọi thứ lên một chút
Brant

2
Không sử dụng getnếu bạn không muốn có ngoại lệ. Sử dụng filterthay thế.
jcdyer

@MikeGraham Câu trả lời hay - một gợi ý (liên kết?) Tại sao việc đoản mạch dễ xảy ra lỗi sẽ rất hay.
kratenko

83

Đây là một sự tấn công khủng khiếp, nhưng tôi đã sử dụng nó ngay khi tôi muốn viết một chuỗi hành động để gỡ lỗi:

exec "try: some_problematic_thing()\nexcept: problem=sys.exc_info()"
print "The problem is %s" % problem[1]

Đối với hầu hết các phần, tôi không bị làm phiền bởi hạn chế không-đơn-dòng-thử-ngoại trừ, nhưng khi tôi chỉ đang thử nghiệm và tôi muốn readline nhớ lại toàn bộ đoạn mã cùng một lúc trong trình thông dịch tương tác. mà tôi có thể điều chỉnh nó bằng cách nào đó, mẹo nhỏ này rất hữu ích.

Đối với mục đích thực tế bạn đang cố gắng hoàn thành, bạn có thể thử locals().get('c', b); lý tưởng hơn là sử dụng một từ điển thực thay vì ngữ cảnh cục bộ, hoặc chỉ cần gán c cho Không trước khi chạy bất cứ thứ gì có thể-hoặc-có-thể-không đặt nó.


26
Này, điều này trả lời câu hỏi! :)
Steve Bennett

4
Thích câu trả lời này, siêu lộn xộn, nhưng một dòng, chỉ theo cách tôi thích.
Patrick Cook

Đây là câu trả lời!! sẽ problem[0]trả về những gì mà hàm đó trả về?
SIslam

4
Exec là một mùi mã và nên tránh trừ khi không có gì khác hoạt động. Nếu một mã dòng quan trọng như vậy thì điều này sẽ hiệu quả, nhưng bạn cần tự hỏi mình tại sao một dòng lại quan trọng như vậy.
Gewthen

4
rõ ràng không phải để sử dụng sản xuất, nhưng chính xác là những gì cần thiết cho một phiên gỡ lỗi khó xử.
ThorSummoner


13

Một cách khác là xác định trình quản lý ngữ cảnh:

class trialContextManager:
    def __enter__(self): pass
    def __exit__(self, *args): return True
trial = trialContextManager()

Sau đó, sử dụng withcâu lệnh để bỏ qua các lỗi trong một dòng:

>>> with trial: a = 5      # will be executed normally
>>> with trial: a = 1 / 0  # will be not executed and no exception is raised
>>> print a
5

Sẽ không có ngoại lệ nào được nêu ra trong trường hợp lỗi thời gian chạy. Nó giống như một try:mà không có except:.


1
Điều đó thật tuyệt! Vì không có thử / ngoại trừ rõ ràng, bạn có thể giải thích ngắn gọn cách trình quản lý ngữ cảnh xử lý lỗi không?
Patrick

8

Phiên bản của câu trả lời poke53280 với các ngoại lệ dự kiến ​​hạn chế.

def try_or(func, default=None, expected_exc=(Exception,)):
    try:
        return func()
    except expected_exc:
        return default

và nó có thể được sử dụng như

In [2]: try_or(lambda: 1/2, default=float('nan'))
Out[2]: 0.5

In [3]: try_or(lambda: 1/0, default=float('nan'), expected_exc=(ArithmeticError,))
Out[3]: nan

In [4]: try_or(lambda: "1"/0, default=float('nan'), expected_exc=(ArithmeticError,))
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
[your traceback here]
TypeError: unsupported operand type(s) for /: 'str' and 'int'

In [5]: try_or(lambda: "1"/0, default=float('nan'), expected_exc=(ArithmeticError, TypeError))
Out[5]: nan

Dấu phẩy trong "eval_exc = (Exception,)" dùng để làm gì? Bạn có thể giải thích được không?
ibilgen

7
parse_float = lambda x, y=exec("def f(s):\n try:\n  return float(s)\n except:  return None"): f(x)

Luôn luôn có một giải pháp.


5

Vấn đề là nó thực sự là một truy vấn django model.objects.get mà tôi đang cố gắng kiểm tra. .get trả về lỗi nếu không tìm thấy dữ liệu nào ... nó không trả về Không (điều này làm phiền tôi)

Sử dụng một cái gì đó như thế này:

print("result:", try_or(lambda: model.objects.get(), '<n/a>'))

Trong đó try_or là một hàm tiện ích do bạn xác định:

def try_or(fn, default):
    try:
        return fn()
    except:
        return default

Tùy chọn bạn có thể hạn chế các loại ngoại lệ được chấp nhận để NameError, AttributeErrorvv


4

Bạn có thể làm điều đó bằng cách truy cập dict namespace sử dụng vars(), locals()hoặc globals(), nào là thích hợp nhất cho tình hình của bạn.

>>> b = 'some variable'
>>> a = vars().get('c', b)

3
Điều này không làm việc chính xác giống như kiểm tra xem một biến được đặt (mặc dù nó nếu bạn đang quan tâm đến một phạm vi cụ thể.) Ngoài ra, ewwwwwwww .....
Mike Graham

4

Làm thế nào về việc sử dụng hai dòng. Là nó ổn ?

>>> try: a = 3; b= 0; c = a / b
... except : print('not possible'); print('zero division error')
...
not possible
zero division error

2

Bạn đã đề cập rằng bạn đang sử dụng django. Nếu nó phù hợp với những gì bạn đang làm, bạn có thể muốn sử dụng:

my_instance, created = MyModel.objects.get_or_create()

createdsẽ là Đúng hoặc Sai. Có lẽ điều này sẽ giúp bạn.


1

nếu bạn thực sự cần quản lý các ngoại lệ:
(sửa đổi từ câu trả lời của poke53280)

>>> def try_or(fn, exceptions: dict = {}):
    try:
        return fn()
    except Exception as ei:
        for e in ei.__class__.__mro__[:-1]:
            if e in exceptions: return exceptions[e]()
        else:
            raise


>>> def context():
    return 1 + None

>>> try_or( context, {TypeError: lambda: print('TypeError exception')} )
TypeError exception
>>> 

lưu ý rằng nếu ngoại lệ không được hỗ trợ, nó sẽ tăng lên như mong đợi:

>>> try_or( context, {ValueError: lambda: print('ValueError exception')} )
Traceback (most recent call last):
  File "<pyshell#57>", line 1, in <module>
    try_or( context, {ValueError: lambda: print('ValueError exception')} )
  File "<pyshell#38>", line 3, in try_or
    return fn()
  File "<pyshell#56>", line 2, in context
    return 1 + None
TypeError: unsupported operand type(s) for +: 'int' and 'NoneType'
>>> 

ngoài ra nếu Exceptionđược đưa ra, nó sẽ khớp với bất kỳ thứ gì bên dưới.
( BaseExceptioncao hơn, vì vậy nó sẽ không khớp)

>>> try_or( context, {Exception: lambda: print('exception')} )
exception

1

Hoạt động trên Python3, lấy cảm hứng từ Walter Mundt

exec("try:some_problematic_thing()\nexcept:pass")

Đối với các dòng đa dạng thành một dòng

exec("try:\n\tprint('FirstLineOk')\n\tsome_problematic_thing()\n\tprint('ThirdLineNotTriggerd')\nexcept:pass")

Ps: Exec không an toàn khi sử dụng trên dữ liệu bạn không có quyền kiểm soát.

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.