Python Debug(调试)的终极指南
off999 2024-11-23 20:37 20 浏览 0 评论
前言
即使您编写了清晰可读的代码,即使您是非常有经验的开发人员,奇怪的bug也不可避免地会出现,您将需要以某种方式调试它们。很多人使用一堆print语句来查看代码中发生了什么。这种方法远不是理想的,有更好的方法可以找出代码的错误所在,本文将探讨其中一些问题和应对方法。
日志是必须的
如果在编写应用程序时没有设置日志记录,那么您最终会后悔的。应用程序中没有任何日志会使故障排除变得非常困难。幸运的是,在Python中,建立基本的日志程序非常简单:
import logging
logging.basicConfig(
filename='application.log',
level=logging.WARNING,
format= '[%(asctime)s] {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s',
datefmt='%H:%M:%S'
)
logging.error("Some serious error occurred.")
logging.warning('Function you are using is deprecated.')这就是所有你需要开始写日志的文件,它看起来像这样,你可以找到文件的路径使用logger . getloggerclass ().root.handlers[0].baseFilename):
[12:52:35] {<stdin>:1} ERROR - Some serious error occurred.
[12:52:35] {<stdin>:1} WARNING - Function you are using is deprecated.这种设置看起来似乎已经足够好了(通常情况下也是如此),但是拥有配置良好、格式化、可读的日志可以使您的工作变得更加容易。改进和扩展配置的一种方法是使用被logger读取的.ini或.yaml文件。举个例子,你可以在配置中做什么:
version: 1
disable_existing_loggers: true
formatters:
standard:
format: "[%(asctime)s] {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s"
datefmt: '%H:%M:%S'
handlers:
console: # handler which will log into stdout
class: logging.StreamHandler
level: DEBUG
formatter: standard # Use formatter defined above
stream: ext://sys.stdout
file: # handler which will log into file
class: logging.handlers.RotatingFileHandler
level: WARNING
formatter: standard # Use formatter defined above
filename: /tmp/warnings.log
maxBytes: 10485760 # 10MB
backupCount: 10
encoding: utf8
root: # Loggers are organized in hierarchy - this is the root logger config
level: ERROR
handlers: [console, file] # Attaches both handler defined above
loggers: # Defines descendants of root logger
mymodule: # Logger for "mymodule"
level: INFO
handlers: [file] # Will only use "file" handler defined above
propagate: no # Will not propagate logs to "root" logger在python代码中使用这种扩展的配置将很难导航、编辑和维护。将内容保存在YAML文件中,可以通过非常特定的设置(如上面的设置)更容易地设置和调整多个日志记录器。
在文件中有了配置,意味着我们需要加载。最简单的方法做与YAML文件:
import yaml
from logging import config
with open("config.yaml", 'rt') as f:
config_data = yaml.safe_load(f.read())
config.dictConfig(config_data)Python logger实际上并不直接支持YAML文件,但是它支持字典配置,可以使用YAML .safe_load轻松地从YAML创建字典配置。如果您更倾向于使用旧的.ini文件,那么我只想指出,对于新应用程序,根据文档,推荐使用字典configs。
__repr__ 可读的日志
对代码进行简单的改进,使其更具可调试性,可以在类中添加__repr__方法。如果你不熟悉这个方法-它所做的只是返回一个类实例的字符串表示。使用__repr__方法的最佳实践是输出可用于重新创建实例的文本。例如:
class Circle:
def __init__(self, x, y, radius):
self.x = x
self.y = y
self.radius = radius
def __repr__(self):
return f"Rectangle({self.x}, {self.y}, {self.radius})"
...
c = Circle(100, 80, 30)
repr(c)
# Circle(100, 80, 30)除了__repr__,在调用print(实例)时,执行__str__方法也是一个好主意。有了这两种方法,你可以通过打印你的变量得到很多信息。
针对字典的__missing__方法
如果出于某种原因需要实现自定义dictionary类,那么在尝试访问一些实际上不存在的密钥时,您可能会遇到一些由keyerror引起的错误。为了避免在代码中到处查看丢失了哪个键(key),你可以实现特殊的__miss__方法,每次KeyError被提出时调用。
class MyDict(dict):
def __missing__(self, key):
message = f'{key} not present in the dictionary!'
logging.warning(message)
return message # Or raise some error instead上面的实现非常简单,只返回和记录丢失键的消息,但是您还可以记录其他有价值的信息,以便了解代码中出现了什么问题。
调试崩溃的应用程序
如果您的应用程序在您有机会了解其中发生了什么之前就崩溃了,那么您可能会发现这个技巧非常有用。
使用-i参数运行应用程序(python3 -i app.py)会导致程序一退出就启动交互式shell。此时,您可以检查变量和函数。
如果这还不够好,您可以带一个更强大的工具 - pdb - Python调试器。pdb有很多特性,可以单独写一篇文章来说明。但这里有一个例子和最重要的部分的纲要。让我们先看看崩溃脚本:
# crashing_app.py
SOME_VAR = 42
class SomeError(Exception):
pass
def func():
raise SomeError("Something went wrong...")
func()现在,如果我们用-i参数运行它,我们就有机会调试它:
# Run crashing application
~ $ python3 -i crashing_app.py
Traceback (most recent call last):
File "crashing_app.py", line 9, in <module>
func()
File "crashing_app.py", line 7, in func
raise SomeError("Something went wrong...")
__main__.SomeError: Something went wrong...
>>> # We are interactive shell
>>> import pdb
>>> pdb.pm() # start Post-Mortem debugger
> .../crashing_app.py(7)func()
-> raise SomeError("Something went wrong...")
(Pdb) # Now we are in debugger and can poke around and run some commands:
(Pdb) p SOME_VAR # Print value of variable
42
(Pdb) l # List surrounding code we are working with
2
3 class SomeError(Exception):
4 pass
5
6 def func():
7 -> raise SomeError("Something went wrong...")
8
9 func()
[EOF]
(Pdb) # Continue debugging... set breakpoints, step through the code, etc.上面的调试会话非常简单地展示了使用pdb可以做什么。程序结束后,我们进入交互式调试会话。首先,导入pdb并启动调试器。此时,我们可以使用所有pdb命令。作为上面的示例,我们使用p命令打印变量,使用l命令列出代码。大部分时间你可能会想要设置断点,可以与b LINE_NO和运行程序,直到断点(c),然后继续与年代,逐页浏览功能的选择可能与w。
堆栈跟踪
假设您的代码是运行在远程服务器上的Flask或Django应用程序,在那里您无法获得交互式调试会话。在这种情况下,你可以使用traceback和sys包来了解你的代码中失败的地方:
import traceback
import sys
def func():
try:
raise SomeError("Something went wrong...")
except:
traceback.print_exc(file=sys.stderr)在运行时,上面的代码将打印引发的最后一个异常。除了打印异常,您还可以使用traceback包来打印stacktrace (traceback. print_stack())或提取原始堆栈帧,格式化它并进一步检查它(traceback. format_list(traceback.extract_stack()))。
在调试期间重新加载模块
有时,您可能在交互式shell中调试或试验某些函数,并经常对其进行更改。为了使运行/测试和修改的循环更容易,您可以运行importlib.reload(模块),以避免在每次更改后重新启动交互会话:
>>> import func from module
>>> func()
"This is result..."
# Make some changes to "func"
>>> func()
"This is result..." # Outdated result
>>> from importlib import reload; reload(module) # Reload "module" after changes made to "func"
>>> func()
"New result..."这个技巧更多的是关于效率而不是调试。能够跳过一些不必要的步骤,使您的工作流程更快、更高效总是很好的。一般来说,不时地重新加载模块是一个好主意,因为它可以帮助您避免调试已经被修改了很多次的代码。
总结
Debug是一门艺术。
英文原文?:https://towardsdatascience.com/ultimate-guide-to-python-debugging-854dea731e1b?
- 上一篇:Python 调试技巧
- 下一篇:python调试的几种方式
相关推荐
- 阿里云国际站ECS:阿里云ECS如何提高网站的访问速度?
-
TG:@yunlaoda360引言:速度即体验,速度即业务在当今数字化的世界中,网站的访问速度已成为决定用户体验、用户留存乃至业务转化率的关键因素。页面加载每延迟一秒,都可能导致用户流失和收入损失。对...
- 高流量大并发Linux TCP性能调优_linux 高并发网络编程
-
其实主要是手里面的跑openvpn服务器。因为并没有明文禁p2p(哎……想想那么多流量好像不跑点p2p也跑不完),所以造成有的时候如果有比较多人跑BT的话,会造成VPN速度急剧下降。本文所面对的情况为...
- 性能测试100集(12)性能指标资源使用率
-
在性能测试中,资源使用率是评估系统硬件效率的关键指标,主要包括以下四类:#性能测试##性能压测策略##软件测试#1.CPU使用率定义:CPU处理任务的时间占比,计算公式为1-空闲时间/总...
- Linux 服务器常见的性能调优_linux高性能服务端编程
-
一、Linux服务器性能调优第一步——先搞懂“看什么”很多人刚接触Linux性能调优时,总想着直接改配置,其实第一步该是“看清楚问题”。就像医生看病要先听诊,调优前得先知道服务器“哪里...
- Nginx性能优化实战:手把手教你提升10倍性能!
-
关注△mikechen△,十余年BAT架构经验倾囊相授!Nginx是大型架构而核心,下面我重点详解Nginx性能@mikechen文章来源:mikechen.cc1.worker_processe...
- 高并发场景下,Spring Cloud Gateway如何抗住百万QPS?
-
关注△mikechen△,十余年BAT架构经验倾囊相授!大家好,我是mikechen。高并发场景下网关作为流量的入口非常重要,下面我重点详解SpringCloudGateway如何抗住百万性能@m...
- Kubernetes 高并发处理实战(可落地案例 + 源码)
-
目标场景:对外提供HTTPAPI的微服务在短时间内收到大量请求(例如每秒数千至数万RPS),要求系统可弹性扩容、限流降级、缓存减压、稳定运行并能自动恢复。总体思路(多层防护):边缘层:云LB...
- 高并发场景下,Nginx如何扛住千万级请求?
-
Nginx是大型架构的必备中间件,下面我重点详解Nginx如何实现高并发@mikechen文章来源:mikechen.cc事件驱动模型Nginx采用事件驱动模型,这是Nginx高并发性能的基石。传统...
- Spring Boot+Vue全栈开发实战,中文版高清PDF资源
-
SpringBoot+Vue全栈开发实战,中文高清PDF资源,需要的可以私我:)SpringBoot致力于简化开发配置并为企业级开发提供一系列非业务性功能,而Vue则采用数据驱动视图的方式将程序...
- Docker-基础操作_docker基础实战教程二
-
一、镜像1、从仓库获取镜像搜索镜像:dockersearchimage_name搜索结果过滤:是否官方:dockersearch--filter="is-offical=true...
- 你有空吗?跟我一起搭个服务器好不好?
-
来人人都是产品经理【起点学院】,BAT实战派产品总监手把手系统带你学产品、学运营。昨天闲的没事的时候,随手翻了翻写过的文章,发现一个很严重的问题。就是大多数时间我都在滔滔不绝的讲理论,却很少有涉及动手...
- 部署你自己的 SaaS_saas如何部署
-
部署你自己的VPNOpenVPN——功能齐全的开源VPN解决方案。(DigitalOcean教程)dockovpn.io—无状态OpenVPNdockerized服务器,不需要持久存储。...
- Docker Compose_dockercompose安装
-
DockerCompose概述DockerCompose是一个用来定义和管理多容器应用的工具,通过一个docker-compose.yml文件,用YAML格式描述服务、网络、卷等内容,...
- 京东T7架构师推出的电子版SpringBoot,从构建小系统到架构大系统
-
前言:Java的各种开发框架发展了很多年,影响了一代又一代的程序员,现在无论是程序员,还是架构师,使用这些开发框架都面临着两方面的挑战。一方面是要快速开发出系统,这就要求使用的开发框架尽量简单,无论...
- Kubernetes (k8s) 入门学习指南_k8s kubeproxy
-
Kubernetes(k8s)入门学习指南一、什么是Kubernetes?为什么需要它?Kubernetes(k8s)是一个开源的容器编排系统,用于自动化部署、扩展和管理容器化应用程序。它...
欢迎 你 发表评论:
- 一周热门
-
-
抖音上好看的小姐姐,Python给你都下载了
-
全网最简单易懂!495页Python漫画教程,高清PDF版免费下载
-
Python 3.14 的 UUIDv6/v7/v8 上新,别再用 uuid4 () 啦!
-
python入门到脱坑 输入与输出—str()函数
-
宝塔面板如何添加免费waf防火墙?(宝塔面板开启https)
-
Python三目运算基础与进阶_python三目运算符判断三个变量
-
(新版)Python 分布式爬虫与 JS 逆向进阶实战吾爱分享
-
飞牛NAS部署TVGate Docker项目,实现内网一键转发、代理、jx
-
慕ke 前端工程师2024「完整」
-
失业程序员复习python笔记——条件与循环
-
- 最近发表
- 标签列表
-
- python计时 (73)
- python安装路径 (56)
- python类型转换 (93)
- python进度条 (67)
- python吧 (67)
- python的for循环 (65)
- python格式化字符串 (61)
- python静态方法 (57)
- python列表切片 (59)
- python面向对象编程 (60)
- python 代码加密 (65)
- python串口编程 (77)
- python封装 (57)
- python写入txt (66)
- python读取文件夹下所有文件 (59)
- python操作mysql数据库 (66)
- python获取列表的长度 (64)
- python接口 (63)
- python调用函数 (57)
- python多态 (60)
- python匿名函数 (59)
- python打印九九乘法表 (65)
- python赋值 (62)
- python异常 (69)
- python元祖 (57)
