函数的参数
函数传参的基本规则
- 函数的参数默认命名是按照position来赋值的,但是有keyword arguments 的时候, kwargs 的优先级高于position
- 并且函数在传参的时候,positional arguments 一定是在 keyword arguments 的前面, 不然会报错
def main():
def student(name, age, weight, height, loc):
pass
stu1 = student('小明', 18, loc='L.A', height=1.8, weight=150)
if __name__ == '__main__':
main()
*args(可变参数)
- 在 *args 代表了把传入的一个个positionl arguments包装成了一个tuple传入函数
**kwargs(可变关键字参数)
- **kwargs 代表了把传入的一个个 keyword arguments包装成了一个dict传入函数
*(关键字参数)
- 在*后面的参数必须是 keyword arguments
函数传参时 * 的作用
- 在函数传入的tuple和list参数前面加上 * 会把传入的list和tuple里的元素拆成按照原来序列排列的一个一个的 positional arguments
- 在函数传入的set参数前面加上 * 会把传入的set中的key拆散成一个一个无序的 positional arguments
- 在函数传入的dict参数前面加上 * 会把传入的dict中的key拆散成一个一个按照原来序列排列的positional arguments,而自动忽略掉dict中key的value
函数传参时**的作用
- **只能作用于传入函数中的set和dict参数
- 在函数传入的set参数前面加上** 会把传入的set中的key拆散成一个一个无序的 positional arguments,其作用与在set前加上一个*一样
- 在函数传入的dict参数前面加上**会把传入的dict拆散个一个个key与value对应的keyword arguments
在定义函数的时候,参数不能声明为nonlocal,这样会报错
def f(x, y):
nonlocal x
return x + y
高阶函数—f(g(x))
- 一个函数作为另一个函数的参数而调用的行为称为高阶函数
# 通过向函数中传入函数,可以写出更通用的代码
# calc函数中的第二个参数是另一个函数 它代表了一个二元运算
# 这样calc函数就不需要跟某一个特定的二元运算符耦合在一起
# 所以calc函数变得通用性更强 可以由传入的第二个参数决定到底用什么运算符
def calc(my_list, op):
total = my_list[0]
for index in range(1, len(my_list)):
total = op(total, my_list[index])
return total
def my_mul(my_list):
total = 1
for val in my_list:
total *= val
return total
def main():
my_list = [1, 3, 5, 7, 9]
def mul(x, y):
return x * y
print(calc(my_list, mul))
if __name__ == '__main__':
main()
Decorator(装饰器)
- 当我们想增强函数的功能确不想改变函数的定义时,我们可以用Decorator来增强函数
- decorator就是一个返回函数的高阶函数
def fun1(func2):
def func3(a, b):
print('这是装饰器')
return func(a, b)
return func3
# 在 fnuc2 @ func1的时候实际上就是执行了 func2 = func1(func2)语句
@ fun1
def fun2(a, b):
retunrn(a + b)
类之间的关系
Is a 继承关系
继承类称为子类,被继承类称为父类(基类、超类)
方法重写(override): 覆盖/置换/覆写
- 子类在继承父类之后 对方法进行了重新实现
- 当我们给子类对象发送消息时执行的是子类重写过的方法
多态行为
- 因为方法重写,所以不同的类使用同样的方法表现出不同的行为,体现多态行为
Has a 关联关系
- 普通整体和部分的就叫 - 聚合关系 - 强关联
- 如果整体对部分的生命周期负责 - 合成关系 - 最强关联
Use a 依赖关系
合成聚合复用原则
- 复用时要尽量使用组合/聚合关系(关联关系),少用继承
抽象类
- python 没有从语言层面支持抽象类的概念
- 我们可以通过abc模块来制造抽象类的效果
- 在定义类的时候通过制定metaclass = ABCmeta 可以将类声明为抽象类
- 抽象类是不能创建对象的 抽象类存在的意义是专门拿给其它类继承
- abc模块中还有一个包装器abstractmethod
- 通过这个包装器可以将方法包装为抽象方法 必须要求子类进行重写
- from abc import ABCmeta, abstractclassmethod
文件的读写
相对路径与绝对路径
- 从根目录一层一层到文件的位置称为文件的绝对位置
- 以文件为现在的位置为参照而找到其它文件的位置,称为相对位置,在相对位置中,一个点表示当前目录,两个点表示上一级目录,以此类推
open 关键字
- 可以用 open(’file_name’, ‘r’, encoding=’utf-8’)来读取文件中的内容
- 其中r为读取,w为写入,a为追加,如果读、写的是二进制数据,就在后面加b,如rb,wb,ab
def main():
try:
with open('doc.txt', 'rb', encoding='utf-8') as fs:
fs.write('who are you\n')
fs.write('你是谁\n')
fs.write('you can do it')
# content = f.read()
# print(content)
# for line in f:
# print(line)
my_list = fs.readlines()
print(my_list)
except (FileNotFoundError, IOError):
# 可以用元组的方式,也可以用下面的分行模式
print('指定的文件无法打开')
# except IOError as e: #程序调试时,可以让程序报错,也可以用 as 这样的语法
# print(e)
# print('读写文件时出现错误')
print('程序结束')
if __name__ == '__main__':
main()
代码保护机制
from math import sqrt
# try 保护代码
# except 捕获异常
# finally 释放尾部资源
def main():
file_names = ('a.txt', 'b.txt', 'c.txt')
fs_list = []
try:
# 把可能出状况(在执行时有风险的代码)放到 try 代码块保护执行
for filename in file_names:
fs_list.append(open(filename, 'w'))
# except可以写多个分别用于处理不同的异常状况
except FileNotFoundError:
pass
# 如果 try中出现了状况,就可通过except来捕获错误(异常),来进行对应的错误
except IOError:
pass
# 如果没有出现状况那么就可以把无风险的代码放到else中执行
else:
pass
finally:
# 不管程序正常还是异常租后这里的代码一定会执行
# 所以此处最适合释放外部资源的操作
for fs in fs_list:
fs.close()
if __name__ == '__main__':
main()
代码编写的七大原则
单一职责原则
开闭原则
依赖倒转原则(x)
里式替换原则
借口隔离原则(x)
合成聚合复用原则
迪米特法则(最少知识原则)