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在源碼中的調用:

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

由以上源碼可以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表示所有行 其他值貌似沒有作用
意外發現
在查看源碼是,發現了一個用於表示警告消息的類

該類非常簡單,就是保存了一些警告信息,然后覆蓋了 __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)
如果參數特比多的話,你懂的......
