Thực hành tốt nhất cho Python khẳng định


483
  1. Có vấn đề về hiệu năng hoặc bảo trì mã với việc sử dụng assertnhư một phần của mã tiêu chuẩn thay vì sử dụng nó chỉ cho mục đích gỡ lỗi không?

    assert x >= 0, 'x is less than zero'

    tốt hơn hoặc xấu hơn

    if x < 0:
        raise Exception, 'x is less than zero'
    
  2. Ngoài ra, có cách nào để đặt quy tắc kinh doanh như thế if x < 0 raise errorluôn luôn được kiểm tra mà không có try/except/finally, nếu bất cứ lúc nào trong suốt mã xcó ít hơn 0, sẽ xảy ra lỗi, như khi bạn đặt assert x < 0ở đầu hàm, bất cứ nơi nào trong hàm Trường hợp xtrở thành ít hơn 0 thì một ngoại lệ được nêu ra?



29
Tham số -O và -OO python sẽ loại bỏ các xác nhận của bạn. Điều đó sẽ thúc đẩy suy nghĩ của bạn về những gì nó tốt cho.
Peter Lada

4
Liên kết của Thomasz Zielinski đã bị hỏng, giờ là: mail.python.org/pipermail/python-list/2013-November/660568.html . Tôi khá chắc chắn rằng pipermail có chức năng ID không ổn định, tôi đã tìm thấy các liên kết khác từ bên trong cùng một pipermail trỏ đến cùng một url với cùng một ý định.
quodlibetor

3
Trong trường hợp mail.python.org/pipermail/python-list/2013-November/660568.html di chuyển lại, nó được lưu trữ tại archive.is/5GfiG . Tiêu đề của bài viết là "Khi nào nên sử dụng khẳng định" và là một bài viết xuất sắc (một bài viết thực sự) về các thực tiễn tốt nhất cho Python assert.
clacke

Câu trả lời:


144

Để có thể tự động đưa ra một lỗi khi x trở thành nhỏ hơn 0 trong suốt hàm. Bạn có thể sử dụng mô tả lớp . Đây là một ví dụ:

class LessThanZeroException(Exception):
    pass

class variable(object):
    def __init__(self, value=0):
        self.__x = value

    def __set__(self, obj, value):
        if value < 0:
            raise LessThanZeroException('x is less than zero')

        self.__x  = value

    def __get__(self, obj, objType):
        return self.__x

class MyClass(object):
    x = variable()

>>> m = MyClass()
>>> m.x = 10
>>> m.x -= 20
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "my.py", line 7, in __set__
    raise LessThanZeroException('x is less than zero')
LessThanZeroException: x is less than zero

10
Mặc dù các thuộc tính được triển khai như mô tả, tôi sẽ không gọi đây là một ví dụ về việc sử dụng chúng. Đây là một ví dụ về các thuộc tính trong và của chính chúng: docs.python.org/l Library / fiances.html #property
Jason Baker

3
Các thuộc tính nên được sử dụng trong MyClass khi cài đặt x. Giải pháp này quá chung chung.

113
Câu trả lời khá hay, giống như vậy, nhưng phải KHÔNG NÊN với câu hỏi ... Chúng ta có thể đánh dấu câu trả lời của Deestan hoặc John Mee là câu trả lời hợp lệ không?
Vajk Hermecz

4
Điều này không xuất hiện để trả lời tiêu đề của câu hỏi. Ngoài ra, đây là một thay thế kém cho tính năng thuộc tính lớp của Python.
Dooms101

10
@VajkHermecz: Thật ra, nếu bạn đọc lại câu hỏi, đây là hai câu hỏi trong một. Mọi người chỉ nhìn vào tiêu đề chỉ quen thuộc với câu hỏi đầu tiên, mà câu trả lời này không trả lời. Câu trả lời này thực sự có một câu trả lời cho câu hỏi thứ hai.
ArtOfWarfare

742

Các xác nhận nên được sử dụng để kiểm tra các điều kiện không bao giờ xảy ra . Mục đích là để sụp đổ sớm trong trường hợp trạng thái chương trình bị hỏng.

Các ngoại lệ nên được sử dụng cho các lỗi có thể xảy ra và bạn hầu như luôn luôn tạo các lớp Ngoại lệ của riêng mình .


Ví dụ: nếu bạn đang viết một hàm để đọc từ tệp cấu hình thành một dictđịnh dạng không chính xác trong tệp sẽ tăng lên ConfigurationSyntaxError, trong khi bạn có thể assertbạn sẽ không quay lại None.


Trong ví dụ của bạn, nếu xlà một giá trị được đặt qua giao diện người dùng hoặc từ nguồn bên ngoài, một ngoại lệ là tốt nhất.

Nếu xchỉ được đặt bởi mã của riêng bạn trong cùng một chương trình, hãy đi với một xác nhận.


126
Đây là cách đúng để sử dụng khẳng định. Chúng không nên được sử dụng để kiểm soát dòng chương trình.
Thane Brimhall

41
1 cho đoạn cuối cùng - mặc dù bạn nên rõ ràng đề cập đến mà assertchứa một tiềm ẩn if __debug__và có thể được tối ưu hóa đi - như câu trả lời John Mee của tiểu bang
Tobias KIENZLER

3
Đọc lại câu trả lời của bạn Tôi nghĩ rằng bạn có thể không có nghĩa là các điều kiện không bao giờ xảy ra có nghĩa là một quy tắc, nhưng mục đích là để sụp đổ sớm trong trường hợp tình trạng chương trình bị hỏng thường xảy ra với điều kiện bạn không mong đợi đến bao giờ xảy ra .
Bentley4

10
khẳng định chỉ nên được sử dụng để bắt các vấn đề không được phục hồi; hầu như luôn luôn lỗi mã (không phải đầu vào xấu). khi một xác nhận được kích hoạt, điều đó có nghĩa là chương trình ở trạng thái có thể nguy hiểm để tiếp tục, vì nó có thể bắt đầu nói chuyện với mạng hoặc ghi vào đĩa. mã mạnh mẽ chuyển 'nguyên tử' từ trạng thái hợp lệ sang trạng thái hợp lệ khi đối mặt với đầu vào xấu (hoặc độc hại). mức cao nhất của mỗi luồng nên có một rào cản lỗi. các rào cản lỗi tiêu thụ đầu vào từ thế giới bên ngoài thường thất bại chỉ với một lần lặp của rào cản (while / try), rollback / log on error.
Rob

10
"Các xác nhận nên được sử dụng để kiểm tra các điều kiện không bao giờ xảy ra." Đúng. Và ý nghĩa của "nên" thứ hai là: Nếu điều này xảy ra, mã chương trình không chính xác.
Lutz Prechelt

362

Các câu lệnh "khẳng định" được loại bỏ khi quá trình biên dịch được tối ưu hóa . Vì vậy, có, có cả sự khác biệt về hiệu suất và chức năng.

Trình tạo mã hiện tại không phát ra mã cho câu lệnh khẳng định khi yêu cầu tối ưu hóa tại thời điểm biên dịch. - Tài liệu Python 2 Tài liệu Python 3 Tài liệu

Nếu bạn sử dụng assertđể triển khai chức năng ứng dụng, sau đó tối ưu hóa việc triển khai vào sản xuất, bạn sẽ bị ảnh hưởng bởi lỗi "but-it-works-in-dev".

Xem PYTHONOPTIMIZE-O -OO


26
Ồ Đó là lưu ý siêu quan trọng! Tôi đã lên kế hoạch sử dụng các xác nhận để kiểm tra một số thứ không bao giờ thất bại, thất bại sẽ chỉ ra rằng ai đó đã rất cẩn thận thao tác dữ liệu của tôi mà họ đang gửi để cố gắng truy cập vào dữ liệu mà họ không nên truy cập. Nó sẽ không hoạt động, nhưng tôi muốn nhanh chóng đóng cửa nỗ lực của họ bằng một lời khẳng định, do đó, việc tối ưu hóa trong sản xuất sẽ đánh bại mục đích. Tôi đoán tôi sẽ chỉ là raisemột Exceptionthay thế. Ồ - tôi vừa phát hiện ra một tên thích hợp SuspiciousOperation Exceptionvới các lớp con trong Django! Hoàn hảo!
ArtOfWarfare

Nhân tiện, @ArtOfWarfare nếu bạn chạy bandittrên mã của mình, nó sẽ cảnh báo bạn về điều này.
Nagev

132

Bốn mục đích của assert

Giả sử bạn làm việc trên 200.000 dòng mã với bốn đồng nghiệp Alice, Bernd, Carl và Daphne. Họ gọi mã của bạn, bạn gọi mã của họ.

Sau đó assertbốn vai trò :

  1. Thông báo cho Alice, Bernd, Carl và Daphne những gì mã của bạn mong đợi.
    Giả sử bạn có một phương thức xử lý danh sách các bộ dữ liệu và logic chương trình có thể bị phá vỡ nếu các bộ dữ liệu đó không phải là bất biến:

    def mymethod(listOfTuples):
        assert(all(type(tp)==tuple for tp in listOfTuples))

    Điều này đáng tin cậy hơn thông tin tương đương trong tài liệu và dễ bảo trì hơn nhiều.

  2. Thông báo cho máy tính những gì mã của bạn mong đợi.
    assertthực thi hành vi thích hợp từ những người gọi mã của bạn. Nếu mã của bạn gọi mã của Alices và mã của Bernd gọi cho bạn, thì nếu không assert, nếu chương trình gặp sự cố trong mã Alices, Bernd có thể cho rằng đó là lỗi của Alice, Alice điều tra và có thể cho rằng đó là lỗi của bạn, thực tế bạn sẽ điều tra và nói với Bernd rằng đó là sự thật của anh ấy. Mất rất nhiều công việc.
    Với khẳng định, bất cứ ai nhận được một cuộc gọi sai, họ sẽ nhanh chóng có thể thấy đó là lỗi của họ chứ không phải của bạn. Alice, Bernd, và tất cả các bạn đều có lợi. Tiết kiệm số lượng lớn thời gian.

  3. Thông báo cho người đọc mã của bạn (bao gồm cả chính bạn) những gì mã của bạn đã đạt được tại một số điểm.
    Giả sử bạn có một danh sách các mục và mỗi mục có thể sạch (tốt) hoặc có thể là smorsh, trale, gullup hoặc twinkled (tất cả đều không được chấp nhận). Nếu đó là smorsh thì nó phải không được chỉnh sửa; nếu đó là câu chuyện thì nó phải được cân bằng; nếu nó gullup thì nó cũng phải được theo dõi (và sau đó cũng có thể được điều chỉnh); nếu nó lấp lánh thì nó phải được lấp lánh một lần nữa trừ thứ năm. Bạn có ý tưởng: Đó là thứ phức tạp. Nhưng kết quả cuối cùng là (hoặc nên là) rằng tất cả các mục đều sạch. Điều đúng (TM) cần làm là tóm tắt ảnh hưởng của vòng lặp làm sạch của bạn như

    assert(all(entry.isClean() for entry in mylist))

    Câu nói này giúp giảm đau đầu cho mọi người đang cố gắng hiểu chính xác những gì mà vòng lặp tuyệt vời đang đạt được. Và người thường xuyên nhất trong số những người này có thể sẽ là chính bạn.

  4. Thông báo cho máy tính những gì mã của bạn đã đạt được tại một số điểm.
    Nếu bạn quên không tăng tốc một mục cần sau khi chạy nước rút, assertsẽ tiết kiệm được một ngày của bạn và tránh việc mã của bạn phá vỡ Daphne thân yêu sau đó.

Trong tâm trí của tôi, asserthai mục đích của tài liệu (1 và 3) và bảo vệ (2 và 4) đều có giá trị như nhau.
Thông báo cho mọi người thậm chí có thể nhiều giá trị hơn thông báo cho máy tính vì nó có thể ngăn chặn những sai lầm rất là assertmục tiêu để catch (trong trường hợp 1) và rất nhiều sai lầm tiếp theo trong mọi trường hợp.


34
5. khẳng định isinstance () giúp PyCharm (python IDE) biết loại biến, nó được sử dụng để tự động hoàn tất.
Cjkjvfnby

1
Xác nhận các giả định mã tài liệu cho những gì là đúng tại thời điểm thực hiện hiện tại. Đó là một nhận xét giả định, được kiểm tra.
pyj

9
Về 2 và 4: Bạn nên rất cẩn thận rằng các khẳng định của bạn không quá nghiêm ngặt. Khác các khẳng định chính họ có thể là điều duy nhất giữ cho chương trình của bạn được sử dụng trong một thiết lập chung hơn. Đặc biệt là các kiểu khẳng định đi ngược lại cách gõ vịt của trăn.
zwirbeltier

9
@Cjkjvfnby Hãy cẩn thận về việc lạm dụng isinstance () như được mô tả trong mục blog này: " isinstance () được coi là có hại ". Bây giờ bạn có thể sử dụng tài liệu để chỉ định các loại trong Pycharm.
nhị phân

2
Sử dụng khẳng định trong một cách đảm bảo hợp đồng. Thông tin thêm về Thiết kế theo Hợp đồng en.wikipedia.org/wiki/Design_by_contract
Leszek Zarna

22

Ngoài các câu trả lời khác, khẳng định bản thân ném ngoại lệ, nhưng chỉ Ass AssErrors. Từ quan điểm thực dụng, các xác nhận không phù hợp khi bạn cần kiểm soát hạt tốt đối với những trường hợp ngoại lệ mà bạn nắm bắt.


3
Đúng. Nó có vẻ ngớ ngẩn khi bắt ngoại lệ xác nhận lỗi trong người gọi.
Raffi Khatchadourian

Điểm rất tốt. Một sắc thái có thể dễ dàng bị bỏ qua khi chỉ nhìn vào các câu hỏi ban đầu từ cấp độ vĩ mô. Ngay cả khi không có vấn đề với các xác nhận bị loại bỏ khi tối ưu hóa, việc mất các chi tiết cụ thể về loại lỗi xảy ra sẽ khiến việc gỡ lỗi trở nên khó khăn hơn nhiều. Chúc mừng, outis!
cfwschmidt

Câu trả lời của bạn có thể được đọc như thể bạn có thể muốn nắm bắt AssertionErrors, khi bạn đồng ý với nó là chi tiết thô. Trong thực tế, bạn không nên bắt chúng.
Tomasz Gandor

19

Điều duy nhất thực sự sai với cách tiếp cận này là thật khó để tạo ra một ngoại lệ rất mô tả bằng cách sử dụng các tuyên bố khẳng định. Nếu bạn đang tìm kiếm cú pháp đơn giản hơn, hãy nhớ rằng bạn cũng có thể làm một cái gì đó như thế này:

class XLessThanZeroException(Exception):
    pass

def CheckX(x):
    if x < 0:
        raise XLessThanZeroException()

def foo(x):
    CheckX(x)
    #do stuff here

Một vấn đề khác là việc sử dụng assert để kiểm tra điều kiện thông thường là nó gây khó khăn cho việc vô hiệu hóa các xác nhận gỡ lỗi bằng cách sử dụng cờ -O.


24
Bạn có thể nối một thông báo lỗi vào một xác nhận. Đây là tham số thứ hai. Điều đó sẽ làm cho nó mô tả.
Raffi Khatchadourian

10

Từ tiếng Anh khẳng định ở đây được sử dụng theo nghĩa chửi thề , khẳng định , chấp nhận . Nó không có nghĩa là "kiểm tra" hoặc "nên được" . Điều đó có nghĩa là bạn với tư cách là một lập trình viên đang tuyên bố tuyên thệ ở đây:

# I solemnly swear that here I will tell the truth, the whole truth, 
# and nothing but the truth, under pains and penalties of perjury, so help me FSM
assert answer == 42

Nếu mã là chính xác, việc chặn các sự kiện đơn lẻ , lỗi phần cứng và như vậy, sẽ không có xác nhận nào bị lỗi . Đó là lý do tại sao hành vi của chương trình cho người dùng cuối không bị ảnh hưởng. Đặc biệt, một khẳng định không thể thất bại ngay cả trong các điều kiện lập trình đặc biệt . Nó không bao giờ xảy ra. Nếu nó xảy ra, lập trình viên nên được kích hoạt cho nó.


8

Như đã nói trước đây, các xác nhận nên được sử dụng khi mã của bạn KHÔNG NÊN đạt đến một điểm, có nghĩa là có lỗi ở đó. Có lẽ lý do hữu ích nhất mà tôi có thể thấy để sử dụng một khẳng định là bất biến / pre / postcondition. Đây là một cái gì đó phải đúng ở đầu hoặc cuối của mỗi lần lặp của một vòng lặp hoặc một hàm.

Ví dụ: một hàm đệ quy (2 hàm riêng biệt để 1 xử lý đầu vào xấu và hàm kia xử lý mã xấu, khiến nó khó phân biệt với đệ quy). Điều này sẽ trở nên rõ ràng nếu tôi quên viết câu lệnh if, điều gì đã sai.

def SumToN(n):
    if n <= 0:
        raise ValueError, "N must be greater than or equal to 0"
    else:
        return RecursiveSum(n)

def RecursiveSum(n):
    #precondition: n >= 0
    assert(n >= 0)
    if n == 0:
        return 0
    return RecursiveSum(n - 1) + n
    #postcondition: returned sum of 1 to n

Những bất biến vòng lặp này thường có thể được biểu diễn bằng một xác nhận.


2
Điều này được thực hiện tốt nhất với các nhà trang trí (@precondition và @postcondition)
Caridorc 19/07/2015

@Caridorc lợi ích cụ thể của việc đó là gì?
Chiel ten Brinke

@ChieltenBrinke tự viết mã, thay vì #precondition: n >= 0 và một lời khẳng định, anh ta chỉ có thể viết@precondition(lambda n: n >= 0)
Caridorc

@Caridorc Là những người trang trí dựng sẵn sau đó? Và làm thế nào để tạo ra tài liệu từ đó?
Chiel ten Brinke

@ChieltenBrinke không tích hợp sẵn nhưng dễ thực hiện stackoverflow.com/questions/12151182/ . Đối với tài liệu, chỉ cần vá __doc__thuộc tính bằng cách cung cấp một chuỗi bổ sung
Caridorc 6/2/2016

4

một vấn đề hiệu suất?

  • Hãy nhớ "làm cho nó hoạt động trước khi bạn làm cho nó hoạt động nhanh" .
    Rất ít phần trăm của bất kỳ chương trình nào thường có liên quan đến tốc độ của nó. Bạn luôn có thể loại bỏ hoặc đơn giản hóa assertnếu nó từng là một vấn đề về hiệu suất - và hầu hết trong số họ sẽ không bao giờ như vậy.

  • Hãy thực dụng :
    Giả sử bạn có một phương thức xử lý một danh sách các bộ dữ liệu không trống và logic chương trình sẽ bị phá vỡ nếu các bộ dữ liệu đó không phải là bất biến. Bạn nên viết:

    def mymethod(listOfTuples):
        assert(all(type(tp)==tuple for tp in listOfTuples))

    Điều này có thể tốt nếu danh sách của bạn có xu hướng dài mười mục, nhưng nó có thể trở thành vấn đề nếu chúng có một triệu mục. Nhưng thay vì loại bỏ hoàn toàn tấm séc có giá trị này, bạn chỉ có thể hạ cấp nó xuống

    def mymethod(listOfTuples):
        assert(type(listOfTuples[0])==tuple)  # in fact _all_ must be tuples!

    giá rẻ nhưng có khả năng sẽ bắt hầu hết các lỗi chương trình thực tế .


2
Nên assert(len(listOfTuples)==0 or type(listOfTyples[0])==tuple).
osa

Không, nó không nên. Đó sẽ là một thử nghiệm yếu hơn nhiều, bởi vì nó không còn kiểm tra thuộc tính 'không trống' mà thứ hai khẳng định sẽ kiểm tra. (Đầu tiên thì không, mặc dù vậy.)
Lutz Prechelt

1
Khẳng định thứ hai không kiểm tra rõ ràng thuộc tính không trống; đó là một tác dụng phụ. Nếu nó đưa ra một ngoại lệ do danh sách trống, người làm việc với mã (ai đó hoặc tác giả, một năm sau khi viết nó) sẽ nhìn chằm chằm vào nó, cố gắng tìm hiểu xem liệu khẳng định đó có thực sự bắt được không tình huống danh sách trống hoặc nếu đó là một lỗi trong chính nó. Hơn nữa, tôi không thấy cách không kiểm tra trường hợp trống là "yếu hơn nhiều", trong khi chỉ kiểm tra phần tử đầu tiên là "đúng 97%".
osa

3

Vâng, đây là một câu hỏi mở và tôi có hai khía cạnh mà tôi muốn chạm vào: khi nào cần thêm các xác nhận và cách viết thông báo lỗi.

Mục đích

Để giải thích cho người mới bắt đầu - các xác nhận là các câu có thể gây ra lỗi, nhưng bạn sẽ không bắt được chúng. Và chúng thường không nên được nuôi dưỡng, nhưng trong cuộc sống thực, đôi khi chúng vẫn được nuôi dưỡng. Và đây là một tình huống nghiêm trọng, mà mã không thể phục hồi, cái mà chúng ta gọi là "lỗi nghiêm trọng".

Tiếp theo, đó là 'mục đích gỡ lỗi', trong khi, chính xác, nghe có vẻ rất phản cảm. Tôi thích 'công thức bất biến, không bao giờ bị vi phạm' công thức tốt hơn, mặc dù nó hoạt động khác nhau trên những người mới bắt đầu khác nhau ... hoặc thậm chí kiểm soát dòng chảy với nó.

Phong cách

Trong Python, assertlà một câu lệnh, không phải là một hàm! (hãy nhớ rằng assert(False, 'is true')sẽ không tăng. Nhưng, có cách đó:

Khi nào và bằng cách nào, để viết 'thông báo lỗi' tùy chọn?

Điều này áp dụng triệt để cho các khung kiểm tra đơn vị, thường có nhiều phương thức chuyên dụng để thực hiện các xác nhận ( assertTrue(condition),assertFalse(condition), assertEqual(actual, expected) v.v.). Họ cũng thường cung cấp một cách để bình luận về khẳng định.

Trong mã vứt đi bạn có thể làm mà không cần thông báo lỗi.

Trong một số trường hợp, không có gì để thêm vào xác nhận:

def dump (cái gì đó): khẳng định isinstance (cái gì đó, Dumpable) # ...

Nhưng ngoài ra, một thông báo rất hữu ích để liên lạc với các lập trình viên khác (đôi khi là những người dùng tương tác mã của bạn, ví dụ như trong Ipython / Jupyter, v.v.).

Cung cấp cho họ thông tin, không chỉ rò rỉ chi tiết thực hiện nội bộ.

thay vì:

assert meaningless_identifier <= MAGIC_NUMBER_XXX, 'meaningless_identifier is greater than MAGIC_NUMBER_XXX!!!'

viết:

assert meaningless_identifier > MAGIC_NUMBER_XXX, 'reactor temperature above critical threshold'

hoặc thậm chí có thể:

assert meaningless_identifier > MAGIC_NUMBER_XXX, f'reactor temperature({meaningless_identifier }) above critical threshold ({MAGIC_NUMBER_XXX})'

Tôi biết, tôi biết - đây không phải là một trường hợp cho một xác nhận tĩnh, nhưng tôi muốn chỉ ra giá trị thông tin của tin nhắn.

Thông điệp tiêu cực hay tích cực?

Điều này có thể gây tranh cãi, nhưng nó làm tôi đau khi đọc những thứ như:

assert a == b, 'a is not equal to b'
  • đây là hai điều trái ngược nhau được viết bên cạnh nhau. Vì vậy, bất cứ khi nào tôi có ảnh hưởng đến codebase, tôi cố gắng chỉ định những gì chúng ta muốn, bằng cách sử dụng các động từ bổ sung như 'phải' và 'nên', và không nói những gì chúng ta không muốn.

    khẳng định a == b, 'a phải bằng b'

Sau đó, nhận AssertionError: a must be equal to bđược cũng có thể đọc được và câu lệnh có vẻ hợp lý trong mã. Ngoài ra, bạn có thể lấy một cái gì đó từ nó mà không cần đọc dấu vết (đôi khi thậm chí không có sẵn).


1

Cả việc sử dụng assertvà nâng cao các ngoại lệ là về giao tiếp.

  • Các xác nhận là các tuyên bố về tính chính xác của mã được giải quyết tại các nhà phát triển : Một xác nhận trong mã thông báo cho người đọc mã về các điều kiện phải được đáp ứng cho mã là chính xác. Một xác nhận không thành công trong thời gian chạy thông báo cho các nhà phát triển rằng có một lỗi trong mã cần sửa.

  • Các ngoại lệ là các dấu hiệu về các tình huống không điển hình có thể xảy ra trong thời gian chạy nhưng không thể giải quyết bằng mã trong tay, được xử lý tại mã gọi để xử lý tại đó. Sự xuất hiện của một ngoại lệ không chỉ ra rằng có một lỗi trong mã.

Thực hành tốt nhất

Do đó, nếu bạn coi sự xuất hiện của một tình huống cụ thể trong thời gian chạy là một lỗi mà bạn muốn thông báo cho các nhà phát triển về ("Xin chào nhà phát triển, tình trạng này cho thấy có lỗi ở đâu đó, vui lòng sửa mã.") đi cho một khẳng định. Nếu xác nhận kiểm tra các đối số đầu vào của mã của bạn, thông thường bạn nên thêm vào tài liệu rằng mã của bạn có "hành vi không xác định" khi các đối số đầu vào vi phạm các điều kiện đó.

Nếu thay vào đó, sự xuất hiện của chính tình huống đó không phải là dấu hiệu của lỗi trong mắt bạn, mà thay vào đó là một tình huống có thể (có thể hiếm gặp nhưng) mà bạn nghĩ nên xử lý bằng mã máy khách, hãy đưa ra một ngoại lệ. Các tình huống khi ngoại lệ được nêu ra phải là một phần của tài liệu về mã tương ứng.

Có vấn đề về hiệu suất [...] khi sử dụng không assert

Việc đánh giá các xác nhận mất một thời gian. Chúng có thể được loại bỏ tại thời gian biên dịch, mặc dù. Điều này có một số hậu quả, tuy nhiên, xem bên dưới.

Có vấn đề bảo trì mã [...] khi sử dụng không assert

Thông thường các xác nhận cải thiện khả năng duy trì của mã, vì chúng cải thiện khả năng đọc bằng cách làm cho các giả định rõ ràng và trong thời gian chạy thường xuyên xác minh các giả định này. Điều này cũng sẽ giúp bắt hồi quy. Tuy nhiên, có một vấn đề cần được ghi nhớ: Biểu thức được sử dụng trong các xác nhận sẽ không có tác dụng phụ. Như đã đề cập ở trên, các xác nhận có thể được loại bỏ tại thời điểm biên dịch - điều đó có nghĩa là các tác dụng phụ tiềm ẩn cũng sẽ biến mất. Điều này có thể - vô tình - thay đổi hành vi của mã.


1

Một khẳng định là để kiểm tra -
1. điều kiện hợp lệ,
2. tuyên bố hợp lệ,
3. logic thực sự;
mã nguồn. Thay vì thất bại toàn bộ dự án, nó đưa ra một báo động rằng có gì đó không phù hợp trong tệp nguồn của bạn.

Trong ví dụ 1, vì biến 'str' không phải là null. Vì vậy, không có bất kỳ khẳng định hoặc ngoại lệ được nêu ra.

Ví dụ 1:

#!/usr/bin/python

str = 'hello Python!'
strNull = 'string is Null'

if __debug__:
    if not str: raise AssertionError(strNull)
print str

if __debug__:
    print 'FileName '.ljust(30,'.'),(__name__)
    print 'FilePath '.ljust(30,'.'),(__file__)


------------------------------------------------------

Output:
hello Python!
FileName ..................... hello
FilePath ..................... C:/Python\hello.py

Trong ví dụ 2, var 'str' là null. Vì vậy, chúng tôi đang cứu người dùng khỏi việc đi trước chương trình bị lỗi bằng tuyên bố khẳng định .

Ví dụ 2:

#!/usr/bin/python

str = ''
strNull = 'NULL String'

if __debug__:
    if not str: raise AssertionError(strNull)
print str

if __debug__:
    print 'FileName '.ljust(30,'.'),(__name__)
    print 'FilePath '.ljust(30,'.'),(__file__)


------------------------------------------------------

Output:
AssertionError: NULL String

Khoảnh khắc chúng ta không muốn gỡ lỗi và nhận ra vấn đề khẳng định trong mã nguồn. Vô hiệu hóa cờ tối ưu hóa

python -O assertStatement.py
sẽ không có gì được in


0

Trong các IDE như PTVS, PyCharm, các assert isinstance()câu lệnh Cánh có thể được sử dụng để cho phép hoàn thành mã cho một số đối tượng không rõ ràng.


Điều này dường như có trước việc sử dụng các chú thích loại hoặc của typing.cast.
Acumenus

-1

Đối với giá trị của nó, nếu bạn đang xử lý mã dựa trên assertchức năng chính xác, thì việc thêm mã sau đây sẽ đảm bảo rằng các xác nhận được bật:

try:
    assert False
    raise Exception('Python assertions are not working. This tool relies on Python assertions to do its job. Possible causes are running with the "-O" flag or running a precompiled (".pyo" or ".pyc") module.')
except AssertionError:
    pass

2
Điều này không trả lời câu hỏi của OP về thực tiễn tốt nhất.
codeforester
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.