網站首頁 編程語言 正文
1. 少使用數字字面量
下面的代碼使用數字來作為判斷條件的語句,如果你從別人手里接手過這部分代碼,很難第一時間理解它的意義。
def mark_trip_as_featured(trip): ? ? """將某個旅程添加到推薦欄目 ? ? """ ? ? if trip.source == 11: ? ? ? ? do_some_thing(trip) ? ? elif trip.source == 12: ? ? ? ? do_some_other_thing(trip) ? ? ... ... ? ? return
我們可以使用枚舉的方式,對這些數字部分做一些說明。
from enum import IntEnum class TripSource(IntEnum): ? ? FROM_WEBSITE = 11 ? ? FROM_IOS_CLIENT = 12 def mark_trip_as_featured(trip): ? ? if trip.source == TripSource.FROM_WEBSITE: ? ? ? ? do_some_thing(trip) ? ? elif trip.source == TripSource.FROM_IOS_CLIENT: ? ? ? ? do_some_other_thing(trip) ? ? ... ... ? ? return
將重復出現的數字定義成枚舉類型,不僅改善了代碼的可讀性,還降低了代碼出現 Bug
的機率。
當然不是所有的數字都需要用到枚舉說明,像常見數字下標 0 和 -1
就不需要。
2. 裸字符串處理的問題
“ 裸字符串處理 ” 這里指只使用基本的加減乘除和循環、配合內置函數/方法來操作字符串,獲得我們需要的結果。
def fetch_users(conn, min_level=None, gender=None, has_membership=False, sort_field="created"): ? ? """獲取用戶列表 ? ? ? ? :param int min_level: 要求的最低用戶級別,默認為所有級別 ? ? :param int gender: 篩選用戶性別,默認為所有性別 ? ? :param int has_membership: 篩選所有會員/非會員用戶,默認非會員 ? ? :param str sort_field: 排序字段,默認為按 created "用戶創建日期" ? ? :returns: 列表:[(User ID, User Name), ...] ? ? """ ? ? # 一種古老的 SQL 拼接技巧,使用 "WHERE 1=1" 來簡化字符串拼接操作 ? ? # 區分查詢 params 來避免 SQL 注入問題 ? ? statement = "SELECT id, name FROM users WHERE 1=1" ? ? params = [] ? ? if min_level is not None: ? ? ? ? statement += " AND level >= ?" ? ? ? ? params.append(min_level) ? ? if gender is not None: ? ? ? ? statement += " AND gender >= ?" ? ? ? ? params.append(gender) ? ? if has_membership: ? ? ? ? statement += " AND has_membership == true" ? ? else: ? ? ? ? statement += " AND has_membership == false" ? ?? ? ? statement += " ORDER BY ?" ? ? params.append(sort_field) ? ? return list(conn.execute(statement, params))
這樣做雖然看起來簡單,符合直覺,但是隨著函數邏輯變得復雜,這段代碼會變得容易出錯。
更好的選擇是利用一些開源的對象化模塊來操作他們。
這里使用了 SQLAlchemy
。
def fetch_users_v2(conn, min_level=None, gender=None, has_membership=False, sort_field="created"): ? ? """獲取用戶列表 ? ? """ ? ? query = select([users.c.id, users.c.name]) ? ? if min_level is not None: ? ? ? ? query = query.where(users.c.level >= min_level) ? ? if gender is not None: ? ? ? ? query = query.where(users.c.gender == gender) ? ? query = query.where(users.c.has_membership == has_membership).order_by(users.c[sort_field]) ? ? return list(conn.execute(query))
其它的替換思路:
Q: 目標/源字符串是結構化的,遵循某種格式嗎?
其它的開源的對象化模塊。
- SQL:SQLAlchemy
- XML:lxml
- JSON、YAML …
嘗試使用模板引擎而不是復雜字符串處理邏輯來達到目的。
- Jinja2
- Mako
- Mustache
3. 展開復雜的計算字面量表達式
def f1(delta_seconds): ? ? # 如果時間已經過去了超過 11 天,不做任何事 ? ? if delta_seconds > 950400: ? ? ? ? return? ? ? ...
“為什么我們不直接把代碼寫成 if delta_seconds < 11 * 24 * 3600: 呢?”
“性能”,答案一定會是“性能”。 Python 是一門解釋型語言,所以預先計算出 950400 正是因為我們不想讓每次對函數 f1 的調用都帶上這部分的計算開銷。
不過事實是:即使我們把代碼改成 if delta_seconds < 11 * 24 * 3600:,函數也不會多出任何額外的開銷。
當我們的代碼中需要出現復雜計算的字面量時,請保留整個算式吧。它對性能沒有任何影響,而且會增加代碼的可讀性。
def f1(delta_seconds): ? ? if delta_seconds < 11 * 24 * 3600: ? ? ? ? return
4.實用技巧
4.1布爾值也是數字
True
和 False
可以當成 1 和 0 使用
>>> True + 1 2 >>> 1 / False Traceback (most recent call last): ? File "", line 1, in ZeroDivisionError: division by zero
計數簡化操作。
>>> l = [1, 2, 4, 5, 7] >>> sum(i % 2 == 0 for i in l) 2
如果將某個布爾值表達式作為列表的下標使用,可以實現類似三元表達式的目的:
# 類似的三元表達式:"Javascript" if 2 > 1 else "Python" >>> ["Python", "Javascript"][2 > 1] 'Javascript'
4.2改善字符串的可讀性。
對于字符串我們常使用 \ 和 + 來講字符串拆分成好幾段。
還有一種簡單的方法是用 ()。
用 ()括起來就可以隨意拆行了。
s = ( ? ? "There is something really bad happened during the process. " ? ? "Please contact your administrator." )
對于多級縮進字符串:
可以調用其他的標準庫來達到簡化效果。
from textwrap import dedent def main(): ? ? if user.is_active: ? ? ? ? # dedent 將會縮進掉整段文字最左邊的空字符串 ? ? ? ? message = dedent("""\ ? ? ? ? ? ? Welcome, today's movie list: ? ? ? ? ? ? - Jaw (1975) ? ? ? ? ? ? - The Shining (1980) ? ? ? ? ? ? - Saw (2004)""")
大數字也可以變得更加可閱讀:
在數字之間加入下劃線。
>>> 10_000_000.0 ?# 以“千”為單位劃分數字 10000000.0 >>> 0xCAFE_F00D ?# 16進制數字同樣有效,4個一組更易讀 3405705229 >>> 0b_0011_1111_0100_1110 ?# 二進制也有效 16206 >>> int('0b_1111_0000', 2) ?# 處理字符串的時候也會正確處理下劃線 240
4.3以 r 開頭的內建字符串函數。
例如 : .split() 和 .rsplit() 的區別是,一個從左到右分割字符串,另一個是從右到左處理字符串。
合理使用一些現成 string 操作函數可以讓工作事半功倍。
4.4 float (" inf ")
float ( " inf " )
和 float ( " -inf ")
,對應著無窮大和無窮小。
float( " -inf ") < 任意數值 < float( " inf ")
一些可以用上的場合。
# A. 根據年齡升序排序,沒有提供年齡放在最后邊 >>> users = {"tom": 19, "jenny": 13, "jack": None, "andrew": 43} >>> sorted(users.keys(), key=lambda user: users.get(user) or float('inf')) ['jenny', 'tom', 'andrew', 'jack'] # B. 作為循環初始值,簡化第一次判斷邏輯 >>> max_num = float('-inf') >>> # 找到列表中最大的數字 >>> for i in [23, 71, 3, 21, 8]: ...: ? ?if i > max_num: ...: ? ? ? ? max_num = i ...: >>> max_num 71
5.常見誤區
5.1“value += 1” 并非線程安全
如下:這個操作并不是線程安全的。
這個簡單的累加語句,會被編譯成包括取值和保存在內的好幾個不同步驟。
而在多線程環境下,任意一個其他線程都有可能在其中某個步驟切入進來,阻礙你獲得正確的結果。
def incr(value): ? ? value += 1 # 使用 dis 模塊查看字節碼 import dis dis.dis(incr) ? ? ? 0 LOAD_FAST ? ? ? ? ? ? ? ?0 (value) ? ? ? 2 LOAD_CONST ? ? ? ? ? ? ? 1 (1) ? ? ? 4 INPLACE_ADD ? ? ? 6 STORE_FAST ? ? ? ? ? ? ? 0 (value) ? ? ? 8 LOAD_CONST ? ? ? ? ? ? ? 0 (None) ? ? ?10 RETURN_VALUE
常用 dis
模塊去驗證自己的操作,有時候,結果和我們預想的并不一樣。
5.2字符串拼接并不慢
Python 的字符串拼接(+=)在 2.2 以及之前的版本確實很慢。
但之后的版本做了更新,效率已經大大提升,所有字符串的拼接還是可以使用的。
原文鏈接:https://blog.csdn.net/weixin_46442179/article/details/123559908
相關推薦
- 2022-01-14 path.join()和path.resolve()區別
- 2022-06-22 Git配置用戶簽名方式及原因說明_其它綜合
- 2022-12-04 C#目錄和文件管理操作詳解_C#教程
- 2022-04-20 聊一聊數據請求中Ajax、Fetch及Axios的區別_AJAX相關
- 2022-10-24 Python?NumPy教程之遍歷數組詳解_python
- 2022-09-08 C++實現Dijkstra算法的示例代碼_C 語言
- 2022-12-24 c++類成員函數如何做函數參數_C 語言
- 2022-09-20 Android畫圖實現MPAndroidchart折線圖示例詳解_Android
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支