动手做科研-day02-如何掌握Python工程流程
01. 拉取一个git仓库
问题1:不知道如何拉取别人的git仓库, 并没有图中的Clone Git Repository

在自己新建的文件夹中不能操作。
解决过程:参考博客, 但是发现并没有..., 需要初始化仓库

初始化后出现..., 按照博客内容进行操作



可以拉取别人的远程仓库, 问题解决
02. 拉取仓库代码运行
问题1: 在点击运行后并不是很理解控制台上的显示是什么意思
[Running] python -u "c:\Users\dell\Desktop\test\hand on reaserch\chapter_02\day_06_git_clone\python-practice\sum_of_list.py"
解决过程:询问GPT

知道了 -u的含义是保证所有的输出得到显示, 问题解决
问题2: 控制台的输出代码不是很懂
Traceback (most recent call last):
解决过程:询问GPT

根据自己以前深度学习跑代码的经验,应该是python开始自动寻找哪个代码出现了问题, 并且从大到小开始寻找问题, 比如先是一个大函数, 然后去里面的具体代码中找哪个地方报了错。
03. debug代码
问题1:在debug过程中的步过和步入有什么区别?
解决过程:
自己在实践中,如果把原来的代码写成一个函数如下:
# 原来的
if __name__ == "__main__":
a = [0, 1, 2, 3, 4, 5, 6]
sum = 0
for i in range(10): # 0-6
print("i:", i)
sum = sum + a[i] # a[7] = ? a[0] = 0, a[1]=1, ... a[6]=6
print("sum:", sum)
# 改
def main():
a = [0, 1, 2, 3, 4, 5, 6]
sum = 0
for i in range(10): # 0-6
print("i:", i)
sum = sum + a[i] # a[7] = ? a[0] = 0, a[1]=1, ... a[6]=6
print("sum:", sum)
if __name__ == "__main__":
main()
![]() |
|---|
| 将断点打在main()处, 步过 |
![]() |
| 将断点打在main()内部, 步过 |
可以发现,打在外部的函数调用的地方上,步过不会跳进函数内部执行继续让你执行,而是直接自己执行完返回结果,在外部的地方继续下一步让你执行,如果打断点打在内部则会一步步执行代码。
| |
|---|
| 将断点打在main()处, 步入 |
实践总结:在范围小的地方,步过和步入基本相同, 在可调用的地方,步过不会具体到里面让你debug,但是步入会进入调用的地方让你继续debug
# GPT回答
在调试(debug)代码时,“步过”(Step Over)和“步入”(Step Into)是两个常用的调试操作,它们用于控制调试器如何执行代码行。它们之间的主要区别在于调试器如何处理函数调用。
### 1. **步过(Step Over)**
- **功能**: “步过”命令会让调试器执行当前行的代码,但如果当前行包含一个函数调用,调试器不会进入该函数的内部,而是直接执行完这个函数后停在下一行代码上。
- **用途**: 当你不关心某个函数的内部实现细节,只想知道它返回了什么,或者你知道该函数已经被充分测试过,不需要再检查它时,可以使用“步过”。
**例子**:
```python
def sum(a, b):
return a + b
x = sum(2, 3) # 当前行
y = x * 2
```
如果你在 `x = sum(2, 3)` 这一行使用“步过”,调试器将执行 `sum` 函数,但不会进入 `sum` 函数的内部,而是直接在 `y = x * 2` 这一行暂停。
### 2. **步入(Step Into)**
- **功能**: “步入”命令会让调试器执行当前行的代码,如果当前行包含一个函数调用,调试器会进入该函数的内部,并在函数的第一行代码处暂停。
- **用途**: 当你想要检查函数的内部行为,了解函数内部是如何工作的,或者想要追踪一个可能导致问题的函数时,可以使用“步入”。
**例子**:
```python
def sum(a, b):
return a + b # 如果步入,这一行会被暂停
x = sum(2, 3) # 当前行
y = x * 2
```
如果你在 `x = sum(2, 3)` 这一行使用“步入”,调试器将进入 `sum` 函数,并在 `return a + b` 这一行暂停,允许你逐步调试函数的内部逻辑。
### 总结
- **步过(Step Over)**:执行当前行的代码,不进入函数内部,适用于对函数内部不感兴趣的情况。
- **步入(Step Into)**:执行当前行的代码并进入函数内部,适用于需要调试和检查函数内部逻辑的情况。
和实践类似,问题解决
02. 利用log进行debug
解决:利用GPT查询如何利用log进行debug
# GPT回答
使用日志(log)进行调试是一种非常有效的方式,特别是在处理复杂的系统或无法直接使用调试器的情况下。通过在代码中插入日志语句,你可以跟踪程序的执行流程、变量的值以及发生的异常,帮助你定位和解决问题。
以下是如何使用日志进行调试的详细步骤:
### 1. **导入日志库**
在 Python 中,你可以使用内置的 `logging` 模块进行日志记录。首先需要导入它:
```python
import logging
```
### 2. **配置日志记录**
在使用日志记录之前,你需要配置日志的格式、级别和输出方式(如控制台、文件等)。这是一个简单的配置示例:
```python
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s - %(levelname)s - %(message)s',
filename='app.log', # 如果不需要输出到文件,可以省略 filename 参数
filemode='w') # 'w' 表示每次运行程序时清空日志文件,'a' 表示追加日志
```
- **level**: 设置日志记录的最低级别。常见级别包括:
- `DEBUG`: 最详细的信息,用于诊断问题。
- `INFO`: 一般性的信息,如程序正常运行的输出。
- `WARNING`: 警告信息,表示程序可能有问题,但不影响运行。
- `ERROR`: 错误信息,表示程序遇到严重问题,可能无法继续运行。
- `CRITICAL`: 严重错误,表示程序可能会崩溃。
- **format**: 指定日志输出的格式。常用的格式占位符包括:
- `%(asctime)s`: 日志记录的时间戳。
- `%(levelname)s`: 日志级别。
- `%(message)s`: 日志消息内容。
- **filename**: 如果你希望将日志输出到文件,可以指定一个文件名。
- **filemode**: 文件模式,'w' 表示每次运行程序时重写日志文件,'a' 表示追加日志到现有文件。
### 3. **插入日志语句**
在需要调试的代码中插入日志语句。根据不同的场景,你可以使用不同的日志级别。例如:
```python
logging.debug('这是一个调试信息,变量 x 的值为: %s', x)
logging.info('程序开始运行')
logging.warning('这是一个警告信息')
logging.error('发生了错误')
logging.critical('这是一个严重错误')
```
### 4. **分析日志输出**
运行程序后,查看生成的日志文件(或控制台输出)来分析程序的行为。通过日志,你可以看到程序执行到哪里、变量的值、是否出现异常等信息。
### 5. **使用日志替代 print 进行调试**
与直接使用 `print` 进行调试不同,使用日志记录有以下优势:
- **可控性**: 通过设置日志级别,可以控制输出的详细程度。例如,在开发阶段使用 `DEBUG` 级别记录详细信息,而在生产环境中使用 `ERROR` 或 `CRITICAL` 级别只记录重要信息。
- **持久性**: 日志可以保存到文件中,方便之后的分析和回溯。
- **格式化输出**: 日志可以带有时间戳、级别信息,帮助更好地理解程序的运行状态。
### 6. **示例代码**
以下是一个使用日志进行调试的完整示例:
```python
import logging
# 配置日志
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s - %(levelname)s - %(message)s')
def divide(a, b):
logging.debug("正在执行 divide 函数,a: %s, b: %s", a, b)
try:
result = a / b
except ZeroDivisionError as e:
logging.error("尝试除以零: %s", e)
return None
logging.info("除法结果: %s", result)
return result
if __name__ == "__main__":
x = 10
y = 0
logging.info("程序开始运行")
divide(x, y)
logging.info("程序结束")
```
在这个例子中,`divide` 函数中记录了调试信息和错误处理,而主程序记录了程序的开始和结束。在运行这个程序时,日志将显示出详细的执行过程,并且在发生错误时记录错误信息。
尝试根据给定的示例代码对下拉远程库中的代码进行修改,修改如下:
import logging
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s - %(levelname)s - %(message)s',
filename='app.log', # 如果不需要输出到文件,可以省略 filename 参数
filemode='w') # 'w' 表示每次运行程序时清空日志文件,'a' 表示追加日志
if __name__ == "__main__":
logging.info("程序开始运行")
a = [0, 1, 2, 3, 4, 5, 6]
sum = 0
for i in range(10):
logging.debug("i = %d" % i)
try:
sum = sum + a[i]
logging.debug("sum = %d" % sum)
except IndexError as e:
logging.error("索引越界")
break
logging.info("程序运行结束")
03. 利用log进行debug后记录的.log文件有乱码现象

解决过程:
参考博客得知, 在logging进行记录时默认使用ASCII码进行编码,导致中文无法正常编码,会编成乱码, 需要采用utf-8进行编码。
# 在logging配置处增加编码方式
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s - %(levelname)s - %(message)s',
filename='app.log', # 如果不需要输出到文件,可以省略 filename 参数
filemode='w', # 'w' 表示每次运行程序时清空日志文件,'a' 表示追加日志
encoding='utf-8')
结果生成app.log

问题解决



|
浙公网安备 33010602011771号