你可能不知道的Python 技巧小结

1、对输入的字符串“消毒”

对用户输入的内容“消毒”,这问题几乎适用于你编写的所有程序。通常将字符转换为小写或大写就足够了,有时你还可以使用正则表达式来完成工作,但是对于复杂的情况,还有更好的方法:

1

2

3

4

5

6

7

8

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()函数,来生成更大的重映射表(remapping table),并用它来删除字符串中所有的重音。

2、对迭代器切片

如果你尝试直接对迭代器切片,则会得到 TypeError ,提示说该对象不可取下标(not subscriptable),但是有一个简单的解决方案:

1

2

3

4

5

importitertools

s=itertools.islice(range(50),10,20)# <itertools.islice object at 0x7f70fab88138>

forvalins:

...

使用itertools.islice,我们可以创建一个 islice 对象,该对象是一个迭代器,可以生成我们所需的内容。但是这有个重要的提醒,即它会消耗掉切片前以及切片对象 islice 中的所有元素。

(译注:更多关于迭代器切片的内容,可阅读 Python进阶:迭代器与迭代器切片)

3、跳过可迭代对象的开始

有时候你必须处理某些文件,它们以可变数量的不需要的行(例如注释)为开头。 itertools 再次提供了简单的解决方案:

1

2

3

4

5

6

7

8

9

10

11

12

13

string_from_file="""

// Author: ...

// License: ...

//

// Date: ...

Actual content...

"""

importitertools

forlineinitertools.dropwhile(lambdaline:line.startswith("//"), string_from_file.split("\n")):

print(line)

这段代码仅会打印在初始的注释部分之后的内容。如果我们只想丢弃迭代器的开头部分(在此例中是注释),并且不知道有多少内容,那么此方法很有用。

4、仅支持关键字参数(kwargs)的函数

当需要函数提供(强制)更清晰的参数时,创建仅支持关键字参数的函数,可能会挺有用:

1

2

3

4

5

deftest(*, a, b):

pass

test("value for a","value for b")# TypeError: test() takes 0 positional arguments...

test(a="value", b="value 2")# Works...

如你所见,可以在关键字参数之前,放置单个 * 参数来轻松解决此问题。如果我们将位置参数放在 * 参数之前,则显然也可以有位置参数。

5、创建支持 with 语句的对象

我们都知道如何使用 with 语句,例如打开文件或者是获取锁,但是我们可以实现自己的么?是的,我们可以使用__enter__ 和__exit__ 方法来实现上下文管理器协议:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

classConnection:

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 中实现上下文管理的最常见方法,但是还有一种更简单的方法:

1

2

3

4

5

6

7

8

9

10

fromcontextlibimportcontextmanager

@contextmanager

deftag(name):

print(f"<{name}>")

yield

print(f"</{name}>")

with tag("h1"):

print("This is Title.")

上面的代码段使用 contextmanager 装饰器实现了内容管理协议。tag 函数的第一部分(yield 之前)会在进入 with 语句时执行,然后执行 with 的代码块,最后会执行 tag 函数的剩余部分。

6、用__slots__节省内存

如果你曾经编写过一个程序,该程序创建了某个类的大量实例,那么你可能已经注意到你的程序突然就需要大量内存。那是因为 Python 使用字典来表示类实例的属性,这能使其速度变快,但内存不是很高效。通常这不是个问题,但是,如果你的程序遇到了问题,你可以尝试使用__slots__ :

1

2

3

4

5

6

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__的类不能使用多重继承。