03函数和模块的使用


函数和模块的使用

函数的参数

#函数的参数

#普通参数 最简单的参数

#收集参数:不确定要传递多少个参数,使用*args,最后会形成一个元组
def fuc(*args):
    sum=0
    for i in args:
        sum+=i
    print(sum,args)

fuc(1,2,3,4,5,5,6)#26 (1, 2, 3, 4, 5, 5, 6)
*args表示任何多个无名参数,它是一个tuple;

#收集关键字参数
def fuc(**kwargs):
    for i,j in kwargs.items():
        print(i,j)
fuc(name='huang',age=12,sex='男')
**kwargs表示关键字参数,它是一个 dict。
并且同时使用args和kwargs时,必须*args参数
列要在kwargs前,像foo(a=1, b=‘2’, c=3, a’, 
1, None, )这样调用的话,会提示语法错误“SyntaxError: non-keyword arg after keyword arg”。

函数变量的作用域

#global
num=1#不可变变量
ls1=[1,2,3]#可变变量


def main():
    # 在函数内部无法改变不可变的变量,将其改为全局变量
    global num
    num+=1
    # 在函数内部可以改变可变变量
    ls1.append(4)
    print(ls1,num)
    print(globals())#用来查找所有全局变量
    print(locals())#用来查找所有局部变量

main()
#print
print(globals())
print(locals())
#函数内定义的变量函数外不能使用,除非变成全局变量
#nonlocal函数
#直接看例子,如果有两层函数,内层函数想调用外层函数的不可变的变量(整型等),内层函数现需要用nonlocal引用。
'''
这是外层的注释
'''
def outer():
    '''
    这是一个函数的注释
    :return:
    '''
    num=10
    ls1=[1,2,3]
    def inner():
        nonlocal num
        num+=1
        ls1.append(4)
        print(num,ls1)
    return inner()

outer()

print(globals())
'''
脚本有默认的魔法方法,其中__name__==__main__的时候是脚本作为主程序运行,当脚本作为模块的时候__name__就是脚本名字
__doc__是脚本的注释
'''
# '__name__': '__main__',
# '__doc__': '\n这是外层的注释\n',
#单独打印函数的注释
print(outer.__doc__)

高阶函数

递归函数

#递归函数就是定义了一个函数,然后在函数内,自己调用自己
#递归函数必须有结束
#一层一层进入再一层一层返回
def digui(num):
    print(num,end='')
    if num>0:
        digui(num-1)
    #进到最里层后先打印最里层然后在一层一层出来
    print(num,end='')
    
digui(3)#32100123
#用递归函数实现阶乘
def jiecheng(num):
    if num==1:
        return 1
    else:
        return num*jiecheng(num-1)

print(jiecheng(5))
#用递归函数实现斐波那契数列
def feibonaqie(n):
    '''
    求第n位的斐波那契数列是什么
    :param n:
    :return:
    '''
    if n==1:
        return 1
    if n==2:
        return 1
    #第n为等与n-1位加n-2位
    else:
        return feibonaqie(n-1)+feibonaqie(n-2)

print(feibonaqie(5))

回调函数

#回调函数就是将函数作为传入的参数
def huidiao(x,y,f):
    print(f([x,y]))
huidiao(1,2,sum)

闭包函数

#在函数中返回了一个函数,并且内函数使用了外函数的局部变量

#作用一是可以保护变量受更改
#一个简单的闭包,可以保护money不能在外部更改
def outer():
    money=0
    def inner():
        nonlocal money
        money+=100
        print(money)
    return inner

res=outer()
res()
#查看一个函数是不是闭包,如果是返回cell,如果不是返回None
print(res.__closure__)
#作用2 写一个装饰器
#这个func就是我们要接收的函数(需要装饰的函数)
#我们设置一个装饰器,它的功能就是在原函数print之前先print一句话
def func1(func):
    def func2():
        print('我是闭包')
        #这里传回的是原函数的执行
        return func()
    #这里将闭包传回
    return func2
#语法糖
@func1
def func():
    print('这是一个普通的函数')
#假如装饰器和被装饰的函数都有参数的处理
#写一个带参数的装饰器,装饰一个带参数的函数
#装饰器有三层
def outer(sex):#装饰器参数写外层
    def medium(fun):
        def inner(x,y):#函数参数写内层
            if sex=='man':
                print('我是男的,我喜欢奥运')
            else:
                print('我是女的,我不喜欢奥运')
            return fun(x,y)#返回时候别忘了传参数
        return inner
    return medium

#给这个函数加一个装饰器
@outer('男')
def winter_olypic(time,area):
    print(f'{area}要在{time}月举办奥运会了!')

winter_olypic(12,'北京')

匿名函数 lambda表达式

#定义一个不需要名字的函数,在相对简单的函数构造中使用

#定义一个加法
res=lambda x,y:x+y
print(res(1,2))

#定义一个分支结构
res_=lambda x:f'这是{x}' if x=='man' else f'这不是{x}'
print(res_('man'))

迭代器

#用来访问集合元素的一种方式,迭代器可以记住访问遍历的位置,迭代器只能一个一个遍历,不能后退。

#iter()可以转换为迭代器对象
#功能:将一个可迭代对象,转为一个迭代器对象
#参数:可迭代对象(list,list,tuplt,set,range,str)
#返回迭代器对象

#取值方式(一次性)
#使用next()去调用,每一次可以取迭代器里面的一个数据
#使用list()可以一次性取出
#使用for()循环取出
list1='abcd'
ls=iter(list1)
print(ls,type(ls))# 
print(next(ls))#a
print(list(ls))#['b', 'c', 'd']
list1='abcd'
ls=iter(list1)

#检测是可迭代对象还是迭代器
from collections import Iterator,Iterable
#字符串是一个可迭代对象,但不是迭代器对象
print(isinstance(list1,Iterable))#True
print(isinstance(list1,Iterator))#False
#迭代器是一个可迭代对象,也是迭代器对象
print(isinstance(ls,Iterator))
print(isinstance(ls,Iterable))

内置函数

#range() 包头不包尾

#取值方式
#转为list
res=range(10)
print(list(res))
#for循环
for i in res:
    print(i,end='')
#转为迭代器
res_=iter(res)
print(next(res_))
print(next(res_))
#zip(*iterable)接收任意个可迭代对象,之后把第i个元素组合在一起返回一个元组迭代器
ls1=[1,2,3]
ls2=set([4,5,6])
ls3=(7,8,9)

res=zip(ls1,ls2,ls3)
print(res)#

from collections import Iterator
print(isinstance(res,Iterator))#True

#可以使用迭代器的取值方式
print(next(res))#(1, 4, 7)
print(list(res))# [(2, 5, 8), (3, 6, 9)]
#*和*zip的探究
#在python中,*可以拆掉外层的数据结构,但是一般不能单独使用
ls0=[(1,),(2,)]
ls00={(1,)}
ls000=[1,2,3]
# print(*ls0,*ls00)#(1,) (2,) (1,)
# print(*ls000)#1 2 3
#如果直接res=*ls0会报错

#对于迭代器对象同样可以,但是会使迭代器对象变空
list1=[1,2,3]
list_=iter(list1)
print(*list_)#1 2 3
print(list_)#
print(list(list_))#[]

#因此在*使用zip函数的过程中就有这样的用途
ls1=[1,2,3]
ls2=set([4,5,6])
ls3=(7,8,9)
#*号可以拆掉数据外层结构
print((*zip(ls1,ls2,ls3)))#将zip返回的迭代器对象变成了三个单独的元组(1, 4, 7) (2, 5, 8) (3, 6, 9)
'''
因此在下面就有这样的操作
首先zip(*zip(ls1,ls2,ls3))是先合在一起变成迭代器对象,拆开后变成三个元组,在进行zip就恢复到原来的三个元组了,在使用*list可以看到三个单独的元组了
'''
print(*list(zip(*zip(ls1,ls2,ls3))))#(1, 2, 3) (4, 5, 6) (7, 8, 9)
#数学相关
#abs
print(abs(-10))#10
#sum中必须是可迭代对象
print(sum([1,2,3]))#6
#max
print(max(1,2,3),max([1,2,3]))#3
# 求幂
print(pow(5,4))#625
#四舍五入
print(round(1.5))#2
#进制相关
#转化为二进制bin
#转化为八进制oct
#转化为16进制hex
#转化为ascii码ord
#将字符转为ascii码chr
print(bin(10),
      oct(10),
      hex(10),
      ord('a'),
      chr(98))
#0b1010 0o12 0xa 97 b

其他高阶函数

#sorted(iterable;reverse=False;key=函数)
#返回排序后的结果
#运行原理:把可迭代的数据一个一个取出然后放到key里面的函数里处理,并按照函数中return的结果再进行排序,返回一个新的列表
ls1=[1,-3,4,8,5,6,10]
print(sorted(ls1))#[-3, 1, 4, 5, 6, 8, 10]
print(sorted(ls1,reverse=True,key=abs))#[10, 8, 6, 5, 4, -3, 1]
print(sorted(ls1,key=lambda x:x%2))#[4, 8, 6, 10, 1, -3, 5]
#map(func,iterable)
#对传入的可迭代对象放入func中进行处理,之后返回一个迭代器对象
ls1=[1,2,3,4]
res=map(lambda x:x**2,ls1)
print(list(res))
#reduce(func,iterable)
#从迭代对象中取出两个元素放入func中计算,得到的结果在与可迭代对象中的第三个元素放入func中计算,以此类推到最后
# 返回func最终运算的处理结果
#将'123'转换成123
from functools import reduce
ls1='123'
result=reduce(lambda x,y:int(x)*10+int(y),ls1)
print(result)#123
#filter(func,iterable)
#把每个数据输入func,True保留,False丢弃,返回迭代器

varlist=[1,2,3,4,5,6,7,8]
res=filter(lambda x:x%2==0,varlist)
print(list(res))