如何让你的代码更有python味?
大部分编程语言都有共性,也有个性。下手害怕个性,视为异端,抵触之;上手善用个性,欣欣然,妙用之。
1、三元表达式
别抱怨python没有三元表达式,请看:
intro = None
introduction = "haha" if intro == None or len(intro) == 0 else intro
含义隽永,妙味无穷。千言万语,尽在一行中。
2、*和**的运用
定义:一个星号和两个星号分别对list和dict进行packing和unpacking,
请听题:
v, *end = [10, 20, 30]
# gives v= 1, end = [2, 3]
v, *middle, z= [1, 2, 3, 4]
# gives v= 1, middle = [2, 3], z= 4
v, *middle, z= [1, 2, 3, 4]
# gives v= 1, middle = [2, 3]
传可变参数也是用它们:
def add(*args):
sum = 0
for arg in args:
sum += arg
return sum
def say(**kwargs):
for k,v in kwargs.items():
print(f"{k} = {v}")
有了这两个函数,我们可以这样用:
add(1, 2)
add(1, 2, 3)
say(username='user1', passwd='123')
say(username='user1', passwd='123', age=10)
多方便,多神奇啊。
3、列表的使用
列表能运算,能带表达式,能lambda,请听题:
listOfNones = [None] * 6
# gives [None, None, None, None, None, None]
listOfFives = [[5]] *5
# gives [[5], [5], [5], [5], [5]]
filtered_list = [item for item in sequence if item != x]
## to avoid generating a new object, use generators
filtered_list = (item for item in sequence if item != x)
result = list(map(lambda x:x**2, [i for i in range(3)]))
4、妙用yield
用yield而不是return语句,能改善程序结构,提高执行效率。yield把数据含在嘴里,迭代一次,就往外吐一次数据。
定理:
- 含有yield的函数叫一个生成器
- 一个函数可以有多个yield语句
- 生成器在迭代时才会做真正的计算,每迭代一次就执行一次
def calculate(size):
result = []
for i in range(size):
result.append(i**2)
return result
for val in calculate(1_000_000):
print(val)
改为:
def calculate(size):
for i in range(size):
yield i**2
for val in calculate(1_000_000):
print(val)
这样更节省内存。
典型的使用案例:scrapy中做网页抓取时,每遇到一个url链接,就yield一把,不断往外"吐"链接,如此循环下去,就形成了深度优先遍历。
4、巧用context manager
Python中,我们通常在两类代码块中分配资源:
- try … finally
- with
例如读大文件的典型写法:
with open("data.txt", "r") as f:
text = f.read()
采用context manager能帮我们管理资源申请和释放:
import contextlib
@contextlib.contextmanager
def db_handler():
try:
stop_db()
yield
finally:
start_db()
with db_handler():
db_backup()
这样等价于:
try:
stop_db()
db_backup()
finally:
start_db()
5、活用Namespace and Scope
例子待补充(TODO)
6、记得用def repr(self) -> str:方法
好处是你在日志中方便打印你的类的内容:
class User():
def __init()__:
self.username = ''
self.passwd = ''
def __repr__(self) -> str:
return f"my name is {self.username}, passwd is {self.passwd}"
logger.debug(f"the user is :{user}")
类似于序列化一个对象吧。
7、注意用Mutable 缺省参数
看例子就明白:
def add_to_shopping_cart(food, shopping_cart = []):
shopping_cart.append(food)
return shopping_cart
print(add_to_shopping_cart("egg"))
# ["egg"]
print(add_to_shopping_cart("milk"))
# ["egg","milk"]
def add_to_shopping_cart(food, shopping_cart=None):
shopping_cart = shopping_cart or []
shopping_cart.append(food)
return shopping_cart
print(add_to_shopping_cart("egg"))
# ['egg']
print(add_to_shopping_cart("milk"))
# ["milk"]
8、学会用传参技法
- Positional Arguments: These arguments are parts of the function’s meaning. They appear in the order in which they were written in the original function definition. For example, send_email(title, recipient, body).
- Keyword Arguments: Otherwise known as kwargs, these come in handy when dealing with a function that has many arguments. In that case, kwargs can be used with default values. For example, send_message(message, recipient, cc=None).
- Arbitrary Arguments Tuple: If your function needs an undefined number of arguments, you can use the *args construct to pass a tuple of arguments to the function. For example, def calc_ave(*nums). The nums will be a tuple with as many values as the user wants.
- Arbitrary Keyword Argument Dictionary: Similar to the arbitrary argument tuple, if a function requires an undetermined number of named arguments, you can use the **kwargs construct.
9、此处无声
def collect_account_ids_from_arns(arns):
collected_account_ids = set()
for arn in arns:
matched = re.match(ARN_REGEX, arn)
if matched is not None:
account_id = matched.groupdict()["account_id"]
collected_account_ids.add(account_id)
return collected_account_ids
def collect_account_ids_from_arns(arns):
matched_arns = filter(None, (re.match(ARN_REGEX, arn) for arn in arns))
return {m.groupdict()["account_id"] for m in matched_arns}
def collect_account_ids_from_arns(arns):
return { matched.groupdict()["account_id"] for arn in arns if (matched := re.match(ARN_REGEX, arn)) is not None }
10、学会设计和用Python接口
歌曰:
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.