欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

关于 Python_你一定没读过的8个技巧

程序员文章站 2023-08-30 15:44:25
介绍 Python 功能和小技巧的文章网上有无数篇,比如变量解压缩,partial 偏函数,枚举可迭代对象... 但关于 Python 我们能说的还有很多。所以今天我将向大家展示一些我知道和有使用过的特性,这些特性在其它文章或博客中很少被提及: 消毒字符串输入 对用户输入内容进行消毒几乎适用于你写的 ......

关于 Python_你一定没读过的8个技巧

介绍 python 功能和小技巧的文章网上有无数篇,比如变量解压缩,partial 偏函数,枚举可迭代对象... 但关于 python 我们能说的还有很多。所以今天我将向大家展示一些我知道和有使用过的特性,这些特性在其它文章或博客中很少被提及:

消毒字符串输入

对用户输入内容进行消毒几乎适用于你写的每一个程序。通常来说转换字符大小写的操作就足够了,有时候用 regex 正则表达式就能完成,但对于比较复杂的情况,我们有更好的办法:

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() 函数来重新生成映射。

迭代器切片

如果尝试对 iterator 进行切片,则会出现 typeerror和"generator object is not subscriptable"的报错,但我们有一个简单的解决办法:

import itertools
s = itertools.islice(range(50), 10, 20) # <itertools.islice object at 0x7f70fab88138>
for val in s:
...

 

通过使用 itertools.islice我们可以创建一个 islice对象,该对象是产生所需项目的迭代器。不过这里需要注意的是,它会消耗所有的生成器项直到切片的开始为止,而且还会消耗 islice对象中的所有项。

跳过可迭代对象的开始部分

有时候你不得不去处理这样一些文件,它们的开头是毫无用处的行,比如注释之类的。itertools再一次地能在这里派上用场:

string_from_file = """
// author: ...
// license: ...
//
// date: ...
actual content...
"""
import itertools
for line in itertools.dropwhile(lambda line: line.startswith("//"), string_from_file.split
print(line)

 

这个代码片段只会生成文件开始注释之后的部分。如果我们只想丢弃可迭代对象开头的某些项(比如这个例子中的注释部分),但不确定这个项的大小,这个方法很实用。

创建支持 with声明的对象

大家想必都知道如何用 with声明来打开文件或者获取锁,但我们能实现自己的 with声明吗?是的,实际上通过使用 enter和 exit我们就可以实现一个上下文管理器协议:

class connection:
def __init__(self):
...
def __enter__(self):
# initialize connection...
def __exit__(self, type, value, traceback):
# close connection...
with connection() as c:
# __enter__() executes
...
# conn.__exit__() executes

 

这是 python 中实现上下文管理最常见的方法,但其实还有一种更简单的方法:

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之前),然后再执行该块,最后执行 tag()剩下的部分。

用 slots节省内存

如果在你编写的程序中会创建某个类的大量实例,那么你肯定已经注意到你的程序会占用大量内存。这是因为 python 使用 dictionary 来表示类实例的属性,虽然它速度很快但内存效率却很低。大部分情况下这个问题并不那么严重,但如果它对你的程序来说是一个大问题,你可以尝试使用 slots:

class person:
__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 使用的是小型的固定大小的数组,而不是 dictionary,这就大大减少了每个实例所需的内存。使用 slots也有缺点——我们无法声明任何新属性,并且只能在 slots上使用它们。同样,带有 slots的类不能使用多重继承。

限制 cpu 和内存使用

如果你不是想通过优化程序来降低它的 cpu 和内存使用率,而是想简单粗暴地直接限制它为某个数字,那么 python 中有一个库可以做到:

import signal
import resource
import os
# to limit cpu time
def time_exceeded(signo, frame):
print("cpu exceeded...")
raise systemexit(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 时间被超出,我们将注册导致系统退出的信号。至于内存方面,我们再次获取软限制与硬限制,并使用带有 size 参数的 setrlimit和获取的硬限制对其进行设置。

控制可导入和不可导入的内容

有些语言对于到处成员变量,方法和接口有着非常明确的机制,比如 golang,在 go 中仅有以大写字母开头的成员才能被导出。另一方面,在 python 中,所有内容都可以到处,除非我们使用 all:

def foo():
pass
def bar():
pass
__all__ = ["bar"]

 

根据上面的代码片段,我们可以看出只有 bar()会被导出。另外,我们可以将 all保留为空,并且从此模块导入时,不会输出任何 attributeerror。

比较运算符的简便方法

python 中有很多比较运算符:lt , le , gt 和 ge,但有没有更容易的方法呢?functools.total_ordering就可以办到:

from functools import total_ordering
@total_ordering
class number:
def __init__(self, value):
self.value = value
def __lt__(self, other):
return self.value < other.value
def __eq__(self, other):
return self.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的过程中,往往因为没有资料或者没人指导从而导致自己不想学下去了,因此我特意准备了个群 592539176 ,群里有大量的pdf书籍、教程都给大家免费使用!不管是学习到哪个阶段的小伙伴都可以获取到自己相对应的资料!

总结

上述的特性与操作都不一定是你在日常 python 编程中常用到的,但其中一些时不时会让你感到头疼。上面所提供的解决方案大多简化了很多任务,这些任务用较为常见的方法处理都会比较冗长无聊。另外要指出的一点是,所有的这些功能都是 python 标准库的一部分。在我看来,其中一些功能类似于“标准库中的非标准功能”,因此每当你想要在 python 中实现某些功能时,首先去标准库里找一找,如果没有这个功能,那肯定是你找得不够仔细,如果实在是没有,再去找相关的第三方库。

 

关于 Python_你一定没读过的8个技巧