關於 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 中實現某些功能時,首先去標準庫裏找一找,如果沒有這個功能,那肯定是你找得不夠仔細,如果實在是沒有,再去找相關的第三方庫。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章