python自动化测试 第 4 章.函数与代码复用
函数与代码复用
从上往下执行,根据逻辑的过程一条一条去运行,面向过程编程。一步一步的执行。
函数式编程(很难,编程范式,) 面向函数
面向过程, 面向对象,函数编程
看下面一段伪代码:
if cpu使用率 >80%:
连接邮箱
发送邮件
关闭邮箱
if 内存使用率 >80%:
连接邮箱
发送邮件
关闭邮箱
if 硬盘使用率 >80%:
连接邮箱
发送邮件
关闭邮箱
- 面向过程编程
- 优点:逻辑清晰,简单易懂
- 缺点:代码冗余问题,很多重复的代码
1. 函数的概念
把一段具有特定功能的,语句组,用函数名来表示,通过函数名来调用完成功能。
函数也可以看做是一段具有名字的程序,在需要的地方调用执行,不需要在每个执行地方重复编写这些代码。
函数式一种功能的抽象。
- 优点:解决了代码冗余的问题
- 缺点;执行流程不直观(相对面向过程来说会难理解)
2. python中函数的定义
语法:
def 函数名(参数1,参数2,...):
函数体(多行完成特定功能的代码)
return 返回值
原则:
-
函数体最好不要超过一页(太长了不好)
-
功能单一(如果功能太多,有多处要调用时其中某个功能时,调用不方便)
3. 函数的调用过程
- 调用程序在调用处暂停执行后面的程序,先跳转到函数体里面执行函数代码
- 在调用时将实参赋值给函数的形参
- 执行函数体语句
- 函数调用结束返回结果,程序回到调用处向前继续执行
4. 函数的参数
定义函数时 ()里面的参数叫形参(形式参数),就是一个变量名,供函数体里的代码调用
调用函数时,传入()里的参数叫实参(实际参数),它就是实际数据,会传递给形参
4.1 形参
4.1.1 必须参数
必须传递的实际参数
直接定义在函数名后的()里的参数就是必须参数
案例:
定义一个函数,接收两个数,然后打印他们的和
def func(a, b):
print(a+b)
func(1, 2)
4.1.2 默认参数
在函数名后() 中,以参数名=默认值
的形式定义的形参,就叫做默认参数。
案例:
定义一个函数,它接受两个参数content和times,
- content 是函数要打印的内容
- times是函数打印的次数,如果不传递默认打印一次
注意:默认形参必须定义在必须形参的后面
def func(content, times=1):
for _ in range(times):
print(content)
func('Hello, World', times=10) # 调用时,可以不传times,就默认times=1
for循环,当循环变量在循环体中不使用时,常用下划线表示,如上述例子
4.1.3 不定参数
定义函数的时候,不确定调用的时候回传递多少个实参
位置不定参
在函数名的()中,在形参的前面加上一个*号可以定义位置不定参,通常这个形参叫args
args会接收函数调用时,以位置方式传递过来的超过了形参数量的多余的实参,作为元组;
比如:
下述例子中,func定义时定义了1个必须参数和位置不定参,调用时,如果传递了三个参数,即除了前面1个必须参数,剩下的参数会组成一个元组
def func(a, *args):
print(a, args, type(args))
func(1) # 输出1 () <class 'tuple'>
func(1,2) # 输出1 (2,) <class 'tuple'>
func(1,2,3) # 输出1 (2,3) <class 'tuple'>
案例:
定义一个函数,接受2个以上的数,打印它们的和。
def my_sum(x, y, *args):
res = x + y
for i in args:
res = res + i
print(res)
my_sum(1, 2, 3, 4)
关键字不定参
在函数名后的()中,在形参的前面加上**
号,可以定义关键字不定参,通常参数名叫 kwargs
它用来接受函数调用时,以关键字的方式传递过来的多余的实参,并组成一个字典。
def func(a, **kwargs):
print(a, kwargs, type(kwargs))
func(1, b=2) # 1 {'b': 2} <class 'dict'>
func(a=1, b=2, c=3) # 1 {'b': 2, 'c': 3} <class 'dict'>
形参定义的顺序(语法)
必须按照顺序:必须参数,默认参数,位置不定参,关键字不定参
4.2 实参
4.2.1 位置传递
调用函数时,传递实参默认会按照形参的位置一一对应
案例
定义一个函数,实现打印一个数的n次幂
def func(x, n):
res = x**n
print(res)
func(2, 3)
func(3, 2)
4.2.2 关键字传递
传递实参时,以形参名=实参
的形式传递参数,关键字参实参
当一个函数的参数很多的时候,记不住位置的时候,手动指定
注意:关键字参数要放在位置参数的后面
def func(x, n):
res = x**n
print(res)
func(2, n=3) # 等价于func(x=2, n=3) 或func(n=3,x=2)
func( n=3,2) # 会报错,3和2都传给n,x没有传递到参数,关键字参数要放在位置参数的后面
func( 3,x=2) # 会报错,3和2都传给x了
5. 参数解包
*,**
在传递实参的时候的用法也叫参数解包
*
可以在传递实参的时候解包可迭代对象 =》 把迭代对象里的每一个元素按照位置参数依次传入函数
*
解包
def add(x,y,*args):
sum = x + y
for i in args:
sum += i
print(sum)
ls = [i for i in range(10000)]
add(*ls) # 相当于add (ls[0],ls[1],....ls[9999])
add(*range(10000)) # 也等价于这么写,因为range(10000)是一个可迭代对象,可以对其进行解包
列表生成式
ls = [i for i in range(10000)] # 创建0到9999,步长为1的列表
print(ls)
**
解包
在传递实参的时候,可以通过**
对字典对象进行解包
以key=value的关键字的形式传递实参
def connect(host,db,user,pwd,charset):
"""
假装是一个连接数据库的函数
"""
print('你要连接的数据库地址是{},数据库名是:{},用户名:{},密码是:{},字符集是{}'.format(host, db, user, pwd, charset))
db_config = {
'host':'127.0.0.1',
'db':'pye34',
'user' : 'root',
'pwd':'123456',
'charset':'utf-8'
} # 先定义一个字典
connect(**db_config) # 调用函数时用解包方法传参
connect(host=db_config['host'], db=db_config['db'], user=db_config['user'], pwd=db_config['pwd'], charset=db_config['charset']) # 等价于上面的方式,不如上面方式好
6 函数返回值
return 关键字来返回结果,并退出函数。
在函数里一旦执行return 函数就退出了
return 可以返回 0 个,1个,多个函数运行结束后的结果,返回多个值的时候,返回元组(安全,取值高效)
函数可以没有返回值,也就是可以没有return 语句, 这是函数返回None
def add(x, y, *args):
sum = x + y
for i in args:
sum = sum + i
return sum
res=add(1, 2,3)
print(res)
案例:返回多个值
定义一个函数接受被除数x和除数y,返回他们的商和余数
def my_mod(x, y):
s_g = None
y_s = None
if x < y:
s_g = 0
y_s = x
else:
s_g = 0
while x >= y:
x = x-y
s_g += 1
y_s = x
return s_g, y_s
res = my_mod(10,3)
print(res)
如果想返回列表,或者字典,就要在return语句定义好对应类型
def my_mod(x, y):
s_g = None
y_s = None
if x < y:
s_g = 0
y_s = x
else:
s_g = 0
while x >= y:
x = x-y
s_g += 1
y_s = x
return [s_g, y_s] # 返回列表
return {'商': s_g, '余数': y_s} # 返回字典
res = my_mod(10,3)
print(res) # [10, 3],{'商': 3, '余数': 1}
**执行return语句后,函数会终止执行
def is_odd(num):
if num % 2 == 0:
return False
return True # 此处可以省略else语句,因为if的条件成立后,就return False了,程序就已经结束了,如果if条件不成立就跳过return False,继续向下执行,此时就会执行return True了;不是所有的else都能省略,此处是因为有return,比如下面的程序就不能省略else
print(is_odd(1))
score = int(input('输入一个整数'))
if score > 0:
print('正数')
else:
print('非正数') # 不能省略else,如果省略,输入正数时,两个print语句都会执行,也就是说, print('非正数')这个语句是必然执行的
7. lambda函数
匿名函数,用来定义简单的,能够在一行内表示的函数。
语法:
lambda arg1,arg2,...: expression
看下面列子,怎么把成绩从小到大排列
ls = [('语文', 100),('数学', 99),('英语', 88)]
# 试试用列表的排序方法
ls.sort()
print(ls) # 输出[('数学', 99), ('英语', 88), ('语文', 100)]
.sort()这个方法是默认对第一个元素进行排序,也就是(语文,数学,英语),按照第一个字符编码顺序(语,数,英)
help(ls.sort)
查看对应的用法
sort(*, key=None, reverse=False) method of builtins.list instance
Stable sort IN PLACE.
key=None,key是一个函数,是排序的依据,所以要写一个函数来获取列表中各元素的分数
ls = [('语文', 100),('数学', 99),('英语', 88)]
ls.sort()
def sort_by(item): # item是一个二元元组
return item[1] # 获取分数
ls.sort(key=sort_by)
print(ls)
下面程序等价于上面的程序,使用lambda函数的写法更加好
ls = [('语文', 100),('数学', 99),('英语', 88)]
ls.sort()
ls.sort(key=lambda item: item[1]) #利用lambda函数的写法
print(ls)
ls.sort(key=lambda item: item[1], reverse=True) #分数从大到小排列
def fun(x, y):
return x + y
# 等价于下面这个
func = lambda x, y: x+y
lambda 函数一般不会直接定义,通常是作为参数传递给其他函数作为参数使用。
8. 变量作用域
变量能够被访问的范围,就要做作用域。
- 全局作用域 - 全局变量
- 局部作用域 - 局部变量
全局变量能够被函数里访问
s = 1
def fun():
print(s) #在函数里面调用全局变量s
fun()
在函数的外面 不能访问函数里面的变量
def fun():
b = 2 # 局部变量
print(b)
print(b) # 报错
找变量只能从里往外找
b=1
def fun():
b = 2 # 局部变量
print(b)
fun() # 打印出局部变量2
全局变量名和局部变量名重名不起冲突的,一般上不要取重复名字的变量
在函数里面不能直接修改不可变的全局变量,如果是可变的数据类型(如:列表),可以在函数中直接修改
b=1
def fun():
b = b + 2 # 会出现报错,因为函数中没定义变量b,虽然全局变量定义了b,但是函数无法直接修不可变的全局变量
print(b)
fun()
用global改变全局变量(不可变类型)
a = 1
def fun():
global a # 申明 a是全局变量
a += 1
fun()
9. python的内置(内建)函数
import builtins
print(dir(builtins))
大写字母开头的是异常类型,小写开头的是python内置函数
['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BlockingIOError', 'BrokenPipeError', 'BufferError', 'BytesWarning', 'ChildProcessError', 'ConnectionAbortedError', 'ConnectionError', 'ConnectionRefusedError', 'ConnectionResetError', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False', 'FileExistsError', 'FileNotFoundError', 'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'InterruptedError', 'IsADirectoryError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'ModuleNotFoundError', 'NameError', 'None', 'NotADirectoryError', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'PermissionError', 'ProcessLookupError', 'RecursionError', 'ReferenceError', 'ResourceWarning', 'RuntimeError', 'RuntimeWarning', 'StopAsyncIteration', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'TimeoutError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning', 'WindowsError', 'ZeroDivisionError', '__build_class__', '__debug__', '__doc__', '__import__', '__loader__', '__name__', '__package__', '__spec__', 'abs', 'all', 'any', 'ascii', 'bin', 'bool', 'breakpoint', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'exec', 'exit', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'quit', 'range', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip']
常用的内置函数
9.1获取最大/小值,max与min
min(1,2,3)
min([1,2,3])
min('abcdefg')
max('abcdefg')
9.2print函数
print(value,..,sep=' ', end='\n')
- value 会打印 value 的字符串形式
- sep 分隔符,当有多个 value 时默认用空格作为分割
- end 每次打印在最后默认添加回车换行符
打印传入对象的字符串形式
print(1,2,3,sep=',')
1,2,3
print(1,end='')
print(2)
9.3 input
接收用户的输入数据,以字符串的形式返回。
可以接收字符串参数最为提示信息输出
9.4 type
type(object)
返回 object 的类型
9.5 dir
dir([object])
返回传入对象的所有属性和方法名的列表
print(dir(1))
['abs', 'add', 'and', 'bool', 'ceil', 'class', 'delattr', 'dir', 'divmod', 'doc', 'eq', 'float', 'floor', 'floordiv', 'format', 'ge', 'getattribute', 'getnewargs', 'gt', 'hash', 'index', 'init', 'init_subclass', 'int', 'invert', 'le', 'lshift', 'lt', 'mod', 'mul', 'ne', 'neg', 'new', 'or', 'pos', 'pow', 'radd', 'rand', 'rdivmod', 'reduce', 'reduce_ex', 'repr', 'rfloordiv', 'rlshift', 'rmod', 'rmul', 'ror', 'round', 'rpow', 'rrshift', 'rshift', 'rsub', 'rtruediv', 'rxor', 'setattr', 'sizeof', 'str', 'sub', 'subclasshook', 'truediv', 'trunc', 'xor', 'as_integer_ratio', 'bit_length', 'conjugate', 'denominator', 'from_bytes', 'imag', 'numerator', 'real', 'to_bytes']
9.6help
help(builtins.object)
返回内建对象的帮助信息
help(help)
9.7len
len(obj)
返回容器的元素个数
len([1,2,3])
9.8hash
hash(obj)
返回对象的 hash 值
hash('a')
3636161774609400683
9.9iter
iter(iterable)
根据传入的可迭代对象返回一个迭代器
iter('abcd')
<str_iterator at 0x7f98b7dd2eb0>
9.10id
id(obj)
返回传入对象的身份 id(虚拟内存地址的整数形式)
id(1)
4344134656
9.11range
range(stop) -> range object
range(start, stop[,step])
返回一个 range object 对象,产生整数序列
range(10)