pysnooper是代碼debug神器,比無限low print好不少和也比日誌debug好一些,比斷點調試也好一些,這個很犀利的裝飾器。
https://www.toutiao.com/a6682957535856558606/
DeBug Python代碼全靠print函數?換用這個一天2K+Star的工具吧
對其修改了2點。
一、因爲部署通常是linux,開發是windows,因此能夠禁止linux上使用調試,相同的代碼在linux上運行,調試裝飾器自動失效,由於忘了註釋掉裝飾器,在生產調試會消耗性能。
二、將代碼運行軌跡修改爲能夠點擊的,點擊控制檯的行號便可跳轉到pycharm對應的代碼行。
三、提供一個猴子補丁,使用猴子補丁修改三方包的模塊級全局變量MAX_VARIABLE_LENGTH ,最大變量默認是100,但對調試對接方json時候,每每很大,能夠加大到最大顯示10萬個字母。
# -*- coding: utf-8 -*- # @Author : ydf import datetime import os from functools import wraps import decorator import pysnooper # 須要安裝 pip install pysnooper==0.0.11 from pysnooper.pysnooper import get_write_function from pysnooper.tracer import Tracer, get_local_reprs, get_source_from_frame os_name = os.name class TracerCanClick(Tracer): """ 使運行軌跡可點擊。 """ def trace(self, frame, event, arg): if frame.f_code is not self.target_code_object: if self.depth == 1: return self.trace else: _frame_candidate = frame for i in range(1, self.depth): _frame_candidate = _frame_candidate.f_back if _frame_candidate is None: return self.trace elif _frame_candidate.f_code is self.target_code_object: indent = ' ' * 4 * i break else: return self.trace else: indent = '' self.frame_to_old_local_reprs[frame] = old_local_reprs = \ self.frame_to_local_reprs[frame] self.frame_to_local_reprs[frame] = local_reprs = \ get_local_reprs(frame, variables=self.variables) modified_local_reprs = {} newish_local_reprs = {} for key, value in local_reprs.items(): if key not in old_local_reprs: newish_local_reprs[key] = value elif old_local_reprs[key] != value: modified_local_reprs[key] = value newish_string = ('Starting var:.. ' if event == 'call' else 'New var:....... ') for name, value_repr in newish_local_reprs.items(): self.write('{indent}{newish_string}{name} = {value_repr}'.format( **locals())) for name, value_repr in modified_local_reprs.items(): self.write('{indent}Modified var:.. {name} = {value_repr}'.format( **locals())) now_string = datetime.datetime.now().time().isoformat() source_line = get_source_from_frame(frame)[frame.f_lineno - 1] # print(frame) # print(dir(frame.f_code)) # print(frame.f_code.co_filename) file_name_and_line = f'{frame.f_code.co_filename}:{frame.f_lineno}' # print(file_name_and_line) # self.write('{indent}{now_string} {event:9} ' # '{frame.f_lineno:4} {source_line}'.format(**locals())) file_name_and_line2 = f'"{file_name_and_line}"' self.write('{indent}{now_string} {event:9} ' # REMIND 主要是修改了這一行,使debug可點擊。 '{file_name_and_line2:100} {source_line}'.format(**locals())) return self.trace def _snoop_can_click(output=None, variables=(), depth=1, prefix=''): write = get_write_function(output) # noinspection PyShadowingBuiltins @decorator.decorator def decorate(function, *args, **kwargs): target_code_object = function.__code__ with TracerCanClick(target_code_object=target_code_object, write=write, variables=variables, depth=depth, prefix=prefix): return function(*args, **kwargs) return decorate def snoop_deco(output=None, variables: tuple = (), depth=1, prefix='', do_not_effect_on_linux=True, line_can_click=True): # REMIND 對裝飾器再包裝一次,不使用上面的和官方的。 def _snoop(func): nonlocal prefix if prefix == '': prefix = f'調試 [{func.__name__}] 函數 --> ' @wraps(func) def __snoop(*args, **kwargs): if os_name == 'posix' and do_not_effect_on_linux: # 不在linux上debug return func(*args, **kwargs) else: if line_can_click: return _snoop_can_click(output, variables, depth, prefix)(func)(*args, **kwargs) else: return pysnooper.snoop(output, variables, depth, prefix)(func)(*args, **kwargs) return __snoop return _snoop def patch_snooper_max_variable_length(max_lenth=100000): """ 提供一個猴子補丁,三方包默認是變量最大顯示100個字母,對於我這種常常debug對接方json的,要加到10萬才能顯示一個josn。 最好是放在__name__ == main中去執行此補丁,不然因爲模塊是單例的永遠只導入一次,若是本文件被其餘地方導入,也會改變當前python解釋器的其餘也使用snooper地方的運行表現也加到10萬了。 :param max_lenth: :return: """ from pysnooper import tracer tracer.MAX_VARIABLE_LENGTH = max_lenth if __name__ == '__main__': @snoop_deco(line_can_click=True) def fun2(): x = 1 x += 2 fun2()
原版是上面這樣,不能點擊,修改後,直接點擊連接能夠跳轉到代碼對應地方。不用加不少print來肯定代碼運行了什麼分支。python