题图:Photo by Andrew Ridley on Unsplash
设计模式是前人多年总结出来的经验,而反设计模式(Anti-Pattern)就是那些违反正确方式写代码的方法,往往这样的代码从可读性、安全性、正确性等方面都有问题。今天列一些平时写代码的坏习惯,避开这些问题使得我们的代码效率更高,可读性更强,Bug更少。
1、使用标准库中的名字
py文件名跟系统自带的模块名一样导致找不到模块是初学者犯错最多的时候,我最开始也犯这样的错,比如学 random 模块时,将自己的文件名也命名为 random.py, 执行的时候报错。为什么?因为 你在import random的时候,解释器有优先从当前目录加载模块,刚好,当前目录有个random.py ,所以就不会去Python的标准库目录找random模块了。
# random.py
import random
print(random.choice([1, 2, 3]))
AttributeError: module 'random' has no attribute 'choice'
2. 使用内建名称作为变量名
程序员最头疼的事情就是如何给变量命名,如何给类命名,如何给函数命名,有种不好的习惯就是我们为了偷懒或者想不出好的名字时,直接使用内建函数或者内建模块的名字来命名,例如:
id = 5
len = 3
list = [1,2,3]
str = "jack"
以上几个变量名都是系统内建函数名称,一旦被你自己的变量名占用后,后面要使用该函数时直接报错
>>> str(1)
TypeError: 'str' object is not callable
最佳的命名方式要做到见名知义,避免与内建函数冲突,如果实在想不到更好的名字,可以考虑加下划线
id_ = 5
length = 3
numbers = [1,2,3]
name = "jack"
3、变量作用域
你第一次碰到下面这段代码的时候,可能你会很惊讶,这怎么会报错?
a = 1
def fun():
a += 2
print(a)
fun()
报 UnboundLocalError 错误
UnboundLocalError: local variable 'a' referenced before assignment
规则:
如果变量在函数中被引用没有被赋值,那么就是全局变量
如果变量在函数的任意位置被赋予过新的值,那么该变量就是局部变量
如果变量在函数中重新赋予了值,又希望是全部变量,则需要用关键字
global
修饰该变量
a = 1
def fun():
global a
a += 2
print(a)
fun()
4、使用可变对象作为默认参数
这个例子可能你在其他地方有看过,如果面试官问题,为什么会这样的时候,你是否能答出来。
def func(i=0, nums=[]):
nums.append(i)
print(i)
print(nums)
func(i=1)
func(i=1)
输出结果
1
[1]
1
[1, 1]
一个函数调用两次,结果却不一样,这是什么原因?初学者以为这是 Python 的 bug,其实这是陷阱,函数自身也是对象,默认参数会作为该函数对象的两个属性存在。类似于:func.i, func.nums。函数创建之后,nums 已经有一个默认值 []
,第一次调用时,相当于 func.nums.append(1), 第二次调用相当于 func.nums.append(2),因为列表是可变对象,所以,每调用一次,就往列表里面增加了一个元素。
正确的实现方法是:
def func(i=0, nums=None):
if nums is None:
nums = []
nums.append(i)
print(i)
print(nums)
func(i=1)
func(i=1)
5、 不使用列表推导式
将一个列表中的所有元素做平方处理,普通的做法就是新建一个列表,逐个迭代计算出每个值的平方,再加入到新数组中。喜欢装X的可能会把代码写的巨难懂,各种技巧都给你用上,最后只为实现一个简单的需求。90% 的情况下,列表推导式可以代替 map、filter 函数。
普通写法
items = [1, 2, 3, 4, 5]
squared = []
for i in items:
squared.append(i**2)
装B写法
items = [1, 2, 3, 4, 5]
squared = list(map(lambda x: x**2, items))
最佳写法
items = [1, 2, 3, 4, 5]
squared = [x**2 for x in items]
6、不使用 enumerate 函数获取列表元素下标索引
在某些场景,不可避免需要用到列表元素中的下标索引位置,一般程序员的做法就是按照最原始C语言的写法
普通写法
color = ["red", "blue", "green"]
for i in range(len(color)):
print(i, color[i])
装B写法
color = ["red", "blue", "green"]
for i, item in zip(range(len(color)), color):
print(i, item)
最佳写法
color = ["red", "blue", "green"]
for i, item in enumerate(color):
print(i, item)
7、使用 from xxx import *
偷懒的程序员喜欢直接 import * ,虽然能节省一些代码,但是 import *里面隐藏着一些潜在的危险。如果 a,b 两个包里面都有一个叫做 foo 的模块,那么其中一个就会被覆盖。正确的做法就是显示地把需要用到的模块 import 进来,如果遇到重名的模块,则用 as 将其重命名。
from a import foo as foo_a
from b import foo as foo_b
8、使用Python2.X
Python2.7 在2020年官方不再维护,现在都2019年了,所以如果你的系统特别是新系统还用Python2.7的话,不失为最差的开发实践,所以,赶紧升级到Python3.6吧
![640?](https://i-blog.csdnimg.cn/blog_migrate/96401ebc6d00ac5f984d10a35b52c04d.jpeg)
长按识别二维码,关注Python之禅