Python技巧总结
- 正确使用True和False的判断
false_value = [
[],
{},
False,
'',
0,
0.0,
None,
]
for x in false_value:
print(True if value else False)
- 正确返回None值
一个函数里面可能多个返回值都为True或False,这时候就要用is明确指定返回值,如None - if条件优化
- 直接判断——效率最低
- in list 列表判断——效率最高,推荐
- in set 集合——效率居中
- 字符串格式化技巧
- 直接拼接
'{}'.format
'%s'%()
- python3.6+,
f'I'm {age}'
推荐
- Flat is better than nested
-
import this
可以打印python之禅 - nested 指的是if 嵌套、一层层包裹,不推荐
- flat要代码扁平化,用if、 elif,避免多个if,不满足条件直接返回,推荐
-
- 列表解析,也就是列表推导式
除了减少代码量之外,还能提高运行效率,时间接近原来的一半
示例:
[item for item in items if item%2 == 0]
- 字典解析
示例:
a = [1, 2, 3, 4, 5, 6]
{item:str(item) for item in a}
- 字典合并
- 循环添加,也可以字典解析,但并不推荐
- update更新,d1.update(d2)
- python3.5+,
{**d1, **d2, **d3}
推荐
- 字典安全访问
- 用
try-except
抛出异常
# 默认空返回None,也可以设置
d.get('name','unkown')
- python内置defaultdict
from collection import defaultdict
d_new = defaultdict(lamda:'missing', d)
d_new['name'] # 返回name对应的
d_new['asdf'] # 不存在则返回missing
- 关于for循环,类中实现for循环
- 示例
class A:
def __init__(self):
self.data = []
def add(self, x):
self.data.append(x)
def __iter__(self):
# return self.data.__iter__()
# 这里也可以加一个for循环
for item in self.data:
yield item
class B():
def __init__(self, x, y):
self.x = x
self.y = y
b1 = B(x=1, y=2)
b2 = B(x=3, y=4)
a = A()
a.add(b1)
a.add(b2)
for item in a:
print(item.x, item.y)
- 为什么要使用yield
一次性读取可能会占用太多内存,yield可以提高效率 - 如何在递归调用中使用yield
示例:
import os
path = ''
def get_file(folder_name):
for item in os.listdir(folder_name):
full_path = os.path.join(folder_name, item)
if os.path.isfile(full_path):
yield full_path
elif os.path.isdir(full_path):
# 方法一
for item in get_file(full_path):
yield item
# 方法二,python3
yield from get_file(full_path)
for file_name in get_file(path):
print(file_name)
- 巧用lambda
函数参数为函数时,可以考虑能否用lambda实现
Jupyter shift+tab可以查看信息,比如sort排序传入key - 处理程序中的异常
try-except,可以具体抛出某些异常。
总的如except Exception as e:
具体的如except DNSError:
- 函数默认参数
为函数参数设置默认值 - 可变数量参数
def function(x, *args):
print(args)
function(1,2,3,4)
# 结果
[2, 3, 4]
# 注意: 使用```*args```之后,x就不能赋值了,否则会报错SyntaxError
# 当如下形式时,x必须赋值,否则会报错TypeError:
def function(*args, x):
print(args, x)
function(1,2,x=3)
- 字典和
**kwargs
的关系
实现可变数量位置参数
def function(x, **kwargs):
print(x, kwargs)
function(x=1, a=2, b=3, c=4)
# 运行结果
1 {'a':2, 'b':3, 'c':4}
def sum1(x, y):
print(x+y)
sum(x=1, y=2)
sum(**{'x':1, 'y':'2'})
传入参数```**{'x':1, 'y':2}```与传入参数```x=1, y=2```返回结果一样
- 默认参数陷阱
不建议用列表作为参数
def bad_default_arg(s, time, target=[]):
for _ in range(time):
target.append(a)
return target
bad_default_arg(s='a', time=3) # 返回 ['a', 'a', 'a']
bad_default_arg(s='b', time=3, target='a') # 返回 ['a', 'b', 'b', 'b']
bad_default_arg(s='AB', time=2) # 返回 ['a', 'a', 'a', 'AB', 'AB']
# 使用列表作为参数时,假如不指定,则会使用上一次的默认值
bad_default_arg(s='F', time=2) # 返回 ['a', 'a', 'a', 'AB', 'AB', 'F', 'F']
解决方法:
def good_default_arg(s, time, target=None):
if target is None:
target = []
for _ in range(time):
target.append(a)
return target
- 尽量避免使用
from xxx import *
库中方法可能与已命名方法重名,建议用什么引入什么 - 合理使用virtualenv与pip
- 进入文件,virtualenv --python3.6 env 创建虚拟环境
- 激活环境, source env/bin/activate
- 安装使用的库
- pip freeze,把已安装的库写入txt文件里
- 退出环境, deactivate
- pip install -r xxx.txt 安装所有的依赖
- 类的属性和实例属性
- class类中定义属性,尽量在init下定义
- 或者在class下定义
- 类实例的受保护属性和私有属性
- 加一个下划线_,仍然可以被访问,即受保护
- 加两个下划线,无法被访问,即私有,但是实际上还是可以访问的,只不过名字编程了类名_属性名
class A(object):
"""docstring for A"""
def __init__(self, name, age):
super(A, self).__init__()
self.__name = name
self.__age = age
a = A(name='python', age=27)
a.__age # 无法被访问
- 使用类的property
访问类的属性,需要property,但是是只读的
要修改的话,可以定义setter
class B:
def __init__(self, name, age):
self.__name = name
self.__age = age
@property
def name(self):
return self._name
@property
def age(self):
return self._age
@age.setter
def age(self, value):
self.__age = value
def __str__(self):
print('My name is {} and my age is {}'.format(self.__name, self.__age))
b = B('Demo', 30)
print(b)
b.age = 40 # 可以修改
- tuple元组技巧
- 同时赋值,保证个数一致
- enumerate(),将列表变为元组
a = [1, 2, 3, 4]
for item in enumerate(a):
print(item)
# 返回
(0,1)
(1,2)
(2,3)
(3,4)
- 特殊元组namedtuple
import collections
Student = collections.namedtuple('Student', 'id, name, score')
students = [
Student(1, 'ABC', 90),
Student(2, 'XYZ', 85),
Student(3, 'asdf', 80)
]
# 调用
for s in students:
print('name={}, id={}, score={}'.format(s.name, s.id, s.score))
提高可读性及可维护性,效率并无太大区别
- dict和zip
创建字典
# 1
dict(a=1,b=2)
# 2
data = (('a':1), ('b':2)) # 只要是可迭代对象都行
dict(data)
# 3
# 两个元素数量相同的列表
dict(zip(x,y)) # 生成对应字典
- 字典按照key/value大小排序
dict(sorted(d.items(), key=lambda x:x[1], reverse=True))
- 通过debug学习Python生成器
yield生成器 - string操作技巧
s = ' Last Checkpoint: a few seconds ago (unsaved changes) '
最好是链条式做完,而不是一个一个做
- 列表解析取代map和filter
- 上下文管理
with open
- 一个单独的下划线可以怎么用
- for循环中,不使用i,可用_代替
- 输入1+2返回3,实际上3就赋值给了_
- 取用列表或元组的元素时,无关紧要的可用_代替
-
__str__和__repr__
区别
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return f'name={self.name}, age={self.age}'
def __repr__(self):
return f'name:{self.name}, age:{self.age}'
p = Person('Python', 27)
print(p) # 先找__str__没有再找__repr__,都没有打印地址
p # 命令行中输入p,有__repr__才能返回值,否则返回地址
- 定义自己的exception
from exception import NameTooShort
def validate(name):
if len(name) < 10:
raise NameTooShort('Name is too short.')
try:
validate('test')
except NameTooShort as e:
print(e)
# exceprion.py 文件下
class NameTooShort(ValueError):
pass
# 多个错误可以定义一个基类继承自Exception,其他错误都继承这个基类
- mypy做静态类型检查
def sum(x: int, y: int) -> int: # x、y都是int对象,函数返回int对象
return x + y
if __name__ == '__main__':
print(sum('1', '2')) # 并不会报错,用mypy会提示希望是int,但却是str类型
- 改进的namedtuple
# python3.6+
from typing import NmaedTuple
class Car(NmaedTuple):
color: str
mileage: float
automatic: bool
# 以上类型只是建议,不用对应的类型也不会报错,mypy会报错
car = Car('red', '100.01', False)
car.mileage = 100 # 会报错,因为不支持修改数据
- 用哪种数据结构存储数据
- 为了简单用dict或tuple,字典数据得不到保护,元组数据顺序不能乱
- class,灵活,但是普通class属性还是可以改变的,也可以添加属性
- NamedTuple,定义子类,得到有效保护
- Python3.7+ Data Class
from dataclasses import dataclass
@dataclass
class NewPeple:
name: str
age: int
# 仅仅是提示
p1 = NewPeple('A', 20)
p2 = NewPeple('A', 20)
print(p1, p2) # 普通类还要重写__str__ ,__repr__
print('p1=p2?', p1==p2) # 普通类需要重写__eq__