您尚未遇到的有用的Python技巧

已经写了许多有关有趣的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) # 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必要元素的迭代器。 但是,重要的是要注意,此构造使用了生成器的所有元素,直到切片的开头以及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") # TypeError: test() takes 0 positional arguments... test(a="value", b="value 2") #   - ... 

这对于提高代码的可理解性很有用。 如您所见,通过在命名参数列表前面使用参数*可以轻松解决我们的问题。 在这里,很明显,您还可以使用位置参数-如果将它们放在参数*之前。

创建支持with语句的对象


例如,每个人都知道如何打开文件,或者可能知道如何使用with语句设置锁。 但是可以独立实现锁定控制机制吗? 是的,这是真实的。 执行上下文管理协议是使用__enter____exit__方法实现的:

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

这是在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 #     def time_exceeded(signo, frame): print("CPU exceeded...") raise SystemExit(1) def set_max_runtime(seconds): #   signal     soft, hard = resource.getrlimit(resource.RLIMIT_CPU) resource.setrlimit(resource.RLIMIT_CPU, (seconds, hard)) signal.signal(signal.SIGXCPU, time_exceeded) #     def set_max_memory(size): soft, hard = resource.getrlimit(resource.RLIMIT_AS) resource.setrlimit(resource.RLIMIT_AS, (size, hard)) 

这显示了处理器时间和内存大小的限制。 为了限制程序对处理器的使用,我们首先获取特定资源( 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功能?


Source: https://habr.com/ru/post/zh-CN480356/


All Articles