Đây là phiên bản cập nhật cho Python 3.6+
import inspect
def dump_args[func]:
"""
Decorator to print function call details.
This includes parameters names and effective values.
"""
def wrapper[*args, **kwargs]:
func_args = inspect.signature[func].bind[*args, **kwargs].arguments
func_args_str = ", ".join[map["{0[0]} = {0[1]!r}".format, func_args.items[]]]
print[f"{func.__module__}.{func.__qualname__} [ {func_args_str} ]"]
return func[*args, **kwargs]
return wrapper
@dump_args
def test[a, b=4, c="blah-blah", *args, **kwargs]:
pass
test[1]
test[1, 3]
test[1, d=5]
test[1, 2, 3, 4, 5, d=6, g=12.9]
Phiên bản cũ
Phiên bản làm việc với các giá trị mặc định:
def dumpArgs[func]:
'''Decorator to print function call details - parameters names and effective values'''
def wrapper[*func_args, **func_kwargs]:
arg_names = func.func_code.co_varnames[:func.func_code.co_argcount]
args = func_args[:len[arg_names]]
defaults = func.func_defaults or []
args = args + defaults[len[defaults] - [func.func_code.co_argcount - len[args]]:]
params = zip[arg_names, args]
args = func_args[len[arg_names]:]
if args: params.append[['args', args]]
if func_kwargs: params.append[['kwargs', func_kwargs]]
print func.func_name + ' [' + ', '.join['%s = %r' % p for p in params] + ' ]'
return func[*func_args, **func_kwargs]
return wrapper
@dumpArgs
def test[a, b = 4, c = 'blah-blah', *args, **kwargs]:
pass
test[1]
test[1, 3]
test[1, d = 5]
test[1, 2, 3, 4, 5, d = 6, g = 12.9]
Result:
>>> test [ a = 1, b = 4, c = 'blah-blah' ]
test [ a = 1, b = 3, c = 'blah-blah' ]
test [ a = 1, b = 4, c = 'blah-blah', kwargs = {'d': 5} ]
test [ a = 1, b = 2, c = 3, args = [4, 5], kwargs = {'d': 6, 'g': 12.9} ]
Bất kỳ ứng dụng sản xuất nào có thể sẽ có một số hướng dẫn về cách thức và những gì cần phải đăng nhập vào ứng dụng của bạn. Thông thường, các hướng dẫn này xuất phát từ các mô hình công nghiệp chung như nhật ký của tất cả các ngoại lệ. Tuy nhiên, việc thực hiện các hướng dẫn này được để lại cho các nhà phát triển riêng lẻ và dẫn đến cùng một bộ báo cáo ghi nhật ký được lặp lại trong suốt cơ sở mã. Ví dụ, để ghi nhật ký tất cả các trường hợp ngoại lệ, bạn sẽ có một câu lệnh ghi nhật ký trong mỗi khối
def dumpArgs[func]:
'''Decorator to print function call details - parameters names and effective values'''
def wrapper[*func_args, **func_kwargs]:
arg_names = func.func_code.co_varnames[:func.func_code.co_argcount]
args = func_args[:len[arg_names]]
defaults = func.func_defaults or []
args = args + defaults[len[defaults] - [func.func_code.co_argcount - len[args]]:]
params = zip[arg_names, args]
args = func_args[len[arg_names]:]
if args: params.append[['args', args]]
if func_kwargs: params.append[['kwargs', func_kwargs]]
print func.func_name + ' [' + ', '.join['%s = %r' % p for p in params] + ' ]'
return func[*func_args, **func_kwargs]
return wrapper
@dumpArgs
def test[a, b = 4, c = 'blah-blah', *args, **kwargs]:
pass
test[1]
test[1, 3]
test[1, d = 5]
test[1, 2, 3, 4, 5, d = 6, g = 12.9]
9 nắm bắt ngoại lệ và ghi nhật ký theo cấp độ >>> test [ a = 1, b = 4, c = 'blah-blah' ]
test [ a = 1, b = 3, c = 'blah-blah' ]
test [ a = 1, b = 4, c = 'blah-blah', kwargs = {'d': 5} ]
test [ a = 1, b = 2, c = 3, args = [4, 5], kwargs = {'d': 6, 'g': 12.9} ]
0. Nhưng tuyên bố ghi nhật ký cho cùng một kịch bản có thể khác nhau giữa các nhà phát triển do phong cách phát triển cá nhân của họ. Làm thêm giờ Điều này dẫn đến việc đăng nhập phân mảnh và không nhất quán trong ứng dụng. Hơn nữa, các nhà phát triển có thể phạm sai lầm và bỏ lỡ tuyên bố đăng nhập tại những nơi cần thiết.Một cách tiếp cận để giảm bớt vấn đề này là bằng cách sử dụng tính năng trang trí Python. Bài viết này sẽ cung cấp một cái nhìn tổng quan ngắn gọn về các nhà trang trí và trình diễn cách tạo ra một nhà trang trí để trừu tượng các tuyên bố khai thác gỗ phổ biến này. Bạn có thể đọc thêm về trang trí và nhiều cách mà chúng có thể được sử dụng trong mồi tuyệt vời này trên trang trí Python.
Người trang trí là gì
Một người trang trí là một chức năng có một chức năng khác và mở rộng hành vi của nó mà không cần sửa đổi rõ ràng nó. Chúng còn được gọi là chức năng bậc cao.
Các chức năng của Python là những công dân hạng nhất. Điều này có nghĩa là các chức năng có thể được thông qua như đối số hoặc có thể là chủ đề của nhiệm vụ. Vì vậy, nếu bạn có chức năng
>>> test [ a = 1, b = 4, c = 'blah-blah' ]
test [ a = 1, b = 3, c = 'blah-blah' ]
test [ a = 1, b = 4, c = 'blah-blah', kwargs = {'d': 5} ]
test [ a = 1, b = 2, c = 3, args = [4, 5], kwargs = {'d': 6, 'g': 12.9} ]
1, bạn có thể sử dụng nó như bất kỳ đối tượng nào khác và đi sâu vào các thuộc tính của nó.def sum[a, b=10]:
return a+b
>>> sum
>>> sum.__code__.co_varnames # Names of local variables
['a', 'b']
Vì các chức năng hoạt động như một đối tượng, bạn có thể gán
>>> test [ a = 1, b = 4, c = 'blah-blah' ]
test [ a = 1, b = 3, c = 'blah-blah' ]
test [ a = 1, b = 4, c = 'blah-blah', kwargs = {'d': 5} ]
test [ a = 1, b = 2, c = 3, args = [4, 5], kwargs = {'d': 6, 'g': 12.9} ]
2 cho một hàm khác. Sau đó, gọi >>> test [ a = 1, b = 4, c = 'blah-blah' ]
test [ a = 1, b = 3, c = 'blah-blah' ]
test [ a = 1, b = 4, c = 'blah-blah', kwargs = {'d': 5} ]
test [ a = 1, b = 2, c = 3, args = [4, 5], kwargs = {'d': 6, 'g': 12.9} ]
2 sẽ gọi chức năng này thay vì cái mà chúng tôi đã xác định trước đó. Các trình trang trí sử dụng hành vi này bằng cách gán >>> test [ a = 1, b = 4, c = 'blah-blah' ]
test [ a = 1, b = 3, c = 'blah-blah' ]
test [ a = 1, b = 4, c = 'blah-blah', kwargs = {'d': 5} ]
test [ a = 1, b = 2, c = 3, args = [4, 5], kwargs = {'d': 6, 'g': 12.9} ]
2 một hàm mới lấy >>> test [ a = 1, b = 4, c = 'blah-blah' ]
test [ a = 1, b = 3, c = 'blah-blah' ]
test [ a = 1, b = 4, c = 'blah-blah', kwargs = {'d': 5} ]
test [ a = 1, b = 2, c = 3, args = [4, 5], kwargs = {'d': 6, 'g': 12.9} ]
2 làm tham số và kết thúc một số logic bổ sung xung quanh nó do đó mở rộng nó mà không cần sửa đổi chức năng.def my_decorator[func]:
def wrapper[*args, **kwargs]:
# do something before `sum`
result = func[*args, **kwargs]
# do something after `sum`
return result
return wrapper
sum = my_decorator[sum]
>>> sum
Mô hình này phổ biến đến mức Python có đường cú pháp để trang trí một chức năng. Vì vậy, thay vì
>>> test [ a = 1, b = 4, c = 'blah-blah' ]
test [ a = 1, b = 3, c = 'blah-blah' ]
test [ a = 1, b = 4, c = 'blah-blah', kwargs = {'d': 5} ]
test [ a = 1, b = 2, c = 3, args = [4, 5], kwargs = {'d': 6, 'g': 12.9} ]
6, chúng ta có thể sử dụng ký hiệu >>> test [ a = 1, b = 4, c = 'blah-blah' ]
test [ a = 1, b = 3, c = 'blah-blah' ]
test [ a = 1, b = 4, c = 'blah-blah', kwargs = {'d': 5} ]
test [ a = 1, b = 2, c = 3, args = [4, 5], kwargs = {'d': 6, 'g': 12.9} ]
7 trên đầu phương thức >>> test [ a = 1, b = 4, c = 'blah-blah' ]
test [ a = 1, b = 3, c = 'blah-blah' ]
test [ a = 1, b = 4, c = 'blah-blah', kwargs = {'d': 5} ]
test [ a = 1, b = 2, c = 3, args = [4, 5], kwargs = {'d': 6, 'g': 12.9} ]
2 như thế này -@my_decorator # Equivalent to `sum = my_decorator[sum]` after the method
def sum[a, b=10]:
return a+b
Ghi nhật ký trang trí
Chúng tôi sẽ tạo ra một trình trang trí xử lý hai kịch bản ghi nhật ký phổ biến - các ngoại lệ ghi nhật ký là đối số phương thức lỗi và ghi nhật ký dưới dạng nhật ký gỡ lỗi.
Hãy bắt đầu bằng cách nắm bắt các ngoại lệ và đăng nhập nó bằng thư viện Python
>>> test [ a = 1, b = 4, c = 'blah-blah' ]
test [ a = 1, b = 3, c = 'blah-blah' ]
test [ a = 1, b = 4, c = 'blah-blah', kwargs = {'d': 5} ]
test [ a = 1, b = 2, c = 3, args = [4, 5], kwargs = {'d': 6, 'g': 12.9} ]
9.import functools
import logging
logging.basicConfig[level = logging.DEBUG]
logger = logging.getLogger[]
def log[func]:
@functools.wraps[func]
def wrapper[*args, **kwargs]:
try:
result = func[*args, **kwargs]
return result
except Exception as e:
logger.exception[f"Exception raised in {func.__name__}. exception: {str[e]}"]
raise e
return wrapper
@log
def foo[]:
raise Exception["Something went wrong"]
ERROR:root:Exception raised in foo. exception: Something went wrong
Traceback [most recent call last]:
File "/foo.py", line 15, in wrapper
result = func[*args, **kwargs]
File "/foo.py", line 28, in foo
raise Exception["Something went wrong"]
Exception: Something went wrong
Ngoài việc thiết lập
def sum[a, b=10]:
return a+b
0, chúng tôi cũng đã sử dụng @functools.wraps. Bộ trang trí def sum[a, b=10]:
return a+b
1 cập nhật chức năng def sum[a, b=10]:
return a+b
2 trông giống như def sum[a, b=10]:
return a+b
3. Công cụ trang trí def sum[a, b=10]:
return a+b
4 của chúng tôi hiện có thể được sử dụng trên bất kỳ chức năng nào để bắt mọi ngoại lệ từ chức năng được bọc và đăng nhập nó một cách nhất quán.Vì hàm
def sum[a, b=10]:
return a+b
2 chấp nhận tất cả các đối số [def sum[a, b=10]:
return a+b
6], bộ trang trí def sum[a, b=10]:
return a+b
4 có thể được mở rộng để nắm bắt tất cả các tham số được truyền cho hàm được trang trí. Chúng ta có thể làm điều này chỉ bằng cách lặp lại trên các arg và kwarg và tham gia chúng để tạo thông báo chuỗi vào nhật ký.def dumpArgs[func]:
'''Decorator to print function call details - parameters names and effective values'''
def wrapper[*func_args, **func_kwargs]:
arg_names = func.func_code.co_varnames[:func.func_code.co_argcount]
args = func_args[:len[arg_names]]
defaults = func.func_defaults or []
args = args + defaults[len[defaults] - [func.func_code.co_argcount - len[args]]:]
params = zip[arg_names, args]
args = func_args[len[arg_names]:]
if args: params.append[['args', args]]
if func_kwargs: params.append[['kwargs', func_kwargs]]
print func.func_name + ' [' + ', '.join['%s = %r' % p for p in params] + ' ]'
return func[*func_args, **func_kwargs]
return wrapper
@dumpArgs
def test[a, b = 4, c = 'blah-blah', *args, **kwargs]:
pass
test[1]
test[1, 3]
test[1, d = 5]
test[1, 2, 3, 4, 5, d = 6, g = 12.9]
0def dumpArgs[func]:
'''Decorator to print function call details - parameters names and effective values'''
def wrapper[*func_args, **func_kwargs]:
arg_names = func.func_code.co_varnames[:func.func_code.co_argcount]
args = func_args[:len[arg_names]]
defaults = func.func_defaults or []
args = args + defaults[len[defaults] - [func.func_code.co_argcount - len[args]]:]
params = zip[arg_names, args]
args = func_args[len[arg_names]:]
if args: params.append[['args', args]]
if func_kwargs: params.append[['kwargs', func_kwargs]]
print func.func_name + ' [' + ', '.join['%s = %r' % p for p in params] + ' ]'
return func[*func_args, **func_kwargs]
return wrapper
@dumpArgs
def test[a, b = 4, c = 'blah-blah', *args, **kwargs]:
pass
test[1]
test[1, 3]
test[1, d = 5]
test[1, 2, 3, 4, 5, d = 6, g = 12.9]
1Chúng tôi đăng nhập các tham số ở cấp độ gỡ lỗi vì chúng tôi không muốn nhật ký của chúng tôi lộn xộn với tất cả các đối số chức năng. Ghi nhật ký có thể được chuyển đổi trên các hệ thống của chúng tôi khi cần thiết. Hãy nhớ rằng điều này sẽ viết tất cả các giá trị đối số vào nhật ký bao gồm mọi dữ liệu hoặc bí mật PII.Keep in mind that this will write all argument values into log including any PII data or secrets.
Bộ trang trí khai thác cơ bản này có vẻ tốt và đã làm những gì chúng tôi đặt ra ban đầu để đạt được. Miễn là một phương pháp được trang trí với
def sum[a, b=10]:
return a+b
4, chúng tôi sẽ ghi lại bất kỳ ngoại lệ nào được nêu trong đó và tất cả các đối số được truyền cho nó.Tuy nhiên, trong một dự án thực sự,
def sum[a, b=10]:
return a+b
0 có thể được trừu tượng hóa vào lớp của chính nó để khởi tạo một logger dựa trên cấu hình nhất định [chẳng hạn như đăng nhập vào một đám mây]. Trong trường hợp này, vô dụng để đăng nhập vào bảng điều khiển bằng cách tạo bộ ghi nhật ký của chúng tôi trong bộ trang trí def sum[a, b=10]:
return a+b
4. Chúng tôi cần một cách để chuyển def sum[a, b=10]:
return a+b
0 hiện có vào người trang trí của chúng tôi trong thời gian chạy. Để làm điều này, chúng tôi có thể mở rộng người trang trí def sum[a, b=10]:
return a+b
4 để chấp nhận def sum[a, b=10]:
return a+b
0 như một cuộc tranh luận.Để bắt chước kịch bản này, chúng ta sẽ bắt đầu với một lớp tạo ra một bộ ghi âm cho chúng ta. Bây giờ chúng tôi sẽ tạo bộ ghi âm cơ bản nhưng bạn có thể tưởng tượng lớp cấu hình hành vi của logger theo yêu cầu.
def dumpArgs[func]:
'''Decorator to print function call details - parameters names and effective values'''
def wrapper[*func_args, **func_kwargs]:
arg_names = func.func_code.co_varnames[:func.func_code.co_argcount]
args = func_args[:len[arg_names]]
defaults = func.func_defaults or []
args = args + defaults[len[defaults] - [func.func_code.co_argcount - len[args]]:]
params = zip[arg_names, args]
args = func_args[len[arg_names]:]
if args: params.append[['args', args]]
if func_kwargs: params.append[['kwargs', func_kwargs]]
print func.func_name + ' [' + ', '.join['%s = %r' % p for p in params] + ' ]'
return func[*func_args, **func_kwargs]
return wrapper
@dumpArgs
def test[a, b = 4, c = 'blah-blah', *args, **kwargs]:
pass
test[1]
test[1, 3]
test[1, d = 5]
test[1, 2, 3, 4, 5, d = 6, g = 12.9]
2Vì tại thời điểm viết người trang trí, chúng tôi không biết liệu chức năng cơ bản sẽ vượt qua chúng tôi
>>> sum
>>> sum.__code__.co_varnames # Names of local variables
['a', 'b']
4 hoặc >>> sum
>>> sum.__code__.co_varnames # Names of local variables
['a', 'b']
5 hay không có logger nào, người trang trí chung của chúng tôi sẽ có thể xử lý tất cả chúng.def dumpArgs[func]:
'''Decorator to print function call details - parameters names and effective values'''
def wrapper[*func_args, **func_kwargs]:
arg_names = func.func_code.co_varnames[:func.func_code.co_argcount]
args = func_args[:len[arg_names]]
defaults = func.func_defaults or []
args = args + defaults[len[defaults] - [func.func_code.co_argcount - len[args]]:]
params = zip[arg_names, args]
args = func_args[len[arg_names]:]
if args: params.append[['args', args]]
if func_kwargs: params.append[['kwargs', func_kwargs]]
print func.func_name + ' [' + ', '.join['%s = %r' % p for p in params] + ' ]'
return func[*func_args, **func_kwargs]
return wrapper
@dumpArgs
def test[a, b = 4, c = 'blah-blah', *args, **kwargs]:
pass
test[1]
test[1, 3]
test[1, d = 5]
test[1, 2, 3, 4, 5, d = 6, g = 12.9]
3Mã trên trông khá đáng sợ nhưng hãy để tôi tóm tắt nó. Nhà trang trí
def sum[a, b=10]:
return a+b
4 hiện xử lý ba kịch bản khác nhau -Không có logger nào được thông qua: Đây là kịch bản tương tự những gì chúng tôi đã làm cho đến trước đó. Bộ trang trí chỉ đơn giản được sử dụng làm tuyên bố
4 trên đầu hàm. Trong trường hợp này, người trang trí nhận được một logger bằng cách gọi phương thứcdef sum[a, b=10]: return a+b
8 và sử dụng nó cho phần còn lại của phương thức.: This is same scenario what we have been doing up until before this. The decorator is simply used as>>> sum >>> sum.__code__.co_varnames # Names of local variables ['a', 'b']
4 statement on top of the function. In this case the decorator gets a logger by callingdef sum[a, b=10]: return a+b
8 method and uses it for rest of the method.>>> sum >>> sum.__code__.co_varnames # Names of local variables ['a', 'b']
4 được thông qua: Công cụ trang trí>>> sum >>> sum.__code__.co_varnames # Names of local variables ['a', 'b']
4 của chúng tôi hiện có thể chấp nhận ví dụdef sum[a, b=10]: return a+b
4 làm đối số. Sau đó, nó có thể gọi phương thức>>> sum >>> sum.__code__.co_varnames # Names of local variables ['a', 'b']
2 để tạo một bộ ghi chép lồng nhau và sử dụng phần còn lại của nó.: Ourdef my_decorator[func]: def wrapper[*args, **kwargs]: # do something before `sum` result = func[*args, **kwargs] # do something after `sum` return result return wrapper sum = my_decorator[sum]
4 decorator can now accept instance ofdef sum[a, b=10]: return a+b
4 as an argument. It can then call>>> sum >>> sum.__code__.co_varnames # Names of local variables ['a', 'b']
2 method to create a nested logger and use it rest of the way.def my_decorator[func]: def wrapper[*args, **kwargs]: # do something before `sum` result = func[*args, **kwargs] # do something after `sum` return result return wrapper sum = my_decorator[sum]
def dumpArgs[func]:
'''Decorator to print function call details - parameters names and effective values'''
def wrapper[*func_args, **func_kwargs]:
arg_names = func.func_code.co_varnames[:func.func_code.co_argcount]
args = func_args[:len[arg_names]]
defaults = func.func_defaults or []
args = args + defaults[len[defaults] - [func.func_code.co_argcount - len[args]]:]
params = zip[arg_names, args]
args = func_args[len[arg_names]:]
if args: params.append[['args', args]]
if func_kwargs: params.append[['kwargs', func_kwargs]]
print func.func_name + ' [' + ', '.join['%s = %r' % p for p in params] + ' ]'
return func[*func_args, **func_kwargs]
return wrapper
@dumpArgs
def test[a, b = 4, c = 'blah-blah', *args, **kwargs]:
pass
test[1]
test[1, 3]
test[1, d = 5]
test[1, 2, 3, 4, 5, d = 6, g = 12.9]
4
5 được thông qua: Trong kịch bản thứ ba này, chúng ta có thể vượt qua bản ghi chính thay vì vượt qua lớp>>> sum >>> sum.__code__.co_varnames # Names of local variables ['a', 'b']
4.: In this third scenario we can pass the logger itself instead of passing>>> sum >>> sum.__code__.co_varnames # Names of local variables ['a', 'b']
4 class.>>> sum >>> sum.__code__.co_varnames # Names of local variables ['a', 'b']
def dumpArgs[func]:
'''Decorator to print function call details - parameters names and effective values'''
def wrapper[*func_args, **func_kwargs]:
arg_names = func.func_code.co_varnames[:func.func_code.co_argcount]
args = func_args[:len[arg_names]]
defaults = func.func_defaults or []
args = args + defaults[len[defaults] - [func.func_code.co_argcount - len[args]]:]
params = zip[arg_names, args]
args = func_args[len[arg_names]:]
if args: params.append[['args', args]]
if func_kwargs: params.append[['kwargs', func_kwargs]]
print func.func_name + ' [' + ', '.join['%s = %r' % p for p in params] + ' ]'
return func[*func_args, **func_kwargs]
return wrapper
@dumpArgs
def test[a, b = 4, c = 'blah-blah', *args, **kwargs]:
pass
test[1]
test[1, 3]
test[1, d = 5]
test[1, 2, 3, 4, 5, d = 6, g = 12.9]
5Chúng tôi vẫn chưa hoàn thành. Ngay cả trong hình thức hiện tại của chúng tôi trang trí log của chúng tôi bị hạn chế. Một hạn chế là chúng ta phải có sẵn
def sum[a, b=10]:
return a+b
0 hoặc >>> sum
>>> sum.__code__.co_varnames # Names of local variables
['a', 'b']
4 trước phương pháp chúng ta muốn trang trí. Nói cách khác, tham chiếu đến logger phải tồn tại trước khi phương thức tồn tại. Điều này có thể hoạt động trong trường hợp hàm đích là một phần của lớp và phương pháp lớp def my_decorator[func]:
def wrapper[*args, **kwargs]:
# do something before `sum`
result = func[*args, **kwargs]
# do something after `sum`
return result
return wrapper
sum = my_decorator[sum]
7 có thể khởi tạo logger, nhưng nó đã giành được công việc với các chức năng bên ngoài bối cảnh của lớp. Trong nhiều ứng dụng trong thế giới thực, chúng tôi sẽ không có từng mô -đun hoặc chức năng tạo ra logger của riêng họ. Thay vào đó, chúng tôi có thể muốn chuyển bộ ghi vào chức năng. def sum[a, b=10]:
return a+b
0 hoặc >>> sum
>>> sum.__code__.co_varnames # Names of local variables
['a', 'b']
4 sẽ được đưa vào các phương pháp hạ nguồn. Nói cách khác, một hàm có thể có logger được truyền cho nó trong tham số của nó.Nhưng nếu hàm là một phần của lớp thì
def sum[a, b=10]:
return a+b
0 sẽ được đưa vào lớp và không vào mọi phương pháp của lớp. Trong trường hợp này, chúng tôi sẽ muốn sử dụng logger có sẵn cho lớp của chúng tôi thay thế.Vì vậy, mục tiêu của chúng tôi là nắm bắt
def sum[a, b=10]:
return a+b
0 được thông qua như là lập luận cho chức năng được trang trí hoặc được chuyển cho hàm tạo lớp của chức năng được trang trí của chúng tôi và sử dụng nó để đăng nhập từ chính bộ trang trí. Bằng cách thực hiện điều này, người trang trí của chúng tôi có thể được tách rời hoàn toàn từ chính bộ ghi và sẽ sử dụng bất kỳ logger nào có sẵn cho phương pháp cơ bản trong thời gian chạy.or passed to the class constructor of our decorated function, and use it to log from the decorator itself. By doing this our decorator can be completely decoupled from the logger itself and will utilize whatever logger is available to the underlying method at runtime.Để làm điều này, chúng tôi sẽ lặp lại đối số
>>> sum
2 và >>> sum
3 và kiểm tra xem chúng tôi có nhận được def sum[a, b=10]:
return a+b
0 trong bất kỳ ai trong số họ không. Để kiểm tra xem hàm này có phải là một phần của lớp không, chúng ta có thể kiểm tra xem đối số đầu tiên của >>> sum
2 có thuộc tính >>> sum
6 không. Nếu đối số đầu tiên có thuộc tính >>> sum
6, chúng tôi sẽ lặp lại trên >>> sum
8 và kiểm tra xem một trong những giá trị này có phải là logger của chúng tôi không. Cuối cùng, nếu không có gì hoạt động, chúng tôi sẽ mặc định theo phương thức >>> sum
>>> sum.__code__.co_varnames # Names of local variables
['a', 'b']
8.def dumpArgs[func]:
'''Decorator to print function call details - parameters names and effective values'''
def wrapper[*func_args, **func_kwargs]:
arg_names = func.func_code.co_varnames[:func.func_code.co_argcount]
args = func_args[:len[arg_names]]
defaults = func.func_defaults or []
args = args + defaults[len[defaults] - [func.func_code.co_argcount - len[args]]:]
params = zip[arg_names, args]
args = func_args[len[arg_names]:]
if args: params.append[['args', args]]
if func_kwargs: params.append[['kwargs', func_kwargs]]
print func.func_name + ' [' + ', '.join['%s = %r' % p for p in params] + ' ]'
return func[*func_args, **func_kwargs]
return wrapper
@dumpArgs
def test[a, b = 4, c = 'blah-blah', *args, **kwargs]:
pass
test[1]
test[1, 3]
test[1, d = 5]
test[1, 2, 3, 4, 5, d = 6, g = 12.9]
6Người trang trí trên đủ chung chung để làm việc cho 2 kịch bản nữa ngoài 3 kịch bản chúng ta đã thảo luận trước đây -
0 hoặcdef sum[a, b=10]: return a+b
4 được chuyển sang phương pháp trang trí>>> sum >>> sum.__code__.co_varnames # Names of local variables ['a', 'b']
def dumpArgs[func]:
'''Decorator to print function call details - parameters names and effective values'''
def wrapper[*func_args, **func_kwargs]:
arg_names = func.func_code.co_varnames[:func.func_code.co_argcount]
args = func_args[:len[arg_names]]
defaults = func.func_defaults or []
args = args + defaults[len[defaults] - [func.func_code.co_argcount - len[args]]:]
params = zip[arg_names, args]
args = func_args[len[arg_names]:]
if args: params.append[['args', args]]
if func_kwargs: params.append[['kwargs', func_kwargs]]
print func.func_name + ' [' + ', '.join['%s = %r' % p for p in params] + ' ]'
return func[*func_args, **func_kwargs]
return wrapper
@dumpArgs
def test[a, b = 4, c = 'blah-blah', *args, **kwargs]:
pass
test[1]
test[1, 3]
test[1, d = 5]
test[1, 2, 3, 4, 5, d = 6, g = 12.9]
7- Hoặc
0 hoặcdef sum[a, b=10]: return a+b
4 được chuyển đến phương pháp>>> sum >>> sum.__code__.co_varnames # Names of local variables ['a', 'b']
7 lưu trữ chức năng được trang trídef my_decorator[func]: def wrapper[*args, **kwargs]: # do something before `sum` result = func[*args, **kwargs] # do something after `sum` return result return wrapper sum = my_decorator[sum]
def dumpArgs[func]:
'''Decorator to print function call details - parameters names and effective values'''
def wrapper[*func_args, **func_kwargs]:
arg_names = func.func_code.co_varnames[:func.func_code.co_argcount]
args = func_args[:len[arg_names]]
defaults = func.func_defaults or []
args = args + defaults[len[defaults] - [func.func_code.co_argcount - len[args]]:]
params = zip[arg_names, args]
args = func_args[len[arg_names]:]
if args: params.append[['args', args]]
if func_kwargs: params.append[['kwargs', func_kwargs]]
print func.func_name + ' [' + ', '.join['%s = %r' % p for p in params] + ' ]'
return func[*func_args, **func_kwargs]
return wrapper
@dumpArgs
def test[a, b = 4, c = 'blah-blah', *args, **kwargs]:
pass
test[1]
test[1, 3]
test[1, d = 5]
test[1, 2, 3, 4, 5, d = 6, g = 12.9]
8Một điều bổ sung chúng tôi đã làm là bọc tất cả các mã trước khi gọi hàm được trang trí
def sum[a, b=10]:
return a+b
3 trong khối @my_decorator # Equivalent to `sum = my_decorator[sum]` after the method
def sum[a, b=10]:
return a+b
6. Chúng tôi không muốn thực hiện thất bại do các vấn đề trong việc đăng nhập ngay cả trước khi chức năng đích được gọi. Trong mọi trường hợp logic ghi nhật ký của chúng tôi sẽ gây ra lỗi trong hệ thống.Sự kết luận
Bộ trang trí trên là một điểm khởi đầu tốt và có thể được mở rộng hoặc đơn giản hóa theo các yêu cầu. Nó làm giảm khả năng bỏ lỡ việc ghi nhật ký ngoại lệ và chuẩn hóa các thông báo lỗi trên khắp ứng dụng.
Tiếp cận với tôi trong các ý kiến dưới đây cho bất kỳ câu hỏi mà bạn có thể có.