当前位置: 代码网 > it编程>前端脚本>Python > Python编程中需要避免的21个代码反模式实战详解

Python编程中需要避免的21个代码反模式实战详解

2025年11月25日 Python 我要评论
1.print 语句里手动四舍五入错误示范:value = 3.1415926 print(round(value, 2)) # 这样写并不会报错,但有更好的方式为什么不推荐?这种做法没错,但

1.print 语句里手动四舍五入

错误示范:

value = 3.1415926   
print(round(value, 2))  # 这样写并不会报错,但有更好的方式

为什么不推荐?

这种做法没错,但 python 其实提供了更优雅的方法:

更好的写法:

print(f"{value:.2f}")  # 格式化字符串,简洁又直观

{:.2f} 代表保留两位小数,既美观又避免不必要的 round() 调用。

2.频繁在 numpy 和普通列表之间转换

错误示范:

import numpy as np   
data = [1, 2, 3, 4]   
data_np = np.array(data)   
max_value = max(data_np)  # 这里用了 python 内置的 max,而不是 numpy 的

为什么是坑?

numpy 主要用于高效的数值计算,它的"numpy.max()“速度远快于 python 内置的"max()”,但上面的代码却使用了后者,导致性能下降。

更好的写法:

max_value = np.max(data_np)  # 充分利用 numpy 的优化

在数据分析中,最好一开始就决定用 numpy 或 pandas,并始终保持一致,而不是来回转换。

3.用字符串操作文件路径

错误示范:

filename = "c:\\users\\admin\\documents\\file.txt"   
folder = "c:\\users\\admin\\documents"   
path = folder + "\\" + "file.txt"  # 这样拼接路径很容易出错

为什么不推荐?

直接用字符串拼接路径,不仅代码不优雅,而且不同系统的路径分隔符不同(windows 用 \,linux 和 macos 用 /),这可能导致跨平台问题。

更好的写法:

from pathlib 
import path   
folder = path("c:/users/admin/documents")   
path = folder / "file.txt"  # 使用 pathlib 更安全、可读性更高

"pathlib"让路径操作更直观,能自动适配不同系统的路径格式。

4.写 io 函数时只支持文件路径

错误示范:

def save_data(path, data):       
with open(path, "w") as f:           
f.write(data)

为什么是坑?

上面的函数只支持文件路径,用户无法传入其他类型的 io 对象,比如"stringio"(内存中的文件),或者网络流。

更好的写法:

def save_data(file_obj, data):       
file_obj.write(data)

这样,用户既可以传"open(“file.txt”, “w”)“,也可以传"io.stringio()”,更加灵活。

5.用"+"号拼接字符串

错误示范:

result = ""   
for i in range(100):       
result += str(i)  # 每次拼接都会创建新字符串,效率极低

为什么是坑?

python 的字符串是不可变对象,每次"+"拼接都会生成新字符串,导致性能问题。

更好的写法:

from io 
import stringio   
buffer = stringio()   
for i in range(100):       
buffer.write(str(i))   
result = buffer.getvalue()  # 这样不会频繁创建新字符串

或者:

result = "".join(str(i) for i in range(100))  # 使用 join 拼接更高效

6.用"eval()"解析字符串

错误示范:

data = "{'name': 'alice', 'age': 25}"   
parsed = eval(data)  # 有安全风险!

为什么是坑?

"eval()"可能执行恶意代码,比如:

evil_data = "__import__('os').system('rm -rf /')"   
eval(evil_data)  # 可能导致灾难性后果!

更好的写法:

import json   
parsed = json.loads(data.replace("'", '"'))  # 更安全的解析方式

"json.loads()"只能解析 json,不会执行恶意代码。

7.依赖全局变量存储函数输入/输出

错误示范:

result = none  # 全局变量   
def compute(x, y):       
global result      
result = x + y  # 改变全局变量,增加了函数的副作用

为什么不推荐?

全局变量会导致代码难以维护,函数变得不纯(即依赖外部状态),可能出现意想不到的 bug。

更好的写法:

def compute(x, y):       
return x + y  # 让函数返回值,而不是改写全局变量

这样,"compute()"不会影响外部变量,调用时更安全:

result = compute(3, 5)

8.误以为"and"和"or"只返回布尔值

错误示范:

result = 5 or 10  # 你以为 result 是 true?错,它是 5

为什么是坑?

在 python 中,“or"和"and"不一定返回"true"或"false”,而是返回"第一个确定结果的值":

print(5 or 10)  # 输出 5,因为 5 是真值,or 不再继续判断   
print(0 or 10)  # 输出 10,因为 0 是假值,or 继续检查 10   
print(5 and 10)  # 输出 10,因为 and 需要所有条件都为真   
print(0 and 10)  # 输出 0,因为 and 发现 0 是假值,直接返回

如何避免?

如果你只是想得到"true"或"false",请用"bool()":

is_valid = bool(5 or 10)  # 这样才是标准布尔值

9.变量名全是单个字母

错误示范:

def calc(a, b, c):       
d = a * b + c       
return d

为什么是坑?

这种写法让代码难以阅读,别人(包括你自己)以后再看时,完全不知道 abc 代表什么。

更好的写法:

def calc(price, quantity, discount):       
total = price * quantity + discount       
return total

变量名有意义,代码可读性就会大大提升!

10.“div"和"mod"分开计算,而不是用"divmod()”

错误示范:

quotient = 17 // 5   
remainder = 17 % 5

为什么是坑?

python 早就提供了"divmod()",可以一次性得到商和余数:

quotient, remainder = divmod(17, 5)  # 代码更简洁

这不仅减少了计算次数,也让代码更 pythonic。

11.不知道"@property",还在写 getter/setter

错误示范:

class person:       
def __init__(self, name):           
self._name = name          
def get_name(self):           
return self._name          
def set_name(self, value):           
self._name = value

为什么是坑?

在 python 里,属性访问应该尽量像直接访问变量那样自然。

更好的写法:

class person:       
def __init__(self, name):           
self._name = name          
@property       
def name(self):           
return self._name          
@name.setter       
def name(self, value):           
self._name = value

现在,我们可以这样用:

p = person("alice")   
print(p.name)  # 直接访问,像变量一样   
p.name = "bob"  # 直接赋值

这样写既符合 python 风格,又方便后续扩展(比如添加数据验证)。

12.误把“属性”当“变量”,导致性能问题

错误示范:

class circle:       
def __init__(self, radius):           
self.radius = radius          
@property       
def area(self):           
print("calculating area...")  # 这行会频繁执行           
return 3.14 * self.radius ** 2
c = circle(10)  
 print(c.area)  # 每次访问都计算一次面积   
 print(c.area)  # 计算了两次,浪费性能

为什么是坑?

有些计算量较大的属性(如"area"),不应该每次访问都重新计算。

更好的写法:

from functools 
import cached_property      
class circle:       
def __init__(self, radius):           
self.radius = radius          
@cached_property       
def area(self):           
print("calculating area...")  # 只计算一次           
return 3.14 * self.radius ** 2

这样"area"只会在第一次访问时计算,之后直接返回缓存值,提升性能。

13.在遍历列表时修改它

错误示范:

numbers = [1, 2, 3, 4, 5]   
for num in numbers:       
if num % 2 == 0:           
numbers.remove(num)

为什么是坑?

遍历时修改列表,可能会跳过一些元素。例如:

numbers = [1, 2, 4, 5]   
for num in numbers:       
if num % 2 == 0:           
numbers.remove(num)   
print(numbers)  # 结果为 [1, 4,5](漏删 4)

更好的写法:

numbers = [1, 2, 3, 4, 5]   
numbers = [num for num in numbers if num % 2 != 0]  # 直接用列表推导式   
print(numbers)  # [1, 3, 5]

或者,先复制一份列表:

for num in numbers[:]:       
if num % 2 == 0:           
numbers.remove(num)

14.滥用"map()“和"filter()”

错误示范:

numbers = [1, 2, 3, 4, 5]   
squared = list(map(lambda x: x ** 2, numbers))   
evens = list(filter(lambda x: x % 2 == 0, numbers))

为什么是坑?

虽然"map()"和"filter()"没错,但 python 里有更好的方式——列表推导式。

更好的写法:

squared = [x ** 2 for x in numbers]  # 代码更简洁   
evens = [x for x in numbers if x % 2 == 0]  # 也更易读

这样写既直观又符合 pythonic 风格。

15.乱用 dunder 方法(魔法方法)

错误示范:

class person:       
def __init__(self, name):           
self.name = name          
def __iadd__(self, other):           
print(f"{self.name} 和 {other.name} 成为了朋友!")           
return self
p1 = person("alice")   
p2 = person("bob")   
p1 += p2  # 这真的合适吗??

为什么是坑?

dunder 方法(即双下划线方法)应该遵循 python 语言的预期行为,比如 __add__() 代表加法,而 __iadd__()+=)本该用于数值运算。但这里却用它来实现“成为朋友”的逻辑,让 += 变成了一个不符合直觉的操作。

更好的写法:

class person:       
def __init__(self, name):           
self.name = name           
self.friends = []          
def add_friend(self, other):           
print(f"{self.name} 和 {other.name} 成为了朋友!")           
self.friends.append(other)
p1.add_friend(p2)  # 这样更直观

魔法方法要谨慎使用,否则会让代码变得奇怪且难以理解!

16.用正则解析 html / xml

错误示范:

import re   html = "<div><p>hello, world!</p></div>"   
match = re.search(r"<p>(.*?)</p>", html)   
print(match.group(1))  # 这样做并不靠谱

为什么是坑?

html 是上下文敏感的,不能用正则完美解析,除非页面结构极其简单,否则你迟早会翻车。

更好的写法:

from bs4 import beautifulsoup   
html = "<div><p>hello, world!</p></div>"   
soup = beautifulsoup(html, "html.parser")   
print(soup.p.text)  # 这样解析才靠谱

如果你需要处理 html / xml,请用"beautifulsoup"或"lxml"这类专业的解析库,而不是正则表达式

17.不知道"r"“”(原始字符串)

错误示范:

pattern = "\\d+\\.\\d+"  # 正则表达式匹配浮点数   
print(re.findall(pattern, "the price is 3.14"))

为什么是坑?

\ 在字符串里是转义字符,如果写"\d+",python 会误以为 \d 是转义字符,这会导致正则解析出错。

更好的写法:

pattern = r"\d+\.\d+"  # 使用原始字符串

加个 r"",就能避免转义问题,写正则时 必须养成加 r 的习惯

18.误解"super()"的行为

错误示范:

class a:       
deff(self):          
print("a.f")      
classb(a):       
deff(self):           
print("b.f")           
super().f()      
classc(b):  # 正确继承顺序:c -> b -> a       
deff(self):           
print("c.f")           
super().f()      
c = c()   
c.f()  # 输出顺序为 c.f -> b.f -> a.f    

为什么是坑?

python 采用"c3 线性化"(mro 规则),"super()"并不只是简单地调用父类,而是根据 mro 确定顺序。上面的代码会输出:

c.f   b.f   a.f  # 你以为 b 之后是 a?其实是 b -> a

更好的写法:

print(c.mro())  # 用 .mro() 确认方法解析顺序

使用"super()"前,建议先查看 mro,以免调用顺序与你想象的不同!

19.传递原始字典或元组,而不是用数据

错误示范:

def process_data(data):       
return data["name"].upper(), data["age"] + 1     
person = {"name": "alice", "age": 25}   
print(process_data(person))

为什么是坑?

如果字典键名变了,你的代码就会崩溃,而且代码可读性很差。

更好的写法:

from dataclasses 
import dataclass      
@dataclass   
class person:       
name: str       
age: int      
def process_data(person: person):       
return person.name.upper(), person.age + 1      
p = person("alice", 25)   
print(process_data(p))

用"dataclass"代替字典,代码会更清晰,ide 还能自动补全属性!

20.还在用"namedtuple()“,而不是"namedtuple”

错误示范:

from collections 
import namedtuple   
person = namedtuple("person", ["name", "age"])

为什么是坑?

"namedtuple"需要用字符串定义字段,而且没有类型注解支持。

更好的写法:

from typing 
import namedtuple      
class person(namedtuple):       
name: str       
age: int

使用"namedtuple",不仅更易读,而且支持类型注解,适合现代 python 代码。

21.在导入时执行代码(import-time side effects)

错误示范:

# utils.py   
print("utils module loaded!")  # 只要 import 这个模块,就会执行这行代码
import utils  # 这里会自动输出 "utils module loaded!"

为什么是坑?

模块导入时不应该有副作用!这样会影响性能,并导致意想不到的行为。

更好的写法:

def main():       
print("utils module loaded!")      
if __name__ == "__main__":       
main()  # 只有直接运行这个文件时才执行

用"if name == “main”"保护代码,确保它不会在 import 时执行!

以上就是python编程中需要避免的21个代码反模式实战详解的详细内容,更多关于python反模式的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com