Python-警告處理


python 下Warning的使用

起因是這樣的,當我使用pymysql模塊執行建表的sql語句時獲,在控制台輸出了紅色的消息,但是程序並沒有終止而是繼續運行了

sql語句如下:

CREATE TABLE IF NOT EXISTS test(age int);

整體代碼:

import pymysql
conn = pymysql.connect(
    user= "root",
    password="",
    database="test"
)

c = conn.cursor()
c.execute("create table if not exists abc(age int)")

得到的警告信息如下:

"""
NoneType: None
/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/pymysql/cursors.py:170: Warning: (1050, "Table 'abc' already exists")
  result = self._query(query)
"""
Process finished with exit code 0

sql語句是如果表存在則放棄創建,這意味着這個警告是應該的,並沒有邏輯上的錯誤,但是這個紅色的消息,讓人看着不爽,於是找到了如下解決方案:

from warnings import filterwarnings
filterwarnings("ignore",category=pymysql.Warning)

問題得到解決,作為強迫症患者,必須在深入研究一下,得出以下結論:

warning模塊中主要的兩個方法

1.warn

該方法用於輸出一個警告信息 
#參數一: message 表示警告的詳細信息
#參數二: category 類別,需要一個類作為參數,該類必須是Warning的子類,Warning類是Exception的子類,用於給警告設置一個具體的類型
#參數三: stacklevel 指定調用棧的層級,用於確定要從哪一級獲取行號
#參數四: 沒研究

stacklevel在源碼中的調用:

image-20190722221550778

上述代碼獲得一個frame,用於獲取行號

image-20190722221746845

由以上源碼可以get到一個小技能即獲取行號

python獲取行號:

import sys
f = sys._getframe() # f 是一個對象class為 frame 但是該類無法直接訪問,猜想是系統底層隱藏的畢竟與解釋器核心數據相關
print(f.f_lineno) # f_lineno就是用於獲取行號的屬性

"""
在源碼中可以看到_getframe函數是可以給一個整型參數的,
經過測試,得出結論,該參數用於,指定從棧的哪一個位置獲取行號,
"""

#測試代碼:
1 import sys
2 def task():
3    f = sys._getframe(2)
4    print(f.f_lineno)
5 
6 def task2():
7    task()
8 
9 task2()

"""
0表示從當前位置,即執行_getframe的地方 
1表示獲取上一級調用位置的行號 即第7行
2表示上上級 即第9行 以此類推...  
"""

2.filterwarnings

該方法用於過濾警告信息 
#參數action:    表示如何處理這個警告
							 可選的值 "error", "ignore", "always", "default", "module","once"
  						 error會將警告作為異常拋出
    					 ignore表示忽略該類警告不會打印
      				 once表示該相同類型相同消息的警告僅打印一次
#參數category:  需要一個類,表示是要過濾的警告類別
#參數module:    需要一個模塊,表示是要過濾的模塊名稱
#參數lineno:		一個整型,表示要過濾哪一行的警告 0表示所有行  其他值貌似沒有作用

意外發現

在查看源碼是,發現了一個用於表示警告消息的類

image-20190722230232847

該類非常簡單,就是保存了一些警告信息,然后覆蓋了 __str__函數,用於自定義字符串形式

其中的初始化函數引起了我的注意,分析了一下,發現這個寫法不錯,可以簡化初始化中的屬性賦值操作於是做了一下實驗:

# 通用的類初始化方法
class Person():
    def __init__(self,a,b,c):
        for k,v in locals().items():
            if k != "self":
                setattr(self,k,v)

p = Person(1,2,3)
print(p.a)
print(p.b)

該方法最大的好處在於,無論初始化方法中需要多少參數都可以一一賦值,對於初始化參數多的類非常友好;

其原理是通過locals()來獲取函數中的局部變量的字典形式,然后遍歷字典,排除self之后其他的都設置為self的屬性,用形參的名字作為熟悉名,大大減少了一堆重復的賦值代碼!

否則你的代碼可能是這樣的:

class Person():
    def __init__(self,a,b,c,d):
        self.a = a
        self.b = b 
        self.c = c
        self.d = d

p = Person(1,2,3,4)
print(p.a)
print(p.b)
print(p.c)

如果參數特比多的話,你懂的......


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM