Python优化代码的技巧分享
作者:工业四次元
短路运算(Short-circuit operation)
咱们都知道,短路运算也就是 ”与 ,或 ,非“ 这几个组成。但是有些时候,我们很多 if-else语句其实可以使用这种短路运算来简写代码的。
例, 获取用户信息,不存在的用户则返回匿名用户, 代码:
def get_user(user): # 常规代码 if user: return user return "匿名用户" # 短路来简写代码 def get_user(user): return user or "匿名用户"
使用短路运算处理,那么就只需要一行代码即可,这样写也挺易读的。
切片替代循环(Slice)
使用切片代替循环或递归来操作序列。切片是一种用于从一个序列(如字符串、列表、元组等)中获取一部分或全部元素的语法。
例,反转数据,代码:
# 使用循环 def reverse(lst): new_lst = [] for i in range(len(lst) - 1, -1, -1): new_lst.append(lst[i]) return new_lst lst = [1, 2, 3, 4, 5] print(reverse(lst)) # [5, 4, 3, 2, 1] # 使用切片 def reverse(lst): return lst[::-1] lst = [1, 2, 3, 4, 5] print(reverse(lst)) # [5, 4, 3, 2, 1]
切片的操作比循环或递归更简单并且高效,因为切片是基于内置函数实现的,而循环或递归是基于自定义函数实现。
列表推导式(List Comprehension)
列表推导式是一种用于从一个可迭代对象(如列表、元组、字典、集合等)创建一个新的列表的简洁的语法。
例,从一个列表中筛选出所有的偶数,并将它们乘以2,代码:
# 使用普通的循环 lst = [1, 2, 3, 4, 5, 6] new_lst = [] for x in lst: if x % 2 == 0: new_lst.append(x * 2) print(new_lst) # [4, 8, 12]
# 使用列表推导式 lst = [1, 2, 3, 4, 5, 6] new_lst = [x * 2 for x in lst if x % 2 == 0] print(new_lst) # [4, 8, 12]
一行代码实现循环、条件判断和赋值等操作,提高了代码的可读性和效率,而且运行速度也更快(可以思考一下为什么更快)。
生成器表达式(Generator Expression)
生成器表达式是一种类似于列表推导式的语法,但是它不会一次性生成一个完整的列表,而是返回一个生成器对象,可以按需逐个产生元素。
例,计算一个列表中所有偶数的平方和,代码:
# 使用普通的循环 lst = [1, 2, 3, 4, 5, 6] sum = 0 for x in lst: if x % 2 == 0: sum += x ** 2 print(sum) # 56
# 使用生成器表达式 lst = [1, 2, 3, 4, 5, 6] sum = sum(x ** 2 for x in lst if x % 2 == 0) print(sum) # 56
这个生成器表达式可以节省内存空间,提高性能,适合处理大量或无限的数据,而且不会占用额外的内存空间,特别适用于读取大批量的数据。当然我们也可以用yeild也能做一个生成器,这个太东西很牛逼。
枚举(Enumerate)
枚举是一种用于同时获取可迭代对象中的元素和索引的函数。枚举可以避免使用额外的变量来记录索引,提高了代码的可读性和效率。
例,打印一个列表中每个元素及其对应的索引,代码:
# 使用普通的循环 lst = ["a", "b", "c", "d", "e"] index = 0 for x in lst: print(index, x) index += 1 # 输出: # 0 a # 1 b # 2 c # 3 d # 4 e
# 使用枚举 lst = ["a", "b", "c", "d", "e"] for index, x in enumerate(lst): print(index, x) # 输出: # 0 a # 1 b # 2 c # 3 d # 4 e
使用枚举的代码更加简洁和清晰,而且不需要手动更新索引。
三元运算符(Ternary Operator)
三元运算符是一种用于根据一个条件表达式来选择两个不同的值的简洁的语法。
例,根据一个数字的正负来赋值一个字符串,代码:
# 使用普通的if-else语句 num = -5 if num > 0: sign = "positive" else: sign = "negative" print(sign) # negative
# 使用三元运算符 num = -5 sign = "positive" if num > 0 else "negative" print(sign) # negative
三元运算符可以用一行代码实现简单的条件判断和赋值,提高了代码的可读性和效率,而且不需要多余的变量和语句。
字典处理条件判断
遇到if循环语句很长的时候,其实可以使用字典来替代,两者的执行效率没有试验过,感觉差不了多少。
例, 使用字典来判断返回值, 代码:
# 使用多个if-elif-else语句 def foo(x): if x == "a": return 1 elif x == "b": return 2 elif x == "c": return 3 else: return -1 print(foo("a")) # 1 print(foo("d")) # -1 # 使用字典 def foo(x): dic = {"a": 1, "b": 2, "c": 3} return dic.get(x, -1) print(foo("a")) # 1 print(foo("d")) # -1
合理利用字典的get方法,可以减少很多代码的使用。
装饰器(Decorator)
装饰器是一种用于在不修改原函数定义和调用的情况下,给函数添加额外的功能或修改其行为的语法。
例,给一个函数添加一个计时的功能,记录其运行时间,代码:
# 使用普通的函数调用 import time def foo(): # do something time.sleep(1) start = time.time() foo() end = time.time() print(f"foo() took {end - start} seconds to run.")
# 使用装饰器 import time def timer(func): def wrapper(*args, **kwargs): start = time.time() result = func(*args, **kwargs) end = time.time() print(f"{func.__name__}() took {end - start} seconds to run.") return result return wrapper @timer # 相当于 foo = timer(foo) def foo(): # do something time.sleep(1) foo()
装饰器能做的事太多了,比如flask 框架,真尼玛装饰器用到飞天。勇哥也就一般用于实现一些通用的功能,如日志、缓存、计时、权限检查等,让代码可复用更强一写。
上下文管理器(Context Manager)
上下文管理器是一种用于在执行某些操作之前和之后自动执行一些预设的操作的语法。上下文管理器可以用于实现一些资源管理的功能,
例如,打开一个文件,读取其内容,并在完成后自动关闭文件,代码:
# 使用普通的try-finally语句 file = open("test.txt", "r") try: content = file.read() print(content) finally: file.close()
# 使用上下文管理器 with open("test.txt", "r") as file: content = file.read() print(content)
使用上下文管理器我们一般用于 打开和关闭文件、获取和释放锁、连接和断开数据库等。代码的安全性问题和可读性也很好处理。
Lambda 表达式(Lambda Expression)
lambda表达式(代替简单的函数定义来创建匿名函数。lambda表达式是一种用于定义一个只有一行代码的函数的简洁的语法。
例,处理排序sorted,指定字段,代码:
lst = [9,2,3,4,5,5,1,2,3] # 不使用lambda表达式 def add(item): return item print(sorted(add, item)) # 使用lambda表达式 print(sorted(lst, key=lambda x:x))
lambda表达式我们一般用来实现一些简单的功能,如排序、过滤、映射等。使用匿名函数,代码有时候少写一些外,还有一点就是 lambda 表达式用完就会在内存中舍弃,也挺好。
map 函数
map函数代替循环来对可迭代对象中的每个元素应用一个函数。map函数是一种用于将一个函数作用于一个可迭代对象中的每个元素,并返回一个新的可迭代对象的函数。
例,将一批字符列表字符串转数字列表,代码:
# 不使用map函数 lst = ["1", "2", "3", "4", "5"] new_lst = [] for x in lst: new_lst.append(int(x)) print(new_lst) # [1, 2, 3, 4, 5] # 使用map函数 lst = ["1", "2", "3", "4", "5"] new_lst = list(map(int, lst)) print(new_lst) # [1, 2, 3, 4, 5]
是不是看起来代码又少了很多,而且这种内置函数,一般速度都比咱们自己写的代码运行效率高,基于这个强大的高阶函数,我们可以用来实现一些批量处理的功能,如类型转换、格式化、计算,数据合并等。
filter 函数
filter函数代替循环来从可迭代对象中筛选出满足一个条件的元素。filter函数是一种用于将一个条件函数作用于一个可迭代对象中的每个元素,并返回一个只包含满足条件元素的新的可迭代对象的函数。
例,从一个列表中挑选符合要求的数据出来组成另一个列表,代码:
# 不使用filter函数 lst = [1, 2, 3, 4, 5] new_lst = [] for x in lst: if x % 2 == 0: new_lst.append(x) print(new_lst) # [2, 4] # 使用filter函数 lst = [1, 2, 3, 4, 5] new_lst = list(filter(lambda x: x % 2 == 0, lst)) print(new_lst) # [2, 4]
filter函数可以用于实现一些筛选和过滤的功能,如删除空值、去重、选择子集等,也是一个很牛的高阶函数。
@properyt 装饰器
@property 装饰器有些时候可以用来替代 geter和setter 方法来管理类书信。这个装饰器装饰的函数会转为一个属性的语法,可以在访问和修改属性的时候,执行一些额外的操作,不用显式调用。
例,对类属性的修改与获取, 代码:
# 不使用@property装饰器 class Person: def __init__(self, name, age): self.name = name self.age = age def get_name(self): return self.name def set_name(self, name): if not isinstance(name, str): raise TypeError("name must be a string") self.name = name def get_age(self): return self.age def set_age(self, age): if not isinstance(age, int): raise TypeError("age must be an integer") if age < 0 or age > 150: raise ValueError("age must be between 0 and 150") self.age = age p = Person("kira", 40) # 实例化 print(p.get_name()) # kira print(p.get_age()) # 40 p.set_name("勇哥") p.set_age(35) print(p.get_name()) # 勇哥 print(p.get_age()) # 35 # 使用@property装饰器 class Person: def __init__(self, name, age): self._name = name self._age = age @property def name(self): return self._name @name.setter def name(self, name): if not isinstance(name, str): raise TypeError("name must be a string") self._name = name @property def age(self): return self._age @age.setter def age(self, age): if not isinstance(age, int): raise TypeError("age must be an integer") if age < 0 or age > 150: raise ValueError("age must be between 0 and 150") self._age = age p = Person("kira", 30) print(p.name) # kira print(p.age) # 30 p.name = "勇哥" p.age = 35 print(p.name) # 勇哥 print(p.age) # 35
从上面的代码,我们就可以了解到@property 可以做的事就很多了,比如实现属性管理,数据验证,类型转换,缓存... 可读性和安全性也不错.
slots属性
来到本文的最后一个要分享的 slots 属性,这个事用来指定一个类可以有那些属性的语法,可以用来替代一下__dict__ 来节省类的内存空间,因为他避免了给每个实例创建一个 dict 属性来存储所有属性和值。一般用于内存优化。
例,指定一个类实例时只有指定的属性,代码:
# 不使用__slots__属性 class Person: def __init__(self, name, age): self.name = name self.age = age p = Person("勇哥", 90) print(p.__dict__) print(p.__sizeof__())
输出:
{'name': '测试玩家勇哥', 'age': 90}
32
# 使用__slots__属性 class Person: # 指定该类只能拥有name和age两个属性 __slots__ = ("name", "age") def __init__(self, name, age): self.name = name self.age = age p = Person("Alice", 20) print(p.__sizeof__()) print(p.__dict__)
输出:
Traceback (most recent call last):
File "D:\app\apitest\debug\ts.py", line 82, in <module>
print(p.__dict__) # AttributeError: 'Person' object has no attribute '__dict__'
AttributeError: 'Person' object has no attribute '__dict__'
32
很明显,这个类已经没有了__dict__属性了,也就是可以减少内存占用,提高访问速度这种玩意,但是也有不好的地方,比如不能多重继承了,也不能添加新属性。要打印出来你限制的属性也就只能dir 或者 getter来获取了。总之小伙伴们看着使用吧。
最后,推荐一款应用开发神器
关于目前低代码在技术领域很活跃!
低代码是什么?一组数字技术工具平台,能基于图形化拖拽、参数化配置等更为高效的方式,实现快速构建、数据编排、连接生态、中台服务等。通过少量代码或不用代码实现数字化转型中的场景应用创新。它能缓解甚至解决庞大的市场需求与传统的开发生产力引发的供需关系矛盾问题,是数字化转型过程中降本增效趋势下的产物。
这边介绍一款好用的低代码平台——JNPF快速开发平台。近年在市场表现和产品竞争力方面表现较为突出,采用的是最新主流前后分离框架(SpringBoot+Mybatis-plus+Ant-Design+Vue3)。代码生成器依赖性低,灵活的扩展能力,可灵活实现二次开发。
以JNPF为代表的企业级低代码平台为了支撑更高技术要求的应用开发,从数据库建模、Web API构建到页面设计,与传统软件开发几乎没有差异,只是通过低代码可视化模式,减少了构建“增删改查”功能的重复劳动,还没有了解过低代码的伙伴可以尝试了解一下。
以上就是Python优化代码的技巧分享的详细内容,更多关于Python优化代码的资料请关注脚本之家其它相关文章!