Việc sử dụng của Ass assert trong Python là gì?


Câu trả lời:


1084

Các assert lệnh tồn tại trong hầu hết mọi ngôn ngữ lập trình. Nó giúp phát hiện sớm các vấn đề trong chương trình của bạn, trong đó nguyên nhân rõ ràng, thay vì muộn hơn là tác dụng phụ của một số hoạt động khác.

Khi bạn làm ...

assert condition

... Bạn đang nói với chương trình kiểm tra điều kiện đó và ngay lập tức gây ra lỗi nếu điều kiện đó là sai.

Trong Python, nó gần tương đương với điều này:

if not condition:
    raise AssertionError()

Hãy thử nó trong trình bao Python:

>>> assert True # nothing happens
>>> assert False
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError

Các xác nhận có thể bao gồm một thông báo tùy chọn và bạn có thể vô hiệu hóa chúng khi chạy trình thông dịch.

Để in một tin nhắn nếu xác nhận thất bại:

assert False, "Oh no! This assertion failed!"

Đừng không sử dụng dấu ngoặc đơn để gọi assertnhư một hàm. Đó là một tuyên bố. Nếu bạn làm, assert(condition, message)bạn sẽ chạy assertvới một (condition, message)tuple là tham số đầu tiên.

Đối với việc vô hiệu hóa chúng, khi chạy pythonở chế độ tối ưu hóa, nơi __debug__False, báo cáo khẳng định sẽ bị bỏ qua. Chỉ cần vượt qua -Ocờ:

python -O script.py

Xem ở đây để các tài liệu liên quan.


92
Nit: khẳng định là một tuyên bố và không phải là một chức năng. Và không giống như in , trong Python 3 nó vẫn là một tuyên bố .
Bob Stein

2
@Chaine khẳng định có nghĩa là "đảm bảo rằng * một cái gì đó" là Đúng ". Vì vậy, khẳng định a == 3 sẽ đảm bảo rằng a bằng 3; nếu a không bằng 3 (tức là a == 3 là Sai) thì nó sẽ gây ra lỗi
Ant

5
Nếu tôi chỉ có thể sử dụng if not condition: raise AssertError(), tại sao tôi nên sử dụng khẳng định? Có bất kỳ điều kiện nào theo đó khẳng định là tốt hơn ngoài việc chỉ là một hình thức if not conditiontuyên bố ngắn hơn ?
alpha_989

6
@ alpha_989 a) nó ngắn hơn và dễ đọc hơn, b) bạn có thể vô hiệu hóa các câu lệnh khẳng định khi chạy trình thông dịch (không như vậy với hướng dẫn sử dụng if). Đọc tài liệu để biết thêm thông tin :)
slezica

9
hoàn toàn không thể hiểu làm thế nào mà câu trả lời này nhận được nhiều phiếu bầu như vậy, thực ra những câu trả lời khác cũng vậy. câu hỏi là "Việc sử dụng của ass assert trong Python là gì?", vì vậy nó đang hỏi: khi nào nên sử dụng, hay chính xác hơn: kịch bản sử dụng là gì assert, nhưng sau khi đọc tất cả các câu trả lời, tôi hoàn toàn không có gì tôi muốn!
lnshi

424

Coi chừng dấu ngoặc đơn. Như đã chỉ ra ở trên, trong Python 3, assertvẫn là một câu lệnh , do đó, tương tự với print(..), người ta có thể ngoại suy tương tự với assert(..)hoặcraise(..) nhưng bạn không nên.

Điều này rất quan trọng vì:

assert(2 + 2 == 5, "Houston we've got a problem")

sẽ không làm việc, không giống như

assert 2 + 2 == 5, "Houston we've got a problem"

Lý do thứ nhất sẽ không hoạt động là bool( (False, "Houston we've got a problem") )đánh giáTrue .

Trong tuyên bố assert(False), đây chỉ là các dấu ngoặc đơn dư thừa xung quanh False, đánh giá nội dung của chúng. Nhưng với assert(False,)dấu ngoặc đơn bây giờ là một tuple và một tuple không trống đánh giá Truetrong bối cảnh boolean.


18
Tôi đến đây để tìm thông tin chính xác này về parens và thông báo theo dõi. Cảm ơn.
tuyệt vời

6
Nhưng assert (2 + 2 = 5), "Houston we've got a problem"nên ổn chứ?
SherylHohman

4
@SherylHohman bạn cũng có thể thử tự chạy nó và xem nó có hoạt động hay không
DarkCygnus

2
Đừng quên rằng mọi người thường sử dụng dấu ngoặc đơn để tiếp tục dòng ẩn tuân thủ PEP 8 Ngoài ra, cũng đừng quên rằng các bộ dữ liệu không được xác định bởi dấu ngoặc đơn mà bởi sự tồn tại của dấu phẩy (bộ dữ liệu không liên quan gì đến parens ngoại trừ mục đích của ưu tiên điều hành).
cowbert

4
assert (2 + 2 = 5), "Houston we've got a problem"sẽ không hoạt động ... nhưng nó không liên quan gì đến tuyên bố khẳng định, điều này tốt. Tình trạng của bạn sẽ không hoạt động vì đó không phải là điều kiện. Thiếu một giây =.
n1k31t4

133

Như các câu trả lời khác đã lưu ý, asserttương tự như ném một ngoại lệ nếu một điều kiện nhất định không đúng. Một sự khác biệt quan trọng là các câu lệnh khẳng định bị bỏ qua nếu bạn biên dịch mã của mình với tùy chọn tối ưu hóa -O. Các tài liệu nói rằng assert expressiontốt hơn có thể được mô tả là tương đương với

if __debug__:
   if not expression: raise AssertionError

Điều này có thể hữu ích nếu bạn muốn kiểm tra kỹ mã của mình, sau đó phát hành phiên bản tối ưu hóa khi bạn hài lòng rằng không có trường hợp xác nhận nào của bạn thất bại - khi tối ưu hóa được bật, __debug__biến trở thành Sai và các điều kiện sẽ ngừng được đánh giá. Tính năng này cũng có thể giúp bạn hiểu ra nếu bạn đang dựa vào các xác nhận và không nhận ra chúng đã biến mất.


Điều này có nghĩa là, nếu một biến nhất định hoặc đầu vào đúng (theo hợp đồng mà chương trình được viết) có thể dẫn đến sự cố chương trình, khi người dùng chạy (giả sử rằng cờ -O được sử dụng khi người dùng chạy chương trình), thay vào đó bạn nên sử dụng if Not Error: raise Exception(“ this is a error”)? Bằng cách đó, chương trình vẫn sẽ hiển thị nguồn lỗi, khi người dùng chạy nó ..
alpha_989

Mặt khác, nếu bạn cho rằng chương trình có thể bị lỗi do logic / triển khai mã không chính xác (nhưng không phải do đầu vào theo hợp đồng với người dùng chương trình), bạn nên sử dụng assertcâu lệnh nào? Giả định ở đây là khi chương trình được phát hành cho người dùng cuối, bạn đang sử dụng cờ -O, do đó giả sử rằng tất cả các lỗi đã được xóa. Do đó, bất kỳ lỗi hoặc sự cố chương trình là do đầu vào của chương trình hợp lệ theo hợp đồng, nhưng không thể được chương trình xử lý. Vì vậy, nó nên cảnh báo người dùng như vậy.
alpha_989

@ alpha_989 điều đó hoàn toàn chính xác. Tôi thích nghĩ về các xác nhận là kiểm tra sự tỉnh táo chỉ để giúp bạn là nhà phát triển để đảm bảo rằng những gì bạn nghĩ là đúng là thực sự đúng trong khi bạn phát triển.
Christopher Shroba

52

Mục tiêu của một xác nhận trong Python là thông báo cho các nhà phát triển về các lỗi không thể phục hồi trong một chương trình.

Các xác nhận không nhằm mục đích báo hiệu các điều kiện lỗi dự kiến, như không tìm thấy tập tin, trong đó người dùng có thể thực hiện hành động khắc phục (hoặc chỉ cần thử lại).

Một cách khác để xem xét nó là nói rằng các xác nhận là tự kiểm tra nội bộ trong mã của bạn. Họ làm việc bằng cách tuyên bố một số điều kiện là không thể trong mã của bạn. Nếu những điều kiện này không có nghĩa là có lỗi trong chương trình.

Nếu chương trình của bạn không có lỗi, những điều kiện này sẽ không bao giờ xảy ra. Nhưng nếu một trong số họ không xảy ra chương trình sẽ sụp đổ với một lỗi khẳng định nói cho bạn chính xác “không thể” điều kiện đã được kích hoạt. Điều này làm cho việc theo dõi và sửa lỗi trong chương trình của bạn dễ dàng hơn nhiều.

Đây là một bản tóm tắt từ một hướng dẫn về các xác nhận của Python mà tôi đã viết:

Tuyên bố khẳng định của Python là một trợ giúp gỡ lỗi, không phải là một cơ chế để xử lý các lỗi thời gian chạy. Mục tiêu của việc sử dụng các xác nhận là để cho phép các nhà phát triển tìm ra nguyên nhân gốc có khả năng gây ra lỗi nhanh hơn. Một lỗi xác nhận sẽ không bao giờ được nêu ra trừ khi có lỗi trong chương trình của bạn.


Cảm ơn bài viết. Rất hữu ích để hiểu asserttuyên bố và khi sử dụng này. Tôi đang cố gắng để hiểu một số thuật ngữ mà bạn đã giới thiệu trong bài viết.
alpha_989

Tôi nghĩ rằng tôi sẽ đăng các bình luận ở đây để nhiều người có thể được hưởng lợi từ việc làm rõ. Xin lỗi nếu những câu hỏi quá ngây thơ.
alpha_989

Trong blog của bạn mà bạn đã liên kết, bạn đưa ra một ví dụ mà bạn đã đề cập rằng `assert 0 <= price <= product ['price']` là chính xác, nhưng sử dụng` assert user.is_admin (), 'Phải có đặc quyền của quản trị viên để xóa '`và assert store.product_exists(product_id), 'Unknown product id'không phải là một cách thực hành tốt, bởi vì nếu gỡ lỗi bị tắt thì userngay cả khi không admincó thể sẽ xóa sản phẩm. Bạn có coi assert user.is_admin()là một unrecoverablelỗi? Tại sao điều này không phải là một self-check?
alpha_989

Nếu bạn cho rằng 'user.is_admin () `là đầu vào của người dùng và do đó không nên được sử dụng trong một assert statement, bạn pricecũng không thể được coi là đầu vào của người dùng? Tại sao bạn coi assert user.is_admin()như xác nhận dữ liệu nhưng không assert price?
alpha_989

1
@LaryxDecidua Không, bạn chỉ cần đọc nó trên trang web của tôi, hướng dẫn có sẵn công khai. Chỉ cần nhấn thoát hoặc nhấp vào biểu tượng "x" nhỏ nếu bạn không quan tâm đến bản tin. Hy vọng điều này sẽ giúp :-)
dbader

51

Những người khác đã cung cấp cho bạn các liên kết đến tài liệu.

Bạn có thể thử những điều sau trong một vỏ tương tác:

>>> assert 5 > 2
>>> assert 2 > 5
Traceback (most recent call last):
  File "<string>", line 1, in <fragment>
builtins.AssertionError:

Câu lệnh đầu tiên không làm gì cả, trong khi câu lệnh thứ hai đưa ra một ngoại lệ. Đây là gợi ý đầu tiên: các xác nhận rất hữu ích để kiểm tra các điều kiện phải đúng ở một vị trí nhất định của mã của bạn (thông thường, bắt đầu (điều kiện tiên quyết) và kết thúc của một hàm (postconditions)).

Các xác nhận thực sự gắn liền với lập trình bằng hợp đồng, đây là một thực hành kỹ thuật rất hữu ích:

http://en.wikipedia.org/wiki/Design_by_contract .


Vì vậy, điều đó có nghĩa là chúng ta có thể kiểm tra mã trong một tình huống như khẳng định (2> 5) và tiếp tục phát sinh lỗi khác?

20
Mất parens, khẳng định không phải là một chức năng.
thuốc viên

2
Mất parens là quan trọng hơn nó dường như. Xem bên dưới .
Evgeni Sergeev

6
Khẳng định thực sự có từ ngày trước (trước khi "hợp đồng") với Turing, khi ông viết một trong những bài báo sớm nhất về cách các lập trình viên có thể giải quyết nhiệm vụ khá khó khăn là tạo ra các chương trình chính xác. Tìm thấy bài báo đó là một bài tập cho người đọc, vì tất cả các lập trình viên có thể được hưởng lợi từ việc làm quen với công việc của mình. :-) turingarchive.org
Ron Burk

17

Từ tài liệu:

Assert statements are a convenient way to insert debugging assertions into a program

Tại đây bạn có thể đọc thêm: http://docs.python.org/release/2.5.2/ref/assert.html


Tôi thích bình luận này vì nó chỉ giải thích những gì nó rất rõ ràng. câu hỏi của tôi là "nếu tôi đã viết một bài kiểm tra đơn vị thích hợp, tại sao tôi lại cần một khẳng định"? những thứ đó không chạy trong sản xuất dù sao đi nữa.
dtc

17

Tuyên bố khẳng định có hai hình thức.

Các hình thức đơn giản assert <expression>, tương đương với

if __debug__:
    if not <expression>: raise AssertionError

Hình thức mở rộng assert <expression1>, <expression2>, tương đương với

if __debug__:
    if not <expression1>: raise AssertionError, <expression2>

16

Các xác nhận là một cách có hệ thống để kiểm tra xem trạng thái bên trong của chương trình có đúng như lập trình viên mong đợi hay không, với mục tiêu là bắt lỗi. Xem ví dụ dưới đây.

>>> number = input('Enter a positive number:')
Enter a positive number:-1
>>> assert (number > 0), 'Only positive numbers are allowed!'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError: Only positive numbers are allowed!
>>> 

1
Ngoài ra, các xác nhận thường có thể được sử dụng trong các chương trình thử nghiệm đơn vị. stackoverflow.com/questions/1383/what-is-unit-testing
panofish

7

Dưới đây là một ví dụ đơn giản, hãy lưu tệp này trong tệp (giả sử b.py)

def chkassert(num):
    assert type(num) == int


chkassert('a')

và kết quả khi $python b.py

Traceback (most recent call last):
  File "b.py", line 5, in <module>
    chkassert('a')
  File "b.py", line 2, in chkassert
    assert type(num) == int
AssertionError

6

nếu câu lệnh sau assert là true thì chương trình vẫn tiếp tục, nhưng nếu câu lệnh sau assert là false thì chương trình sẽ báo lỗi. Đơn giản như thế.

ví dụ:

assert 1>0   #normal execution
assert 0>1   #Traceback (most recent call last):
             #File "<pyshell#11>", line 1, in <module>
             #assert 0>1
             #AssertionError

4

Các assert lệnh tồn tại trong hầu hết mọi ngôn ngữ lập trình. Nó giúp phát hiện sớm các vấn đề trong chương trình của bạn, trong đó nguyên nhân rõ ràng, thay vì muộn hơn là tác dụng phụ của một số hoạt động khác. Họ luôn mong đợi một Trueđiều kiện.

Khi bạn làm một cái gì đó như:

assert condition

Bạn đang nói với chương trình kiểm tra điều kiện đó và ngay lập tức gây ra lỗi nếu nó sai.

Trong Python, assertbiểu thức , tương đương với:

if __debug__:
    if not <expression>: raise AssertionError

Bạn có thể sử dụng biểu thức mở rộng để truyền một thông báo tùy chọn :

if __debug__:
    if not (expression_1): raise AssertionError(expression_2)

Hãy thử nó trong trình thông dịch Python:

>>> assert True # Nothing happens because the condition returns a True value.
>>> assert False # A traceback is triggered because this evaluation did not yield an expected value.
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError

Có một số cảnh báo để xem trước khi sử dụng chúng chủ yếu cho những người coi là chuyển đổi giữa các câu lệnh assertifcâu lệnh. Mục đích sử dụngassert là vào các dịp khi chương trình xác minh một điều kiện và trả về một giá trị sẽ dừng chương trình ngay lập tức thay vì thực hiện một số cách khác để bỏ qua lỗi:

1. Dấu ngoặc đơn

Như bạn có thể nhận thấy, asserttuyên bố sử dụng hai điều kiện. Do đó, không sử dụng dấu ngoặc đơn để thu nhận chúng như một lời khuyên rõ ràng. Nếu bạn làm như:

assert (condition, message)

Thí dụ:

>>> assert (1==2, 1==1)
<stdin>:1: SyntaxWarning: assertion is always true, perhaps remove parentheses?

Bạn sẽ chạy assertvới một (condition, message)đại diện cho một tuple là tham số đầu tiên và điều này xảy ra gây ra tuple không trống trong Python luônTrue . Tuy nhiên, bạn có thể làm riêng mà không gặp vấn đề gì:

assert (condition), "message"

Thí dụ:

>>> assert (1==2), ("This condition returns a %s value.") % "False"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError: This condition returns a False value.

2. Mục đích gỡ lỗi

Nếu bạn đang tự hỏi về việc sử dụng assert tuyên bố. Lấy một ví dụ được sử dụng trong cuộc sống thực:

* Khi chương trình của bạn có xu hướng kiểm soát từng tham số được nhập bởi người dùng hoặc bất cứ điều gì khác:

def loremipsum(**kwargs):
    kwargs.pop('bar') # return 0 if "bar" isn't in parameter
    kwargs.setdefault('foo', type(self)) # returns `type(self)` value by default
    assert (len(kwargs) == 0), "unrecognized parameter passed in %s" % ', '.join(kwargs.keys())

* Một trường hợp khác là về toán học khi 0 hoặc không dương dưới dạng hệ số hoặc hằng số trên một phương trình nhất định:

def discount(item, percent):
    price = int(item['price'] * (1.0 - percent))
    print(price)
    assert (0 <= price <= item['price']),\
            "Discounted prices cannot be lower than 0 "\
            "and they cannot be higher than the original price."

    return price

* hoặc thậm chí là một ví dụ đơn giản về triển khai boolean:

def true(a, b):
    assert (a == b), "False"
    return 1

def false(a, b):
    assert (a != b), "True"
    return 0

3. Xử lý dữ liệu hoặc xác nhận dữ liệu

Điều quan trọng nhất là không dựa vào assertcâu lệnh để thực hiện xử lý dữ liệu hoặc xác thực dữ liệu vì câu lệnh này có thể được tắt khi khởi tạo Python bằng -Ohoặc -OOgắn cờ - có nghĩa là giá trị 1, 2 và 0 (như mặc định), hoặc PYTHONOPTIMIZEbiến môi trường .

Giá trị 1:

* khẳng định bị vô hiệu hóa;

* tập tin mã byte được tạo bằng cách sử dụng .pyophần mở rộng thay vì .pyc;

* sys.flags.optimizeđược đặt thành 1 (True );

* và, __debug__được đặt thành False;

Giá trị 2: vô hiệu hóa thêm một thứ nữa

* tài liệu bị vô hiệu hóa;

Do đó, sử dụng assertcâu lệnh để xác thực một loại dữ liệu dự kiến ​​là cực kỳ nguy hiểm, ngụ ý ngay cả đối với một số vấn đề bảo mật. Sau đó, nếu bạn cần xác thực một số quyền, tôi khuyên bạn nên raise AuthErrorthay thế. Là một điều kiện tiên quyết, một assertchương trình thường được sử dụng bởi các lập trình viên trên các thư viện hoặc mô-đun không có người dùng tương tác trực tiếp.


3

Như được tóm tắt chính xác trên Wiki Wiki :

Khẳng định là một biểu thức boolean tại một điểm cụ thể trong chương trình, điều này sẽ đúng trừ khi có lỗi trong chương trình.

Bạn có thể sử dụng một assertcâu lệnh để ghi lại sự hiểu biết của bạn về mã tại một điểm chương trình cụ thể. Ví dụ: bạn có thể ghi lại các giả định hoặc đảm bảo về đầu vào (điều kiện tiên quyết), trạng thái chương trình (bất biến) hoặc đầu ra (hậu điều kiện).

Nếu khẳng định của bạn không bao giờ thất bại, đây là một cảnh báo cho bạn (hoặc người kế nhiệm của bạn) rằng sự hiểu biết của bạn về chương trình đã sai khi bạn viết nó và nó có khả năng chứa lỗi.

Để biết thêm thông tin, John Regehr có một bài đăng blog tuyệt vời về Sử dụng Xác nhận , cũng áp dụng cho assertcâu lệnh Python .


2

Nếu bạn muốn biết chính xác chức năng dành riêng làm gì trong python, hãy nhập vào help(enter_keyword)

Hãy chắc chắn nếu bạn đang nhập một từ khóa dành riêng mà bạn nhập nó dưới dạng một chuỗi.


2

Python khẳng định về cơ bản là một công cụ gỡ lỗi kiểm tra điều kiện để tự kiểm tra nội bộ mã của bạn. Khẳng định làm cho việc gỡ lỗi thực sự dễ dàng khi mã của bạn rơi vào trường hợp cạnh không thể. Khẳng định kiểm tra những trường hợp không thể.

Giả sử có một chức năng để tính giá của mặt hàng sau khi giảm giá:

def calculate_discount(price, discount):
    discounted_price = price - [discount*price]
    assert 0 <= discounted_price <= price
    return discounted_price

ở đây, discounted_price không bao giờ có thể nhỏ hơn 0 và lớn hơn giá thực tế. Vì vậy, trong trường hợp điều kiện trên bị vi phạm, khẳng định sẽ gây ra Lỗi xác nhận, giúp nhà phát triển xác định rằng điều gì đó không thể xảy ra.

Hy vọng nó giúp :)


2
assertlà hữu ích trong bối cảnh gỡ lỗi, nhưng không nên dựa vào bối cảnh gỡ lỗi.
FluxIX

2

Giải thích ngắn gọn của tôi là:

  • asserttăng AssertionErrornếu biểu thức là sai, nếu không thì tiếp tục mã và nếu có dấu phẩy thì nó sẽ là gì AssertionError: whatever after commavà mã là như sau:raise AssertionError(whatever after comma)

Một hướng dẫn liên quan về điều này:

https://www.tutorialspoint.com/python/assertions_in_python.htmlm


Câu trả lời cung cấp cách sử dụng một assert, nhưng không phải khi nào sử dụng (hoặc không sử dụng) một assert; cũng lưu ý rằng một assertcó thể bị vô hiệu hóa nếu __debug__Falsesẽ hữu ích.
FluxIX

1

Trong Pycharm, nếu bạn sử dụng assertcùng với isinstanceđể khai báo loại đối tượng, nó sẽ cho phép bạn truy cập các phương thức và thuộc tính của đối tượng cha trong khi bạn đang mã hóa, nó sẽ tự động hoàn thành.

Ví dụ, giả sử self.object1.object2là một MyClassđối tượng.

import MyClasss

def code_it(self):
    testObject = self.object1.object2 # at this point, program doesn't know that testObject  is a MyClass object yet
    assert isinstance(testObject , MyClasss) # now the program knows testObject is a MyClass object
    testObject.do_it() # from this point on, PyCharm will be able to auto-complete when you are working on testObject

0

Như được viết trong các câu trả lời khác, các câu assertlệnh được sử dụng để kiểm tra trạng thái của chương trình tại một điểm nhất định.

Tôi sẽ không lặp lại những gì đã nói về thông điệp liên quan, dấu ngoặc đơn hoặc -Otùy chọn và __debug__hằng số. Kiểm tra tài liệu cho thông tin đầu tay. Tôi sẽ tập trung vào câu hỏi của bạn: việc sử dụng là assertgì? Chính xác hơn, khi nào (và khi không) nên sử dụng assert?

Các assertbáo cáo rất hữu ích để gỡ lỗi một chương trình, nhưng không khuyến khích kiểm tra đầu vào của người dùng. Tôi sử dụng quy tắc ngón tay cái sau: giữ các xác nhận để phát hiện tình huống này không nên xảy ra . Một đầu vào của người dùng có thể không chính xác, ví dụ mật khẩu quá ngắn, nhưng đây không phải là trường hợp không nên xảy ra . Nếu đường kính của một vòng tròn không lớn gấp đôi bán kính của nó, thì bạn không nên xảy ra chuyện này. trường hợp này.

Điều thú vị nhất, trong suy nghĩ của tôi, việc sử dụng assertđược lấy cảm hứng từ lập trình theo hợp đồng như được mô tả bởi B. Meyer trong [Xây dựng phần mềm hướng đối tượng] ( https://www.eiffel.org/doc/eiffel/Object-Orients_Software_Con cản% 2C_2nd_Edition ) và được triển khai trong [Ngôn ngữ lập trình Eiffel] ( https://en.wikipedia.org/wiki/Eiffel_(programming_lingu) ). Bạn không thể mô phỏng hoàn toàn việc lập trình bằng hợp đồng bằng cách sử dụng assertcâu lệnh, nhưng thật thú vị khi giữ ý định đó.

Đây là một ví dụ. Hãy tưởng tượng bạn phải viết một headhàm (như [ headhàm trong Haskell] ( http://www.zvon.org/other/haskell/Outputprelude/head_f.html )). Thông số kỹ thuật bạn đưa ra là: "nếu danh sách không trống, hãy trả về mục đầu tiên của danh sách". Nhìn vào các triển khai sau:

>>> def head1(xs): return xs[0]

>>> def head2(xs):
...     if len(xs) > 0:
...         return xs[0]
...     else:
...         return None

(Vâng, điều này có thể được viết là return xs[0] if xs else None, nhưng đó không phải là vấn đề) .

Nếu danh sách không trống, cả hai hàm đều có cùng kết quả và kết quả này là chính xác:

>>> head1([1, 2, 3]) == head2([1, 2, 3]) == 1
True

Do đó, cả hai triển khai đều (tôi hy vọng) đúng. Chúng khác nhau khi bạn cố lấy mục đầu của danh sách trống:

>>> head1([])
Traceback (most recent call last):
...
IndexError: list index out of range

Nhưng:

>>> head2([]) is None
True

Một lần nữa, cả hai triển khai đều đúng, bởi vì không ai nên chuyển một danh sách trống cho các hàm này (chúng tôi nằm ngoài đặc tả ). Đó là một cuộc gọi không chính xác, nhưng nếu bạn thực hiện một cuộc gọi như vậy, bất cứ điều gì cũng có thể xảy ra. Một hàm tăng một ngoại lệ, hàm kia trả về một giá trị đặc biệt. Điều quan trọng nhất là: chúng ta không thể dựa vào hành vi này . Nếu xstrống, điều này sẽ hoạt động:

print(head2(xs))

Nhưng điều này sẽ làm hỏng chương trình:

print(head1(xs))

Để tránh một số bất ngờ, tôi muốn biết khi tôi chuyển một số đối số không mong muốn cho một hàm. Nói cách khác: Tôi muốn biết khi nào hành vi quan sát được không đáng tin cậy, bởi vì nó phụ thuộc vào việc thực hiện, không phụ thuộc vào đặc điểm kỹ thuật. Tất nhiên, tôi có thể đọc các đặc tả, nhưng các lập trình viên không phải lúc nào cũng đọc kỹ các tài liệu.

Hãy tưởng tượng nếu tôi có cách chèn đặc tả vào mã để có được hiệu ứng sau: khi tôi vi phạm đặc tả, ví dụ: bằng cách chuyển một danh sách trống tới head, tôi nhận được cảnh báo. Đó sẽ là một trợ giúp tuyệt vời để viết một chương trình chính xác (tức là tuân thủ các đặc điểm kỹ thuật). Và đó là nơi assert bước vào hiện trường:

>>> def head1(xs):
...     assert len(xs) > 0, "The list must not be empty"
...     return xs[0]

>>> def head2(xs):
...     assert len(xs) > 0, "The list must not be empty"
...     if len(xs) > 0:
...         return xs[0]
...     else:
...         return None

Bây giờ chúng tôi có:

>>> head1([])
Traceback (most recent call last):
...
AssertionError: The list must not be empty

Và:

>>> head2([])
Traceback (most recent call last):
...
AssertionError: The list must not be empty

Lưu ý rằng head1ném một AssertionError, không phải một IndexError. Điều đó quan trọng bởi vì AssertionErrorkhông phải là bất kỳ lỗi thời gian chạy nào : nó báo hiệu sự vi phạm đặc tả. Tôi muốn một cảnh báo, nhưng tôi nhận được một lỗi. May mắn thay, tôi có thể vô hiệu hóa kiểm tra (sử dụng -Otùy chọn), nhưng với rủi ro của riêng tôi. Tôi sẽ làm điều đó một vụ tai nạn thực sự tốn kém, và hy vọng điều tốt nhất. Hãy tưởng tượng chương trình của tôi được nhúng vào một con tàu vũ trụ đi qua một lỗ đen. Tôi sẽ vô hiệu hóa các xác nhận và hy vọng chương trình đủ mạnh để không bị sập càng lâu càng tốt.

Ví dụ này chỉ là về các điều kiện tiên quyết, bạn có thể sử dụng assertđể kiểm tra các điều kiện hậu (giá trị trả về và / hoặc trạng thái) và bất biến (trạng thái của một lớp). Lưu ý rằng việc kiểm tra hậu điều kiện và bất biến có assertthể rất phức tạp:

  • đối với các điều kiện hậu, bạn cần gán giá trị trả về cho một biến và có thể lưu trữ trạng thái vô hình của đối tượng nếu bạn đang xử lý một phương thức;
  • đối với bất biến, bạn phải kiểm tra trạng thái trước và sau khi gọi phương thức.

Bạn sẽ không có thứ gì đó tinh vi như Eiffel, nhưng bạn có thể cải thiện chất lượng chung của một chương trình.


Tóm lại, asserttuyên bố là một cách thuận tiện để phát hiện tình huống không nên xảy ra . Vi phạm đặc điểm kỹ thuật (ví dụ: chuyển một danh sách trống đến head) là lớp đầu tiên, điều này không nên xảy ra . Do đó, trong khi asserttuyên bố có thể được sử dụng để phát hiện bất kỳ tình huống bất ngờ nào, đó là một cách đặc quyền để đảm bảo rằng đặc tả được đáp ứng. Khi bạn đã chèn các assertcâu lệnh vào mã để thể hiện đặc tả, chúng tôi có thể hy vọng bạn đã cải thiện chất lượng của chương trình vì các đối số không chính xác, giá trị trả về không chính xác, trạng thái không chính xác của một lớp ..., sẽ được báo cáo.


-2

format: assert Expression [, argument] Khi assert gặp câu lệnh, Python đánh giá biểu thức. Nếu câu lệnh không đúng, một ngoại lệ được đưa ra (ass assError). Nếu xác nhận thất bại, Python sử dụng ArgumentExpression làm đối số cho AssertsError. Các ngoại lệ của AssertsError có thể được bắt và xử lý như bất kỳ ngoại lệ nào khác bằng cách sử dụng câu lệnh ngoại trừ thử, nhưng nếu không được xử lý, chúng sẽ chấm dứt chương trình và tạo ra một dấu vết. Thí dụ:

def KelvinToFahrenheit(Temperature):    
    assert (Temperature >= 0),"Colder than absolute zero!"    
    return ((Temperature-273)*1.8)+32    
print KelvinToFahrenheit(273)    
print int(KelvinToFahrenheit(505.78))    
print KelvinToFahrenheit(-5)    

Khi đoạn mã trên được thực thi, nó tạo ra kết quả sau:

32.0
451
Traceback (most recent call last):    
  File "test.py", line 9, in <module>    
    print KelvinToFahrenheit(-5)    
  File "test.py", line 4, in KelvinToFahrenheit    
    assert (Temperature >= 0),"Colder than absolute zero!"    
AssertionError: Colder than absolute zero!    

-2
def getUser(self, id, Email):

    user_key = id and id or Email

    assert user_key

Có thể được sử dụng để đảm bảo các tham số được truyền trong lệnh gọi hàm.


1
Điều này sẽ hoạt động, nhưng theo những gì tôi hiểu, khẳng định không nên được sử dụng để kiểm tra đầu vào của người dùng, vì chúng có thể bị tắt trong thời gian chạy. Nếu bạn thực sự muốn thực thi hoặc xác thực đầu vào của người dùng, hãy sử dụng if not user_key: raise ValueError()Kiểm tra 2 đoạn cuối tại đây: wiki.python.org/moin/UsingAssertionsEffectively
alpha_989

assertkhông nên được sử dụng để xác nhận đầu vào vì xác thực sẽ bị loại bỏ nếu __debug__False. Ngoài ra, việc sử dụng các xác nhận cho các mục đích không gỡ lỗi có thể khiến mọi người bắt được các kết quả AssertionError, điều này có thể làm cho việc gỡ lỗi trở nên khó khăn hơn thay vì ít hơn.
FluxIX

-4
>>>this_is_very_complex_function_result = 9
>>>c = this_is_very_complex_function_result
>>>test_us = (c < 4)

>>> #first we try without assert
>>>if test_us == True:
    print("YES! I am right!")
else:
    print("I am Wrong, but the program still RUNS!")

I am Wrong, but the program still RUNS!


>>> #now we try with assert
>>> assert test_us
Traceback (most recent call last):
  File "<pyshell#52>", line 1, in <module>
    assert test_us
AssertionError
>>> 

-4

Về cơ bản, ý nghĩa của từ khóa khẳng định là nếu điều kiện không đúng thì nó thông qua một trình xác nhận khác, nó tiếp tục ví dụ như trong python.

mã-1

a=5

b=6

assert a==b

ĐẦU RA:

assert a==b

AssertionError

mã-2

a=5

b=5

assert a==b

ĐẦU RA:

Process finished with exit code 0

2
vui lòng định dạng mã của bạn đúng cách. Ngoài ra, làm thế nào để cải thiện câu trả lời trước đây?
c2huc2hu

Có bất kỳ vấn đề trong lời giải thích của tôi?
ujjwal_bansal

lời giải thích của bạn không thêm bất cứ điều gì vào các câu trả lời hiện có và ngữ pháp kém khiến bạn khó đọc. nếu bạn đang tìm kiếm câu hỏi để trả lời, hãy xem xét việc duyệt nguồn cấp câu hỏi mới.
c2huc2hu

Câu trả lời được cung cấp sẽ trả lời cách sử dụng một assert, nhưng không trả lời khi nào nên sử dụng (hoặc không sử dụng) một assert.
FluxIX
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.