Chúng ta có thể trả về một ngoại lệ từ một hàm trong python không?
Tăng một ngoại lệLà nhà phát triển Python, bạn có thể chọn ném ngoại lệ nếu có điều kiện xảy ra Show Để ném (hoặc tăng) một ngoại lệ, hãy sử dụng từ khóa data EmailVerificationResult = EmailVerified string | VerifyFailed | VerifyExpired string9 Ví dụBáo lỗi và dừng chương trình nếu x nhỏ hơn 0 x = -1 nếu x < 0. Từ khóa data EmailVerificationResult = EmailVerified string | VerifyFailed | VerifyExpired string9 được sử dụng để đưa ra một ngoại lệ Bạn có thể xác định loại lỗi nào sẽ gây ra và văn bản sẽ in cho người dùng Ví dụTăng TypeError nếu x không phải là số nguyên x = "xin chào" nếu không gõ(x) là int. Một ngày nọ, tôi nhận được một câu hỏi về một số mã cũ mà tôi đã viết, thay vì đưa ra một ngoại lệ cho một điều kiện lỗi như người đọc mong đợi, lại trả về một đối tượng lỗi
Mã được đề cập bên dưới (được sửa đổi một chút và loại bỏ một số phương thức không thú vị). Nó là một phần của hệ thống thực hiện xác minh địa chỉ email thông qua các liên kết ma thuật trong email from dataclasses import dataclass class VerifyFailed: pass VerifyFailed = VerifyFailed() # singleton sentinel value @dataclass class VerifyExpired: email: str class EmailVerifyTokenGenerator: def token_for_email(self, email): ... def email_from_token(self, token): """ Extracts the verified email address from the token, or a VerifyFailed constant if verification failed, or VerifyExpired if the link expired. """ max_age = settings.EMAIL_VERIFY_TIMEOUT try: unencoded_token = self.url_safe_decode(token) except (UnicodeDecodeError, binascii.Error): return VerifyFailed try: return self.signer.unsign(unencoded_token, max_age=max_age) except (SignatureExpired,): return VerifyExpired(self.signer.unsign(unencoded_token)) except (BadSignature,): return VerifyFailed Tóm lại, chúng tôi có một chức năng trích xuất địa chỉ email từ mã thông báo, kiểm tra chữ ký HMAC đi kèm với nó. Có 3 khả năng chúng tôi muốn giải quyết
Nó đang sử dụng các chức năng của người ký của Django để thực hiện công việc nặng nhọc, nhưng điều đó không quan trọng đối với mục đích của chúng tôi, bởi vì chúng tôi đang hoàn thiện nó Để tiếp tục thiết kế API của chúng tôi cho đoạn mã này, đây là một số tùy chọn không hợp lệ
Sau khi loại trừ những điều đó, chúng ta có hai ứng cử viên chính về cách thiết kế data EmailVerificationResult = EmailVerified string | VerifyFailed | VerifyExpired string1
Cả hai điều này đều thỏa mãn tiêu chí “hố thành công”. Nếu nhà phát triển vô tình không xử lý các trường hợp lỗi, họ sẽ không gặp lỗi khi chúng tôi xác minh địa chỉ email không được xác minh. Thay vào đó, chúng tôi có thể sẽ có một loại trình gỡ lỗi nào đó, trong trường hợp ứng dụng web, như ứng dụng này, có nghĩa là trang lỗi 500 đang được nhìn thấy và nội dung nào đó trong nhật ký của chúng tôi cho thấy khá rõ ràng điều gì đã xảy ra Nếu chúng ta chọn tăng ngoại lệ, mã ngây thơ không kiểm tra ngoại lệ sẽ đơn giản là không tiến xa hơn - ngoại lệ sẽ lan rộng và chấm dứt trình xử lý. Với tùy chọn thứ hai nơi chúng tôi trả về các đối tượng lỗi, những đối tượng đó không thể vô tình được chuyển đổi thành giá trị thành công — đối tượng data EmailVerificationResult = EmailVerified string | VerifyFailed | VerifyExpired string5 chứa địa chỉ email, nhưng nó có dạng giá trị hoàn toàn khác với trường hợp hạnh phúc Ở một mức độ nào đó, cả hai cách tiếp cận này đều tôn trọng nguyên tắc có thể được tóm tắt là Parse Don't Validate. Thay vì chỉ xác thực mã thông báo và trích xuất địa chỉ email dưới dạng hai thứ độc lập, chúng tôi đang phân tích cú pháp mã thông báo và mã hóa kết quả xác thực theo loại đối tượng mà sau đó sẽ chuyển qua chương trình Nhưng cái nào tốt hơn? Một trong những ảnh hưởng đến suy nghĩ của tôi là cách thức hoạt động của các kiểu trong Haskell và ngôn ngữ tương tự khác giúp dễ dàng tạo các kiểu và hàm tạo. Trong Haskell, sau đây là tất cả mã bạn cần để xác định kiểu trả về cho loại hàm này và 3 hàm tạo dữ liệu khác nhau mà bạn cần, sau đó thực hiện nhiệm vụ kép để khớp mẫu data EmailVerificationResult = EmailVerified string | VerifyFailed | VerifyExpired string Bây giờ, Python gần như không ngắn gọn như vậy, nhưng các lớp dữ liệu là một cải tiến lớn để xác định những thứ như data EmailVerificationResult = EmailVerified string | VerifyFailed | VerifyExpired string5 Trong Haskell, do kiểm tra kiểu tĩnh, mẫu này khiến mã gọi không thể vô tình xử lý giá trị trả về một cách chính xác. Nhưng ngay cả trong Python, thứ không được tích hợp sẵn, tôi nghĩ vẫn có một số lợi thế hấp dẫn
Tuy nhiên, trong những năm kể từ khi tôi viết mã, một số lập luận có lẽ thuyết phục hơn đã xuất hiện cho phương thức đối tượng lỗi Đầu tiên, với một số thay đổi nhỏ (cụ thể là loại bỏ giá trị sentinel singleton), giờ đây chúng ta có thể thêm chữ ký loại cho data EmailVerificationResult = EmailVerified string | VerifyFailed | VerifyExpired string8 data EmailVerificationResult = EmailVerified string | VerifyFailed | VerifyExpired string1 (Bạn có thể cần cho các phiên bản Python cũ hơn) Bản thân đây là một lợi ích từ quan điểm tài liệu và để được trợ giúp IDE/trình soạn thảo tốt hơn Chúng ta có thể tiến xa hơn với mypy. Chúng tôi có thể cấu trúc mã cuộc gọi của mình như sau để sử dụng kiểm tra tính toàn diện của mypy data EmailVerificationResult = EmailVerified string | VerifyFailed | VerifyExpired string2 Bây giờ, nếu chúng tôi xóa một trong các khối này, giả sử khối data EmailVerificationResult = EmailVerified string | VerifyFailed | VerifyExpired string5 (hoặc nếu chúng tôi đã thêm một tùy chọn khác vào data EmailVerificationResult = EmailVerified string | VerifyFailed | VerifyExpired string8), mypy sẽ bắt khối đó cho chúng tôi data EmailVerificationResult = EmailVerified string | VerifyFailed | VerifyExpired string5 Với phương thức đối tượng lỗi, chúng ta cũng có thể viết mã xử lý của mình bằng cách khớp mẫu cấu trúc. Mã tương đương, bao gồm kiểm tra toàn diện mypy của chúng tôi, bây giờ trông như thế này data EmailVerificationResult = EmailVerified string | VerifyFailed | VerifyExpired string6 Điều này đã phá hủy địa chỉ email trong data EmailVerificationResult = EmailVerified string | VerifyFailed | VerifyExpired string5 được tích hợp sẵn — nó bị ràng buộc với tên verify_result = verifier.email_from_token(token) log_verify_result(request.ip_address, verify_result) # etc.2 trong nhánh đó Hy vọng rằng điều này mang lại sự biện minh tốt cho cách tiếp cận mà tôi đã thực hiện với mã này. Đôi khi các ngoại lệ tốt hơn - thường là khi những điều được đề cập ở trên không áp dụng hoặc áp dụng ngược lại - nhưng tôi nghĩ các đối tượng lỗi cũng có vị trí của chúng và đôi khi là một giải pháp tốt hơn nhiều Bạn có thể trả lại ngoại lệ trong Python không?Lưu ý rằng khi bạn trả về một đối tượng thuộc lớp Ngoại lệ, bạn sẽ nhận được một đại diện cho giá trị được liên kết của nó, thường là mục đầu tiên trong danh sách các đối số của nó. In the example above, this is the string explanation of the exception. In some cases, it may be a tuple with other information about the exception.
Bạn có thể in một Python ngoại lệ không?Nếu bạn định in ngoại lệ, tốt hơn nên sử dụng print(repr(e)) ; ngoại lệ cơ sở. Việc triển khai __str__ chỉ trả về thông báo ngoại lệ, không phải loại. Hoặc, sử dụng mô-đun theo dõi, có các phương pháp để in ngoại lệ hiện tại, được định dạng hoặc truy nguyên đầy đủ.
Hàm có thể trả về bằng Python không?Hàm trả về một hàm khác trong Python
. Đối tượng hạng nhất là một đối tượng có thể được gán cho một biến, được truyền dưới dạng đối số cho hàm hoặc được sử dụng làm giá trị trả về trong hàm. we can return a function from another function. A first-class object is an object that can be assigned to a variable, passed as an argument to a function, or used as a return value in a function.
3 loại ngoại lệ chính trong Python là gì?Có ba loại lỗi chính có thể phân biệt được trong Python. lỗi cú pháp, ngoại lệ và lỗi logic . |