初级

1. print 大法

print调试

2. log的debug级别调试

基础使用
import logging

logging.basicConfig(level=logging.DEBUG, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s")

oLogger = logging.getLogger(__name__)

oLogger.info("start script 123")
oLogger.debug("a = %s" % 1)
oLogger.warning("错误的id")
oLogger.error("异常情况")
oLogger.critical("十分严重")
日志级别

使用logger.setLevel(logging.INFO)方法就可以设置日志级别
INFO:会输出除了debug之外的所有信息 (个人理解,用于日常正式日志记录,这些日志需要永久保存的)
DEBUG: 会输出所有信息,包括INFO (个人理解,用于开发环境,需要详细的日志信息,这些日志是可以隔一段时间清楚的)
WARNNING:只会输出同级或者更高级的日志信息
ERROR:只会输出同级或者更高级的日志信息
CRITICAL:只会输出同级或者更高级的日志信息

记录到文件
动态配置
  1. 从logging拿到filehandler,
  2. 设置filehandler属性
  3. 从logging拿到logger,然后把handler给logger
def LogToFile():
    # 设置文件handle
    oHandle = logging.FileHandler("log/logging.txt")
    oHandle.setLevel(logging.DEBUG)
    oFormatter = logging.Formatter("[%(asctime)s - %(name)s - %(levelname)s - %(message)s]")
    oHandle.setFormatter(oFormatter)

    # 添加handle到oLog上
    oLog = logging.getLogger(__name__)
    oLog.addHandler(oHandle)

    # 记录日志
    oLog.info("start script 123")
    oLog.debug("a = %s" % 1)
    oLog.warning("错误的id")
    oLog.error("异常情况")
    oLog.critical("十分严重")
通过配置文件配置

有多种方式配置,这里使用json格式配置
json文件中内容:

{
  "version":1,
  "formatters": {
    "simple": {
      "format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
    }
  },
  "handlers": {
      "info_handler":{
        "class": "logging.FileHandler",

        "level": "INFO",
        "formatter": "simple",
        "filename": "info.log"
      }
  },
  "loggers": {
    "my_module": {
      "level": "ERROR",
      "handlers": ["info_handler"]
    }
  }

}

使用:

import json
import logging.config
PATH_LOG_CONF = r"D:\study\python\pycode\python_study\log\logging.json"
#从json中读取配置来记录日志
def LogFromJson():
    with open(PATH_LOG_CONF) as f:
        dConfig = json.load(f)
        logging.config.dictConfig(dConfig)			#读取配置文件
        oLog = logging.getLogger("my_module")		#获取指定logger
        oLog.error("model test2")


if __name__ == "__main__":
    LogFromJson()

进阶

1. 使用pysnoop调试工具

下载:pip install pysnooper
导入使用

from pysnooper import snoop
""" watch:关注属性,注意,watch是个元组;
depth:递归深度,默认为1
"testsnooplog.txt"把snoop追加输出到log文件中,可不填,默认输出到控制台
watch_explode:展开输出字典的值,个人感觉没啥用"""
@snoop("testsnooplog.txt", watch=("oTestA.m_Num",), depth=2)
def DoMain():
    oTestA = CTestA()
    oTestA.m_Num = 3            # 测试关注属性的变化
    print(oTestA.m_Num)
    # 测试字典变量追踪
    dTempDict = {1: 1, 2: 2}
    dTempDict[1] = 3            # 变量更改也会打印
    if 1:
        iTemp = GetSum(1, 2)    # 测试递归深度
    del oTestA.m_Num

"testsnooplog.txt“中的内容如下

Source path:... D:/study/python/pycode/python_study/调试.py
22:04:16.486441 call        24 def DoMain():
22:04:16.499442 line        25     oTestA = CTestA()
    Starting var:.. self = <__main__.CTestA object at 0x01C04950>
    22:04:16.506444 call         5     def __init__(self):
    22:04:16.518447 line         6         self.m_Num = 1
    22:04:16.524947 return       6         self.m_Num = 1
    Return value:.. None
New var:....... oTestA = <__main__.CTestA object at 0x01C04950>
New var:....... oTestA.m_Num = 1
22:04:16.536450 line        26     oTestA.m_Num = 3            # 测试关注属性的变化
Modified var:.. oTestA.m_Num = 3
22:04:16.555453 line        27     print(oTestA.m_Num)
22:04:16.567956 line        29     dTempDict = {1: 1, 2: 2}
New var:....... dTempDict = {1: 1, 2: 2}
22:04:16.573956 line        30     dTempDict[1] = 3            # 变量更改也会打印
Modified var:.. dTempDict = {1: 3, 2: 2}
22:04:16.586458 line        32         iTemp = GetSum(1, 2)    # 测试递归深度
    Starting var:.. iNumA = 1
    Starting var:.. iNumB = 2
    22:04:16.598461 call        36 def GetSum(iNumA, iNumB):
    22:04:16.616965 line        37     return iNumA + iNumB
    22:04:16.622965 return      37     return iNumA + iNumB
    Return value:.. 3
New var:....... iTemp = 3
22:04:16.633466 line        33     del oTestA.m_Num
22:04:16.645969 return      33     del oTestA.m_Num
Return value:.. None
Elapsed time: 00:00:00.171530

2. __setattr__方法

在更改某个实例的属性的时候,会调用__setattr__方法,
通过__setattr__我们可以追踪某个属性的更改,查看属性在什么时候被更改了
测试代码如下,类被初始化的时候调用一次__setattr__,更改的时候调用一次,总共两次

class CTestA(object):
    def __init__(self):
        self.m_Num = 1

    def __setattr__(self, key, value):
        if hasattr(self, key):
            print("the attribute {} changed from {} to {}".format(key, self.__getattribute__(key), value))
        else:
            print("the attribute {} changed to {}".format(key, value))
        super(CTestA, self).__setattr__(key, value)


if __name__ == "__main__":
    oTestA = CTestA()
    oTestA.m_Num = 3
    print(oTestA.m_Num)

输出如下

D:\study\python3.6.8\python.exe D:/study/python/pycode/python_study/调试.py
the attribute m_Num changed to 1
the attribute m_Num changed from 1 to 3
3

Process finished with exit code 0

3. __delattr__方法

同2,在属性被删除的时候调用
在上面CTestA重写如下方法

def __delattr__(self, item):
        print("the item {} has being delete".format(item))
        super(CTestA, self).__delattr__(item)

然后再main中调用del oTestA.m_Num
输出如下

D:\study\python3.6.8\python.exe D:/study/python/pycode/python_study/调试.py
the attribute m_Num changed to 1
the attribute m_Num changed from 1 to 3
3
the item m_Num has being delete

Process finished with exit code 0