一、函数
函数是实现特定功能的代码段的封装,在需要时可以多次调用函数来实现该功能
1. 内置函数
Python内置了许多非常有用的函数,可以直接调用
2. 自定义函数
语法:
def 函数名(形参1,形参2,...):
函数体
注意:
- 函数名可以包含数字、字母、下划线,但不能以数字开头
- 如果函数有返回值,使用return关键字
- 定义函数后函数中的代码并不会执行,需要调用函数才会执行
# 定义函数,使用def
def calc(num1, num2): # 必选参数,也称为位置参数,不能省略
res = num1 + num2
return res
# print(calc(3, 5)) # 调用函数
# 参数类型检查
def my_abs(x):
# 可以为函数添加文档注释,也称为文档字符串doc string
""" 计算绝对值 :param x: 参数 :return: 返回x的绝对值 """
# 对参数类型进行检查
if not isinstance(x, (int, float)):
raise TypeError('参数类型不正确,只能为数值类型')
# 抛出异常
if x >= 0:
return x
else:
return x
# print(my_abs('aaa'))
# print(help(my_abs))
# 默认参数,即有默认值的参数
def my_pow(x, y=2):
if y == 0:
return 1
res = x
for i in range(y - 1):
res *= x
return res
# print(my_pow(5))
# 可变参数,使用*号,表示参数个数是可变的
def my_sum(x, *y):
print(x)
print(y) # 接收到的实际上是一个tuple
# my_sum(3, 5, 8, 12, 4)
# 不建议下面的这种写法,建议将必选参数放在最前面
def my_sum2(*y, x):
print(y)
print(x)
my_sum2(12, 4, 2, 7, x=9) # 必选参数在后面时需要指定参数名
# 对于可变参数,可以直接传入list或tuple,只需要在参数前添加一个*
nums = [12, 4, 2, 64, 23, 9]
# my_sum(4, nums[0], nums[1], nums[2], nums[3], nums[4], nums[5])
# my_sum(4, *nums) # 关键字参数,使用**,也表示参数个数是可变的,但传递的是带名称的参数
def f1(x, **y):
print(x)
print(y) # 接收到的实际上一个dict
# f1(3, a=5, b=9, c=18)
# 对于关键字参数,可以直接传入一个dict,只需要在参数前添加**
user = {'id': 1001, 'name': 'tom', 'age': 18}
# f1(4, id=user['id'], name=user['name'], age=user['age'])
# f1(4, **user)
# 命名关键字参数,限制关键字参数的名字,使用*分隔,*号后面的参数表示命名关键字参数
def f2(x, *, name, age):
print(x)
print(name)
print(age)
# f2(4, name='alice', age=20)
# 接收任意参数
def f3(*args, **kwargs):
print(args)
print(kwargs)
f3(1, 43, 'aaa', name='alice', age=20)
# 空函数,表示以后再实现
def empty():
pass # 使用pass
# 函数的返回值,返回多个值
def f1():
name = 'tom'
age = 20
sex = 'male'
return name, age, sex
# print(f1()) # 返回值实际上是一个tuple
a, b, c = f1()
# print(a, b, c)
# 函数的返回值,返回一个函数,即将函数作为返回值
def f2(x):
print(111)
z = 6
def f3(y):
print(x * y+z) # 内部函数使用了外部函数的参数或局部变量,称为闭包
return f3
# fn = f2(3)
# fn(5)
# 递归函数:一个函数在内部调用自身,这个函数就是递归函数
# 计算x的y次方,如计算2的5次方
def calc(x, y):
# 常规方式
# if y == 0:
# return 1
# i = 1
# res = x
# while i < y:
# res *= x
# i += 1
# return res
# 递归方式
# 2*2*2*2*2=2*(2*2*2*2)=2*(2*(2*2*2))=
if y == 0:
return 1
else:
return x * calc(x, y-1) # 不停的调用自己,递归太深可能会抛出栈溢出异常
print(calc(2, 99999999999999))
3. 变量作用域和命名空间
'''
变量作用域scope:指的是变量生效的区域
两种作用域:
1.全局作用域
函数以外的区域都是全局作用域
在全局作用域中定义的变量,都是全局变量
2.函数作用域,也称为局部作用域
函数内的区域,每调用一次函数就会创建一个新的函数作用域
在函数作用域中定义的变量,都是局部变量
变量的查找顺序:
先在当前作用域中查找,如果没有则向上一级作用域中查找,直到查找全局作用域,如果还是没有,则报错
'''
a = 5 # 全局变量
if True:
c = 5 # 全局变量,在Python中没有块级作用域
def fn():
b = 8 # 局部变量
print('函数内部:a=', a)
print('函数内部:b=', b)
print('函数内部:c=', c)
fn()
print('函数外部:a=', a)
# print('函数外部:b=', b)
print('函数外部:c=', c)
x = 1
def f1():
x = 2
def f2():
x = 3
print(x)
print('' * 80)
# global关键字
def fn2():
# a = 10 # 在函数中为变量赋值时,默认都是为局部变量赋值
# 如果希望在函数中修改全局变量,要使用global关键字来声明变量
global a
a = 10
print('函数内部:a=', a)
fn2()
print('函数外部:a=', a)
print('*' * 80)
'''
命名空间namespace:指的是变量存储的位置,每一个变量都要存储在指定的命名空间中
每个作用域都有一个对应的命名空间
全局命名空间,用来存储全局变量;函数命名空间,用来存储函数中的变量
命名空间实际上就是一个字典dict,是一个专门用来存储变量的字典
'''
# locals() 获取当前作用域的命名空间
scope = locals() # 在全局作用域中调用locals(),获取的就是全局命名空间
print(scope)
print(type(scope))
# 通过scope操作命名空间中的变量(不建议)
print(scope['a'])
scope['c'] = 666
scope['z'] = 'tom'
print(scope['c'])
print(scope['z'])
# print(z)
print('*' * 80)
def fn3():
a = 888
scope = locals() # 在函数中调用locals(),获取到的是函数命名空间
scope['b'] = 222
print(scope)
print(scope['b'])
# globals() 可以在任意位置获取全局命名空间
global_scope = globals()
print(global_scope)
print(global_scope['a'])
fn3()
4. 高级特性
迭代和列表生成式
# 导入模块
import collections
'''
迭代:也称为遍历,循环获取每一个元素
'''
for i in ['tom', 'jack', 'alice']:
print(i, end=' ')
print()
for i in ('tom', 'jack', 'alice'):
print(i, end=' ')
print()
for i in {'name': 'tom', 'age': 18, 'sex': 'male'}.keys():
print(i, end=' ')
print()
for k, v in {'name': 'tom', 'age': 18, 'sex': 'male'}.items():
print(k, v)
for i in 'hello':
print(i)
# 判断对象是否是可迭代的
print(isinstance('hello', collections.Iterable))
# 获取索引和值
# 方式1:自己获取索引
names = ['tom', 'jack', 'alice']
for i in range(len(names)):
print(i, names[i])
# 方式2:使用enumerate()函数,转换为索引元素对
print(enumerate(names))
print(isinstance(enumerate(names), collections.Iterable))
for k, v in enumerate(names):
print(k, v)
print('' * 80)
'''
列表生成式:用来创建list的生成式
'''
# 生成[0,99]的list
# nums = range(0, 100)
nums = list(range(0, 100)) # 转换为list
# print(nums, type(nums))
# print(isinstance(range(0, 100), collections.Iterable))
# for i in range(0, 100):
# print(i)
# 生成一个包含[1,100]之间所有3的倍数的list
# 方式1
# lst = []
# for i in range(1, 101):
# if i % 3 == 0:
# lst.append(i)
#方式2
lst = [i for i in range(1, 101) if i % 3 == 0] # 等价于a = list(range(1, 101))
print(lst)
迭代器和生成器
'''
迭代器iterator:用来访问集合元素的一种方式,可以记住迭代的位置
'''
nums = [3, 8, 12, 54, 2, 7]
it = iter(nums) # 调用iter()函数创建迭代器
print(type(it))
print(next(it)) # 调用next()函数获取迭代器的下一个元素
print(next(it)) # 只能往前不能后退
# 使用for...in循环遍历迭代器
for i in it:
print(i)
'''
生成器generator:在循环过程中依次计算获取值的对象(节省空间、效率高)
创建生成器的方式:
方式1:把一个列表生成式的[]改成()
方式2:在函数中使用yield关键字,此时该函数就变成一个生成器函数
'''
# 方式1:把一个列表生成式的[]改成()
generator = (i for i in range(1, 100))
print(type(generator)) # generator类型
# 获取生成器的下一个值
print(next(generator)) # 获取时才生成值,类似于Oracle中sequence
print(next(generator))
print(next(generator))
# 使用for...in循环遍历生成器
for i in generator:
print(i)
print('' * 80)
# 方式2:在函数中使用yield关键字,此时该函数就变成一个生成器函数
def gen():
print('one')
yield 13
print('two')
yield 8
print('three')
yield 25
print('four')
yield 38
# 生成器函数与普通函数的执行流程不一样:
# 普通函数是顺序执行,执行到最后一行或遇到return时结束
# 生成器函数是在每次调用next()时执行,遇到yield语句就返回,下一次调用next()时会从上次返回的yield语 句处继续执行
g = gen() # generator类型
print(type(g))
print(next(g))
print(next(g))
# 使用for...in循环遍历生成器
for i in g:
print(i)
高阶函数
'''
高阶函数:一个函数接收另一个函数作为参数,这种函数称为高阶函数
'''
nums = [12, 4, 3, 23, 65, 1, 234, 22]
# 定义一个函数,用来检查数字是否大于5
def f1(x):
if x > 5:
return True
return False
# 自定义高阶函数,用来过滤列表中的元素
def fn(fun, lst):
""" 将列表中所有符合条件的元素筛选出来,返回一个新列表
:param fun: 条件函数
:param lst: 要进行筛选的列表
:return: 返回新列表
"""
new_list = []
for i in lst:
if fun(i):
new_list.append(i)
return new_list
nums1 = fn(f1, nums)
print(nums1)
def f2(x):
return x % 2 == 0
print(fn(f2, nums))
# 内置高阶函数 filter(),用于过滤序列
nums2 = filter(f1, nums)
print(list(nums2))
# 内置高阶函数 map(),用于处理序列
def f3(x):
return x * x
nums3 = map(f3, nums)
print(list(nums3))
# 内置高阶函数 sorted(),用于排序
print(sorted(nums))
print(sorted(nums,key=abs))
匿名函数和装饰器
'''
匿名函数:没有名字的函数,使用lambda关键字
'''
nums = [12, 4, 32, 5, 23, 7]
# def fn(x):
# return x * 2 + 1
nums_new = list(map(lambda x: x * 2 + 1, nums))
print(nums_new)
# 将匿名函数赋给变量(不建议)
a = lambda x: x + 1
print(a(2))
print('' * 80)
'''
装饰器:在代码运行期间动态增加功能,称为装饰器Decoration,类似于AOP
'''
# 定义一个装饰器,为函数添加打印日志的功能
def log(fn):
def wrapper(*args, **kwargs):
print('开始执行%s()函数。。。' % fn.__name__)
res = fn(*args, **kwargs)
print('执行%s()函数结束。。。' % fn.__name__)
return res
return wrapper # 返回装饰函数
# @log
def even(lst):
for