首页 > 编程语言 >第04天-python函数与高阶函数

第04天-python函数与高阶函数

时间:2023-02-09 01:55:21浏览次数:50  
标签:return 函数 04 python add fn print def

1、函数和传实参
1.1、Python函数
1.1.1、函数的三分类
数学定义
y=f(x) ,y是x的函数,x是自变量。y=f(x0, x1, ..., xn)

Python函数
由若干语句组成的语句块、函数名称、参数列表构成,它是组织代码的最小单元
完成一定的功能

函数的作用
结构化编程对代码的最基本的封装,一般按照功能组织一段代码
封装的目的为了复用,减少冗余代码
代码更加简洁美观、可读易懂

函数的三分类:
内建函数,如max()、reversed()等
库函数,如math.ceil()等
自定义函数,使用def关键字定义
1.1.2、函数定义
def 函数名(参数列表):
    函数体(代码块)
    [return 返回值]
    
函数名就是标识符,命名要求一样
语句块必须缩进,约定4个空格
Python的函数若没有return语句,会隐式返回一个None值
定义中的参数列表称为形式参数,只是一种符号表达(标识符),简称形参


#def    #关键字,用来定义函数,称为定义时
def add(x,y):      #add是标识符,函数的名称也叫"add". 
                   # x、y由于是在def定义时使用的标识符,称为形式参数,简称形参,用来占位用的,表示未来你要提供的参数个数
    return x + y   #return 反回值
    
    
add  #函数也是对象,add是一个标识符,指代一个具体的函数对象,程序员通过标识符操作函数
<function __main__.add(x, y)>

add.__name__  #特殊属性,来展示函数的名称
'add'
1.1.3、函数调用
函数定义,只是声明了一个函数,它不能被执行,需要调用执行
调用的方式,就是函数名后加上小括号,如有必要在括号内填写上参数
调用时写的参数是实际参数,是实实在在传入的值,简称实参

def add(x, y):     # 函数定义
    result = x + y # 函数体
    return result  # 返回值
    
out = add(4,5) # 函数调用,可能有返回值,使用变量接收这个返回值
print(out)     # print函数加上括号也是调用 


上面代码解释:
    定义一个函数add,及函数名是add,能接受2个参数
    该函数计算的结果,通过返回值返回,需要return语句
    调用时,通过函数名add后加2个参数,返回值可使用变量接收
    函数名也是标识符
    返回值也是值
    定义需要在调用前,也就是说调用时,已经被定义过了,否则抛NameError异常
    函数是可调用的对象,callable(add)返回True
    
看看这个函数是不是通用的?体会一下Python函数的好处


1.1、调用add
    1.1.1、callable可调用的
    callable(add)
    True

    1.1.2、添加实际参数
    add(1,2)   #调用并送入实实在在的参数,称为实际参数,简称实参
    add(1,2)   #函数标识符后面使用小括号就是调用或执行,称为调用时,调用时必须提供符合形参列表要求的参数,否则报错
    3

    执行结果
    result = add(1,2)
    result 
    3

    result = add(1,2) + 100
    result
    103

    add('a','b'),add([1],[2]),add(1,2)  #拼接在一起
    ('ab', [1, 2], 3)

# python是动态类型,本来就没办法约定变量的类型,项目规模扩大,很多人要协同工作
1.1.4、函数两种参数
函数在定义是要定义好形式参数,调用时也提供足够的实际参数,一般来说,形参和实参个数要一致(可变参数除外)。

两种传参:
形参(5种): 是在定义的时候  add(x=2,y=3)
实参: 是在调用的时候,送入的实实在在的参数 add(2,4)
1.1.4.1、实参传参方式
1、位置传参
定义时def f(x, y, z), 调用使用 f(1, 3, 5),按照参数定义顺序传入实参

2、关键字传参
定义时def f(x, y, z),调用使用 f(x=1, y=3, z=5),使用形参的名字来传入实参的方式,如果使用了形参名字,那么传参顺序就可和定义顺序不同
要求位置参数必须在关键字参数之前传入,位置参数是按位置对应的


1.0、传参介绍
# 调用时的实参,实参的传参方式是发生在调用时,到目前为止,python发明的传参方式只有这2种
# 实参按顺序一一对应形参


1.1、按位置传入实际参数,简称(位置传参)
def add(x,y):
    result = x + y 
    return result
    
add(4,5),add(10,11)
(9, 21)


1.2、按照名称对应,按照名称对应顺序可以不一致。这种方式称为(关键字传参keyword)
add(x=5,y=6),add(y=7,x=100)
(11, 107)

    1.2.1、位置传参与关键字传参混用
    add(2, y=4)
    6

    1.2.2、位置传参不能在关键字传参后面,否则会报错
    10   ---->位置传参    x=4   ---->关键字传参
    add(x=4,10)
    SyntaxError: positional argument follows keyword argument (Temp/ipykernel_11188/2615036514.py, line 1)
      File "C:\Users\jackie\AppData\Local\Temp/ipykernel_11188/2615036514.py", line 1
        add(x=4,10)
               ^
    SyntaxError: positional argument follows keyword argument
2、形参1
2.1、传参不同方式
2.1、传参不同方法
def add (x=4, y=5):    #定义时,未来要使用形参x,y,如果实参不提供,那么就用缺省值顶
    print(x,y)
    return x + y
2.1.1、缺省值传参
  2.1.1、缺省值传参
    add(),add(10)
    4 5
    10 5
    (9, 15)
2.1.2、单关键字传参
    2.1.2、单关键字传参
    add(),add(10),add(8,y=6),add(y=23)
    4 5
    10 5
    8 6
    4 23
    (9, 15, 14, 27)
2.1.3、按名称对应传参
    2.1.3、按名称对应传参
    add(y=5,x=3)
    3 5
    8
    
2.1.3.1、按位置传参报错
      2.1.3.1、按位置传参报错
        add(11,x=9)           ------>11就传给了x ,所以会报错
            TypeError: add() got multiple values for argument 'x'
        ------------------------------------------------------------------------
        TypeError    Traceback (most recent call last)
        ~\AppData\Local\Temp/ipykernel_11188/3981599427.py in <module>
        ----> 1 add(11,x=9)
        TypeError: add() got multiple values for argument 'x'
        
        
        
        add(1,2, y=4)        ------->1传递给x,2传递给y, 关键字再去传参就会报错
                TypeError: add() got multiple values for argument 'y'
        ------------------------------------------------------------------------
        TypeError        Traceback (most recent call last)
        ~\AppData\Local\Temp/ipykernel_19248/2676440.py in <module>
        ----> 1 add(1,2, y=4)
        TypeError: add() got multiple values for argument 'y'
        
          add(x=4,10)        ------->位置传参不能在关键字传参后面,否则会报错
            SyntaxError: positional argument follows keyword argument  (Te                  nel_11188/2615036514.py, line 1)
          "C:\Users\jackie\AppData\Local\Temp/ipykernel_11188/2615036514.py", line
                add(x=4,10)
            SyntaxError: positional argument follows keyword argument
2.2、形参缺省值
缺省值也称为默认值,可以在函数定义时,为形参增加一个缺省值。其作用:
    参数的默认值可以在未传入足够的实参的时候,对没有给定的参数赋值为默认值
    参数非常多的时候,并不需要用户每次都输入所有的参数,简化函数调用


def add(x=4, y=5):
    return x+y
    
测试调用 add()、add(x=5)、add(y=7)、add(6, 10)、add(6, y=7)、add(x=5, y=6)、
add(y=5, x=6)、add(x=5, 6)、add(y=8, 4)、add(11, x=20)

能否这样定义 def add(x, y=5) 或 def add(x=4,y) ?

# 定义一个函数login,参数名称为host、port、username、password
def login(host='localhost', port=3306, username='root', password='root'):
    print('mysql://{2}:{3}@{0}:{1}/'.format(host, port, username, password))

login()
login('127.0.0.1')
login('127.0.0.1', 3361, 'wayne', 'wayne')
login('127.0.0.1', username='wayne')
login(username='wayne', password='wayne', host='www.zhgedu.com')
2.2.1、缺省值计算:
1.1、缺省值计算:
def add(x, y=6):
    return x + y
add(x=10),add(1,7)
(16, 8)

报错:
def add(x=4,y):    #缺省值应该尽量放在参数中靠后的位置   
    return x + y

正常执行:
def add(x,y=4):    #缺省值应该尽量放在参数中靠后的位置   
    return x + y   
2.2.1.1、传参连接数据库
   1.1.1、各种传参方法
    add(1),add(1,7),add(x=10),add(6,y=16),add(x=20,y=30),add(y=21,x=11)
    (7, 8, 16, 22, 50, 32)

    传参连接数据库
    def connect(host='localhost',port=3306, user='root',password='root'):
        print("mysql://{2}:{3}@{0}:{1}/".format(host,port,user,password))

    connect(),connect('192.168.142.111'),connect(password='zhgedu',user='zhgedu')
    mysql://root:root@localhost:3306/
    mysql://root:[email protected]:3306/
    mysql://zhgedu:zhgedu@localhost:3306/
    (None, None, None)
2.3、可变参数
需求:写一个函数,可以对多个数累加求和
def sum(iterable):
    s = 0
    for x in iterable:
        s += x
    return s
    
print(sum([1,3,5]))
print(sum(range(4)))


上例,传入可迭代对象,并累加每一个元素。
也可以使用可变参数完成上面的函数。

def sum(*nums):
    sum = 0
    for x in nums:
        sum += x
    return sum
    
print(sum(1, 3, 5))
print(sum(1, 2, 3))


1、可变位置参数
    在形参前使用 * 表示该形参是可变位置参数,可以接受多个实参
    它将收集来的实参组织到一个tuple中
2、可变关键字参数
    在形参前使用 ** 表示该形参是可变关键字参数,可以接受多个关键字参数
    它将收集来的实参的名称和值,组织到一个dict中
    
def showconfig(**kwargs):
    for k,v in kwargs.items():
        print('{}={}'.format(k,v), end=', ')
showconfig(host='127.0.0.1', port=8080, username='wayne', password='zhgedu')

混合使用
可以定义为下列方式吗?
def showconfig(username, password, **kwargs)
def showconfig(username, *args, **kwargs)
def showconfig(username, password, **kwargs, *args) # ?

总结:
有可变位置参数和可变关键字参数
可变位置参数在形参前使用一个星号*
可变关键字参数在形参前使用两个星号**
可变位置参数和可变关键字参数都可以收集若干个实参,可变位置参数收集形成一个tuple,可变关键字参数收集形成一个dict
混合使用参数的时候,普通参数需要放到参数列表前面,可变参数要放到参数列表的后面,可变位置参数需要在可变关键字参数之前


使用举例
def fn(x, y, *args, **kwargs):
    print(x, y, args, kwargs, sep='\n', end='\n\n')

fn(3, 5, 7, 9, 10, a=1, b='abc')
fn(3, 5)
fn(3, 5, 7)
fn(3, 5, a=1, b='abc')
fn(x=1, y=2, z=3)         ----->z=3传到**kwargs中 
fn(x=3, y=8, 7, 9, a=1, b='abc') # ?    ------>关键字传参必须在位置传参后面
fn(7, 9, y=5, x=3, a=1, b='abc') # ?    ------>y=5与9冲突了

fn(x=3, y=8, 7, 9, a=1, b='abc'),错在位置传参必须在关键字传参之前
fn(7, 9, y=5, x=3, a=1, b='abc'),错在7和9已经按照位置传参了,x=3、y=5有重复传参了
2.3.1、iterable可迭代对象传参
    1.1.2、iterable可迭代对象传参
    def s(iterable):
        result = 0
        for x in iterable:
            result +=x
        return result

    s(range(5)),s([1,3,5])   -----> s(range(5)),s([1,3,5])都为一个对象
    (10, 9)
2.3.2、*args剩余可变位置形参
    2.3.2、*args可变的参数
    def s(*args):     
        print(type(args), args)

    s(1,2,3)                  ---->元组,不可变     
    <class 'tuple'> (1, 2, 3)
2.3.2.1、*arges可变参数的错误输出
2.3.2.1、*arges可变参数的错误输出
        def s(*args):     
            print(type(args), args)
            s = 0 
            for x in args:    ----->(range(1,6)) 0 range(1,6)       
                s += x        -----> 0 + range(1,6)
            return s

        s(range(1,6))    --->报错
        TypeError: unsupported operand type(s) for +=: 'int' and 'range'
        ---------------------------------------------------------------
        TypeError      Traceback (most recent call last)
        ~\AppData\Local\Temp/ipykernel_18816/2437433324.py in <module>
        ----> 1 s(1,2,3,4,5),s(range(1,6))
        ~\AppData\Local\Temp/ipykernel_18816/672214113.py in s(*args)
              3     s = 0
              4     for x in args:
        ----> 5         s += x
              6     return s
        TypeError: unsupported operand type(s) for +=: 'int' and 'range'
        
        
        s(x=1,y=2,z=3)  --->报错
            NameError: name 's' is not defined
        ------------------------------------------------------------
        NameError         Traceback (most recent call last)
        ~\AppData\Local\Temp/ipykernel_16960/3695981793.py in <module>
        ----> 1 s(x=1,y=2,z=3)
        NameError: name 's' is not defined
        
        s('a','b','c')  --->报错
2.3.3、**kwargs剩余可变关键字形参
1.1、可变关键字形参:
def fn(**kwargs): 
    print(type(kwargs),kwargs)  
    
fn(x=1,z=20,y=35,m=6,t=23)    --->封装到字典中,可变
<class 'dict'> {'x': 1, 'z': 20, 'y': 35, 'm': 6, 't': 23}

1.2、*args随意位置传参
def fn(user,password,*args):
    print(user,password,args)

fn(1,2,3)
1 2 (3,)

1.3、*args随意位置传参,**kwargs关键字传参
def fn(user,*args,**kwargs):
    print(user,args,kwargs)

fn(1,2,3)
1 (2, 3) {}

1.4、x,y传参,*args随意位置传参,**kwargs关键字传参
def fn (x,y,*args,**kwargs): 
    print(x,y,args,kwargs)
    
fn(1,2,3,4,z=5)    -----> *args可变剩余位置传参(3,4)
1 2 (3, 4) {'z': 5}

fn(4,5)      -----> ()空元组 {}空字典
4 5 () {} 

fn(1,2,3,4,range(6))          ----->*args位置参数收集
1 2 (3, 4, range(0, 6)) {}

fn(1,2,3,4,a=1,b='abc')       ----->**kwargs可变关键字参数收集
1 2 (3, 4) {'a': 1, 'b': 'abc'}

fn(a=1,b='abc',x=100,y=200)   ----->**kwargs剩余的可变关键字参数收集
100 200 () {'a': 1, 'b': 'abc'}

    1.4.1、x=20关键字传参错误
    def fn (x,y,*args,**kwargs): 
        print(x,y,args,kwargs)
        
    fn(1,2,3,4,a=1,b=200,x=20,y=30)
        TypeError: fn() got multiple values for argument 'x'
    ---
    TypeError                Traceback (most recent call last)
    ~\AppData\Local\Temp/ipykernel_13644/3517840218.py in <module>
    ----> 1 fn(1,2,3,4,a=1,b=200,x=20,y=30)
    TypeError: fn() got multiple values for argument 'x'
3、形参2
3.0、实参介绍
实参,发生在调用时,2种
1、位置传参
2、关键字传参
可以混用,但是要求位置传参在前

形参,定义时确定,写在哟数的参数列表中
1、普通参数,接受2种传参,可以位置传参,也可以关键字传参
2、可变位置参数,剩余位置参数,别人都先按照位置对应完了,剩下的没人要的它拿走,*args,收集到一个元组中去,可以为0个。
3、**kwargs,可变关键字形参,剩余关键字参数。别人都先使用关键字优先对应,剩下的没人要的关键字参数被它收集到一个字典中去
4、keyword-only,仅仅只能使用关键字传实参才能把参数对应上的形参。
必须提供,除非它有缺省值
5、positional-only,仅仅接受位置传参的形参。3.8之前没有。
    必须提供,除非它有缺省值
    缺省值和普通参数缺省值一起看,要求有缺省值的必须靠后
3.1、keyword-only参数
先看一段代码
def fn(*args, x, y, **kwargs):
print(x, y, args, kwargs, sep='\n', end='\n\n')

fn(3, 5) #     --->x
fn(3, 5, 7) #  --->x
fn(3, 5, a=1, b='abc') #  --->x
fn(3, 5, y=6, x=7, a=1, b='abc')  -----√

在Python3之后,新增了keyword-only参数。
keyword-only参数:在形参定义时,在一个*星号之后,或一个可变位置参数之后,出现的普通参数,就已经不是普通的参数了,称为keyword-only参数。
def fn(*args, x):
    print(x, args, sep='\n', end='\n\n')
    
fn(3, 5) #
fn(3, 5, 7) #
fn(3, 5, x=7)
7
(3, 5)

keyword-only参数,言下之意就是这个参数必须采用关键字传参。
可以认为,上例中,args可变位置参数已经截获了所有位置参数,其后的变量x不可能通过位置传参传入了。

思考:def fn(**kwargs, x) 可以吗?
def fn(**kwargs, x):
print(x, kwargs, sep='\n', end='\n\n')

直接语法错误了。
可以认为,kwargs会截获所有关键字传参,就算写了x=5,x也没有机会得到这个值,所以这种语法不存在。

keyword-only参数另一种形式
* 星号后所有的普通参数都成了keyword-only参数。
def fn(*, x, y):    ------->*之后看着像普通参数的形参都是keyword-only参数
    print(x, y)
fn(x=6, y=7)
fn(y=8, x=9)


x y 仅关键字参数
def fn(*args, x , y):  #----> x y 仅关键字参数
    print(args,x, y)
    
fn(1, 2, 4, 5, y=5, x=3)
(1, 2, 4, 5) 3 5

def fn(*args,x,y,**kwargs):
    print(args,x,y,kwargs)
    
fn(x=5, a=1,y=7)
() 5 7 {'a': 1}
3.2、Positional-only仅位置’‘/’’参数
Python 3.8 开始,增加了最后一种形参类型的定义:Positional-only参数。(2019年10月发布3.8.0)

def fn(a, /):
    print(a, sep='\n')
    
fn(3)
fn(a=4) # 错误,仅位置参数,不可以使用关键字传参


def foo(a,/,b):
    print(a,b)

foo(23,5)
foo(12,b=20)
23 5
12 20

inspect检查
signature签名对象
parameters参数

import inspect
def foo(a,b,/,c,d,e=20,*args,m=4,n,**kwargs):
    print(a,b,c,d,e,m,n)
    print(args)
    print(kwargs)
sig = inspect.signature(foo)
print(sig)
print(sig.parameters)
for k,v in sig.parameters.items():
    print(k,v.name,v.kind,v.default)
(a, b, /, c, d, e=20, *args, m=4, n, **kwargs)
OrderedDict([('a', <Parameter "a">), ('b', <Parameter "b">), ('c', <Parameter "c">), ('d', <Parameter "d">), ('e', <Parameter "e=20">), ('args', <Parameter "*args">), ('m', <Parameter "m=4">), ('n', <Parameter "n">), ('kwargs', <Parameter "**kwargs">)])

positional位置
keyword关键字
a a POSITIONAL_ONLY <class 'inspect._empty'>
b b POSITIONAL_ONLY <class 'inspect._empty'>
c c POSITIONAL_OR_KEYWORD <class 'inspect._empty'>
d d POSITIONAL_OR_KEYWORD <class 'inspect._empty'>
e e POSITIONAL_OR_KEYWORD 20
args args VAR_POSITIONAL <class 'inspect._empty'>
m m KEYWORD_ONLY 4
n n KEYWORD_ONLY <class 'inspect._empty'>
kwargs kwargs VAR_KEYWORD <class 'inspect._empty'>

进程已结束,退出代码为 0


def foo(a,b,/,c,d,e=20,*args,m=4,n,**kwargs):
    print(a,b,c,d,e,m,n)
    print(args,kwargs)
    print('-'* 30)

foo(1,2,3,4,n=30)
foo(1,2,m=20,n=30,x=40,y=50,d=60,c=70)
------------------------------
1 2 70 60 20 20 30
() {'x': 40, 'y': 50}
------------------------------

foo(1,2,3,4,5,6,7,8,n=10,m=20,x=200)
------------------------------
1 2 3 4 5 20 10
(6, 7, 8) {'x': 200}
------------------------------

foo(0,1,x=2,y=3,e=4,d=5,c=6,n=7,a=0,b=1)
------------------------------
0 1 6 5 4 4 7
() {'x': 2, 'y': 3, 'a': 0, 'b': 1}
------------------------------
3.3、参数的混合使用
# 可变位置参数、keyword-only参数、缺省值
def fn(*args, x=5):
    print(x)
    print(args)
    
fn() # 等价于fn(x=5)
fn(5)
fn(x=6)
fn(1,2,3,x=10)
# 普通参数、可变位置参数、keyword-only参数、缺省值
def fn(y, *args, x=5):
    print('x={}, y={}'.format(x, y))
    print(args)
    
fn()              #--->×
fn(5)             #--->y=5 () x=5 √
fn(5, 6)          #--->y=5  *args=(6) x=5 √
fn(x=6)           #--->×
fn(1, 2, 3, x=10) #--->y=1 *args=(2,3) x=10  √
fn(y=17, 2, 3, x=10) #--->×,位置传参不能再关键字之后
fn(1, 2, y=3, x=10) #--->×
fn(y=20, x=30)    #--->y=20  *args=() x=30 √
# 普通参数、缺省值、可变关键字参数
def fn(x=5, **kwargs):
    print('x={}'.format(x))
    print(kwargs)
    
fn()           #--->√
fn(5)          #--->√
fn(x=6)        #--->√
fn(y=3, x=10)  #--->√
fn(3, y=10)    #--->√
fn(y=3, z=20)  #--->√
3.4、参数规则(连接数据库)
参数列表参数一般顺序是:positional-only参数、普通参数、缺省参数、可变位置参数、keyword-only参数(可带缺省值)、可变关键字参数。

注意:
代码应该易读易懂,而不是为难别人
请按照书写习惯定义函数参数

def fn(a, b, /, x, y, z=3, *args, m=4, n, **kwargs):
    print(a, b)
    print(x, y, z)
    print(m, n)
    print(args)
    print(kwargs)
    print('-' * 30)
    
def connect(host='localhost', user='admin', password='admin', port='3306',db,**kwargs):
    print(host, port)
    print(user, password)
    print(kwargs)

connect(db='cmdb') # 参数的缺省值把最常用的缺省值都写好了
connect(host='192.168.1.123', db='cmdb')
connect(host='192.168.1.123', 'zhgedu','zhgedu' db='cmdb', password='mysql')

定义最常用参数为普通参数,可不提供缺省值,必须由用户提供。注意这些参数的顺序,最常用的先定义
将必须使用名称的才能使用的参数,定义为keyword-only参数,要求必须使用关键字传参
如果函数有很多参数,无法逐一定义,可使用可变参数。如果需要知道这些参数的意义,则使用可、变关键字参数收集
4、参数解构和返回值
4.0、简介
def add(x, y):
    print(x, y)
    return x + y
    
add(4, 5)
add((4, 5)) # 可以吗?
t = 4, 5
add(t[0], t[1])
add(*t)
add(*(4, 5))
add(*[4, 5])
add(*{4, 5}) # 注意有顺序吗?
add(*range(4, 6))

add(*{'a':10, 'b':11}) # 可以吗?
add(**{'a':10, 'b':11}) # 可以吗?
add(**{'x':100, 'y':110}) # 可以吗?

参数解构:
在给函数提供实参的时候,可以在可迭代对象前使用 * 或者 ** 来进行结构的解构,提取出其中所有元素作为函数的实参
使用 * 解构成位置传参
使用 ** 解构成关键字传参
提取出来的元素数目要和参数的要求匹配

#实参解构,结构解开了。
# 一颗星* 表示把线性结构(一维)解开成按位置传参
# **后面Python中只能一种情况mapping字典,**{'a':100,'b':200}解构后就变成了关键字传参
4.1、参数解构
4.1.1、参数解构
1.0、参数解构
def add(*iterable):        #----->*iterable可迭代的
    result = 0
    for x in iterable:
        result += x
    return result
    
add(1, 2, 3)               
6
add(*[1, 3, 5])
9
add(*range(5))
10

# 3.8以后,下面就不可以使用字典解构后的关键字传参了
def add(x, y, /): # 仅位置形参
    print(x, y)
    return x + y
    
add(**{'x':10, 'y':11})
4.1.2、函数解构
1.1、函数解构
def add(x,y):
    print(x,y)
    return x + y
t = (4,5)

add(t[0],t[1])
4 5
9
4.1.2.1、一颗星*解构
4.1.2.1、一颗星*,表示把线性结构解开成按位置传参
add(*t)                                 ----->实参解构,结构解开了
4 5
9

add(*[4,5]),add(*(4,5)),add(*range(4,6)),add(*{'a','b'})
4 5
4 5
4 5
a b
(9, 9, 9, 'ab')

add(*{'a':100, 'b':200})         ---->互相等价
a b
'ab'

add(*{'a':100,'b':200}.keys())   ---->互相等价
a b
'ab'

    1.1.1.1、元组拼合
    add(*{'a':100,'b':200}.items())    ----> #两颗星怎么理解
    ('a', 100) ('b', 200)
    ('a', 100, 'b', 200)
    (1,) + (1,)

    (1,) + (1,)
    (1, 1)
4.1.2.2、两颗星**解构
4.1.2.2、两颗星**后面Python中只能一种情况mapping字典
add(**[4,5])  #**后面python只能一种情况mapping映射,**必须是字典
def add(x,y):
print(x,y)
return x + y

add(**{'x':100,'y':200})
100 200
300

import inspect
def foo(a,b,/):        #----->仅位置传参
print(a,b)

d = {'a':100,'b':200}
foo(*d)   #foo(a-100,b-200)

a b
4.2、函数返回值
先看几个例子
# return语句之后可以执行吗?
def showplus(x):
    print(x)
    return x + 1
    print('~~end~~') # return之后会执行吗?
    
showplus(5)

# 多条return语句都会执行吗
def showplus(x):
    print(x)
    return x + 1
    return x + 2
    
showplus(5)

# 下例多个return可以执行吗?
def guess(x):
    if x > 3:
        return "> 3"
    else:
        return "<= 3"
        
print(guess(10))

# 下面函数执行的结果是什么
def fn(x):
    for i in range(x):
        if i > 3:
            return i
    else:
        print("{} is not greater than 3".format(x))
        
4
3 is not greater than 3
None 
        
print(fn(5)) # 打印什么?
print(fn(3)) # 打印什么?


总结
    Python函数使用return语句返回“返回值”
    所有函数都有返回值,如果没有return语句,隐式调用return None
    return 语句并不一定是函数的语句块的最后一条语句
    一个函数可以存在多个return语句,但是只有一条可以被执行。如果没有一条return语句被执行到,隐式调用return None
    如果有必要,可以显示调用return None,可以简写为return
    如果函数执行了return语句,函数就会返回,当前被执行的return语句之后的其它语句就不会被执行了
    返回值的作用:结束函数调用、返回“返回值”
4.2.1、return函数返回值
1.1、return返回值结束
def add(x, y): # 仅位置形参
    print(x, y)
    print('-------------')    #一个函数执行,碰到了return语句,此函数执行完成
    return x + y
    
add(4,5)
4 5
-------------
9

1.1.1、return使用1
def add(x,y):    
    return 1
    return 2
    
add(4,8)
1

1.1.2、return使用2
def guess(x):
    if x > 0:
        print(x, 'is positive')
        return 'positive'
    elif x == 0:
        print('zero')
        return 0 
    else:
        print(x, 'is negative')
        return 'negative'
        
guess(-1),guess(0),guess(5)
-1 is negative
'negative'
zero
0
5 is positive
'positive'


1.1.3、return使用3
def fn(x):
    for i in range(x):
        if i > 3:
            return i
    else:
        print("{} is not greater than 3".format(x))
print(fn(5))
print(fn(3))

4
3 is not greater than 3
None       ---->正常执行不返回None,如果返回None,里面没有正常执行,或者里面计算不出来


1.1.4、return使用4
def foo():
    return 1, True, 'abc'
    
foo()  #返回了什么,多个值吗? 不是,返回了一个对象元组,返回的依然是单个值,组中有三个元素
(1, True, 'abc')

x,y,z = foo() 
x,y,z
(1, True, 'abc')
5、作用域和嵌套函数
5.1、函数作用域***
作用域
一个标识符的可见范围,这就是标识符的作用域。一般常说的是变量的作用域
def foo():
    x = 100
print(x) # 可以访问到吗

上例中x不可以访问到,会抛出异常(NameError: name 'x' is not defined),原因在于函数是一个封装,它会开辟一个作用域,x变量被限制在这个作用域中,所以在函数外部x变量不可见。

注意:每一个函数都会开辟一个作用域

1.1、函数作用域1
def foo():
    return 1, True, 'abc'
    
x,y,z
(1, True, 'abc')

del x     ----->删除标识符x
x         ----->报错
NameError: name 'x' is not defined


1.2、 函数作用域2
def foo():
    x = 100
    print(x)
    
foo()       ---->自己的函数可以输出
print(x)    ---->外部环境不可以输出
100
NameError: name 'x' is not defined

1.3、函数作用域3
def foo():
    x = 100
    print(x)

def fool():
    print(x)

print(x)
NameError: name 'x' is not defined   ---->print(x)在外环境不能访问内部环境

foo(),fool()
100                                  ---->foo()自己的函数可以定义
NameError: name 'x' is not defined   ---->fool()找不到外面的值

 
image-20210924161427432

 
image-20210924162409568
5.2、作用域分类
5.2.1、全局作用域
在整个程序运行环境中都可见
全局作用域中的变量称为全局变量global

# 全局变量
x = 5 # 全局变量,也在函数外定义
def foo():
    print(x) # 可见吗?为什么?
    
foo()
5.2.1.1、全局作用域图示
5.2.1.1、全局作用域
x = 123          #全局变量x
def foo():
    x = 100
    print(x)

def fool():      ----->此函数自己没有x
    print(x)

print(x),fool()  ----->fool()外部向内穿透,内部变量对外不可见
123
123

一般来讲外部作用域变量可以在函数内部可见,可以使用,  向内部穿透
反过来,函数内部的局部变量,不能在函数外部看到,      对外不可见

 
image-20210924162942742

 
image-20210924163358715
5.2.2、局部作用域
在函数、类等内部可见
局部作用域中的变量称为局部变量,其使用范围不能超过其所在局部作用域
也称为本地作用域local

# 局部变量
def fn1():
    x = 1 # 局部作用域,x为局部变量,使用范围在fn1内
    
def fn2():
    print(x) # x能打印吗?可见吗?为什么?
    
 print(x) # x能打印吗?可见吗?为什么?
5.2.3、函数嵌套
1.1、outer与inner函数嵌套1
在一个函数中定义了另外一个函数
def outer():
    def inner():
        print("inner")
    inner()
    print("outer")

outer() # 可以吗?
inner() # 可以吗?

内部函数inner不能在外部直接使用,会抛NameError异常,因为它在函数外部不可见。
其实,inner不过就是一个标识符,就是一个函数outer内部定义的变量而已。


1.1、函数嵌套1
def outer():
    def inner():    #不是执行了innor,定义了一个内部嵌套的函数对象,inner就是一个局部变量
        pass
    #inter()        #此为inter函数执行
    print('outer----')
    
outer()             #couter不执行,inter函数对象不创建 
outer----

1.2、局部变量inner()创建函数对象
1.2、局部变量inner()创建函数对象
def outer():
    print('----------')
    def inner():     #inner就是一个局部变量,访问不了内部的inner
        pass
    print(inner) 
    print('outer-------')
    
outer()              
----------
<function outer.<locals>.inner at 0x00000229D87C4D38>  #内存中创建的inner函数对象位置改变
outer-------

outer()
----------
<function outer.<locals>.inner at 0x00000229D87C49D8> #内存中创建的inner函数对象位置改变
outer-------
1.2.1、局部变量inner定义并使用
1.2.1、局部变量inner定义并使用
def outer():
    print('----------')
    x = list(range(10))
    def inner():
        print('inner++++')
    inner()
    print(id(x))
    print(inner)
    print('outer-------')
    
outer()
----------
inner++++
2232515727816
<function outer.<locals>.inner at 0x00000207CB95F708>
outer-------
1.3、局部变量x创建列表对象
1.3、局部变量x创建列表对象
def outer():
    print('----------')
    #x = []
    x = list(range(10))
    def inner():
        pass  
    print(id(x))
    print(inner)
    print('outer-------')

outer()
----------
2378749101384
<function outer.<locals>.inner at 0x00000229D87E70D8>   #内存地址不同
outer-------

outer()
----------
2378748961416
<function outer.<locals>.inner at 0x00000229D87E7438>   #内存地址不同
outer-------
1.4、局部作用域的内部穿透
1.4、局部作用域的内部穿透
def outer():
    o =  65                     ----->局部作用域的内部穿透
    def inner():
        print('inner++++',o)
    inner()
    print('outer-------',o)
    
outer()
inner++++ 65
outer------- 65
1.4.1、局部作用域优先用自己的o
1.4.1、局部作用域优先用自己的o
def outer():
    o =  65
    def inner():
        o = 97
        print('inner++++',o)
    inner()
    print('outer-------',o)
    
outer()
inner++++ 97
outer------- 65
1.4.2、局部作用域就近原则
1.4.2、局部作用域就近原则
o = 49
def outer():
    o =  65
    def inner():
        o = 97
        print('inner++++',o)
    inner()
    print('outer-------',o)

outer()
print(o)
inner++++ 97
outer------- 65
49


o = 49
def outer():
    o =  65
    def inner():
        o = 97
        print('inner++++',o,chr(o))
    inner()
    print('outer-------',o,chr(o))
    
chr(65),chr(0x41),chr(0x61)     #给整数返回字符串
(65, 97, 49)
ord('A'),ord('a'),ord('1')      #给的数值出来字符串

(65, 97, 49)
hex(49)       #整数转换为16进制

'0x31'
ord('啊')                       ----->互为转换
21834
chr(21834),chr(0x554a)          ----->互为转换
('啊', '啊')

'啊'.encode(),'啊'.encode('gbk') ----->两种字节编码
(b'\xe5\x95\x8a', b'\xb0\xa1')


从执行的结果来看:
外层变量在内部作用域可见内层作用域inner中,如果定义了o = 97 ,相当于在当前函数inner作用域中重新定义了一个新的变量o,但是,这个o并不能覆盖掉外部作用域outer2中的变量o。只不过对于inner函数来说,其只能可见自己作用域中定义的变量o了
内建函数	函数签名	说明
chr	chr(i)	通过unicode编码返回对应字符
ord	ord(c)	获得字符对应的unicode
print(ord('中'), hex(ord('中')), '中'.encode(), '中'.encode('gbk'))

chr(20013) # '中'
chr(97)
6、闭包和LEGB
6.1、global语句
x = 5
def foo():
    global x # 全局变量
    x += 1
    print(x)
foo()

    使用global关键字的变量,将foo内的x声明为使用外部的全局作用域中定义的x
    全局作用域中必须有x的定义
    
如果全局作用域中没有x定义会怎样?

注意,下面试验如果在ipython、jupyter中做,上下文运行环境中有可能有x的定义,稍微不注意,就
测试不出效果
# 有错吗?
def foo():
    global x
    x += 1
    print(x)
foo()

# 有错吗?
def foo():
    global x
    x = 10
    x += 1
    print(x)
foo()
print(x) # 可以吗

使用global关键字定义的变量,虽然在foo函数中声明,但是这将告诉当前foo函数作用域,这个x变量
将使用外部全局作用域中的x。

即使是在foo中又写了x = 10 ,也不会在foo这个局部作用域中定义局部变量x了。

使用了global,foo中的x不再是局部变量了,它是全局变量。

总结
x+=1 这种是特殊形式产生的错误的原因?先引用后赋值,而python动态语言是赋值才算定义,才
能被引用。解决办法,在这条语句前增加x=0之类的赋值语句,或者使用global 告诉内部作用域,
去全局作用域查找变量定义内部作用域使用x = 10 之类的赋值语句会重新定义局部作用域使用的变量x,但是,一旦这个作用域中使用 global 声明x为全局的,那么x=5相当于在为全局作用域的变量x赋值

global使用原则
外部作用域变量会在内部作用域可见,但也不要在这个内部的局部作用域中直接使用,因为函数的
目的就是为了封装,尽量与外界隔离
如果函数需要使用外部全局变量,请尽量使用函数的形参定义,并在调用传实参解决一句话:不用global。学习它就是为了深入理解变量作用域
6.1.1、函数作用域
1.1、函数作用域
x = 10 
def foo():
    print(x)
foo()

x = 100 
def foo():
    y = x + 1
    print(y)
foo()

x = 200 
def foo():
    x = 300
    y = x + 1
    print(y)
    
10
101
301

    1.1.1、解析式报错
    x = 400
    def foo():
        #x = 200      #x需要在x += 1之前赋值 
        x += 1
        print(x)
    foo()

    local variable 'x' referenced before assignment       ----->局部域的报错

    本地变量在局部作用域里还未被赋值:
    x = 200
    def foo():
        #x = 300      #x需要在y之前赋值
        y = x + 1
        print(y)
        x = 300       #只要出现了x=,在python中就认为x为当前作用域变量
        print(x)
    foo()
6.1.2、global全局作用域
1.2、global全局作用域
x = 200 
def foo():
    global x      #global优先,导致x=无效, 声明x为全局变量
    y = x + 1
    x = 300
    print(y)
foo()
print(x)
201
300

x = 200
def fn():
    global x
    x = 500
    x = x + 1 
    print(x)
fn()
print(x)
500
500
6.1、闭包***
6.1.1、闭包函数1
自由变量:未在本地作用域中定义的变量。例如定义在内层函数外的外层函数的作用域中的变量

闭包:    就是一个概念,出现在嵌套函数中,指的是内层函数引用到了外层函数的自由变量,就形成了闭包。很多语言都有这个概念,最熟悉就是JavaScript

def counter():
    c = [0]
    def inc():
        c[0] += 1 # 报错吗? 为什么 # line 4
        return c[0]
    return inc
    
foo = counter()      # line 8
print(foo(), foo())  # line 9
c = 100
print(foo())         # line 11



6.1.1、闭包函数1
def counter():
    c = [0]
    def inc():
        c[0] += 1
        return c 
    return inc    # return函数,函数对象的地址返回

foo = counter()   #foo是什么,foo指向inc所指向的函数对象
                  #counter执行完,局部变量c和inc还存在吗?
                  #python回收内存是靠垃圾回收,什么是垃圾,看引用计数,引用计数不为0不回收
print(foo(),foo())
[2] [2]

c = 100
print(foo())
[3]
6.1.2、inc闭包函数2
1.2、inc闭包函数2
def counter():
    c = [0]            #要使c给记住,因为inc()内部要用
    def inc():         # inc使用外部的局部变量c
        c[0] += 1      # 用到了c,c是counter局部变量,c = [0]等于c,c为外部函数的自由变量
        return c 
    return inc         # return函数,inc:为闭包函数
    
foo = counter()

foo,foo()
(<function __main__.counter.<locals>.inc()>, [2])

print(foo(),foo())
c = 100 
print(foo())
1 2
3

1.2.1、闭包错误示例1
def counter():
    c = [0]
    def inc():
        c[0] += 1
        return c[0]
    return inc()   # return函数        ----->主要错误配置()
   
foo =  counter()
foo
1

1.2.2、闭包错误示例2
def counter():
    c = 0
    def inc():
        global c 
        c += 1
        return c
    return inc   # return函数
    
fool = counter()
print(fool(),fool())     ----->结果报错
6.1.3、闭包函数引用global3
1.3、闭包函数3
def counter():
    global c 
    c = 0
    def inc():
        global c          ------>当你使用全局变量c的时候,就没有闭包
        c += 1
        return c
    return inc   # return函数
    
fool = counter()
print(c)
print(fool(),fool())
0
1 2

 
image-20210926005647371

 
image-20210926010454555

 
image-20210926011559521
6.2、nonlocal闭包语句
6.2.1、nonlocal语句
nonlocal:将变量标记为不在本地作用域定义,而是在上级的某一级局部作用域中定义,但不能是全局
作用域中定义。
def counter():
    count = 0
    def inc():
        nonlocal count # 声明变量count不是本地变量
        count += 1
        return count
    return inc
    
foo = counter()
print(foo(), foo())

count 是外层函数的局部变量,被内部函数引用。
内部函数使用nonlocal关键字声明count变量在上级作用域而非本地作用域中定义。
代码中内层函数引用外部局部作用域中的自由变量,形成闭包。
6.2.2、nonlocal闭包函数
6.2、nonlocal闭包函数
def counter():
    c = 0
    def inc():
        nonlocal c           #---->不是本地inc内部变量,是外部变量c
        c += 1
        return c
    return inc   # return函数
    
foo2 = counter()
foo2(),foo2(),foo2()
(1, 2, 3)
6.3、函数的销毁
定义一个函数就是生成一个函数对象,函数名指向的就是函数对象。
可以使用del语句删除函数,使其引用计数减1。
可以使用同名标识符覆盖原有定义,本质上也是使其引用计数减1。
Python程序结束时,所有对象销毁。
函数也是对象,也不例外,是否销毁,还是看引用计数是否减为0。

引用计数:
def fn():
    pass
f = fn 
a = [f]      ---->列表引用计数
del fn       ---->删除fn
f            ---->f的引用计数依然存在
a[0] = 100   ---->f变成100,以前的数据丢失 
del f        ---->删除引用计数f
f            ---->f的引用计数不存在
6.4、变量名解析原则LEGB***
Local,本地作用域、局部作用域的local命名空间。函数调用时创建,调用结束消亡

Enclosing,Python2.2时引入了嵌套函数,实现了闭包,这个就是嵌套函数的外部函数的命名空间

Global,全局作用域,即一个模块的命名空间。模块被import时创建,解释器退出时消亡

Build-in,内置模块的命名空间,生命周期从python解释器启动时创建到解释器退出时消亡。例如print(open),print和open都是内置的变量所以一个名词的查找顺序就是LEGB

 
image-20210926112556939
内建函数	函数签名	说明
iter	iter(iterable)	把一个可迭代对象包装成迭代器
next	next(iterable[, default])	取迭代器下一个元素,如果已经取完,继续取抛Stoplteration异常
reversed	reversed(seq)	返回一个翻转元素的迭代器,迭代一个可迭代对象,返回一个迭代器
enumerate	enumerate(seq, start=O)	每一个元素都是数字和元素构成的二元组
7、生成器函数***
7.1、迭代器表
内建函数	函数签名	说明
iter	iter(iterable)	把一个可迭代对象包装成迭代器
next	next(iterable[, default])	取迭代器下一个元素,如果已经取完,继续取抛Stoplteration异常
reversed	reversed(seq)	返回一个翻转元素的迭代器,迭代一个可迭代对象,返回一个迭代器
enumerate	enumerate(seq, start=O)	每一个元素都是数字和元素构成的二元组s
7.1.1、迭代器
1.1、iter迭代器使用
items = [1,3,5,7]
i1 = iter(items)
i1,next(i1)
(<list_iterator at 0x21147c37f88>,1)  ---->列表迭代器
i2 = iter(range(5))
next(i2,'end')        ----->设置缺省值'end'
'end'


1.2、迭代器next
items = [1,3,5,7]
r = reversed(items)  #迭代器都是惰性求值的
r,next(r),next(r)    ---->不可以在走了,不然会报错
(<list_reverseiterator at 0x2114704c848>, 7, 5)

items = [1,3,5,7]
for i,v in enumerate(items):
    print(i,v)
0 1
1 3
2 5
3 7

for x in [1,1,1,1]:       ----->输出的是不同的四个元素
    print(x) 
1
1
1
1

1.3、reversed反转使用报错
s1 = {1,3,5,7}
reversed(s1)          ----->无序反转,不能迭代
TypeError: 'set' object is not reversible


1.4、enumerate二元组
s1 = {1,3,5,7}
g = enumerate(s1)   #返回一个迭代器,二元组(数字,元素)
next(g),next(g),next(g)
((1, 3), (2, 5), (3, 7))

g = enumerate(s1,100)       #指定从100开始
next(g),next(g),next(g)
((100, 1), (101, 3), (102, 5))

for i in g:
    print(i)
(103, 7)
7.2、生成器函数
生成器generator
    生成器指的是生成器对象,可以由生成器表达式得到,也可以使用yield关键字编写一个生成器函
    数,调用这个函数得到一个生成器对象
    生成器对象,是一个可迭代对象,是一个迭代器
    生成器对象,是延迟计算、惰性求值的
    
生成器函数
    函数体中包含yield语句的函数,就是生成器函数,调用后返回生成器对象
    
m = (i for i in range(5)) # 生成器表达式
print(type(m))
print(next(m))
print(next(m))

def inc(): # 生成器函数
    for i in range(5):
        yield i
        
print(type(inc))
print(type(inc()))

g = inc()
print(type(g))
print(next(g))
for x in g:
    print(x)
print('--------------------')
for y in g: # 还有元素吗
    print(y) 
    
普通函数调用,函数会立即执行直到执行完毕。
生成器函数调用,并不会立即执行函数体,而是返回一个生成器对象,需要使用next函数来驱动这个生成器对象,或者使用循环来驱动。
生成器表达式和生成器函数都可以得到生成器对象,只不过生成器函数可以写更加复杂的逻辑。
7.2.1、生成器函数的执行
def gen():
    print(1)
    yield 2
    print(3)
    yield 4
    print(5)
    return 6
    yield 7
    
next(gen()) # ?
next(gen()) # ?
g = gen()
print(next(g)) # ?
print(next(g)) # ?
print(next(g)) # StopIteration
print(next(g, 'End')) # 没有元素给个缺省值

在生成器函数中,可以多次yield,每执行一次yield后会暂停执行,把yield表达式的值返回
再次执行会执行到下一个yield语句又会暂停执行
函数返回
    return语句依然可以终止函数运行,但return语句的返回值不能被获取到
    return会导致当前函数返回,无法继续执行,也无法继续获取下一个值,抛出StopIteration异常
    如果函数没有显式的return语句,如果生成器函数执行到结尾(相当于执行了return None),一样会抛出StopIteration异常
 
 
生成器函数
    包含yield语句的生成器函数调用后,生成 生成器对象 的时候,生成器函数的函数体不会立即执行
    next(generator) 会从函数的当前位置向后执行到之后碰到的第一个yield语句,会弹出值,并暂停函数执行
    再次调用next函数,和上一条一样的处理过程
    继续调用next函数,生成器函数如果结束执行了(显式或隐式调用了return语句),会抛出StopIteration异常
7.2.2、生成器函数
1.1、生成器函数
生成器就是
x = (i for i in range(5))
print(type(x))
print(x)
print(next(x))
print(next(x))
for i in x:
    print(x)
<class 'generator'>
<generator object <genexpr> at 0x0000021147CEC7C8>
0
1
<generator object <genexpr> at 0x0000021147CEC7C8>
<generator object <genexpr> at 0x0000021147CEC7C8>
<generator object <genexpr> at 0x0000021147CEC7C8>
  
7.2.3、yied1生成器函数
7.2.3.1、生成器函数1
1.2、yied1生成器函数
生成器就是特殊的迭代器,可以使用next,当然也可以使用For
迭代器特点,可以使用next,还有到头绝不回头
通过iter可以把任意的可迭代对象包装出一个新的迭代器

1.2.1、生成器函数1
def inc():        #只要这个函数有了yied1,就是生成器函数,生成器函数调用返回不再是返回值,返回一个生成器对象
    for i in range(5):
        yield i
y  = inc()         ----->生成器对象
print((type(y),y))
(<class 'generator'>, <generator object inc at 0x000002BA1DE22EC8>)

for i in y:
    print(i)
0
1
2
3
4
7.2.3.2、生成器函数2
1.2.2、生成器函数2
def test():
    print(1)
    yield 2               ----->yield生成器也会打印出结果
    print(3)
    yield 4
    print(5)
    return 6 
    yield 7
z = test()#z 此函数有没有yield?调用后拿到什么
next(z)   #每驱动一下,就会在yield处暂停函数执行,并且把yield后的值抛出来
1
2
next(z)
3
4
next(z)
5
StopIteration: 6        ----->从这条之后就停止了

def test():
    print(1)
    yield 2               ----->yield生成器也会打印出结果
    print(3)
    yield 4
    print(5)
    return 6 
    yield 7
z = test()
for i in z:
    print(i)
    print('------------')
    print(i,'++')
1                 #print(1)打印1
------------      #'-----'
2 ++              #yield 2 打印2
3                 #print(3)打印3
------------
4 ++              #yield 4 打印4
5                 #print(5)打印5

[i for i in test()], list(test())   
1
3
5
1
3
5
([2, 4], [2, 4])
7.2.3.3、生成器函数3
1.2.3、生成器函数3
def inc():
    for i in range(5):
        yield i    
m = inc()               ----->m是生成器对象
next(m)
0
next(m)
1
next(m),next(m),next(m)
(1, 2, 3)

for i in m:        #for判断如果出现了stopiteration认为到头了,结束循环,不抛异常
    print(i)
0
1
2
3
4
    
for i in inc():   
    print(i)  
inc(),inc(),inc()
(<generator object inc at 0x000001C08A908B48>,
 <generator object inc at 0x000001C08A908D48>,
 <generator object inc at 0x000001C08A908F48>)
 
[inc()]      #一个元素       ----->生成器对象被塞入列表中
[<generator object inc at 0x000001C08A8690C8>]

list(inc())
[0, 1, 2, 3, 4]

tuple(inc())
(0, 1, 2, 3, 4)

set(inc())
{0, 1, 2, 3, 4}

{i for i in inc()}
{0, 1, 2, 3, 4})
7.3、斐波那契数列
def fib():
    a = b = 1
    yield b
    while True:
        a, b = b, a + b
        yield a
        
f = fib()
for i in range(101):
    print(i+1, next(f))
    
斐波那契数列1
斐波那契数列1  
#F(1)-1, F(2)-1,F(n)-F(n - 1)+F(n - 2) (n>2 3,n EN*)
#0、1、1、2、、3、5、8、13、21、34
1 1   a + b 
1 2   3
2 3   5
3 5   8
5 8   13

a = b  = 1
for i in range(5-2):
    a, b = b, a + b #---a,b-1, 1 + 1-1,2  
                    #---a,b - 2,  1 + 2-2,3  
                    #---a,b - 3, 2+3-3,5
a, b
(3, 5)
斐波那契数列2
斐波那契数列2
def fib(n=5):
    a = b = 1
    for i in range(n-2):
        a,b = b, a + b
        print(a,b)
    return b
    
fib()
1 2
2 3
3 5
5

fib(10)
1 2
2 3
3 5
5 8
8 13
13 21
21 34
34 55
斐波那契数列3
斐波那契数列3
def fib(n=5):
    a = b = 1
    yield a               ----->第一次拿到yield  1
    for i in range(n-2):  -----> #fib(3-2),range(1) 0,迭代一下
        a,b = b, a + b
        #print(a,b)
    #return
        yield a           ----->第二次拿到yield  1
    #return
  
f = fib(3)
for index ,v in  enumerate(f,1):    #从1开始
    print(index,v)
1 1
2 1

list(fib(3))
[1, 1]

创建生成器对象fib(3)
for index ,v in  enumerate(fib(3),1):    #从1开始
    print(index,v)
1 1
2 1
斐波那契数列4
斐波那契数列4
def fib():
    a = b = 1
    yield a 
    while True:
        a,b = b , a + b
        yield a
m  = fib()   #生成器函数,就可以得到无限可迭代对象了
for i in range(5):    ------>走5下
    print(i,next(m))
0 1
1 1
2 2
3 3
4 5
7.4、yield from语法
从Python 3.3开始增加了yield from语法,使得yield from iterable 等价于for item initerable: yield item 。
yield from就是一种简化语法的语法糖。


def inc():
    for x in range(1000):
        yield x
# 使用yield from 简化
def inc():
    yield from range(1000) # 注意这个函数出现了yield,也是生成器函数
    
foo = inc()
print(next(foo))
print(next(foo))
print(next(foo))



def foo():
    yield from range(5)
m = foo()
print(next(m)),print(next(m))
0
1
(None, None)

本质上yield from的意思就是,从from后面的可迭代对象中拿元素一个个yield出去。
8、函数调用原理
8.1、函数执行流程
函数执行流程 函数的活动和栈有关。
栈是后进先出的数据结构。
栈是从底向顶端生长,栈中插入数据称为压栈、入栈,从栈顶弹出数据称为出栈。
C语言中,每个栈帧对应着一个未运行完的函数。栈帧中保存了该函数的返回地址和局部变量。
—-> 函数的每一次调用都会创建一个独立的栈帧(Stack Frame)入栈。 因此,可以得到这样一句不准确的话:哪怕是同一个函数两次调用,每一次调用都是独立的,这两次调用没什么关系。
注:函数执行过程辅助网站:http://pythontutor.com/visualize.html#mode=edit,请不要过分依赖这个网站动态效果,不要放弃自己脑子的想象力。
形参都是局部变量,局部变量都要压栈
x = [1,2,3,4]
def fool():
    x = [1,2,3]
    x.append(100)
    return x
fool()
fool()
[1, 2, 3, 100]


y = [1,2,3,4]
def fool(x):
    x[0] += 1
    #x.append(100)
    return x
fool(y)
fool(y)
[3, 2, 3, 4]
9、递归函数
9.1、return递归函数
函数直接或者间接调用自身就是 递归
递归需要有边界条件、递归前进段、递归返回段
递归一定要有边界条件
当边界条件不满足的时候,递归前进
当边界条件满足的时候,递归返回
能不用则不用递归

斐波那契数列递归0
def fib(n=3):                   #------>效率最高1
    a = b = 1
    for i in range(n-2):
        a,b = b, a + b
    return b
%timeit fib(40)
5
5.81 µs ± 503 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
 
递归函数1                       #----->效率较高2
def fib1(n):
    if n < 3:
        return 1
    return fib1(n-1) + fib(n-2)
%timeit fib1(3)
2
%timeit fib1(40)
1134903170
150 µs ± 5.65 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

递归函数2                   #----->效率特别低3,函数的反复压栈,还有递归范围
def fib1(n):
    return 1 if n < 3 else fib1(n-1) + fib(n-2)
%timeit fib1(40)
102334155


递归函数3    ---->循环调用
def fib2(n=3, a=1, b=1):
    if n < 3:
        return b         #----->累加的结果给了b
    a,b = b, a + b
    return fib2(n-1,a,b)
%timeit fib2(10)
55
%timeit fib2(3100)       #------->超出递归的限制范围,


#import sys              #----->函数最多落3000层
print(sys.getrecursionlimit())
3000 

 
image-20210930143643378

 
image-20210930171847733

 
image-20210930174543591
9.2、递归要求
递归一定要有退出条件,递归调用一定要执行到这个退出条件。没有退出条件的递归调用,就是无
限调用

递归调用的深度不宜过深

Python对递归调用的深度做了限制,以保护解释器
  超过递归深度限制,抛出RecursionError: maxinum recursion depth exceeded 超出最大深度
  sys.getrecursionlimit()
9.3、递归效率
使用时间差或者%%timeit来测试一下这两个版本斐波那契数列的效率。很明显循环版效率高。
难道递归函数实现,就意味着效率低吗?
能否改进一下fib_v2函数?
# 递归
def fib_v3(n, a=1, b=1):
    if n < 3:
        return b
    a, b = b, a + b
    print(n, a, b)
    return fib_v3(n-1, a, b) # 函数调用次数就成了循环次数,将上次的计算结果代入下次函数调用
    
fib_v3(101) # fib_v3(35)

思考时,也比较简单,思考fib_v3(3)来编写递归版本代码。
经过比较,发现fib_v3性能不错,和fib_v1循环版接近。但是递归函数有深度限制,函数调用开销较大。
9.4、间接递归
def foo1():
    foo2()
def foo2():
    foo1()
    
foo1()

间接递归调用,是函数通过别的函数调用了自己,这一样是递归。

只要是递归调用,不管是直接还是间接,都要注意边界返回问题。但是间接递归调用有时候是非常不明显,代码调用复杂时,很难发现出现了递归调用,这是非常危险的。

所有,使用良好的代码规范来避免这种递归的发生。


总结
递归是一种很自然的表达,符合逻辑思维
递归相对运行效率低,每一次调用函数都要开辟栈帧
递归有深度限制,如果递归层次太深,函数连续压栈,栈内存很快就溢出了
如果是有限次数的递归,可以使用递归调用,或者使用循环代替,循环代码稍微复杂一些,但是只
要不是死循环,可以多次迭代直至算出结果
绝大多数递归,都可以使用循环实现
即使递归代码很简洁,但是能不用则不用递归
10、匿名函数和排序
10.1、匿名函数
Python中,匿名函数也叫lambda表达式。
匿名:隐藏名字,即没有名称
匿名函数:没有名字的函数。
函数没有名字该如何定义?函数没有名字如何调用?
10.1.1、Lambda表达式
Lambda表达式
Python中,使用Lambda表达式构建匿名函数。

def foo(x):
    return x ** 2
    
lambda x: x ** 2 # 定义
(lambda x: x ** 2)(4) # 调用

foo = lambda x,y: (x+y) ** 2 # 定义函数
foo(1, 2)
# 等价于
def foo(x,y):
    return (x+y) ** 2
    
使用lambda关键字定义匿名函数,格式为lambda [参数列表]: 表达式
参数列表不需要小括号。无参就不写参数
冒号用来分割参数列表和表达式部分
不需要使用return。表达式的值,就是匿名函数的返回值。表达式中不能出现等号
Python的lambda表达式(匿名函数)只能写在一行上,也称为单行函数
匿名函数往往用在为高阶函数传参时,使用lambda表达式,往往能简化代码

# 返回常量的函数
print((lambda :0)())

# 加法匿名函数,带缺省值
print((lambda x, y=3: x + y)(5))
print((lambda x, y=3: x + y)(5, 6))

# keyword-only参数
print((lambda x, *, y=30: x + y)(5))
print((lambda x, *, y=30: x + y)(5, y=10))

# 可变参数
print((lambda *args: (x for x in args))(*range(5))) # 生成器
print((lambda *args: [x+1 for x in args])(*range(5))) # 列表
print((lambda *args: {x%2 for x in args})(*range(5))) # 集合
print((lambda *args: {str(x):x for x in args})(*range(5))) # 字典

print(dict(map(lambda x: (chr(65+x), 10-x), range(5)))) # 高阶函数,构建字典

d = dict(map(lambda x: (chr(65+x), 10-x), range(5))) # 高阶函数
sorted(d.items(), key=lambda x:x[1])
10.1.2、Lambda表达式2
def add(x, y):                 ----->互为等价 
                 #add标识符是全局,形参x,y 形参x, y add指向一个函数对象,函数的名字,函数的名字'add'
    return x + y

add =  lambda x, y: x + y      ----->互为等价 

lambda函数表达式1:
lambda x: x ** 2        #------->使用lambda(函数)表达的单形参的函数,x的2次方
<function __main__.<lambda>(x)>


fn = _                  #------->_表示为out
fn(5)
25

lambda函数表达式2:
#创建函数表达式
def guess(x):
    if x >= 0:
        return 'positive'
    else:
        return 'negative'
        
guess(5)
'positive'


def guess(x):
    return 'positive' if x >= 0 else 'negative'
lambda x: 'positive' if x >=0 else 'negative'
guess = lambda x: 'positive' if x >=0 else 'negative'   #---->创建函数表达式
guess(5)
'positive'
guess(-5)
'negative'


lambda函数表达式3:
def guess(x):
    return 'positive' if x >= 0 else 'negative'
l1  = [lambda x: 'positive' if x >=0 else 'negative']
l1[0](6)             #----->l1[0]表达一个函数,(6)表达一个元素
'positive'

lambda函数表达式4:
lambda :0
<function __main__.<lambda>()>
lambda x: 0
<function __main__.<lambda>(x)>
lambda x: []
<function __main__.<lambda>(x)>
l1 = lambda x: 0
l1(5)
0

lambda函数表达式5:
#函数表达式列表、元组、集合使用
lambda x: x+1, lambda x: x**2
(<function __main__.<lambda>(x)>, <function __main__.<lambda>(x)>)
(lambda x: [x])(5)                 
[5]                        ----->表达出列表
(lambda x: (x,x+1,x+2))(5)  
(5, 6, 7)                  ----->表达出元组
(lambda x: {x, x+1})(5)
{5, 6}                     ----->表达出集合
(lambda x: {x:x+1 for x in range(x)})(5)
{0: 1, 1: 2, 2: 3, 3: 4, 4: 5}                ----->表达出字典
(lambda x: {str(x):x+1 for x in range(x)})(5)
{'0': 1, '1': 2, '2': 3, '3': 4, '4': 5}      ----->表达出字符串


lambda函数表达式6:
#创建生成器对象
g = (lambda x: (i**2 for i in range(5)))(5)          #---->创建生成器对象
next(g)                
9
(lambda x: [i for i in range(5)])(5)
[0, 1, 2, 3, 4]
(lambda x: [i**2 for i in range(5)])(5)
[0, 1, 4, 9, 16]
(lambda x: {i**2 for i in range(5)})(5)
{0, 1, 4, 9, 16}
(lambda x: {i%2 for i in range(5)})(5)
{0, 1}


lambda函数表达式7:
#设置元组
(lambda x, y: (x,y+10))(3,4)     #---->设置两个参数变成元组
(3, 14)
(lambda x=5, y=6: (x,y))(3)     
(3, 6)           ----->设置x传参数
(lambda x=5, y=6: (x,y))(3,y=7)
(3, 7)
(lambda  *args: list(args))(3,4,5)    #---->将arg中所有元素拿出来装到list里面去
[3, 4, 5]     ---->相同
(lambda  *args: [i for i in args])(3,5,7)
[3, 5, 7]     ---->相同
(lambda  *args, x: (x ,[i for i in args]))(3,5,7,x=10)
(10, [3, 5, 7])


lambda函数表达式8:              
#lambda作为比较
sorted([1,7,4,2],key=lambda x: x+10)      
[1, 2, 4, 7]            ------>做降序
sorted([1,7,4,2],key=lambda x: 10-x)
[7, 4, 2, 1]            ------>做升序


lambda函数表达式9:  
#比较做升序
def fn(x):
    if isinstance(x,str):
        return int(x,16)
    else:
        return x
sorted([1,7,3,'a',12,4], key=lambda x: int(x, 16) if isinstance(x, str) else x)  
[1, 3, 4, 7, 'a', 12]

sorted([('a',100),('b',50),('c',1)], key = lambda x: x[1])
[('c', 1), ('b', 50), ('a', 100)]         ------>做升序
d = dict([('a',100),('b',50),('c',1)]) 
sorted(d.items(),key = lambda item: item[1])
[('c', 1), ('b', 50), ('a', 100)]         ------>做升序

 
image-20211007223115815

 
image-20211007234054116
11、高阶函数和时间模块
11.1、一等公民
函数在Python是一等公民(First-Class Object)
函数也是对象,是可调用对象
函数可以作为普通变量,也可以作为函数的参数、返回值
11.2、高阶函数
高阶函数(High-order Function)
    数学概念 y = f(g(x))
    在数学和计算机科学中,高阶函数应当是至少满足下面一个条件的函数
        接受一个或多个函数作为参数
        输出一个函数
        
观察下面的函数定义,回答问题

def counter(base):
    def inc(step=1):
        nonlocal base
        base += step
        return base
    return inc
    
请问counter是不是高阶函数?
上面代码有没有问题?如果有,如何改?
如何调用以完成计数功能?
f1 = counter(5)和f2=counter(5),请问f1和f2相等吗?

def counter(base):
    def inc(step=1): # 有没有闭包?
        nonlocal base # 形参base也是外部函数counter的local变量
        base += step
        return base
    return inc
    
c1 = counter(5)
print(c1())
print(c1())
print(c1())

f1 = counter(5)
f2 = counter(5)
print(f1 == f2) # 相等吗?
11.2.1、高阶函数使用
高阶函数1:
def counter(base):      #---->base是局部变量(在外面的),是counter局部变量   
    def inc(step=1):
        nonlocal base    #---->非本地的局部变量base,而是外层的局部变量
        base += step     #---->这个base是局部变量
        return base      #---->返回base这个局部变量
    return inc        #返回一个函数对象
    
foo  = counter(100)
foo()
101
foo()
102

f1 = counter(5)      #各自在内存的不同位置
f2 = counter(5)      #各自在内存的不同位置
print(f1 is f2)      #每次调用的内存地址不同
print(f1 == f2)      #比较内存地址
False
False


11.2.2、时间模块
datetime模块
datetime类是时间高级类

    类方法,即使用类调用的方法,由类方法获得一个时间对象
        now(tz=None) 返回当前时间的datetime对象,时间到微秒,如果tz为-
        -None,返回当前时区的不带时区信息的时间
        utcnow() 不带时区的0时区时间
        fromtimestamp(timestamp, tz=None) 从一个时间戳返回一个datetime-
        -对象
        
    时间对象方法  
        timestamp() 返回一个到微秒的时间戳
            时间戳:格林威治时间1970年1月1日0点到现在的秒数
        构造方法 datetime.datetime(2016, 12, 6, 16, 29, 43, 79043)
        year、month、day、hour、minute、second、microsecond,取datetime- 
        -对象的年月日
        时分秒及微秒
        weekday() 返回星期的天,周一0,周日6
        isoweekday() 返回星期的天,周一1,周日7
        date() 返回日期date对象
        time() 返回时间time对象
        
import datetime

# 类方法获得时间对象
print(datetime.datetime.now(datetime.timezone(datetime.timedelta(hours=8)))) #

时区时间
print(datetime.datetime.now()) # 无时区时间
print(datetime.datetime.utcnow()) # UTC时间,可以认为是GMT或0时区时间

# 时间戳操作
stamp = datetime.datetime.now().timestamp() # 获得时间戳
print(stamp)
dt = datetime.datetime.fromtimestamp(stamp) # 从时间戳获得时间对象
print(dt)

print(type(dt.date()), dt.date())
print(type(dt.time()), dt.time())



1.1、import datetime   #模块
#时间也是对象。 datetime类,timedalta类(增量)
datetime.datetime.now()     #now返回当前时间的实列,对象
datetime.datetime(2021, 10, 8, 10, 56, 25, 440947)
datetime.datetime.utcnow()  #简单认为,格林威治时间,0时区
datetime.datetime(2021, 10, 8, 3, 4, 45, 353669)
datetime.timezone(datetime.timedelta(hours=8))  #相对于utc的一个时区 
datetime.timezone(datetime.timedelta(seconds=28800))


1.2、计算同类型时间差(不同类型时间差报错):
1.2.1、当前时间
d1 = datetime.datetime.now()   
d1
datetime.datetime(2021, 10, 8, 14, 41, 3, 669716)
1.2.2、不带时区的0时区时间
d2 = datetime.datetime.now(datetime.timezone(datetime.timedelta(hours=8)))
d2
datetime.datetime(2021, 10, 8, 14, 42, 44, 758063, tzinfo=datetime.timezone(datetime.timedelta(seconds=28800)))
1.2.3、同类型时间差计算
d3 = datetime.datetime.now()
d2 - d1  #---->报错
d3 - d1  #---->时间差   

1.3、时间戳: 
datetime.timedelta(seconds=158, microseconds=980028)#timedelta时间增量
d2.timestamp()   #---->1970到现在的时间戳
1633663092.041996
d3.timestamp()   #---->1970到现在的时间戳
1633663244.301467

1.4、构造时间对象的方式:
d4 = datetime.datetime(2021, 10, 8, 3, 12, 45, 291699)
d4
datetime.datetime(2021, 10, 8, 3, 12, 45, 291699)

d5 = datetime.datetime.fromtimestamp(1633663085)
d5
datetime.datetime(2021, 10, 8, 11, 18, 5)

1.5、构建时间对象:
1.5.1、解析字符串
d6 = datetime.datetime.strptime('2018716 20:30:15','%Y%m%d %H:%M:%S' ) #parse(解析字符串)  %Y=年 %m=月 %d=日  %H=小时 %M=分钟  %S=秒  %z=时区
d6
datetime.datetime(2018, 7, 16, 20, 30, 15)

1.5.2、timedelta时间增量使用
d6 + datetime.timedelta(2, hours=1)        #------>增加2天一小时
datetime.datetime(2018, 7, 18, 21, 30, 15)
(d3 - d1).total_seconds()                  #------>d3与d1时间差
158.980028

1.5.3、显示年月日
d6.strftime('%Y-%m-%d %H:%M:%S')     #显示年月日 
'2018-07-16 20:30:15'
d2.strftime('%Y-%m-%d %H:%M:%S %z')  #显示年月日(显示时区)
'2021-10-08 11:18:12 +0800'

"{} {}".format(d6.year,"年")         #显示年月日 
'2018 年'

"{} 年{}月{}日 {}时{}分{}              秒".format(d6.year,d6.month,d6.day,d6.hour,d6.minute,d6.second)
'2018 年7月16日 20时30分15秒'         #显示年月日 


1.6、time时间模块
import time 
time.sleep(10)        #阻塞当前线程,睡10s
print('------------------')
print(123)
------------------
123

import time
while True:
    time.sleep(1)
    print('___________________')
___________________
___________________
___________________
___________________
___________________


1.6.1、rsplit时间拆分
d7 = datetime.datetime.strptime('20200909 20:10:30  +0800', '%Y%m%d %H:%M:%S %z')
d7
datetime.datetime(2020, 9, 9, 20, 10, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=28800)))

'20200909 20:10:30  +0800'.rsplit(maxsplit=1)[0]  #-->rsplit时间拆分
'20200909 20:10:30'

datetime.datetime.strptime('20200909 20:10:30  +0800'.rpartition(' ')[0], '%Y%m%d %H:%M:%S ')                        #-->rspartiton时间拆分
datetime.datetime(2020, 9, 9, 20, 10, 30)

 
image-20211008143137749

 
image-20211009115737911
12、内建高阶函数
12.1、排序sorted
排序sorted
定义sorted(iterable, *, key=None, reverse=False) ->list

sorted(lst, key=lambda x:6-x) # 返回新列表
list.sort(key=lambda x: 6-x) # 就地修改
12.1.1、sorted排序
sorted([1,2,3,5,'7'],key=str)
[1, 2, 3, 5, '7']

sorted([12,1,2,'a'],key=lambda x: str(x), reverse=True)   #---->reverse反转
['a', 2, 12, 1]

升序
sorted([12,1,2,'a'],key=lambda x: x if isinstance(x,int)  else int(x, 16))   #----->isinstance(实列)
[1, 2, 'a', 12]                                                              #----->16为16进制
降序
sorted([12,1,2,'a'],key=lambda x: x-6 if isinstance(x,int)  else int(x, 16))
[1, 2, 12, 'a']
12.2、过滤filter
定义filter(function, iterable)
对可迭代对象进行遍历,返回一个迭代器
function参数是一个参数的函数,且返回值应当是bool类型,或其返回值等效布尔值。
function参数如果是None,可迭代对象的每一个元素自身等效布尔值

list(filter(lambda x: x%3==0, [1,9,55,150,-3,78,28,123]))
list(filter(None, range(5)))
list(filter(None, range(-5, 5)))
12.2.1、filter过滤
next(filter(None,[1,2,3]))     #---->None表示filter使用每一个元素自身等效True或False(过滤掉),True通过
1

list(filter(None,[1,2,3]))
[1, 2, 3]

list(filter(None,range(-4,4)))
[-4, -3, -2, -1, 1, 2, 3]

list(filter(None,[0,1,-1,True,False,'','abc',[],(),{},set()]))
[1, -1, True, 'abc']

list(filter(lambda x: x,range(10)))    #filter如果写函数,单个参数
[1, 2, 3, 4, 5, 6, 7, 8, 9]
list(filter(lambda x: [x],range(10)))    #filter如果写函数,单个参数
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

list(filter(lambda x: x%2 == 0, range(10)))     #-->互为等价
[0, 2, 4, 6, 8]
[x for x in range(10) if x % 2 == 0]            #-->互为等价
[0, 2, 4, 6, 8]
12.3、映射map
定义map(function, *iterables) -> map object
对多个可迭代对象的元素,按照指定的函数进行映射
返回一个迭代器

list(map(lambda x: 2*x+1, range(10)))
dict(map(lambda x: (x%5, x), range(500)))
dict(map(lambda x,y: (x,y), 'abcde', range(10)))
12.3.1、map映射
list(map(lambda x: x+1,range(5)))
[1, 2, 3, 4, 5]

list(map(lambda x: (x,x+1),range(5)))         #--->生成字典
[(0, 1), (1, 2), (2, 3), (3, 4), (4, 5)]
 
dict(map(lambda x: (str(x),x+1),range(5)))    #--->生成字典
{'0': 1, '1': 2, '2': 3, '3': 4, '4': 5}

dict(map(lambda x: (x+0x30,x+1),range(5)))    #--->0x30为48
{48: 1, 49: 2, 50: 3, 51: 4, 52: 5}

dict(map(lambda x: (chr(x+97),x+1),range(5))) #--->生成字典
{'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}

list(map(lambda x,y:(x,y),[1,2,3,4],'abcd'))  
[(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd')]

dict(map(lambda x,y:(x,y),[1,2,3,4],'abcd'))  #--->生成字典
{1: 'a', 2: 'b', 3: 'c', 4: 'd'}
12.4、拉链函数zip
zip(*iterables)
像拉链一样,把多个可迭代对象合并在一起,返回一个迭代器
将每次从不同对象中取到的元素合并成一个元组

list(zip(range(10),range(10)))
list(zip(range(10),range(10),range(5),range(10)))

dict(zip(range(10),range(10)))
{str(x):y for x,y in zip(range(10),range(10))}
12.4.1、zip拉链函数
list(zip(range(5)),range(5),range(5),'abc')     #---->zip从每个range中拿去一个元素形成三元组
(0, 0, 0), (1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4)]

list(zip(range(5),range(5),range(5),'abc'))
[(0, 0, 0, 'a'), (1, 1, 1, 'b'), (2, 2, 2, 'c')]

构建字典(常用方式)
dict(zip('abc',[1,2,3,4]))
{'a': 1, 'b': 2, 'c': 3}

标签:return,函数,04,python,add,fn,print,def
From: https://www.cnblogs.com/zikang/p/17103897.html

相关文章

  • 第02天-python线性数据结构
    1、数值处理1.1、内建常用数据类型1.1.1、分类数值型int、float、complex、bool序列sequence字符串str、字节序列bytes、bytearray列表list、元组t......
  • 第03天-python字节序列字典
    1、字节序列和切片1.1、字节序列Python3引入两个新的类型bytes、bytearray。bytes不可变字节序列;bytearray是可变字节数组。字节的世界里面没有编码1.2、编码与解......
  • 04-Verilog基础
    ModuleModule是verilog中的关键字,是对电路建模的最小单元。verilog中构建一个电路,对于一个硬件进行描述在module中进行。半加器modulehalf_adder(S,C,A,B);outp......
  • Python,形参,实参,值传递,地址传递
    1.值传递在实参向形参传递的过程中,传递的只是实参的值,而在函数体操作的时候,实际操作的并不是实参而是形参,所以,值传递不改变原变量值。2.地址传递在实参向形参传递的过程中......
  • 二分查找 Leetcode704
    1.二分查找(Leetcode704)题目:给定一个n(n在[1,10000]之间)个元素有序的(升序)整型数组nums和一个目标值target,写一个函数搜索nums中的target,如果目标值存在返回下标,否......
  • Python mock
    官方链接:https://docs.python.org/zh-cn/3/library/unittest.mock-examples.htmlMock备注:常用的有两个mock类:Mock和MagicMock,在多数示例中,Mock与MagicMock两个类......
  • 【视频】风险价值VaR原理与Python蒙特卡罗Monte Carlo模拟计算投资组合实例|附代码数
    原文链接:http://tecdat.cn/?p=22862 最近我们被客户要求撰写关于风险价值VaR的研究报告,包括一些图形和统计输出。风险价值(VaR)是一种统计数据,用于量化公司、投资组......
  • python学习——【第四弹】
    前言上一篇文章​​python学习——【第一弹】​​中,我们了解了python当中的流程控制语句,这篇文章我们接着学习python中的序列。这篇文章先给大家介绍不可变序列字符串和可......
  • 1行Python代码,对话ChatGPT,网友:太方便了!
    大家好,这里是程序员晚枫。最近ChatGPT火爆全球,哪怕你不是程序员,应该也听过他的大名了。今天我们就来一起体验一下~1行Python代码就够了!上代码导入poai这个库后,只需要1......
  • centos7安装python3.X(与Python2.X共存)
    先卸载自带的python3centos7自带python2.7和python3.6卸载自带的python3.6,重新安装python3.7卸载python3.6#卸载python3rpm-qa|greppython3|xargsrpm-ev--allma......