前言
本文是 Clean Code in Python 这本书的第二章书的读书笔记。
本书主要讲述怎么写出更具阅读性、以及更好维护的 python 代码。
第二章主要介绍怎么写出更 Pythonic 的代码。
Indexes and Slices
对于列表和元组这类的数据结构,更 Pythonic 的做法是尽量使用 索引 以及 切片 来操作里面的元素,直接上代码。展示怎么使用 索引
>>> my_numbers = (4, 5, 3, 9)
>>> my_numbers[-1]
9
>>> my_numbers[-3]
5展示使用 切片
>>> my_numbers = (1, 1, 2, 3, 5, 8, 13, 21)
>>> my_numbers[2:5]
(2, 3, 5)
>>> my_numbers[:3]
(1, 1, 2)
>>> my_numbers[3:]
(3, 5, 8, 13, 21)
>>> my_numbers[::]
(1, 1, 2, 3, 5, 8, 13, 21)
>>> my_numbers[1:7:2]
(1, 3, 8)
>>> interval = slice(1, 7, 2)
>>> my_numbers[interval]
(1, 3, 8)
>>> interval = slice(None, 3)
>>> my_numbers[interval] == my_numbers[:3]
True创建自定义序列
想要实现一个自定义的序列类,在类中实现这两个魔术方法即可: __getitem__ 和 __len__。
实现的手段有两种:继承 和 封装。
封装:
class Items:
def __init__(self, *values):
self._values = list(values)
def __len__(self):
return len(self._values)
def __getitem__(self, item):
return self._values.__getitem__(item)
继承:
class UserItems(collections.UserList):
pass
Context Managers
这里记录实现 ContextManager的三种方式。直接在类中实现 __enter__ 和 __exit__
def stop_service():
run("systemctl stop service")
def start_service():
run("systemctl start service")
class ServiceHandler:
def __enter__(self):
stop_service()
return self
def __exit__(self, exc_type, ex_value, ex_traceback):
start_service()
2. 调用contextlib里面的contextmanager装饰器
import contextlib
def stop_service():
run("systemctl stop service")
def start_service():
run("systemctl start service")
@contextlib.contextmanager
def service_handler():
stop_service()
yield
start_service()
3. 自定义装饰器
import contextlib
def stop_service():
run("systemctl stop service")
def start_service():
run("systemctl start service")
class Servicehandler_Decorator(contextlib.ContextDecorator):
def __enter__(self):
stop_service()
def __exit__(self, ext_type, ex_value, ex_traceback):
start_service()
Properties
对于 python 类内属性,如果想要定义属性为私有,更 Pythonic 的做法的使用单下划线,尽量不要使用双下划线。同时尽量使用 Properties 装饰器来为类里面的私有属性提供统一的访问接口。
import re
EMAIL_FORMAT = re.compile(r"[^@]+@[^@]+\.[^@]+")
def is_valid_email(potentially_valid_email: str):
return re.match(EMAIL_FORMAT, potentially_valid_email) is not None
class User:
def __init__(self, username):
self.username = username
self._email = None
@property
def email(self):
return self._email
@email.setter
def email(self, new_email):
if not is_valid_email(new_email):
raise ValueError(
f"Can't set{new_email}as it's not a valid email"
)
self._email = new_email
上面代码使用 property 装饰器修饰操作私有属性 email 的方法,使得该方法同时成为了外部接口,可以在外部定义这个私有变量,并且在接收之前使用了 is_valid_email 方法进行了校验。