已经写了许多有关有趣的Python功能的文章。 他们谈论将列表和元组拆包成变量,谈论函数的部分应用,谈论使用可迭代对象。 但是在Python中还有更多的东西。 我们今天翻译的文章的作者说,他想谈谈他使用的某些Python功能。 同时,他还没有遇到对这些可能性的描述,类似于此处给出的描述。 您可能没有在其他任何地方阅读过有关它们的信息。

清除输入字符串数据
清除用户输入的数据的任务几乎与所有程序有关。 通常,此输入处理归结为将字符转换为大写或小写。 有时可以使用正则表达式清除数据。 但是在任务很复杂的情况下,您可以应用更成功的方法来解决它。 例如-这:
user_input = "This\nstring has\tsome whitespaces...\r\n" character_map = { ord('\n') : ' ', ord('\t') : ' ', ord('\r') : None } user_input.translate(character_map)
在这里,您可以看到空白字符
"\n"
和
"\t"
如何用常规空格替换,以及如何从字符串中完全删除字符
"\r"
。 这是一个简单的示例,但我们可以通过使用
unicodedata
包及其
combining()
函数的大型字符重映射表来扩展它。 这种方法允许您从行中删除那里不需要的所有内容。
获取迭代器片
如果尝试获取迭代器的切片,则会遇到
TypeError
错误,这表明您无法订阅生成器对象。 但是,这个问题可以解决:
import itertools s = itertools.islice(range(50), 10, 20)
使用
itertools.islice
方法,可以创建一个
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("\n")): print(line)
该代码仅在位于文件开头的注释块之后返回行。 当您只需要丢弃可迭代对象开始处的元素(在我们的情况下为行),但是其确切数目未知时,这种方法会很有用。
仅支持命名参数的函数(kwargs)
为了在使用某个函数时使其成为可能,以便仅将命名参数传递给该函数,可以执行以下操作:
def test(*, a, b): pass test("value for a", "value for b")
这对于提高代码的可理解性很有用。 如您所见,通过在命名参数列表前面使用参数
*
可以轻松解决我们的问题。 在这里,很明显,您还可以使用位置参数-如果将它们放在参数
*
之前。
创建支持with语句的对象
例如,每个人都知道如何打开文件,或者可能知道如何使用
with
语句设置锁。 但是可以独立实现锁定控制机制吗? 是的,这是真实的。 执行上下文管理协议是使用
__enter__
和
__exit__
方法实现的:
class Connection: def __init__(self): ... def __enter__(self):
这是在Python中实现上下文管理器功能的最常用方法,但是同一件事可以更轻松地完成:
from contextlib import contextmanager @contextmanager def tag(name): print(f"<{name}>") yield print(f"</{name}>") with tag("h1"): print("This is Title.")
在这里,上下文管理协议是使用
contextmanager
装饰器实现的。 输入
with
块时,将执行
tag
函数的第一部分(
yield
之前)。 然后执行该块,然后执行
tag
功能的其余部分。
使用__插槽__节省内存
如果您曾经编写过能够创建大量特定类实例的程序,那么您可能会注意到此类程序可能意外地需要大量内存。 这是因为Python使用字典来表示类实例的属性。 这对性能有很好的影响,但是就内存消耗而言,它的效率很低。 但是,通常,此功能不会引起问题。 但是,如果在类似情况下遇到内存不足的情况,则可以尝试使用
__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使用固定大小的小数组来存储属性,而不是字典。 这严重减少了类的每个实例所需的内存量。 使用
__slots__
属性有一些缺点。 因此,使用它,我们不能声明新的属性,我们只限于
__slots__
属性。 此外,具有
__slots__
属性的类不能使用多重继承。
CPU和内存限制
如果只需要严格限制可用资源,而不是优化程序或改善处理器使用方式,则可以使用适当的库:
import signal import resource import os
这显示了处理器时间和内存大小的限制。 为了限制程序对处理器的使用,我们首先获取特定资源(
RLIMIT_CPU
)的非硬限制(软限制)和硬限制(硬限制)的值。 然后,我们使用
seconds
参数指定的一定
seconds
和先前获得的硬性极限值来设置极限。 之后,我们注册
signal
处理程序,当超过分配给程序的处理器时间时,该
signal
处理程序将启动退出过程。 对于内存,我们再次获取非刚性和硬性限制的值,然后使用
setrlimit
方法设置限制,然后将约束的大小(
size
)和先前获得的硬性限制的值传递给该方法。
控制可以从模块导入什么,不能从模块导入什么
某些语言从变量,方法和接口模块中导出的机制非常清晰。 例如,只有名称以大写字母开头的实体才会导出到Golang。 在Python中,所有内容都会导出。 但仅在使用
__all__
属性之前:
def foo(): pass def bar(): pass __all__ = ["bar"]
在上面的示例中,仅
bar
功能将被导出。 而且,如果将
__all__
属性保留为空,则模块将不会导出任何内容。 尝试从此类模块中导入某些内容将引发
AttributeError
错误。
简化比较运算符的创建
有很多比较运算符。 例如
__lt__
__le__
,
__gt__
,
__ge__
__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))
这里使用
functools.total_ordering
装饰器来简化实现类实例的排序的过程。 为了确保其操作,仅需要声明比较运算符
__lt__
和
__eq__
。 这是装饰器构造其余比较运算符所需的最低要求。
总结
这并不是说我在这里谈论的所有内容在每个Python程序员的日常工作中都是绝对必要的。 但是,这里介绍的一些技术有时会很有帮助。 此外,它们还可以简化问题的解决方案,因为通常的解决方案可能需要大量代码和大量单调的工作。 另外,我想指出的是,讨论的所有内容都是Python标准库的一部分。 老实说,其中一些功能对于标准库似乎有些出乎意料。 这表明,如果有人打算用Python实现一些不太普通的东西,那么他应该首先在标准库中四处逛逛。 如果您不能立即在这里找到所需的东西,那么再次在这里挖掘是值得的,这很值得。 是的,如果彻底的搜索没有成功,那么很可能根本就没有您需要的东西。 如果是这样,那么您应该转向第三方库。 在它们中绝对可以找到它。
亲爱的读者们! 您是否知道乍一看就被称为“标准”的任何标准Python功能?
