手动释放资源
在Python中,我们经常要临时调用一些资源来实现某些目的,例如打开文件、连接数据库等。如果因为包括但不限于出错中断、忘了写等各种原因没有正确释放资源,那么资源可能会一直被占用,可能导致其他函数/进程无法使用,或导致资源泄露。
Python的上下文管理器是一种用于管理资源分配和释放的机制,它可以确保资源在使用后能够被正确地关闭或释放,即使运行过程中出现异常。
例子1:文件读写
错误的实现:手动打开和关闭
f = open('a.txt', "w")
f.write('Hello')
f.close()
正确的实现:使用with上下文管理器
with open('a.txt', "w") as f:
f.write('Hello')
例子2:数据库连接
错误的实现:手动打开和关闭数据库连接和游标
import pymysql
# 假设config已经声明了连接配置
connection = pymysql.connect(**config)
cursor = connection.cursor()
cursor.execute("SELECT * FROM users")
result = cursor.fetchall()
cursor.close()
connection.close()
正确的实现:使用with上下文管理器
import pymysql
with pymysql.connect(**config) as connection:
with connection.cursor() as cursor:
cursor.execute("SELECT * FROM users")
result = cursor.fetchall()
混用 == 和 is
==
用于判断值是否相等,is
判断两个对象是否是同一个对象。
在Python中,False == 0
成立。如果我们需要严格判断某个对象是Bool False,那么应该使用is
,例如
def foo() -> int|bool:
pass
result = foo()
if result == False:
print("运行失败")
else:
print(f"运行结果为{result}")
假如foo()
正确运行并返回了0,那么也会被错误地归类于运行失败的情况。
如果我们需要匹配所有 Bool False 等价的值,那,那 也 不 能 用 ==
因为a==False
无法匹配空列表、空字符串、空元组、None等更多的 Bool False 等价的值。
你应该使用
not a
哦对了,我亲爱的上帝,这么写真的很蠢
bool(a) is not True
len(a) is 0
如果非要总结一下的话,那就是,对于单例对象实例(如True
,None
等内置的永生对象)的判断,请直接使用is
。
函数默认实参采用可变对象
我相信,如果没有刻意了解或者被IDE敲打过,大部分初学者都会掉进这个坑里,而且还百思不得其解。
但是上期讲过啦,复习一下吧
使用try…except捕获所有异常
部分人甚至不愿意使用except Exception as e
然后日志记录
这样只会让你默默地无视掉这个错误,然后默默地排查到底哪出错,最后默默地emo。
更有甚者:
import time
while True:
try:
print('Hi')
time.sleep(1)
except:
print('Bye')
恭喜你,ctrl+c杀不掉这个进程,因为KeyboardInterrupt
被except代码块捕获并无视掉了。
当然你可以赌一下在except
代码块的运行期间引发异常
正确的方式,只捕获有限的、已知的、可能的异常类型
try:
foo()
exception ConnectionError:
print("gg")
try:
foo()
exception (ConnectionError, KeyboardInterrupt):
print("Bye")
有生成器和迭代器我不用,诶就是玩
正确的行为
for i in range(1, 11):
print(i)
错误的行为
for i in [1,2,3,4,5,6,7,8,9,10]:
print(i)
外星人行为
for i in [j for j in range(1, 11)]:
print(i)
—分割线—
正确的行为
for i in "Hello, world!":
print(i)
cpp大手子行为
a = "Hello, world!"
for i in range(len(a)):
print(a[i])
—分割线—
写cpp的外星人行为
a = [j for j in range(1, 11)]
for i in range(len(a)):
print(a[i])
生成器和迭代器能够避免在初始化阶段构建整个列表,避免了无谓的内存和CPU消耗,尤其是面对大量数据时。
逻辑表达式混乱
为了你的身心健康,请使用德摩根定律化简逻辑表达式
if !((A and B) or C):
print("OK")
对于上式,可以化简:
not (A and B) and C
(not A or not B) and C
这样清楚多了
当然建议在判断块中再做一次拆分:
if (not A) or (not B):
if C:
另外,哪怕你再熟悉运算次序,也建议通过括号显式地指明
not '' == 0
(not '') == 0
not ('' == 0)