这些 Python 高效率技巧,一般人都不会
off999 2024-10-15 12:08 23 浏览 0 评论
作者:Martin Heinz
翻译:EarlGrey
原文:https://martinheinz.dev/blog/1
你估计已经看了不少关于 Python 技巧的文章,里面可能会提到变量拆包(unpacking)、局部函数等,但是 Python 还有很多不为人知的高效用法,等待着被人发现。本文将介绍作者纵观全网之后,都属于很少没提及的技巧。
清理字符串输入
清理用户输入的问题,几乎适用于我们可能编写的每个程序。通常将字符转换为小写或大写就足够了,这时只需要使用正则即可,但是对于复杂的情况,有一种更好的方法:
user_input = "This\nstring has\tsome whitespaces...\r\n"
character_map = {
ord('\n') : ' ',
ord('\t') : ' ',
ord('\r') : None
}
user_input.translate(character_map) # This string has some whitespaces... "
在上述示例中,可以看到空格符“ \ n”和“ \ t”已被单个空格替换,而“ \ r”已被完全删除。这是一个简单的示例,但是我们可以更进一步,使用 unicodedata
包及其combining
函数生成范围更广的映射表,从字符串中删除所有重音符号。
迭代器切片
如果您尝试获取迭代器的切片,系统会报 TypeError,提示生成器对象不可下标,但是解决方案很简单:
import itertools
s = itertools.islice(range(50),10,20) # <itertools.islice object at 0x7f70fab88138>
for val in s:
...
使用 itertools.islice
,我们可以创建一个islice
对象,该对象是产生所需元素的迭代器。不过,请务必注意,这会消耗所有生成器项,直到切片开始为止,而且还会消耗我们的“ islice”对象中的所有项。
Using itertools.islice
we can create aislice
object which is an iterator that produces desired items. It's important to note though, that this consumes all generator items up until the start of slice and also all the items in ourislice
object.
跳过可迭代对象的开始
有时候需要处理的文件里,明确存在一些不需要的数据行,但是我们不确定数量,比如说代码中的注释。这时, itertools
再次为我们提供了简洁的方案:
string_from_file = """
// Author: ...
// License: ...
//
// Date: ...
Actual content...
"""
import itertools
for line in itertools.dropwhile(lambda line: line.startswith("//"), string_from_file.split("\n")):
print(line)
这段代码仅在初始注释部分之后,才会产生数据行。如果我们只想在迭代器的开头丢弃数据,而又不知道有具体数量时,这个方法很有用。
仅带关键字参数(kwargs)的函数
有时候,使用仅支持关键字参数的函数可以让代码更加清晰易懂:
def test(*, a, b):
pass
test("value for a", "value for b") # TypeError: test takes 0 positional arguments...
test(a="value", b="value 2") # Works...
只需要在关键字参数前面再加一个 *
参数,就可以轻松实现了。当然,如果还希望再加上位置参数,可以在*
参数前面再增加。
创建支持 with语句的对象
我们都知道如何打开文件或使用 with
语句获取锁,但是怎样自己可以实现类似的功能呢?一般来说,我们可以使用__enter__
和__exit__
方法来实现上下文管理器协议:
classConnection:
def __init__(self):
...
def __enter__(self):
# Initialize connection...
def __exit__(self, type, value, traceback):
# Close connection...
withConnection as c:
# __enter__ executes
...
# conn.__exit__ executes
上面是最常见的实现方式,但是还有一种更简单的方法:
from contextlib import contextmanager
@contextmanager
def tag(name):
print(f"<{name}>")
yield
print(f"")
with tag("h1"):
print("This is Title.")
上面的代码段使用 contextmanager
管理器装饰器实现了内容管理协议。进入“ with”块时,执行“ tag”函数的第一部分(在“ yield”之前),然后执行yield
,最后执行其余部分。
用 __slots__节省内存
如果程序需要创建大量的类实例,我们会发现程序占用了大量内存。这是因为 Python 使用字典来表示类实例的属性,这样的话创建速度很快,但是很耗内存。如果内存是你需要考虑的一个问题,那么可以考虑使用 __slots__
:
classPerson:
__slots__ = ["first_name", "last_name", "phone"]
def __init__(self, first_name, last_name, phone):
self.first_name = first_name
self.last_name = last_name
self.phone = phone
当我们定义 __slots__
属性时,Python会使用固定大小的数组(占用内存少)来存储属性,而不是字典,这大大减少了每个实例所需的内存。不过使用__slots__
还有一些缺点:无法声明任何新属性,我们只能使用__slots__
中的那些属性。同样,带有__slots__
的类不能使用多重继承。
限制CPU和内存使用量
如果不是想优化程序内存或CPU使用率,而是想直接将其限制为某个数值,那么Python也有一个可以满足要求的库:
import signal
import resource
import os
# To Limit CPU time
def time_exceeded(signo, frame):
print("CPU exceeded...")
raiseSystemExit(1)
def set_max_runtime(seconds):
# Install the signal handler and set a resource limit
soft, hard = resource.getrlimit(resource.RLIMIT_CPU)
resource.setrlimit(resource.RLIMIT_CPU, (seconds, hard))
signal.signal(signal.SIGXCPU, time_exceeded)
# To limit memory usage
def set_max_memory(size):
soft, hard = resource.getrlimit(resource.RLIMIT_AS)
resource.setrlimit(resource.RLIMIT_AS, (size, hard))
在这里,我们可以设置了最大cpu运行时间以及最大内存使用限制的两个选项。对于cpu限制,我们首先获得该特定资源( RLIMIT_CPU
)的软限制和硬限制,然后使用参数指定的秒数和先前获取的硬限制来设置。
最后,我们注册了一个在超过CPU时间后,让系统退出的信号。至于内存,我们再次获取软限制和硬限制,并使用带有大小参数的 setrlimit
和硬限制完成配置
控制导入的内容
某些语言提供了导出成员(变量,方法,接口)的显式机制,例如Golang,它仅导出以大写字母开头的成员。但是在Python中,所有对象都会导出,除非我们使用 __all__
:
def foo:
pass
def bar:
pass
__all__ = ["bar"]
上面的代码段中,只会导出 bar
函数。另外,如果__all__
的值为空,那么不会导出任何函数,而且在导入该模块时系统会报AttributeError
。
实现比较运算符
如果我们要逐一为某个类实现所有的比较运算符,你肯定会觉得很麻烦,因为要实现的方法还不少,有 __lt__,__le__,__gt__,
和__ge__
。
其实,Python 提供了一种便捷的实现方式,就是通过 functools.total_ordering
装饰器。
from functools import total_ordering
@total_ordering
classNumber:
def __init__(self, value):
self.value = value
def __lt__(self, other):
returnself.value < other.value
def __eq__(self, other):
returnself.value == other.value
print(Number(20) >Number(3))
print(Number(1) <Number(5))
print(Number(15) >=Number(15))
print(Number(10) <=Number(2))
这是怎么实现的呢? total_ordering
可以用来简化实现类排序的过程。我们只需要定义__lt__
和__eq__
(这是映射剩余操作的最低要求),然后就交给装饰器去完成剩余的工作了。
结语
在日常Python编程时,上述特性并非都是必不可少的和有用的,但是其中某些功能可能会不时派上用场,并能简化冗长且令人讨厌的任务。
还要指出的是,所有这些功能都是Python标准库的一部分,而在我看来,其中一些功能似乎不像是应该在标准库中的功能。
因此,每当你决定要用Python实现某些功能时,都请先在标准库中找一找,如果找不到合适的库,那么可能是因为查找的姿势不对。而且即使标准库里没有,有很大的概率已经存在一个第三方库了!
签到送书计划
自律改变自我!第①期打卡送书活动启动!
相关推荐
- Python函数参数和返回值类型:让你的代码更清晰、更健壮
-
在Python开发中,你是否遇到过这些抓狂时刻?同事写的函数参数类型全靠猜调试两小时发现传了字符串给数值计算函数重构代码时不知道函数返回的是列表还是字典今天教你两招,彻底解决类型混乱问题!让你的...
- 有公司内部竟然禁用了python开发,软件开发何去何从?
-
今天有网友在某社交平台发文:有公司内部竟然禁止了python开发!帖子没几行,评论却炸锅了。有的说“太正常,Python本就不适合做大项目”,还有的反驳“飞书全员用Python”。暂且不说这家公司...
- 写 Python 七年才发现的七件事:真正提高生产力的脚本思路
-
如果你已经用Python写了不少脚本,却总觉得代码只是“能跑”,这篇文章或许会刷新你对这门语言的认知。以下七个思路全部来自一线实战,没有花哨的概念,只有可落地的工具与习惯。它们曾帮我省下大量无意义...
- 用Python写一个A*搜索算法含注释说明
-
大家好!我是幻化意识流。今天我们用Python写一个A*搜索算法的代码,我做了注释说明,欢迎大家一起学习:importheapq#定义搜索节点类,包括当前状态、从初始状态到该状态的代价g、从该状态...
- 使用python制作一个贪吃蛇游戏,并为每一句添加注释方便学习
-
今天来设计一个贪吃蛇的经典小游戏。先介绍下核心代码功能(源代码请往最后面拉):游戏功能:-四个难度等级:简单(8FPS)、中等(12FPS)、困难(18FPS)、专家(25FPS)-美...
- Python 之父 Guido van Rossum 宣布退休
-
Python之父GuidovanRossum在推特公布了自己从Dropbox公司离职的消息,并表示已经退休。他还提到自己在Dropbox担任工程师期间学到了很多东西——Python的类型注解(T...
- 4 个早该掌握的 Python 类型注解技巧
-
在Python的开发过程中,类型注解常常被忽视。但当面对一段缺乏类型提示、逻辑复杂的代码时,理解和维护成本会迅速上升,极易陷入“阅读地狱”。本文整理了4个关于Python类型注解的重要技巧...
- 让你的Python代码更易读:7个提升函数可读性的实用技巧
-
如果你正在阅读这篇文章,很可能你已经用Python编程有一段时间了。今天,让我们聊聊可以提升你编程水平的一件事:编写易读的函数。请想一想:我们花在阅读代码上的时间大约是写代码的10倍。所以,每当你创建...
- Python异常模块和包
-
异常当检测到一个错误时,Python解释器就无法继续执行了,反而出现了一些错误的提示,这就是所谓的“异常”,也就是我们常说的BUG例如:以`r`方式打开一个不存在的文件。f=open('...
- 别再被 return 坑了!一文吃透 Python return 语句常见错误与调试方法
-
Pythonreturn语句常见错误与调试方法(结构化详解)一.语法错误:遗漏return或返回值类型错误错误场景pythondefadd(a,b):print(a+b)...
- Python数据校验不再难:Pydantic库的工程化实践指南
-
在FastAPI框架横扫Python后端开发领域的今天,其默认集成的Pydantic库正成为处理数据验证的黄金标准。这个看似简单的库究竟隐藏着哪些让开发者爱不释手的能力?本文将通过真实项目案例,带您解...
- python防诈骗的脚本带注释信息
-
以下是一个简单但功能完整的防诈骗脚本,包含URL检测、文本分析和风险评估功能。代码结构清晰,带有详细注释,适合作为个人或家庭防诈骗工具使用。这个脚本具有以下功能:文本诈骗风险分析:检测常见诈骗关键...
- Python判断语句
-
布尔类型和比较运算符布尔类型的定义:布尔类型只有两个值:True和False可以通过定义变量存储布尔类型数据:变量名称=布尔类型值(True/False)布尔类型不仅可以自行定义,同时也可通过...
- 使用python编写俄罗斯方块小游戏并为每一句添加注释,方便学习
-
先看下学习指导#俄罗斯方块游戏开发-Python学习指导##项目概述这个俄罗斯方块游戏是一个完整的Python项目,涵盖了以下重要的编程概念:-面向对象编程(OOP)-游戏开发基础-数据...
- Python十大技巧:不掌握这些,你可能一直在做无用功!
-
在编程的世界里,掌握一门语言只是起点,如何写出优雅、高效的代码才是真功夫。Python作为最受欢迎的编程语言之一,拥有简洁明了的语法,但要想真正精通这门语言,还需要掌握一些实用的高级技巧。一、列表推导...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- python计时 (73)
- python安装路径 (56)
- python类型转换 (93)
- python进度条 (67)
- python吧 (67)
- python的for循环 (65)
- python格式化字符串 (61)
- python静态方法 (57)
- python列表切片 (59)
- python面向对象编程 (60)
- python 代码加密 (65)
- python串口编程 (77)
- python封装 (57)
- python读取文件夹下所有文件 (59)
- java调用python脚本 (56)
- python操作mysql数据库 (66)
- python获取列表的长度 (64)
- python接口 (63)
- python调用函数 (57)
- python多态 (60)
- python匿名函数 (59)
- python打印九九乘法表 (65)
- python赋值 (62)
- python异常 (69)
- python元祖 (57)