目录
- 参考地址:https://github.com/piglei/one-python-craftsman/blob/master/zh_CN/12-write-solid-python-codes-part-1.md
一:SOLID设计原则
S:单一职责原则:
- 原则: 每一个类,应该只有一个职责。
- 解决方案:
- 1: 拆类
- 2: 使用函数
O: 开放-关闭原则:
- 原则: 对拓展开放,对修改封闭。(通过拓展的方式实现别的功能,而不是改变类的内部代码)
- 解决方案:
- 1:类继承: 关键点(在父类种找到会变的部分,抽象成方法,或着属性,最终允许子类重写它,以改变他的行为)
- 2: 组合和依赖注入改造代码。(在A类中,把变化的东西,抽离到B类中,通过将B类传递到A类内部,来改变A类的功能)
- 3: **数据驱动思想改造代码。**关键点(将经常变动的东西,完全以数据的方式抽离出来。当需求变动时,只改动数据,代码逻辑保持不动。)----传参
L: 里氏替换原则:
- 原则: 当你使用继承时,子类(派生类)对象应该可以在程序中替代父类(基类)对象使用,而不破坏程序原本的功能。
- 简言之: 子类的对象,能够完全替换父类对象使用。
- 解决方案:
- 如果该特征是子类和父类的和核心特征,则将这个核心特征写入到父类中,子类对该特征进行修改。
- 保证:子类父类的同名方法返回同一类型的数据。
I: 接口隔离原则:
- 一个接口所提供的方法,应该就是使用方所需要的方法,不多不少刚刚好
D: 依赖倒置原则:
- 高层模块不应该依赖于低层模块,两者都应该依赖于抽象。(难理解)
二: 边界问题
- https://github.com/piglei/one-python-craftsman/blob/master/zh_CN/15-thinking-in-edge-cases.md
1: 吃感冒药胜过看天气预报:
- 使用异常捕获性能消耗小于判断语句:
res = {}
for key in my_list:
if key in res:
res[key] += 1
else:
res[key] = 1
res = {}
for key in my_list:
try:
res[key] += 1
except keyError:
result[key] = 1
2: 容器内容不存在
2.1: defaultdict的使用:
- defaultdict接受一个工厂函数(factory_function)。
- 这个工厂函数可以是int , set, str等等。
- 这样我们的defaultdict如果key不存在的时候,默认返回的是工厂函数的默认值。
from collections import defaultdict
my_list = [1, 2, 1, 3]
result = defaultdict(int)
for key in my_list:
result[key] += 1
print(result)
# defaultdict(<class 'int'>, {1: 2, 2: 1, 3: 1})
2.2: 字典的setdefault方法和pop方法:
-
我们要修改字典的某个键对应的值,但是我们不确定这个键是否存在。
my_dict = {'name': 'liangshan', 'age': 23} my_dict.setdefault('sex', '男') print(my_dict) # {'name': 'liangshan', 'age': 23, 'sex': '男'} my_dict2 = {'name': 'liangshan'} my_dict2.setdefault('friends', []).append('tom') print(my_dict2) # {'name': 'liangshan', 'friends': ['tom']}
-
如果我们删除字典的键,我们要确定是否存在这个键,如果存在则删除。
my_dict = {'name': 'linagshan'} my_dict.pop('age', None) print(my_dict)
2.3:善于运用切片
-
列表访问超过最大索引则会出现下标越界。
# 需求: 对列表前index个求和,但是不知道列表长度 index = 10 my_list = [1, 2, 3] print(sum(my_list[:10])) # 6
3: 危险的OR
-
短路求值特点: 不能执行的不执行。
print(True or (1/0)) # True
-
经典的or操作:
# 需求: 合并两个字典,如果字典为空则不合并 my_dict = {'name': 'liangshan'} my_dict2 = None my_dict.update(my_dict2 or {}) print(my_dict) # {'name': 'liangshan'}
-
注意: or操作对于None, 0,[], {}, set() , 都会默认是假。
- 例如: 我们需要用户输入时间,如果用户没有输入我们默认是60秒。
- 我们就这样写: config.time = time or 60。
- 但是如果用户输入的是: 0, 则因为or的原因,实际上我们时间变成了60。
4: 避免手动数据校验:
-
学习pydantic库,三方校验模块代替自己进行校验:
- 之前的校验逻辑:
def input_10_to_100(num): if not num: print("不能输入为空") if not num.isdigit(): print("请输入数字类型") if not (10 <= int(num) <= 100): print("请输入10到100的数字") pass
- 现在的校验逻辑:
class NumberInput(BaseModel): # 使用类型注解 conint 定义 number 属性的取值范围 number: conint(ge=10, le=100) def input_10_to_100(number): try: number = NumberInput(number = number) except ValidationError as e: print(e) pass