PY01-03:Python程序过程设计与函数

本文的主题都是关于函数的
  1. 函数的语法;
  2. 函数的对象;
  3. 函数装饰器;
  4. lambda表达式;
  5. Python内置函数;
  6. \cdots\cdots


主题三:程序过程与设计

目标

  • 应用目标

      1. 阶段实战:
      • 股票查询系统的查询结果翻页显示;
      • 信息系统的选择菜单;
      1. 综合实战:
      • 完成股票查询系统的程序结构;

        面向过程的程序设计

      • 完成信息管理系统的程序结构;

  • 技能目标

      1. 能构建模块化的应用程序;
      1. 基本技术应用能力
      • 能正确封装设计函数过程,并实现函数定义;
      • 能正确调用函数完成数据处理;
      • 能在函数中使用装饰器来实现特定应用;
      • 能正确lambda表达式简化程序复杂度;
      • 能正确使用内置标准函数与函数模块;
  • 知识点目标

    • 掌握函数的定义的调用
    • 掌握函数的参数
    • 掌握函数的返回值
    • 掌握函数体与作用域
    • 掌握递归函数
    • 掌握函数对象
    • 掌握函数装饰器
    • 掌握lambda表达式
    • 掌握顶层函数
    • 掌握Python内置标准函数
    • 掌握基本标准模块函数

函数的调用

  在函数的编程方面,我们最容易用到的是经常调用函数。然后是根据需要封装定义函数,再调用。所以在这类我们先从函数调用运算符开始学习函数调用,然后再学习这些调用的函数是怎么实现的。

函数的调用语法

  1. 函数调用的语法
    • Python提供了函数调用运算符号 ()

    函数名(参数1,参数2,......)        # 没有返回值
    变量 = 数名(参数1,参数2,......)    # 有返回值


  • 规则1:
    • 调用函数,参数必须是字面值,已经定义的变量,其他功能语句的返回结果。
a = 20
print('hello', a, a+40, input('输入数据'))

输入数据56
hello 20 60 56
  • 规则2:
    • 如果函数是在其他文件(模块),或者其他目录(包)的文件(模块)中,需要使用import 加载目录下的模块。
    • 在使用函数的时候,根据import的方式,需要指定包路径与模块名。
import os
files = os.listdir()
for f in files:
    print(f)
.DS_Store
.ipynb_checkpoints
a.txt
codes
L0_L1_L2_Regularization.ipynb
py.png
Python入门基础.ipynb
Python入门基础@数据与应用.ipynb
Python入门基础@数据与应用.pptx
Python入门基础@数据运算与流程控制.ipynb
Python入门基础@程序过程设计与函数.ipynb
Python入门基础@课程说明.ipynb
未命名.ipynb
未命名1.ipynb
课件@第01&02次
  • 规则3:
    • 如下情况,参数是可选的。
      • 参数带默认值,比如:sep=','
      • 可选的参数,如果没有传递的时候,就使用默认值。
    • 除此以外的情况,参数都是必须的。
print(1,2,3,4)
print(1,2,3,4,sep='。')
1 2 3 4
1。2。3。4
  • 规则4:

    • 文档中使用....表示的,参数可以多个,不受个数限制
  • 规则5:

    • 可以在调用函数的时候,指定参数名;
    • 如下情况必须指定参数名:
      • 文档中函数参数中出现.....或者*的后面的参数,必须指定参数名。
    • 如下情况,一定不能指定参数名:
      • 文档中函数参数中出现/的前面的参数,不能指定参数名。
print('hello', 'world', sep='...')  # 只要sep使用,就必须使用参数名。
hello...world
  • 规则6:

    • 参数的顺序必须按照文档中显示的顺序传递。
  • 规则7:

    • 使用参数名的参数,可以不按照顺序使用。
    • 没有使用参数名的参数必须按照顺序使用。
    • 一旦某个参数使用了参数名,则后面参数都必须使用参数名。(不使用参数名的参数一定在前面。)
print('hello', 'word', flush=True, sep='...')

from socket import *
socket(AF_INET, SOCK_STREAM, proto=0, fileno=None)
socket(type=SOCK_STREAM, family=AF_INET, proto=0, fileno=None)
# socket(type=SOCK_STREAM, AF_INET, proto=0, fileno=None)
hello...word





<socket.socket fd=60, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('0.0.0.0', 0)>
  1. 使用help查看函数帮助
    • 使用help函数直接查看帮助,从得到的信息中,重点关注如下几个信息:
      • 函数的定义(函数名 + 函数参数 + 函数的返回类型);
      • 函数的作用与返回值;


        在帮助查看函数返回值

简单的函数调用

  1. 输入输出函数
  • input函数

input(prompt=None, /)
    Read a string from standard input.  The trailing newline is stripped.

  • 注意:
    • / 前面的参数不允许使用,参数名


      函数的调用与调用运算发
result = input( '请输入数据:')
请输入数据:56
  • print函数
    print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
    
    Prints the values to a stream, or to sys.stdout by default.
    Optional keyword arguments:
    file:  a file-like object (stream); defaults to the current sys.stdout.
    sep:   string inserted between values, default a space.
    end:   string appended after the last value, default a newline.
    flush: whether to forcibly fl    
fd = open('a.txt', 'w')

print('输出值', 20, sep='|', end='。', file=fd, flush=True)

fd.close()
  1. 数学运算函数
  • abs函数
    • 返回一个数据的绝对值
abs(x, /)
    Return the absolute value of the argument.
a = abs(-1)
print(a)
1
  • divmod函数
    • 求商与余数

divmod(x, y, /)
    Return the tuple (x//y, x%y).  Invariant: div*y + mod == x.

a = divmod(34.5,  7.5)
print(a)
(4.0, 4.5)
  • round函数
    • 四舍五入
    round(...)
        round(number[, ndigits]) -> number
    
a = round(45.7852135, 3)
print(a)
45.785
  • min函数
    • 求最小值

    min(iterable, *[, default=obj, key=func]) -> value
    min(arg1, arg2, *args, *[, key=func]) -> value
    
    With a single iterable argument, return its smallest item. The
    default keyword-only argument specifies an object to return if
    the provided iterable is empty.

key= func模式是Python独有的编程模式,用函数来决定处理的数据。

a = min([1, 5, 3, 8, 9, 2], default=999)
print(a)
b = min([], default=999)
print(b)



dt = {
    '赵德柱': 30, 
    '黄金花': 80,
    '石破天': 70
}
def  func(p):
    return dt[p]

c = min(dt, default=999, key=func)
print(c)
1
999
赵德柱
  • max函数
    • 求最大值

    max(iterable, *[, default=obj, key=func]) -> value
    max(arg1, arg2, *args, *[, key=func]) -> value
    
    With a single iterable argument, return its biggest item. The
    default keyword-only argument specifies an object to return if
    the provided iterable is empty.

dt = {
    '赵德柱': 30, 
    '黄金花': 80,
    '石破天': 70
}
def  func(p):
    return dt[p]

c = max(dt, default=999, key=func)
print(c, dt[c])
黄金花 80
  • sum函数
    • 求和

    sum(iterable, start=0, /)
        Return the sum of a 'start' value (default: 0) plus an iterable of numbers


a = sum([1, 5, 3, 8, 9, 2], 1000)
print(a)
1028
  • pow函数
    • 指数运算

    pow(x, y, z=None, /)
        Equivalent to x**y (with two arguments) or x**y % z (with three arguments)

a = pow(10, 2,)
print(a)

b = pow(10, 2, 10)
print(b)
100
0
  1. 类型判定函数
  • id函数
    • 返回变量的地址

id(obj, /)
    Return the identity of an object.

a = 100
print(id(a))
print(id(100))

# 超过一个字节,就会单独创建空间,并拷贝数据
b =257
print(id(b))
print(id(257))

4405122080
4405122080
4442678512
4442678224
  • isinstance函数
    • 判定变量的类型

    isinstance(obj, class_or_tuple, /)
        Return whether an object is an instance of a class or of a subclass thereof.

a = 'hello'

# 
r = isinstance(a, str)
print(r)
True
  1. 类型转换函数
  • ord函数
    • 返回unicode码
    ord(c, /)
        Return the Unicode code point for a one-character string.

print(ord('汉'))
27721
  • hex函数
    • 返回整数的16进制表示
    hex(number, /)
        Return the hexadecimal representation of an integer.

print(hex(111111111111111111))
0x18abef7846071c7
  • bin函数
    • 返回整数的二进制表示
    bin(number, /)
        Return the binary representation of an integer.
print(bin(888888888888))
0b1100111011110101111010000000111000111000
  • ascii函数
    • 返回字符的ASCII码
    ascii(obj, /)
        Return an ASCII-only representation of an object.
print(ascii('abcdef汉字'))
print(ascii(1245))    # 作为字符串处理
'abcdef\u6c49\u5b57'
1245
  • chr函数
    • 返回unicode的字符表示
    chr(i, /)
        Return a Unicode string of one character with ordinal i; 0 <= i <= 0x10ffff.

print(chr(0x6c49))
  1. 列表有关函数
  • len函数
    • 返回数据结构的长度
    len(obj, /)
        Return the number of items in a container.
print(len([1,2,3,4,5]))
5
  • any函数
    • 判定序列中元素转换为bool后,是否有True。
    any(iterable, /)
        Return True if bool(x) is True for any x in the iterable.
        
        If the iterable is empty, return False.

a = [1, 2, 3, 4, 5, 0]
print(any(a))
True
  • all函数
    • 判定序列中元素转换为bool后,是否都是True。
    all(iterable, /)
        Return True if bool(x) is True for all values x in the iterable.

        If the iterable is empty, return True.
a = [1, 2, 3, 4, 5, 0]
print(all(a))
False

函数变量(函数命名)

  • 把函数当成一个值使用,赋值给变量,变量也像函数一样使用。
  • 函数当成值来使用,不能使用()调用运算符号
  • 函数可以赋值给变量的最大好处是:函数可以命名,与数据值可以命名一样。
  • 函数变量与原来函数的使用完全一样的。
myfunc = print
myfunc(1,2,3,sep='...')
1...2...3

函数的定义与实现

  1. 语法
def  函数名(参数名,.....) :
    语句
    ......
    return  值
  • 规则:

    • 函数名遵循标识字的命名规则。

    • 参数名遵循标识字的命名规则。

    • 参数可以多个,使用逗号分隔。

    • 没有参数的情况,就直接使用空的括号 def 函数名():

    • 需要输出值,就是用return 值;

    • 不需要输出值,下面三种情况都可以:

      • return None
      • return
      • 省略return语句。
    • 函数必须先定义才能调用。

  • 规范:

    • 函数名的命名规范:建议采用小写字母。
    • 函数定义与其他代码之间,前后保留两个空行。
  1. 简单的函数实现与调用
    • 使用函数表示一组代码,通过一个函数名,就可以执行到一组代码,这样代码可以反复调用,提高编码效率。
# print_hello()   # 没有定义不能调用

def  print_hello():    
    print('hello')

print_hello()    # 上面已经定义,可以调用。
print_hello()    # 上面已经定义,可以调用。
print(print_hello())  # 默认返回None
hello
hello
hello
None
  1. 简单函数参数实现与调用
    • 使用参数的好处,就是调用者可以根据需要传递数据。
def  print_hello(info):
    print(info)
    return


print_hello('hello')
print_hello('world')
print(print_hello('ok'))  # 默认返回None
hello
world
ok
None
  1. 简单返回值实现与调用
def  format_color(info):
    val = F'\033[32;40m{info}\033[0m'
    return val

print(format_color('Hello'))
print(format_color('World'))
�[32;40mHello�[0m
�[32;40mWorld�[0m
  1. 函数的文档注释
    • 函数体中的第一行,都会作为文档注释使用。
  • 编码规范:
    • 尽管函数文档注释可以是任何字符串,但建议使用三个双引号来作为文档注释。
def  doc_function():
    """
        这是我的文档注释:
        该函数是空的。
    """
    pass    # 空语句
help(doc_function)
Help on function doc_function in module __main__:

doc_function()
    这是我的文档注释:
    该函数是空的。

在python交互式编程终端查看的帮助:

在终端交互式编程环境中查看帮助
  1. 函数的参数类型说明
    • 可以在函数定义时说明参数类型:

    def 函数名(参数:类型,....)->返回值类型:
def add(a:int, b:int = 55) ->int:
    return a+b


print(add(45))
100
  1. 函数的返回值类型说明
    • 在Python3以后增加了函数的返回值类型说明,语法如下:

def 函数名(参数,...) ->类型:
    语句
    ...
    return  值

  • 函数的返回类型不是强制的。不过我们申明了什么类型,还是按照类型返回!
def  cal(p, q, r)->int:
    """
    计算和与积,返回整数。
    """
    v= (p+q)*r
    return v

print(cal(2,3,4))
20
help(cal)
Help on function cal in module __main__:

cal(p, q, r) -> int
    计算和与积,返回整数。
  • 下面代码也是没有问题的,但是不规范。
def  cal2(p, q, r)->int:
    """
    计算和与积,返回整数。
    """
    v= (p+q)*r

print(cal2(2,3,4))
None

函数的参数

  Python中函数的参数与其他很多语言有差异,使用起来也非常方便。

  1. 参数名(keyword参数)
    • Python中函数定义的参数名,在调用的时候,是可以使用的。
    • 使用参数名的好处就是不用注意参数的顺序。
    • 参数名在调用的时候没使用,语法如下:
      • 参数名 = 参数值
def add(p1, p2):
    return p1 + p2

# 使用参数名
v = add(p2=55, p1=45)
print(v)
100
  1. 可选参数
    • 可选参数也称默认参数,是指在定义函数的时候,参数可以指定默认值,在调用的时候,参数可以不传递,不传递的参数使用默认值作为传递的参数值。

    • 默认参数在定义函数的时候指定,语法如下:

      • 参数名 = 默认值
    • 注意:默认参数一定要放在非默认参数后面。换句话说就是,默认参数后面出现非默认参数是语法错误的。

# 定义默认参数
def add(p1=45, p2=55):
    return p1 + p2

v = add()
print(v)

def add2(p1=45, p2):
    return p1 + p2


  File "<ipython-input-37-ef8d42b4a601>", line 8
    def add2(p1=45, p2):
            ^
SyntaxError: non-default argument follows default argument
  1. 变长参数
    • Python提供两种变长参数:带参数名,不带参数名。
      • 不带参数名的变长参数:

        • 函数定义:*args

        • 函数会使用:参数值1,....,参数值n

        • 说明:参数使用元组类型传递。

      • 带参数名的变长参数:

        • 函数定义:**kwargs

        • 函数使用:参数名1=参数值1,...., 参数名n=参数值n

        • 说明:参数使用字典传递

def add(*arg):
    return arg


# v = add(p1=1, p2=2,p3=3,p4=4,p5=5)    # 不带参数名变长参数,不能使用参数名。
v = add(1, 2,3,4,5)
print(v)

(1, 2, 3, 4, 5)
def add(**arg):
    return arg



# v = add(1, 2,3,4,5)    # 带参数名变长参数,不使用参数名会导致错误。
v = add(p1=1, p2=2,p3=3,p4=4,p5=5)    
print(v)

{'p1': 1, 'p2': 2, 'p3': 3, 'p4': 4, 'p5': 5}
  • 变长参数*与**的顺序
    • * 与 **用来区分带参数名与不带参数名。

      • * 不带参数名
      • ** 带参数名
    • 注意

      • *参数只能出现在**参数前面
    • 在函数体中,使用*与**用来表示参数的使用方式

# *变长参数只能用在**前面,否则语法错误。
def add(**kwargs, *args):
    pass
  File "<ipython-input-40-6028b7d48620>", line 2
    def add(**kwargs, *args):
                      ^
SyntaxError: invalid syntax
  • 变长参数只能一个,不能使用两个
def add(*args1, *args2):
    pass
  File "<ipython-input-41-892fcf8ad5af>", line 1
    def add(*args1, *args2):
                    ^
SyntaxError: invalid syntax
  • 变长参数中*与**的作用
    • *的使用:
      • *:在函数参数定义中使用,负责把函数调用的参数打包成元组。
      • *:在函数体中使用,负责把列表解包成参数列表。
    • **的使用:
      • **:在函数参数定义中使用,负责把函数调用的参数打包成字典。(定义)
      • **:在函数体中使用,负责把字典解包成参数列表。 (调用:作为普通参数传递给其他参数调用)
        函数的参数的压包与解包
def display1(a1,a2,a3,a4):
    print(a1,a2,a3,a4)

def display2(p1, p2,p3):
    print(p1,p2,p3)

def add(*args1, **args2):
    print(type(args1) , type(args2))
    display1(*args1)
    display2(**args2)
    

add(1,2,3,4, p1=1, p2=3, p3=4)
<class 'tuple'> <class 'dict'>
1 2 3 4
1 3 4
  • 变长参数的解包与压包的进一步应用理解
    • 下面通过例子来进一步理解解包。
# 元组解包,把p元组,解包成参数格式。
def add(*args):
    sum = 0
    for v in args:
        sum += v
    return sum


p = (1,2,3,4)
v = add(*p)
print(v)
10
# 元组解包,把p元组,解包成参数格式。
def add(**kwargs):
    print(kwargs)


p= {'p1':1, 'p2':3, 'p3':55}
add(**p)  # 解包后,再压包(不能直接使用)
# add(p)  # 这是错误的

add(p1=30,p2=50,p3=99,p4=88)   # 压包
{'p1': 1, 'p2': 3, 'p3': 55}
{'p1': 30, 'p2': 50, 'p3': 99, 'p4': 88}
  • 变长参数的使用
    • 变长参数就可以按照元组与字典的的使用方式使用。
    • 一般带参数名的变长参数,参数名都可以传递,但在函数中使用到的参数才有意义。
def add(*args):
    sum = 0
    for v in args:
        sum += v
    return sum

v = add(1, 2, 3, 4)
print(v)
v = add(1, 2, 3, 4, 5, 6, 7, 8)
print(v)
10
36
  1. keyword-only参数
    • 也称为强制带命名(关键字参数):再使用参数的时候,必须使用参数名。
    • Python提供了语法机制来约束。
    • 语法: 使用特殊参数*
      |- 在*后的参数,就是强制参数。
      |- 在*前的参数,参数的使用根据前面讲解的规则。
def add(p1, p2=30, * ,p3, p4):
    print(p1,p2,p3,p4)


# add(1,2,3,p4=4) 错误,3必须使用参数名(keyword)
add(1,2,p3=3,p4=4)
add(1,p2=2,p3=3,p4=4)
add(1,p3=3,p4=4)
add(p1=1,p3=3,p4=4)
# add(p1=1,2,p3=3,p4=4)  # 错误,违背了命名参数后面必须是命名参数
1 2 3 4
1 2 3 4
1 30 3 4
1 30 3 4
  1. 参数匹配模型
    • 由于Python中函数的参数引入很多参数语法规则,单个语法容易理解,但多个语法放在一起导致我们容易产生混乱,实际上Python函数的参数的语法规则主要还是断字、短句的范畴,只要能唯一确定调用形式即可,这就存在一套匹配规则,了解匹配规则,容易正确使用语法,在语法冲突的时候,容易知道错误在什么地方。

    • 匹配规则是:

        1. 通过位置分配非关键字参数;
        1. 匹配关键字参数;
        1. 其他额外的非关键字参数分配到 * name 元组中
        1. 其他额外的关键字参数分配到 **name 字典中
        1. 用默认值分配给在头部未得到分配的参数
    • 一个完整的函数参数定义例子

      • * 与*args不能重复使用
      • 变长参数不能匹配歧义。
def func(p1, p2, p3=4,p4=5, *,p7, p8,):
    print(p1,p2,p3,p4,p5,p6,p7,p8)

# def func(p1, p2, p3=4,p4=5, *,p7, p8,*args):    # 匹配歧义
#     print(p1,p2,p3,p4,p5,p6
    
def func2(p1, p2, p3=4,p4=5, *args, p7, p8,):
    print(p1,p2,p3,p4,p5,p6,p7,p8,args)
    
# def func3(p1, p2, p3=4,p4=5, *,p7, p8, **args):    #匹配歧义
#     print(p1,p2,p3,p4,p5,p6,p7,p8,args,kwargs)

  1. 使用参数输出数据
    • 这个语法现象,最终是因为Python全部采用对象管理,参数都是传地址,不是传值。
    • 整数,复数,小数,
a = [1,2,3,4]
def add (p1,p2):
    p1[1] = 88

print(a)
add(a,40)
print(a)
[1, 2, 3, 4]
[1, 88, 3, 4]
a = 257
def add (p1,p2):
    p1 = 400

print(a)       # 因为20不可修改,这个对字符串,元组都是一样。
add(a,40)
print(a)
257
257
  1. 使用函数作为参数
    • 函数参数可以直接使用函数名
    • 函数参数也可以使用函数变量
def mydisplay(val, func):
    func(F'\033[32m{val}!')


mydisplay('helll', print)

myf = print
mydisplay('helll', myf)
�[32mhelll!
�[32mhelll!

函数的返回值

使用return返回数据值

  1. 没有return的默认返回值

    • 函数没有return默认返回None。表示没有返回值。也可以使用return返回None。
  2. 返回数据结构(包含将要学习的对象)

    • Python函数可以返回任意类型,包含数据结构。不过对元组,列表,字典,集合的返回与使用,提供一些独特的使用方式。 在某些场合下元组的括号可以省略。
# 返回元组
def mymod(p1, p2):
    return (p1, p2)

print(mymod(100,200))

# 返回列表
def mymod(p1, p2):
    return [p1, p2]

print(mymod(100,200))

# 返回集合
def mymod(p1, p2):
    return {p1, p2}

print(mymod(100,200))

# 返回字典
def mymod(p1, p2):
    return {'参数1':p1, '参数2':p2}

print(mymod(100,200))
(100, 200)
[100, 200]
{200, 100}
{'参数1': 100, '参数2': 200}
  • 对返回数据结构的处理
# 返回元组
def mymod_tuple(p1, p2):
    return (p1, p2)


# 返回列表
def mymod_list(p1, p2):
    return [p1, p2]


# 返回集合
def mymod_set(p1, p2):
    return {p1, p2}


# 返回字典
def mymod_dict(p1, p2):
    return {'参数1':p1, '参数2':p2}

(r1, r2)= mymod_tuple(100,200)
print(r1,r2)
[r1, r2]= mymod_tuple(100,200)
print(r1,r2)
# {r1, r2}= mymod_tuple(100,200)
r1, r2= mymod_tuple(100,200)    # 省略
print(r1,r2)

(r1, r2)= mymod_list(100,200)
print(r1,r2)
[r1, r2]= mymod_list(100,200)
print(r1,r2)
# {r1, r2}= mymod_list(100,200)
r1, r2= mymod_list(100,200)    # 省略
print(r1,r2)

(r1, r2)= mymod_set(100,200)
print(r1,r2)
[r1, r2]= mymod_set(100,200)
print(r1,r2)
# {r1, r2} = mymod_set(100,200)
r1, r2= mymod_set(100,200)    # 省略
print(r1,r2)

(r1, r2)= mymod_dict(100,200)
print(r1,r2)
[r1, r2]= mymod_dict(100,200)
print(r1,r2)
# {r1, r2} = mymod_dict(100,200)
r1, r2= mymod_dict(100,200)    # 省略
print(r1,r2)

r= mymod_dict(100,200)    # 省略
print(r)
100 200
100 200
100 200
100 200
100 200
100 200
200 100
200 100
200 100
参数1 参数2
参数1 参数2
参数1 参数2
{'参数1': 100, '参数2': 200}
r1, _= mymod_dict(100,200)    # 省略
print(r1, _)    # 一般会使用_占位。
参数1 参数2

返回函数与嵌套函数

  1. 直接返回一个函数
    • 既然函数可以赋值给变量,所以返回函数,使用变量接受返回值,也可以直接使用。
def  myfunc():
    return print;


re = myfunc()

re('hello','world',sep='...')
hello...world
  1. 函数嵌套
    • 在Python中函数是可以嵌套的。就是在函数中海可以定义函数。
    • 函数中嵌套的函数也作为返回值。
def  outter_func():
    def inner_func():
        print('inner function')
    return inner_func;

f = outter_func()
f()
inner function

yeild与生成器Generator

  • python提供了一个yield语句,用来对数据序列的返回操作。
  1. 语法:
    • yield 数据
    • yield必须在函数中使用

val = yield 2 # SyntaxError: 'yield' outside function

  1. yield的作用
    • 自动返回一个生成器对象
    • 这里不解释什么是生成器,但生成器可以创建一个数据序列,可以转换为list类型的数据。
    • 但是yield语句不返回数据
def fc(p):
    x = yield p
    print(x)    # x位None


rv = fc(100)
print(type(rv) ,rv)
print(list(rv), tuple(rv), set(rv))
<class 'generator'> <generator object fc at 0x108d28150>
None
[100] () set()
def fc(p):
    yield p
    yield p+1
    yield p+2


rv = fc(100)
lt = list(rv)
print(lt)
[100, 101, 102]
  • 使用yield产生数据序列
def gen_fc():
    for i in range(5):
        yield I


rv = list(gen_fc())
print(rv)
print(type(gen_fc()))   # 返回一个独特的类型generator
[0, 1, 2, 3, 4]
<class 'generator'>
  1. 生成器(generator)函数
    • 使用yield语句的函数,就是python中一种特殊的函数:生成器函数。(只要调用依次yield语句,该函数就是生成器函数。)
    • 调用生成器函数的时候,并没有执行代码,只是创建了一个生成器(可以理解为代码容器)。
    • 只有访问生成器的时候,代码才得到执行。访问生成器使用生成器对象的__next__函数与send函数。
    • 每次调用,执行到yield就暂停,直到下次调用。
def gen_fc():
    for i in range(5):
        print('before')
        yield I
        print(i)
        if i == 4:
            return 'hello'    # 抛出StopIteration信号。

rv = gen_fc()
# 调用生成器容器中代码,并得到yield的值
r = rv.__next__()
r = rv.__next__()
r = rv.__next__()
r = rv.__next__()
r = rv.__next__()
print('输出', r)
r = rv.__next__()
before
0
before
1
before
2
before
3
before
输出 4
4



---------------------------------------------------------------------------

StopIteration                             Traceback (most recent call last)

<ipython-input-59-1c0094f2f5ac> in <module>()
     15 r = rv.__next__()
     16 print('输出', r)
---> 17 r = rv.__next__()


StopIteration: hello
  • Generator类说明
    • Generator在typing模块中定义。

class Generator(collections.abc.Generator, Iterator)
     |  Abstract base class for generic types.
     |  
     |  A generic type is typically declared by inheriting from
     |  this class parameterized with one or more type variables.
     |  For example, a generic mapping type might be defined as::
  • Generator的操作

        |  __next__(self)
        |      Return the next item from the generator.
        |      When exhausted, raise StopIteration.
        |  
        |  close(self)
        |      Raise GeneratorExit inside generator.
        |  
        |  send(self, value)
        |      Send a value into the generator.
        |      Return next yielded value or raise StopIteration.
        |  
        |  throw(self, typ, val=None, tb=None)
        |      Raise an exception in the generator.
        |      Return next yielded value or raise StopIteration.

  • 生成器操作
    • send操作
# send从上一次yield结束位置开始
def gen_fc():
    for i in range(5):
        print('before')
        yield I
        print(i)
        if i == 4:
            return 'hello'    # 抛出StopIteration信号。

rv = gen_fc()
# rv.send(0)    # TypeError: can't send non-None value to a just-started generator
rv.send(None)
before





0
  • 生成器send与__next__的区别
    • send比起__next__的差异就是可以传递一个值给yield函数,并使得yield语句返回一个值,默认yield函数返回None。
    • 因为yield第一次执行暂停,所以send第一次传递的值没有意义,所以send第一次调用只能传递None值。
    • 当第二次调用的时候,上一次yield开始执行,并返回这次send传递的值。(或者先执行next再执行send一样的效果)
# send与next的区别在于,send在执行的时候,可以传递一个值给yield语句用于返回
def gen_fc():
    for i in range(5):
        print('before')
        re = yield I
        print(F'{re}:{I}')
        if i == 4:
            return 'hello'       # 抛出StopIteration信号。

rv = gen_fc()
rv.send(None)                 # yield后执行不到
print('第01次------')
rv.send(888)
print('第02次------')
rv.send(999)
print('第03次------')
rv.send(111)
print('第04次------')
rv.send(222)
print('第05次------')
before
第01次------
888:0
before
第02次------
999:1
before
第03次------
111:2
before
第04次------
222:3
before
第05次------
  1. 生成器这种工作方式属于协程的技术范畴
    • 所谓协程:就是执行过程中,产生中断(暂停),并返回调用处执行。这个与线程是有区别的,协程系统层面来讲,属于进程或者线程通信的范畴。
    • 再系统底层有一个函数就是yield,用来暂时放弃当前分配的CPU执行机会。


      系统中的yield函数

生成器表达式

  • 语法:( 表达式 for 标识字 in 可迭代数据 if 条件 )
  • 可以把生成器表达式转换为列表:[ 表达式 for 标识字 in 可迭代数据 if 条件 ]
  • 其中for与if 可以嵌套(每个for可以拥有一个if用来过滤数据,不支持else)。
  1. 生成器表达式例子
(x * 2 for x in range(10))
<generator object <genexpr> at 0x108d748e0>
[x * 2 for x in range(10)]
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
(print(x) for x in range(10))
<generator object <genexpr> at 0x108d747d8>
[print(x, end='') for x in range(10)]
0123456789




[None, None, None, None, None, None, None, None, None, None]
  1. 生成器表达式if使用的例子(不要在if中使用else,没有这个语法,但可以在前面表达式中使用)
[x * 2 for x in range(10) if x%2==0 ]
[0, 4, 8, 12, 16]
[x * 2 if x%2==0 else x*3 for x in range(10) ]
[0, 3, 4, 9, 8, 15, 12, 21, 16, 27]
  1. 生成器循环嵌套的例子
[F'{x} + {y}={x + y}' for x in range(5) for y in range(x)]
['1 + 0=1',
 '2 + 0=2',
 '2 + 1=3',
 '3 + 0=3',
 '3 + 1=4',
 '3 + 2=5',
 '4 + 0=4',
 '4 + 1=5',
 '4 + 2=6',
 '4 + 3=7']

函数体与作用域

  函数是独立的块,在Python中,不同的块之间,变量的访问是有约束的。这个部分就来说明函数块与外部的变量的访问规则。

变量的作用域

  因为函数中也可以定义变量,并且参数还传递变量,在函数外部还可以有变量。这些变量名是否可以相同?他们在什么时候释放?(比如函数调用结束后,其中定义的变量释放么?函数测餐食是否释放?)

  1. 全局变量与局部变量
    • 临时变量(也称局部变量):

      • 函数中定义的变量,在函数调用完毕是自动释放的,函数的参数也是自动释放的。这种随着调用环境结束二释放的变量,我们称为临时变量(局部变量)
    • 全局变量

      • 程序结束才释放的变量,我们称为全局变量。(Python中存在顶层函数,其中定义的变量都是全局变量)
    • 全局变量与局部变量使用规则:

      • 在函数中,可以使用全局变量
      • 在全局中,不能使用局部变量
def  func():
    la = 30     # 局部变量
    print('函数局部:',gb)
gb = 40    # 全局变量
func()
print('全局:',la)     # la不能被使用。
函数局部: 40



---------------------------------------------------------------------------

NameError                                 Traceback (most recent call last)

<ipython-input-72-431be1db1f02> in <module>()
      4 gb = 40    # 全局变量
      5 func()
----> 6 print('全局:',la)


NameError: name 'la' is not defined
  1. 全局变量与局部变量的命名冲突
    • 全局变量与局部变量在不同的运行环境中,可以有相同的变量名;
      • 规则:变量名相同,使用的时候遵循一个规则:局部优先。
      • 规则:没有冲突,变量不会产生访问歧义,直接使用全局变量,但全局中不能使用局部变量;
    • 为了区分变量是全局还是局部变量,python引入了一个关键字来处理。
      • global
    • 全局变量申明的语法:global 变量名1, 变量名2,......
      • 就算没有在全局定义全局变量,在函数内部使用global声明的变量都是全局变量。
def  func():
    global glb,glc, gld
    gla = 30     # 局部变量
    
    glb = 888    # 全局变量
    glc = 999    # 全局变量
    gld = 777
    
    
    print('函数局部:',gla, glb, glc,gld)    # 局部优先
    
gla = 40    # 全局变量
glb = 50    # 全局变量
glc = 50    # 全局变量
func()
print('全局:',gla, glb, glc,gld)     # la不能被使用。
函数局部: 30 888 999 777
全局: 40 888 999 777
  1. 函数嵌套中的变量作用域
    • 函数可以嵌套,导致变量的作用域更加复杂。但遵循一个总得规则:
      • 内层可以访问外层,外层不能访问内层。

def func_1():
    a1 = 1
    
    def func_2():
        a2 = 2
        def func_3():
            a3 = 3
            print(a0, a1, a2, a3)
        func_3()
    func_2()
    # print(a2)    # 外层不能访问内层:NameError: name 'a2' is not defined
a0 = 0

func_1()
0 1 2 3



---------------------------------------------------------------------------

NameError                                 Traceback (most recent call last)

<ipython-input-83-139c6e02a295> in <module>()
     13 a0 = 0
     14 
---> 15 func_1()


<ipython-input-83-139c6e02a295> in func_1()
     10         func_3()
     11     func_2()
---> 12     print(a2)
     13 a0 = 0
     14 


NameError: name 'a2' is not defined
  1. 内外层的变量名冲突
    • 可以使用nonlocal来解决内外层的变量名冲突与作用域问题
    • 语法: nonlocal 外层变量, 外层变量, ......
    • 规则:
      • nonlocal与global的使用差别是:nonlocal 绑定的变量必须在外层申明过,global的不需要申明。
      • nonlocal不能绑定全局变量

def func_1():
    a1 = 11
    
    def func_2():
        nonlocal a1
        # nonlocal a0     # SyntaxError: no binding for nonlocal 'a0' found
        a1 = 22
        def func_3():
            a3 = 33
            print(a0, a1, a3)
        func_3()
    func_2()
    print(a1)    # 外层不能访问内层:NameError: name 'a2' is not defined
a0 = 0

func_1()
0 22 33
22

闭包

  • 闭包这个概念也与作用域有关,上面变量作用域都是函数调用完毕变量就被释放,但这种情况存在一种问题。

    • 当函数返回函数,就存在调用函数结束,返回的嵌套函数还在运行,这个函数的外层环境已经被释放,如果其中引用的外层变量就不存在,这种情况的解决,在Python中引入了闭包的概念来解决。
  • 闭包

    • 闭包 = 内部嵌套函数 + 外部引用环境
      • 闭包:内部嵌套函数 + 外部引用环境打包成为一个新的整体,可以解决了函数编程中的嵌套所引发的问题;
def out_func():
    a = 40
    
    
    def in_func():
        nonlocal a   # 不使用这个语句,a赋值当成当前局部变量处理。
        a = a + 1
        print(a)
    
    
    
    return in_func


in_f = out_func()   # 这儿调用完毕,a应该释放,但因为存在函数返回,会把in_func函数与out_func引用环境一起打包(这是内存管理的范畴)。

in_f()   # 该函数引用的外层环境,因为闭包而存在。

41

函数递归

  • 在Python中支持函数调用函数本身的语法(实际基本上所有语言都支持),这种语法现象就是递归。

  • 有的时候使用好递归,可以很方便的解决某些问题。

  • 函数调用函数,逻辑上是无穷递归调用的,所以使用递归的时候处理好两个问题:

    • 递归结束
    • 递归的返回值(这个可以用来产生二叉树)
  • 函数调用函数本身的语法规则与函数调用是一样的。

  • 递归的使用技巧

    • 使用条件结束递归调用。
    • 选择递归的思路:使用初中的数列通项式f_n(x) =f_{n-1}(x) + a_0
  • 使用递归显示某个目录
import os


def list_dir(d, depth):
    fd = os.path.basename(d)
    # print('  ' * depth, fd, sep='|-')
    if os.path.isdir(d):
        files = os.listdir(d)
        for file in files:
            file_path = os.path.join(d, file)
            list_dir(file_path, depth + 1)


list_dir('.', 1)

  • 使用递归生成目录树
import os


def list_dir(d, depth):
    fd = os.path.basename(d)
    # print('\t' * depth, fd, sep='|-')
    v = []
    if os.path.isdir(d):
        files = os.listdir(d)
        for file in files:
            file_path = os.path.join(d, file)
            r = list_dir(file_path, depth + 1)
            v.append(r)
    return {d: v}


re = list_dir('.', 1)
# print(re)

函数对象

函数对象的类型

  1. 我们在前面看见,函数可以作为函数值赋值给变量,这个函数实际是作为函数对象而存在。既然函数可以作为对象值赋值给i变量,函数变量就与函数一样,具备如下变量与函数共有的操作:
    • 函数变量像函数一样调用;
    • 函数变量,可以作为变量使用,在函数参数与返回值中使用;
    • 函数可以使用在变量使用的任何场景;
  2. 作为函数对象,函数可以想对象一样操作,对象具备如下操作:
    • 类型:type
    • 地址:id
def my_func(a, b)->int:
    return a + b

print(my_func)   # 作为变量值使用
print(id(my_func))   # 地址
print(type(my_func))  # 类型 

<function my_func at 0x10d692c80>
4519963776
<class 'function'>
  1. builtins.function的帮助
    • 因为fuction动态构建,使用help(builtins.function)无法查看帮助。只有动态返回的类型才能查看。
      • help(type(my_func)) 能使用这种方式查看到帮助,
    • builtins.function的源代码截图如下:


      函数对象源代码截图
# 使用代码获取帮助
help(function)
---------------------------------------------------------------------------

NameError                                 Traceback (most recent call last)

<ipython-input-13-1e26c449b31c> in <module>()
      1 # 使用代码获取帮助
----> 2 help(function)
      3 a =function()


NameError: name 'function' is not defined
# 不能直接使用function类,函数对象是根据代码而创建的对象,类型时function类型,这个类型在builtins模块中定义。
a =function()
---------------------------------------------------------------------------

NameError                                 Traceback (most recent call last)

<ipython-input-14-5c9b353bc32c> in <module>()
      1 # 不能直接使用function类,函数对象是根据代码而创建的对象,类型时function类型,这个类型在builtins模块中定义。
----> 2 a =function()


NameError: name 'function' is not defined
# 通过定义的函数才能获取这个类型与对象
def my_func(a, b)->int:
    return a + b

print(type(my_func))

# 获取类型的帮助
help(type(my_func))
<class 'function'>
Help on class function in module builtins:

class function(object)
 |  function(code, globals[, name[, argdefs[, closure]]])
 |  
 |  Create a function object from a code object and a dictionary.
 |  The optional name string overrides the name from the code object.
 |  The optional argdefs tuple specifies the default argument values.
 |  The optional closure tuple supplies the bindings for free variables.
 |  
 |  Methods defined here:
 |  
 |  __call__(self, /, *args, **kwargs)
 |      Call self as a function.
 |  
 |  __get__(self, instance, owner, /)
 |      Return an attribute of instance, which is of type owner.
 |  
 |  __new__(*args, **kwargs) from builtins.type
 |      Create and return a new object.  See help(type) for accurate signature.
 |  
 |  __repr__(self, /)
 |      Return repr(self).
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |  
 |  __annotations__
 |  
 |  __closure__
 |  
 |  __code__
 |  
 |  __defaults__
 |  
 |  __dict__
 |  
 |  __globals__
 |  
 |  __kwdefaults__

使用函数对象

  1. 函数的属性
import builtins


def my_func(a: int, b: int=3, *, c: int = 40, d: int) -> int:
    """
    注释文档
    """
    re = 30
    return a + b


# 使用函数对象
print(my_func.__closure__)       # 闭包
print(my_func.__annotations__)   # 参数与返回值说明
print(my_func.__code__)     # 代码
print(my_func.__defaults__)    # 缺省值
print(my_func.__dict__)      # 字典(用来存放属性列表,函数没有)
# print(my_func.__globals__)     # 全局
print(my_func.__kwdefaults__)   # keyword缺省
print('------')
print(my_func.__name__)    # 函数名
print(my_func.__doc__)       # 函数的注释文档
print(my_func.__module__)    # 函数所在模块
print(my_func.__sizeof__())    # 函数占用的内存大小
print(my_func.__str__())        # 代表函数的字符串
print(my_func.__class__)     # 函数的类型
print(my_func.__dir__())     # 函数的目录(成员)
r = my_func.__call__(1, 2, c=3, d=4)    # 使用__call__调用函数。
print(':', r)   # 调用方的返回值

None
{'a': <class 'int'>, 'b': <class 'int'>, 'c': <class 'int'>, 'd': <class 'int'>, 'return': <class 'int'>}
<code object my_func at 0x10d732810, file "<ipython-input-30-5172c4dc30fd>", line 4>
(3,)
{}
{'c': 40}
------
my_func

    注释文档
    
__main__
112
<function my_func at 0x10d671730>
<class 'function'>
['__repr__', '__call__', '__get__', '__new__', '__closure__', '__doc__', '__globals__', '__module__', '__code__', '__defaults__', '__kwdefaults__', '__annotations__', '__dict__', '__name__', '__qualname__', '__hash__', '__str__', '__getattribute__', '__setattr__', '__delattr__', '__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__', '__init__', '__reduce_ex__', '__reduce__', '__subclasshook__', '__init_subclass__', '__format__', '__sizeof__', '__dir__', '__class__']
: 3

函数对象中的闭包属性

  1. 函数闭包产生的条件:
    • 内部函数
    • 作为返回值返回到外部
    • 在外部调用。
- 只有内部函数使用了外部的变量,才会生成闭包

- 闭包是一个元组(因为嵌套的层数,可能是多个)
# 函数闭包产生的条件:内部函数,作为返回值返回到外部,在外部调用。
def out_f():
    a = 45
    def in_f():
        print(a)     # 只有使用了外部的变量,才会生成闭包
        # pass
    print('函数的闭包:', in_f.__closure__)
    return in_f


ff = out_f()
ff()
print('函数的闭包:', ff.__closure__)
print(type(ff.__closure__))
print(type(ff.__closure__[0]))
函数的闭包: (<cell at 0x10d625d68: int object at 0x10b2b3d40>,)
45
函数的闭包: (<cell at 0x10d625d68: int object at 0x10b2b3d40>,)
<class 'tuple'>
<class 'cell'>
  1. 闭包的类型与帮助
# 获取cell的帮助(这个类不能直接查看帮助,只能依托具体的对象查看帮助)
help(type(ff.__closure__[0]))
Help on class cell in module builtins:

class cell(object)
 |  Methods defined here:
 |  
 |  __eq__(self, value, /)
 |      Return self==value.
 |  
 |  __ge__(self, value, /)
 |      Return self>=value.
 |  
 |  __getattribute__(self, name, /)
 |      Return getattr(self, name).
 |  
 |  __gt__(self, value, /)
 |      Return self>value.
 |  
 |  __le__(self, value, /)
 |      Return self<=value.
 |  
 |  __lt__(self, value, /)
 |      Return self<value.
 |  
 |  __ne__(self, value, /)
 |      Return self!=value.
 |  
 |  __repr__(self, /)
 |      Return repr(self).
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |  
 |  cell_contents
 |  
 |  ----------------------------------------------------------------------
 |  Data and other attributes defined here:
 |  
 |  __hash__ = None
  1. 闭包的内容
print(ff.__closure__[0].cell_contents)
45

函数的属性

  1. 在函数中定义不了属性,但可以通过函数对象定义属性
def my_func(a: int, b: int=3, *, c: int = 40, d: int) -> int:
    """
    注释文档
    """
    re = 30
    return a + b

my_func.f_a = 100
my_func.f_b = 600
print(my_func.__dict__)
{'f_a': 100, 'f_b': 600}
  1. 说明:
    • 一般函数属性没有什么用处,一般用于非常专用(专业的语法解析器什么的应用),或者仅仅是传递一个数据。

函数装饰器

装饰器的使用背景

  • 装饰器语法提出的背景是回调(从语法上就是使用函数作为参数传递调用),Python提供了一种更加简洁的回调语法:装饰器(一种软件设计模式的称呼:装饰器模式)。

  • 下面是一个回调的经典例子(这种耦合设计,与Qt的信号与槽非常类似)

def txt_log(info):
    print('信息日志:',info)


def net_log(info):
    print('网络日志:',info)

def biz(lg):
    lg('日志记录')
    print('业务处理')
    lg('日志记录')
    

biz(txt_log)
biz(net_log)
信息日志: 日志记录
业务处理
信息日志: 日志记录
网络日志: 日志记录
业务处理
网络日志: 日志记录

装饰器的内置编程模式

  • 上面是回调来自传统的语法调用,这个编程模式增加了函数之间的耦合程度(因为参数属于函数的一部分),尽管Python宽松的参数类型检查,降低了这种耦合,不像其他语言通过接口等诸多语法来降低这种耦合。但是Python还是提供了一种语法来提供更加便捷的调用方式。
  • 装饰器就是一种编程模式的语法级实现(给已知函数添加新的功能)。
    • 利用python的两个语法:
      • 函数参数可以传递函数;
      • 函数可以返回函数;
    • 确定被装饰的函数,编写一个装饰函数;装饰函数的逻辑如下:
      • 装饰函数提供一个参数,用来传递被装饰的函数;
      • 实现一个内部函数,内部函数,在内部函数中调用被装饰的函数,再调用被装饰的函数的实现中,可以添加额外的功能。
      • 把内部函数作为装饰函数的返回值。
      • 当调用返回的函数的时候,这个函数已经对传递的函数提供了额外的功能。
# 1. 被装饰的函数
def   被装饰者():
    print('被装饰功能实现')
    
    
# 2. 装饰函数:用来对被装饰者增加功能(就是装饰)
def 装饰器(被装饰者参数):
    # 3. 装饰实现:使用内部函数完整多被装饰者的装饰
    def 装饰实现():
        print('额外增加的功能!')
        被装饰者参数()      # 调用被装饰者
        print('其他额外功能增加')
        
    return 装饰实现    # 返回被装饰后的函数


# 4. 被装饰后的函数:调用装饰器得到被装饰后的函数
被装饰以后的函数 = 装饰器(被装饰者)

# 5. 被装饰函数调用:调用返回的函数,得到被装饰的功能
被装饰以后的函数()

额外增加的功能!
被装饰功能实现
其他额外功能增加

装饰器语法

  • 装饰器语法
    • 装饰器语法自动实现装饰过程。
    • 被装饰装饰过的函数就不是原来的函数了,是增加了功能的新的函数。
    @ 装饰器
    def   被装饰函数:
        函数实现
        ...
# 1. 装饰器
def 装饰器_函数(被装饰者传递):
    # 使用内部函数完整多被装饰者的装饰
    def 装饰内部实现():
        print('额外增加的功能!')
        被装饰者传递()      # 调用被装饰者
        print('其他额外功能增加')
        
    return 装饰内部实现    # 返回被装饰后的函数


# 2 使用装饰器语法使用装饰器
@装饰器_函数
def   被装饰者_函数():
    print('被装饰功能实现')

    
# 被装饰者调用
被装饰者_函数()
    
额外增加的功能!
被装饰功能实现
其他额外功能增加

被装饰者的参数

  • 明白了装饰器的原理与机制,怎么实现装饰器传递参数就容易理解,遵循调用过程传递参数。
  • 下面使用一个参数来举例说明( 其他方式的参数以此类推 ):
# 1. 装饰器
def 装饰器_函数(被装饰者传递):
    # 使用内部函数完整多被装饰者的装饰
    def 装饰内部实现(参数):
        print('额外增加的功能!')
        被装饰者传递(参数)      # 调用被装饰者
        print('其他额外功能增加')
        
    return 装饰内部实现    # 返回被装饰后的函数


# 2 使用装饰器语法使用装饰器
@装饰器_函数
def   被装饰者_函数(参数1):
    print('被装饰功能实现', 参数1)

    
# 被装饰者调用
被装饰者_函数(20)
    
额外增加的功能!
被装饰功能实现 20
其他额外功能增加

装饰器的参数

  • 既然装饰器作为函数,也应该存在参数;
  • 装饰器的参数实现,采用的还是装饰器的思维,在原来的装饰器上面再装饰一层函数。
# 1. 装饰器
def 装饰器参数(装饰器参数):                # 装饰器参数传递
    def 装饰器_函数(被装饰者传递):                # 装饰器函数,负责传递被装饰的函数
        # 使用内部函数完整多被装饰者的装饰
        def 装饰内部实现(参数):                       # 装饰实现函数,负责传递被装饰函数的参数
            print('装饰器参数:',装饰器参数)
            print('额外增加的功能!')
            被装饰者传递(参数)      # 调用被装饰者
            print('其他额外功能增加')

        return 装饰内部实现    # 返回被装饰后的函数
    return 装饰器_函数


# 2 使用装饰器语法使用装饰器
@装饰器参数('this is a 装饰器参数')
def   被装饰者_函数(参数1):
    print('被装饰功能实现', 参数1)

    
# 被装饰者调用
被装饰者_函数(20)
装饰器参数: this is a 装饰器参数
额外增加的功能!
被装饰功能实现 20
其他额外功能增加

多重装饰

  • 一般一个装饰器,肯定可以装饰多个函数,在Python语法中,一个函数也可以被多个装饰器装饰。

    • 多个装饰器装饰本质是嵌套装饰
  • 语法:

    • 每个装饰器单独一个语句,修饰最近的函数,包括装饰器也是函数,也可以被装饰。

    @ 装饰器1
    @ 装饰器2
    def 被装饰函数(参数):
        pass

    ```


```python
def log_decorator(param_log):
    def log_wrapper(func):
        def decorator_impl(param_func):
            print('装饰器参数:', param_log)
            print('开始装饰')
            r = func(param_func)   # 被装饰函数调用(被装饰函数参数)
            print('装饰结束')
            return F'被装饰函数返回{r}'   # 装饰器函数的返回值
        
        return  decorator_impl
    
    return log_wrapper


def net_decorator(param_log):
    def net_wrapper(func):
        def decorator_impl(param_func):
            print('装饰器参数:', param_log)
            print('开始装饰')
            r = func(param_func)   # 被装饰函数调用(被装饰函数参数)
            print('装饰结束')
            return F'被装饰函数返回{r}'   # 装饰器函数的返回值
        
        return  decorator_impl
    
    return net_wrapper

@ net_decorator(666) 

@ log_decorator(999)
def biz_db(p):
    print(F'数据处理{p}')
    return 111
    
biz_db(888)

    
    
装饰器参数: 666
开始装饰
装饰器参数: 999
开始装饰
数据处理888
装饰结束
装饰结束





'被装饰函数返回被装饰函数返回111'

lambda表达式

  • lambda表达式(\lambda表达式):本质是解决函数的字面值的问题,因为通常的数据有两种形态:

    • 字面值(也称匿名变量),比如:整数20
    • 变量,比如:a = 20
  • 函数因为其特殊性,在表示的时候,只能使用变量表示,比如函数作为参数只能传函数名,不能传函数代码。

    • 为了能传递函数,Python语言引入了lambda表达式。
    • lambda表达式严格意义上讲是一个自定义的运算表达式,但最终返回的实际上是一个函数对象(所以也称匿名函数)。
  • lambda表达式语法:

    lambda 参数列表: 表达式
  • 等价于:
    def <lambda>( 参数列表): 
        return 表达式
  • lambda表达式没有提供参数与返回值的类型说明。
  • lambda本质是函数,使用方式与函数一样,只是比函数方便多了,可以在传函数参数的时候,直接使用lambda表达式,代码会非常简洁。
la = lambda  x, y: x+y

print(la(45, 55))
100
# 定义完毕直接调用
r = (lambda  x, y: x+y)(45,55)
print(r)
100
# 类型
print(type( lambda  x, y: x+y ))
<class 'function'>

main函数

  • 当我们写第一行语句的时候,实际代码也是通过函数运行的,这个函数就是main函数;

  • 当模块作为import,代码的name是模块名;只有当作为初始执行,实际是调用main来执行,name返回的是main

    • 不管使用python 文件名还是 python -m 模块名 执行,初始执行都从main模块开始执行。
  • 判定name是否等于main可以判定一个模块是引入,还是执行开始执行的。

print(__name__) 
__main__

Python内置标准函数

  • python提供了很多内置函数,前面已经调用过一些,还有一些函数位:
abs() dict() help() min() setattr()
all() dir() hex() next() slice()
any() divmod() id() object() sorted()
ascii() enumerate() input() oct() staticmethod()
bin() eval() int() open() str()
bool() exec() isinstance() ord() sum()
bytearray() filter() issubclass() pow() super()
bytes() float() iter() print() tuple()
callable() format() len() property() type()
chr() frozenset() list() range() vars()
classmethod() getattr() locals() repr() zip()
compile() globals() map() reversed() __import__()
complex() hasattr() max() round()
delattr() hash() memoryview() set()
  1. sorted函数
    • 序列数据排序
    sorted(iterable, /, *, key=None, reverse=False)
        Return a new list containing all items from the iterable in ascending order.

lt = [1, 5, 3, 4, 2]
sorted_lt = sorted(lt)
print(sorted_lt)

# key是一个回调函数,用来处理复杂数据项的处理
dt = {
    'Jack': 89,
    'Rose': 78,
    'Tom': 99
}
# 使用ley处理复杂数据
sorted_dt = sorted(dt, key= lambda x : dt[x], reverse=True)
print(sorted_dt)
[1, 2, 3, 4, 5]
['Tom', 'Jack', 'Rose']
  1. reversed
    • 对序列数据做逆操作
    class reversed(object)
     |  reversed(sequence) -> reverse iterator over values of the sequence
     |  
     |  Return a reverse iterator
lt = [1, 5, 3, 4, 2]
reversed_lt = reversed(lt)

# 返回逆序可迭代对象
print(reversed_lt)      
print(list(reversed_lt))        # 返回的不是列表,是迭代器,可以直接转换为list类型使用。
<list_reverseiterator object at 0x103e40518>
[2, 4, 3, 5, 1]
  1. filter函数
    • 过滤数据
    class filter(object)
     |  filter(function or None, iterable) --> filter object
     |  
     |  Return an iterator yielding those items of iterable for which function(item)
     |  is true. If function is None, return the items that are true.
lt = [1, 5, 3, 4, 2]
filter_lt = filter(None, lt)

print(list(filter_lt))

# 使用lambda函数,过滤奇数
filter_lt = filter(lambda x : True if x % 2 ==0 else False, lt)
print(filter_lt)     # filter对象也是迭代器。
print(list(filter_lt))
[1, 5, 3, 4, 2]
<filter object at 0x103e60c88>
[4, 2]
  1. map函数
    • 对数据做对应映射处理
    class map(object)
     |  map(func, *iterables) --> map object
     |  
     |  Make an iterator that computes the function using arguments from
     |  each of the iterables.  Stops when the shortest iterable is exhausted.
# 技术每个数的平方,使用生成器表达式也可以
lt1 = [1, 5, 3, 4, 2]
# 使用ley处理复杂数据
map_lt = map(lambda x : x**2, lt1)
print(list(map_lt))


lt2 = [6, 3, 2, 1, 4]
map_lt = map(lambda x, y : x * y, lt1,lt2)    # 如果有单个列表,则处理函数就有三个参数

print(map_lt)    # map对象
print(list(map_lt))

[1, 25, 9, 16, 4]
<map object at 0x103ea5588>
[6, 15, 6, 4, 8]
  1. zip函数
    • 合并数据位元组。
    class zip(object)
     |  zip(iter1 [,iter2 [...]]) --> zip object
     |  
     |  Return a zip object whose .__next__() method returns a tuple where
     |  the i-th element comes from the i-th iterable argument.  The .__next__()
     |  method continues until the shortest iterable in the argument sequence
     |  is exhausted and then it raises StopIteration.

lt1 = [1, 5, 3, 4, 2, 88]
lt2 = [6, 3, 2, 1, 4]
# 返回长度,取最短的长度
zip_lt = zip(lt1, lt2)
print(zip_lt)     # zip对象
print(list(zip_lt))

<zip object at 0x103e729c8>
[(1, 6), (5, 3), (3, 2), (4, 1), (2, 4)]
  1. format函数
    • 格式化字符串
    format(value, format_spec='', /)
        Return value.__format__(format_spec)

        format_spec defaults to the empty string.
        See the Format Specification Mini-Language section of help('FORMATTING') for
        details.
  • 格式化规范如下:

    format_spec     ::=  [[fill]align][sign][#][0][width][grouping_option][.precision][type]
    fill            ::=  <any character>
    align           ::=  "<" | ">" | "=" | "^"
    sign            ::=  "+" | "-" | " "
    width           ::=  digit+
    grouping_option ::=  "_" | ","
    precision       ::=  digit+
    type            ::=  "b" | "c" | "d" | "e" | "E" | "f" | "F" | "g" | "G" | "n" | "o" | "s" | "x" | "X" | "%"

a = 20

f_a = format(a, '>+5.2e')
print(f_a)
+2.00e+01
  1. open函数
    • 打开一个文件位文件对象流。
    open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
        Open file and return a stream.  Raise IOError upon failure.
# 在python中打开的文件也是一个可迭代的对象
fd = open('recurit.py')
for line in fd:
    print(line)
fd.close()

import os





def list_dir(d, depth):

    fd = os.path.basename(d)

    print('  ' * depth, fd, sep='|-')

    v = []

    if os.path.isdir(d):

        files = os.listdir(d)

        for file in files:

            file_path = os.path.join(d, file)

            r = list_dir(file_path, depth + 1)

            v.append(r)

    return {d: v}





re = list_dir('.', 1)

print(re)
# 在python中打开的文件也是一个可迭代的对象
fd = open('recurit.py')

lines = list(fd)
print(lines)

fd.close()

['import os\n', '\n', '\n', 'def list_dir(d, depth):\n', '    fd = os.path.basename(d)\n', "    print('  ' * depth, fd, sep='|-')\n", '    v = []\n', '    if os.path.isdir(d):\n', '        files = os.listdir(d)\n', '        for file in files:\n', '            file_path = os.path.join(d, file)\n', '            r = list_dir(file_path, depth + 1)\n', '            v.append(r)\n', '    return {d: v}\n', '\n', '\n', "re = list_dir('.', 1)\n", 'print(re)\n', '\n']
  1. vars,globals与locals函数
    • 返回当前作用域的全局变量与局部变量
    • 如果vars不指定参数,vars与locals是一样的效果。
    • 如果使用参数,等于调用指定对象的dict
    vars(...)
        vars([object]) -> dictionary

        Without arguments, equivalent to locals().
        With an argument, equivalent to object.__dict__.
    globals()
        Return the dictionary containing the current scope's global variables.
    locals()
        Return a dictionary containing the current scope's local variables.

g = globals()
l = locals()
# print(g)
# print(l)

def ff():
    l_a = 89
    print(locals())
    print(vars())

ff()

ff.a=20    # 给函数增加一个属性
v = vars(ff)
print(v)
{'l_a': 89}
{'l_a': 89}
{'a': 20}
  1. eval与exec函数
    • 计算或者执行Python语句与表达式。
    eval(source, globals=None, locals=None, /)
        Evaluate the given source in the context of globals and locals.
    exec(source, globals=None, locals=None, /)
        Execute the given source in the context of globals and locals.
epr = ' 20 + (40-10) / 6, 20, print("heloo")'
r = eval(epr)
print(r)
heloo
(25.0, 20, None)
epr = '20 + (40-10) / 6, 20, print("heloo"), 30'
r =exec(epr)    # 只是执行,不返回值
print(r)

epr = 'import math; r = math.sin(math.pi/6); print(r)'
exec(epr)
heloo
None
0.49999999999999994

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,233评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,013评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,030评论 0 241
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,827评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,221评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,542评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,814评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,513评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,225评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,497评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,998评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,342评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,986评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,812评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,560评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,461评论 2 266

推荐阅读更多精彩内容