每天都在用的20個Python技巧,讓你從此告別平庸!
Hello,大家好,又到周末了,本來想出去放松一下的,結(jié)果北京的溫度可真辣,36度室外溫度,宛如給每個人隨身配備一個小太陽。想了想還是不出去了,怕被烤熟了??,還是在家擼代碼吧!
今天我將向大家分享日常工作中常用的20個Python技巧,小巧而優(yōu)雅,讓你的代碼更加 Pythonic??
Tip1:單行代碼實現(xiàn)變量值交換
學(xué)過 C 語言的朋友應(yīng)該知道,要想交換兩個變量的值,總是需要借助第三個變量緩存,像這樣:
a = 3;
b = 4;
c = a; a = b; b = c;
但是在Python中,你可以直接調(diào)換順序完成變量值交換:
a: str = 'I love you'
b: int = 520
print(f'Before swap: a = {a}, b = ')
a, b = b, a
print(f'After swap: a = {a}, b = ')
# 多個變量同樣適用
c: str = 'Every single night'
a, b, c = c, a, b
print(f'After swap: a = {a}, b = , c = {c}')
Output:
Before swap: a = I love you, b = 520
After swap: a = 520, b = I love you
After swap: a = Every single night, b = 520, c = I love you
Tip2:序列反轉(zhuǎn)很簡單
對于列表或字符串這類序列,想要反轉(zhuǎn)其元素,其實很簡單,只需要通過切片索引即可一步實現(xiàn):
numbers: list[int] = [1, 2, 3, 4, 5]
greeting: str = 'Hello, Jack!'
print(numbers[::-1]) # [5, 4, 3, 2, 1]
print(greeting[::-1]) # !kcaJ ,olleH
-1表示從后往前逐一遍歷元素。
Tip3:字符串乘法
有些時候,你可能需要輸出同一個字符串多次,初學(xué)者可能會老老實實的手動輸入n次目標字符串。比如,輸出5次“l(fā)ove”,你可能會這樣:
target = 'lovelovelovelovelove'
但其實,你可以通過字符串乘法輕松搞定,達到目的的同時代碼還更簡潔,可讀性更強:
target: str = 'loveloveloveloveloveyou!'
target2: str = ('love' * 5) + 'you!' # 等價于 target
print(target) # loveloveloveloveloveyou!
print(target2) # loveloveloveloveloveyou!
Tip4:單行代碼實現(xiàn)條件賦值
假設(shè)你需要判斷一個整數(shù)是奇數(shù)還是偶數(shù),并將結(jié)果賦給另一個變量,常規(guī)的做法是這樣:
number: int = 10
result: str = None
if number % 2 == 0:
result = 'Even'
else:
result = 'Oddd'
但其實你可以通過單行代碼完成條件賦值:
nubmer: int = 10
result: str = 'Even' if nubmer % 2 == 0 else 'Odd'
print(result) # Even
Tip5:字符串連接有妙招
假設(shè)有如下由字符串構(gòu)成的列表:
names: list[str] = ['John', 'Doe', 'Jack', 'Bob', 'Smith']
需要你用指定分隔符(比如逗號)連接后輸出,初學(xué)Python時,只會老老實實的用加號這樣連接:
result: str = ''
for name in names:
result = result + name + ', '
print(result)
但實際上,調(diào)用字符串的內(nèi)置函數(shù) join() 可以輕松實現(xiàn)按照指定分隔符連接字符串,簡單高效:
# 可以使用任何指定分隔符
print(f'Names: {", ".join(names)}')
print(f'Names: {"---".join(names)}')
Output:
Names: John, Doe, Jack, Bob, Smith
Names: John---Doe---Jack---Bob---Smith
Tip6:使用 get 方法獲取字典元素不報錯
獲取字典元素的常規(guī)方法是通過中括號加鍵值的方式,但是如果訪問的鍵值不存在時,則會報 KeyError 錯誤,中止代碼運行。而如果改用字典的 get 方法的話,則可以完全避免這個問題,并且對于不存在的鍵值,還可以設(shè)置個性化返回默認值。
info: dict[str, str] = {'Name': 'John', 'Age': 25}
# print(info['job']) # 報 KeyError 錯誤
print(info.get('job')) # 返回 None
print(info.get('job', -1)) # 返回指定的默認值 -1
Tip7:使用 setdefault 方法給字典設(shè)置默認值
上一個技巧中,我們講到了用 get 方法獲取字典元素不會報錯,但不會對字典本身做任何修改。這里,我們要說的 setdefault 方法也可以根據(jù)鍵值獲取字典元素,但是如果鍵值不存在,它會向字典中添加一個條目。
scores: dict[str, int] = {'Jack': 100, 'Smith': 50}
jacks_score: int = scores.setdefault('Jack', 102)
print(jacks_score)
james_score: int = scores.setdefault('James', 0)
print(james_score)
print(scores) # 現(xiàn)在 scores 會多出一個條目,即 'James': 0
Output:
100
0
{'Jack': 100, 'Smith': 50, 'James': 0}
提問:你知道為什么最后輸出的字典會多出一個新的條目('James': 0)嗎?
Tip8:簡單便捷的元素計數(shù)器
假設(shè)我們想對序列中所有元素出現(xiàn)的頻次進行計數(shù),可以通過Python內(nèi)置的 Counter 模塊輕松實現(xiàn)。比如:
from collections import Counter
letters: list[str] = ['a', 'b', 'c', 'a', 'a', 'c', 'c', 'd']
counter: Counter = Counter(letters)
print(counter.total()) # Output: 8
print(counter.most_common()) # Output: 每個元素出現(xiàn)次數(shù)構(gòu)成的列表
print(counter.most_common(n=3)) # Output: 出現(xiàn)頻次最高的前3個元素
Output:
8
[('a', 3), ('c', 3), ('b', 1), ('d', 1)]
[('a', 3), ('c', 3), ('b', 1)]
Tip9:便捷高效的 Enumerate
很多時候,我們在對序列進行操作的時候,不僅需要獲取它的元素,還需要元素的索引位置。你不需要再通過別的循環(huán)去實現(xiàn)這個目的,在同一個循環(huán)中即可同時獲取序列的位置和元素:
names: list[str] = ['John', 'Doe', 'Jack', 'Bob']
for idx, name in enumerate(names):
print(f'{idx}: {name}')
Output:
0: John
1: Doe
2: Jack
3: Bob
元素索引默認從0開始,如果你不喜歡,你可以自定義任意起始位置。比如,我們想從1開始,只需要給 enumerate 的 start 參數(shù)傳入指定的值即可。
for idx, name in enumerate(names, start=1):
print(f'{idx}: {name}')
Output:
1: John
2: Doe
3: Jack
4: Bob
Tip10:字典合并很簡單
實際工作中,常常會遇到字典合并的情況,我常用的是以下兩種方式,都很Pythonic:
a: dict[str, int] = {'a': 1, 'b': 2}
b: dict[str, int] = {'c': 3, 'd': 4}
c: dict[str, int] = {**a, **b} # 使用雙 * 號解包字典并合并
d: dict[str, int] = a | b # 使用豎線(|)符號合并字典
a |= b # 直接就地執(zhí)行合并操作,等價于 a = a | b
print(a)
print(c)
print(d)
Output:
{'a': 1, 'b': 2, 'c': 3, 'd': 4}
{'a': 1, 'b': 2, 'c': 3, 'd': 4}
{'a': 1, 'b': 2, 'c': 3, 'd': 4}
其中,第二種類似于數(shù)值四合運算中的 +=, -=, *=, /= 操作。
Tip11:千分位標識符——讓你輸入長串?dāng)?shù)字時不再眼花繚亂
有些時候,在輸入一個很大的數(shù)字時,你可能想知道位數(shù)是否滿足,但是肉眼看的話估計讓你眼花繚亂。這個時候你可以給數(shù)字加上分隔符,Python解釋器會忽略分隔符:
big_number: int = 10000000000000000 # 讓你數(shù)有多少個0你是什么感覺?
print(big_number)
big_number2: int = 10_000_000_000_000_000 # 解釋器會忽略下劃線
print(big_number2)
Output:
10000000000000000
10000000000000000
看這個輸出也挺糟心的,其實,輸出也可以加上千分位標識符:
print(f'{big_number:,}') # 解釋器會自動加上千分位標識符
Output:
10,000,000,000,000,000
這樣看是不是瞬間就友好很多,不至于想砸鍵盤了吧!??
Tip12:__call__ 特殊方法——讓類的實例直接可調(diào)用
假設(shè)我們想要一個乘法計算器,實例化后調(diào)用實例本身即可執(zhí)行乘法運算,可以像下面這樣,只需要在類定義中實現(xiàn) __call__ 特殊方法即可:
class Multiplier:
def __init__(self, value: int) -> None:
self.value = value
def __call__(self, other_value: int) -> int:
return self.value * other_value
double: Multiplier = Multiplier(2)
print(double(10)) # Output: 20
print(double(5)) # Output: 10
Tip13:創(chuàng)建你自己的方法鏈技術(shù)
方法鏈是一種非常高效、簡潔且讓你的代碼更加Pythonic的技術(shù),實際工作中經(jīng)常用到。比如,對字符串的操作:
love: str = 'I love you'
result: str = love.replace('love', '?').replace('you', 'u').upper()
print(result) # I ? U
其實,我們也可以實現(xiàn)自己的方法鏈技術(shù),只需要在類定義中,將方法的返回值設(shè)為實例本身(self)即可。
from typing import Self
class Person:
def __init__(self, name: str, age: int) -> None:
self.name = name
self.age = age
def modify_name(self, new_name: str) -> Self:
self.name = new_name
return self
def modify_age(self, new_age: int) -> Self:
self.age = new_age
return self
jack: Person = Person(name='Jack', age=29)
print(f'{jack.name}: {jack.age}') # Output: Jack: 29
jack.modify_name('Stefan').modify_age(17) # modify_name返回實例本身,因此可以接著調(diào)用類的其他方法
print(f'{jack.name}: {jack.age}') # Output: Stefan: 17
Tip14:讓你的控制臺輸出更友好可讀
在做測試時,如果你想讓你的控制臺輸出更加格式化、友好可讀,可以這樣做:
foods: list[str] = ['Apples', 'Oranges', 'Bananas']
# 可指定任意分隔符
print(*foods, sep=', ', end='.\n')
print(*foods, sep=' -- ', end='.\n')
Output:
Apples, Oranges, Bananas.
Apples -- Oranges -- Bananas.
Tip15:__repr__ 特殊方法——讓類實例具象化
一般情況下,當(dāng)你實例化了一個類后,當(dāng)你輸出該實例化對象后,返回的是該對象在內(nèi)存中的地址信息。像下面這樣:
class Person:
def __init__(self, name: str, age: int) -> None:
self.name = name
self.age = age
jack: Person = Person(name='Jack', age=29)
print(jack) # Output: <__main__.Person object at 0x0000019454570A10>
如果你想要看到實例對象的具體信息,那么你只需要實現(xiàn) __repr__ 特殊方法即可:
class Person:
def __init__(self, name: str, age: int) -> None:
self.name = name
self.age = age
def __repr__(self) -> str:
return f'Person(name="{self.name}", age={self.age})'
jack: Person = Person(name='Jack', age=29)
print(jack) # Output:Person(name="Jack", age=29)
Tip16:更優(yōu)雅的獲取序列首尾元素
正常情況下,對于初學(xué)者來說,如果想要獲取序列的首尾元素,一般通過下標索引獲取,像這樣:
first = target_sequence[0]
last = target_sequence[-1]
但是還有更加Pythonic的方式:
people: list[str] = ['John', 'Doe', 'James', 'Bob', 'Smith', 'Stefan']
first_person, *_, last_person = people
print(first_person, last_person) # Output: John Stefan
print(_) # 你猜這會輸出什么?
Tip17:簡潔高效的控制臺輸出方式——你的調(diào)試好幫手
如果控制臺輸出能像下面這樣的話,我相信你的調(diào)試會更加直觀明了:
name: str = 'Jack'
age: int = 29
print(f'{name=}') # 等價于 print(f'name={name}'),下同
print(f'{age=}')
print(f'{5+10=}')
Output:
name='Jack'
age=29
5+10=15
Tip18:round——四舍五入還可以這么用
number: float = 1314521.56789
print(round(number, 2)) # 這種用法 我們的熟悉,保留小數(shù)點后2位
print(round(number, -1))
print(round(number, -3))
第一種用法是我們所熟知的,即保留n位小數(shù)。那么你猜猜后面兩行會輸出什么呢?????
Tip19:字符串替換
與前面 Tip13類似,其實字符串替換很簡單,而且還支持方法鏈技術(shù)。這個例子只是演示字符串的替換,同時警示替換時要格外小心,否則會出現(xiàn)不期望的結(jié)果。
sentence: str = 'The tired red fox on the red farm ate a bored red pig.'
print(sentence.replace('red', 'XXX'))
print(sentence.replace(' red', ' blue'))
Output:
The tiXXX XXX fox on the XXX farm ate a boXXX XXX pig.
The tired blue fox on the blue farm ate a bored blue pig.
如果 red 的前面不加空格的話,就會將我們不想替換的部分也替換掉。像這樣:
print(sentence.replace('red', ' blue'))
圖片
Tip20:自定義獲取元素最大最小值的方式
假設(shè)有一個字符串列表,你想要獲取它的最大最小值,可以通過內(nèi)置的 max 和 min 方法實現(xiàn),默認按照字母順序排序。
names: list[str] = ['John', 'Doe', 'Jack', 'Bob', 'Smith',
'Timothy', 'Amanda', 'Zebra']
# 默認按字母順序排序
print('Max: ', max(names)) # Output: Max: Zebra
print('Min: ', min(names)) # Output: Min: Amanda
假設(shè)我們想按照字符串長度獲取最大最小值,則可以給 max 和 min 方法的 key 參數(shù)傳遞排序行為即可:
for name in names:
print(name, len(name), sep=': ')
print('Max: ', max(names, key=len))
print('Min: ', min(names, key=len))
John: 4
Doe: 3
Jack: 4
Bob: 3
Smith: 5
Timothy: 7
Amanda: 6
Zebra: 5
Max: Timothy
Min: Doe
提問:如果你仔細觀察的話,Doe 和 Bob 的長度都為3,為什么最小值是 Doe?你知道原因嗎?
此外,如果我們想根據(jù)含有某個字符(比如字母‘a(chǎn)’)數(shù)量的多少來獲取最大最小值,又該如何實現(xiàn)呢?你可以定義一個排序函數(shù),然后傳遞給參數(shù) key 即可:
for name in names:
print(name, name.count('a'), sep=': ')
print('Max: ', max(names, key=lambda x: x.count('a')))
print('Min: ', min(names, key=lambda x: x.count('a')))
Output:
John: 0
Doe: 0
Jack: 1
Bob: 0
Smith: 0
Timothy: 0
Amanda: 2
Zebra: 1
Max: Amanda
Min: John