Java教程

本周内容回顾

本文主要是介绍本周内容回顾,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

  本周内容

  • 名称空间
  • 装饰器
  • 有参装饰器
  • 匿名函数

函数的参数

*和**在实参中的作用

*号在实参中是把可以被for循环的数据类型里的数据一个一个的传入函数

**号在专门针对字典的 可以把字典里的键值对当做关键字参数传入

名称空间

名称空间就是存放变量名与变量名和数据值绑定关系的空间

在python中名称空间可以分为内置名称空间、全局名称空间、局部名称空间

内置名称空间就是存放一些python自带的函数名和类名

而全局名称空间就是存放在py文件中用户编写的变量名、函数名、类名

局部名称空间就是存放在函数内运行函数体代码时产生的一些变量名

1.全局名称空间

# 全局名称空间就是存放我们在py文件中编写的一些变量名和函数名以及类名

eg:
name = 'tony'

if True:
    age = 18

for i in range(10):
    print(i)    

def func():
    pass
'''
像上面的变量名和函数名都是存放到全局名称空间中的
普通代码中的变量名
分支结构中的变量名
循环结构中的变量名
还有定义函数的函数名
还有定义类的类名
都是存入到全局名称空间中的
'''

2.局部名称空间

# 局部名称空间就是函数体代码运行过程中产生的变量名会存入到该空间中
eg:
def func():
    name = 'tony'
    age = 18
func()

# 像上面所写的函数 当py文件运行时调用该函数就会运行该函数的代码就会产生两个变量名 这两个变量名就会存入到局部名称空间

3.三者的关系

内置名称空间

  当python解释器运行时创建       当关闭python解释器是销毁

全局名称空间

  当py文件运行时创建            当py文件结束时销毁

局部名称空间

  当函数体代码运行时创建          当函数体代码结束时销毁

4.名称的查找顺序

x = 1
def func():
    x = 10
print(x)  # 1
# print(y)  # 报错
'''
这些变量名都是新产生的
当在全局空间中时会先在全局空间中查找找到就会调用
找不到就会去内置空间找如果找不到就会报错
'''
len = 1
def func():
    len = 10
    print(len)  # 10
func()
print(len)  # 1
'''
在全局空间就会现在全局空间找如果找不到才会取内置空间中找
在局部空间中时也是先在局部空间中找找到调用即可 找不到才会去全局空间中找 
如果全局空间中还找不到 才会取内置空间中找 如果还找不到就会报错
'''
x = 10
def func():
    print(x)  # 10
    print(len)  # <built-in function len>
func()
print(x)  # 10
'''
因为len这个名字在局部和全局名称空间中都没有定义 只能去内置空间中找 找到调用即可
而x在局部中没有就会去全局空间中找 找到调用即可
'''
def func1():
    x = 2
    def func2():
        print(x)
    func2()
func1()
'''
现在查找x的名字是在func2的局部空间中 因为func2中没有x的名字 因为funcx是在func1的局部空间中
所以会先去func1中查找x的名字找到即可  如果func还没找到才回去全局空间中查找
'''

默认情况下查找名字的顺序是:

1.当在全局名称空间中:

  全局名称空间  >>>    内置名称空间

2.当在局部名称空间中:

  局部名称空间  >>>  全局名称空间  >>>   内置名称空间

5.作用域

1.内置名称空间

  在程序的任意位置都可以使用(全局有效)

2.全局名称空间

  在程序的任意位置都可以使用(全局有效)

3.局部名称空间

  在各自局部空间中可以使用(局部有效)

global和nonlocal关键字

1.global关键字

当我们在局部名称空间想要修改全局名称空间时是做不到的所以需要用到global关键字

x = 111
def func():
    x = 100

func()
print(x)  # 111
'''
正常情况下局部名称空间中出现的新的变量名 会被存储到局部名称空间中
所以局部名称空间是不能修改全局名称空间里的值的  所以就会打印111
但是有时候我们需要在局部名称空间中修改全局名称空间中的值
'''
x = 111
def func():
    global x
    x = 100

func()
print(x)  # 100

l1 = [1,2,3,4]
def func():
    l1.append(66)
func()
print(l1)  # [1, 2, 3, 4, 66]

'''
而如果想在局部名称空间中修改全局名称空间中的不可变类型时需要用到 关键字 global
但是如果是可变类型不需要用到  因为可变类型修改值的时候修改的是本身 没有产生新的值
global 就是指定一个变量名 让这个变量名可以在局部名称空间中可以修改全局名称中的值
所以函数里加入一个global关键字的时候 可以让global后面那个变量名可以再局部名称空间修改全局名称空间中的值
所以x就会打印 100
'''

2.nonlocal关键字

当出现局部名称空间的嵌套时局部名称空间中的局部名称空间想要修改外层的局部名称空间的名字时一般情况下是做不到的我们需要nonlocal关键字

def func1():
    x = 1
    l1 = [1, 2]
    def func2():
        x = 999
        l1.append(666)
    func2()
    print(x)  # 1
    print(l1)  # [1, 2, 666]
func1()
'''
正常情况下函数嵌套中的里面那个函数产生新的变量名的时候是存储在func2中的局部空间
可变类型不考虑
所以func2中的变量名的值是改变不了func1中的值的
'''

def func1():
    x = 1
    l1 = [1,2]
    def func2():
        # nonlocal x
        x = 999
        l1.append(666)
    func2()
    print(x)
    print(l1)
func1()
'''
而我们想在func2名称空间中修改func1的值必须用到nonlocal关键字
这样就能在func2名称空间中修改到func1中的值了
不能用global关键字因为global是修改的全局名称空间
'''
x = 20
def func1():
    x = 1
    l1 = [1, 2]
    def func2():
        global x
        x = 999
        l1.append(666)
    func2()
func1()
print(x)  # 999

函数名的多种用法

1.函数名可以用来赋值

就相当于定义一个变量名然后数据值时函数名,就相当于把这个变量名绑定了函数的内存地址

def func():
    print('from func')
func()  # from func
name = func
name()  # from func
name1 = name
name1()  # from func
'''
函数名是可以多次赋值的 因为函数名绑定的是一个内存地址 而内存地址里存放的是函数体代码
而如果想要调用函数代码只需函数名加括号即可
'''

2.函数名可以当做函数的实参

就是把函数名当做函数的实参传入函数

def func():
    print('from func')

def index(a):
    print(a)
    a()  # from func
# index(123)  # 123
# name = 'jason'
# index(name)  # jason
index(func)  # <function func at 0x00000190C0141E18>
# 因为函数名绑定的是一个内存地址所以传入的也是一个内存地址 然后a就可以调用func函数

3.函数名可以当做函数的返回值

就是把函数的返回值写成函数名

def func():
    print('from func')

def index():
    return func
res = index()
print(res)
res()
# index返回的是func的内存地址 然后赋值给res 所以res就可以调用func函数

4.函数名可以当做容器类型的数据值

def func():
    print('from func')


l1 = [1, 2, 3, 4, func]
print(l1)  # [1, 2, 3, 4, <function func at 0x000001C541EC1E18>]
l1[-1]()  # from func
# 因为函数名绑定的是一个内存地址 所以通过索引可以调用函数func

闭包函数的简介

当一个函数需要传参时我们可以直接用形参传值

现在闭包函数也可以当做传参的一种形式

闭包函数要满足两种特征

  1. 定义在函数内部的函数
  2. 内部函数使用了外部函数的名称空间的名字

只有满足以上两种条件才能被称之为闭包函数

username = 'tony'
def func():    
    def inner():
        print(username)
    inner()
func()
'''
像这种情况inner函数虽然在func函数中
但是inner中的名字不是在func中找到的是在全局名称空间中找到的
所以inner不是闭包函数
'''

def func():    
    username = 'tony'
    def inner():
        print(username)
    inner()
func()
'''
像inner函数时在func函数里的并且inner中的变量名的值是用到了func中得到名字
所以inner就可以被称为闭包函数
'''

1.闭包函数的应用

闭包函数可以当做函数传参的第二种方式

def func():
    username = 'tony'

    def inner():
        print(username)

    inner()

func()
'''
想inner函数时在func函数里的并且inner中的变量名的值是用到了func中得到名字
所以inner就可以被称为闭包函数
但是这样传参就只能打印'tony'给写死了所以需要改动下
'''
def func(username):
    def inner():
        print(username)
        pass
    return inner
res = func('tony')  # tony
res()
res = func('kevin')  # kevin
res()
# 这样就能把传参写活了用户想传啥传啥

装饰器

装饰器可以看成是在不改变原来函数的调用方式和函数体代码的前提下增加新功能

# 比如现在我们编写了一个函数
def func():
    print('from func')
func()

# 现在我们这个函数下添加新功能
# 现在我们在执行这个函数时我们需要计算这个函数执行了多长时间

推导流程

import time


def func():
    time.sleep(1)
    print('from func')
'''
既然要计算给函数func添加功能计算运行时间
那么我们可以在调用函数前面获取一个时间戳后面也获取一个时间戳
然后两个时间戳一减即可
'''
start = time.time()
func()
stop = time.time()
print(stop - start)  # 1.0003433227539062
'''
这样虽然说计算出了func函数运行的时间但是存在缺陷
如果py文件中存在多个函数需要计算运行时间
那么就会重复编写代码 编写代码效率太低
我们可以把它封装成函数
'''
def get_time():
    start = time.time()
    func()
    stop = time.time()
    print(stop - start)
get_time()  # 1.0008282661437988
'''
这样也能计算出func的运行时间但是还是有缺陷
因为现在我们把get_time函数的功能写死了只能计算func的运行时间
没法计算其他函数的运行时间
我们可以把func当做变量名 用闭包函数包给它
'''
def home():
    time.sleep(2)
    print('from home')

def outter(func):
    def get_time():
        start = time.time()
        func()
        stop = time.time()
        print(stop - start)
    return get_time
func = outter(func)
func()  # 1.0003347396850586
home = outter(home)
home()  # 2.000154972076416
'''
这样我们就能通过闭包函数动态传参
'''
# 有参装饰器
import time


# 比如现在func有两个形参
def func(a, b):
time.sleep(1)
print('from func')

def outter(func):
def get_time():
start = time.time()
func()
stop = time.time()
print(stop - start)
return get_time
func = outter(func)
func() # 这样会直接报错 因为func有两个形参 那么我们实参就必须要个实参才行
# 怎么解决呢?
# 其实直接在装饰器中添加两个参数即可
def outter(func):
def get_time(a,b):
start = time.time()
func(a,b)
stop = time.time()
print(stop - start)
return get_time
func = outter(func)
func(1,2) # 1.0008280277252197
'''
这样就能计算出func的运行时间 但是这样还是存在着缺陷
因为传参被我们写死了 只能传两个位置实参
所以我们要在形参和实参中都要用到*和**号
'''
def outter(func):
def get_time(*args, **kwargs):
start = time.time()
func(*args, **kwargs)
stop = time.time()
print(stop - start)
return get_time
func = outter(func)
func(1, 2) # 1.0008559226989746
'''
这样被装饰对象不管形参是什么样都可以
这样装饰器基本完成
'''
import time
# 当被装饰器对象有返回值时
def func(a, b):
time.sleep(1)
print('from func')
return 'func的返回值'
res = func(1,2)
print(res) # func的返回值
'''
一般我们获取函数得返回值时就是把函数赋值给一个变量名
那么这个变量名就会接收这个函数的返回值了
而现在我们的装饰器是无法接收被装饰器返回值的
'''
def outter(func):
def get_time(*args, **kwargs):
start = time.time()
func(*args, **kwargs)
stop = time.time()
print(stop - start)
return get_time
func = outter(func)
print(func) # <function outter.<locals>.get_time at 0x000001FFEB00F158>
'''
现在的返回值时get_time的内存地址
现在我们需要一个变量名赋值给被装饰器的函数然后在返回
'''
def outter(func):
def get_time(*args, **kwargs):
start = time.time()
res = func(*args, **kwargs)
stop = time.time()
print(stop - start)
return res # 这样就能把传进来的函数名的返回值返回回去了
return get_time
func = outter(func) # 1.0003952980041504
res = func(1,2)
print(res) # func的返回值
'''
这样就能把被装饰器的返回值原封不动的返回回去
'''

语法糖

from functools import wraps
import time

def outer(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        start = time.time()
        res = func(*args, **kwargs)
        stop = time.time()
        print(stop - start)
        return res

    return wrapper

def index():
    time.sleep(1)
    print('from index')

index = outer(index)
index()
'''
其实这样的装饰器已经很完美了  但是如果被装饰对象变多的时候我们可以把这两行简化成一行
'''


def outer(func):
    @wraps(func)  # 可写可不写 主要是不容易被发现是否被装饰过
    def wrapper(*args, **kwargs):
        start = time.time()
        res = func(*args, **kwargs)
        stop = time.time()
        print(stop - start)
        return res

    return wrapper
@outer
def index():
    '''index的注释'''
    time.sleep(1)
    print('from index')
    return 'inedx的返回值'

res = index()  # from index  1.0003662109375
print(res)  # inedx的返回值
help(index)  #   index的注释
'''
这样我们只需要在被装饰器对象上面一行加一个@装饰器名字 即可
@outer的意思就是把它下面一行的函数名拿来 然后进行  被装饰对象名字 = 装饰器名字(被装饰器对象名字)  操作
比如上方  index = outer(index)
这样就不用我们自己写了
'''

装饰器模板

from functools import wraps


def outer(func):
    @wraps(func)  # 可写可不写 主要是不容易被发现是否被装饰过
    def wrapper(*args, **kwargs):
        res = func(*args, **kwargs)
        return res

    return wrapper

'''
这样我们就能在res = func(*args, **kwargs)前面或则后面添加新功能了然后在被装饰对象上面写上语法糖即可
'''

有参装饰器

def login_auth(func_name):
    def inner(*args, **kwargs):
        res = func_name(*args, **kwargs)
        return res
    return inner
# 这是之前装饰器的模板 这个模板其实已经接近完美 但是如果现在需要在装饰器里还需要添加参数怎么办?
# 就比如现在需要在多个函数前加上用户登入验证 只有登入成功才能执行被装饰对象的函数
# 还要根据不同的数据库验证
def outter(choice):
    def login_auth(func_name):
        def inner(*args, **kwargs):
            username = input('username>>>:').strip()
            password = input('password>>>:').strip()
            if choice == '列表':
                print('基于列表验证')
                res = func_name(*args, **kwargs)
                return res
            elif choice == '字典':
                print('基于字典验证')
                res = func_name(*args, **kwargs)
                return res
            elif choice == '文件':
                print('基于文件验证')
                res = func_name(*args, **kwargs)
                return res
            else:
                print('用户权限不够 无法调用函数')
        return inner
    return login_auth

@ outter('列表')  # index = login_auth(index)
def index():
    pass
index()
# 现在装饰器出现了新的参数而如何给这个参数传值呢?
# 首先如果在inner函数写上形参的话 解释器就会报错 因为这违反了装饰器的功能 使调用函数时发生改变了
# 如果在login_auth函数写上参数的话 也是会报错的 因为这违反了语法糖的语法
# 所以我们只能使用闭包函数传参在装饰器外面在套上一个函数 这样装饰器想要多少个参数多可以传给它为了

多层装饰器

def outter1(func1):
    print('加载了outter1')
    def wrapper1(*args, **kwargs):
        print('执行了wrapper1')
        res1 = func1(*args, **kwargs)
        return res1
    return wrapper1

def outter2(func2):
    print('加载了outter2')
    def wrapper2(*args, **kwargs):
        print('执行了wrapper2')
        res2 = func2(*args, **kwargs)
        return res2
    return wrapper2

def outter3(func3):
    print('加载了outter3')
    def wrapper3(*args, **kwargs):
        print('执行了wrapper3')
        res3 = func3(*args, **kwargs)
        return res3
    return wrapper3


@outter1
# 可以看成是wrapper2当做参数传入 index = outter1(wrapper2)  所以func1就是wrapper2
# 执行outter1时返回的是wrapper1的内存地址 index现在的内存地址变成了wrapper1   index 就相当于wrapper1
@outter2
# 可以看成是wrapper3当做参数传入 index = outter2(wrapper3) 所以func2就是wrapper3
# 执行outter2时返回的是wrapper2的内存地址  index现在的内存地址变成了wrapper2 所以可以把上面的赋值看成
# wrapper2 = outter2(wrapper3)
@outter3
# 就是把index当做参数传入 idnex = outter(被装饰对象函数名:index)  所以func3就是index
# 执行outter3函数的时候返回的是wrapper3的内存地址所以index现在绑定的是wrapper3
# wrapper3 = outter(index)
def index():
    print('from index')
index()
'''
所以运行函数index时因为现在index的内存地址为wrapper1所以会先执行wrapper1()函数
然后运行到res1 = func1(*args, **kwargs)因为现在func1的内存地址为wrapper2 所以会执行wrapper2()函数
因为wrapper2中的func2的内存地址为wrapper3 所以会先执行wrapper3()函数
因为wrapper3中的func3的内存地址为index所以执行index()函数执行完并结束
index()函数结束运行时然后就会结束wrapper3函数然后依次往上结束
'''
'''
所以执行结果为:
加载了outter3
加载了outter2
加载了outter1
执行了wrapper1
执行了wrapper2
执行了wrapper3
from index
'''

递归函数

1.直接调用

def func(i):
    print(i)
    func(i)
func(1)
'''
在一个函数中直接调用自己的就是直接调用
像上方函数的意思就是一直打印1 直到报错
因为python有最大递归深度
'''

2.间接调用

def func():
    print('form func')
    index()
def index():
    print('form index')
    func()
func()
'''
像上方所写的代码在一个函数A中调用了函数B 而函数B中的代码又调用了函数A 就是间接调用
不过也会报错
'''

3.递归函数的应用

递归函数的引用场景:
  1.递推:一层一层的网下寻找真正的答案

  2.回溯:根据一致答案倒推会答案

递归函数:

  1.递归函数每次的调用都必须比上一次简单

  2.递归函数最后必须要有一个明确的结束条件

必须满足以上两个条件才能被称之为递归函数

l1 = [1, [2, [3, [4, [5, [6, [7, [8, [9, [10]]]]]]]]]]
# 然后依次取出里面所有的值
# 首先我可以用到for循环
for i in l:
    if isinstance(i, int):  # isinstance就是判断一个数据值是不是某个数据类型
        print(i)  # 因为for循环是一个一个取值取到第二个的时候是一个列表所以还要for循环
    for j in i:
        if isinstance(j, int):
           print(j)
        for k in j:
            if isinstance(k, int):
                print(k)
            ...
# 这样一直往复下就可以取出所有的值 但是这样写的时候就会发现重复的代码会变多我们可以把重复的代码封装成函数即可
def get_num(l):
    for i in l:
        if isinstance(i, int):
            print(i)
        else:
            get_num(i)
get_num(l1)
# 这样当我们使用递归函数的时候就可以免去复杂的代码编写是代码变得简单

算法之二分法

算法就是解决问题的一些方法

是一些数学公式通过代码编写出来

有时候替我们解决一些问题

算法没有最终解只有一直在优化与完善 很少有最完美的算法

 

# l1 = [11, 23, 39, 45, 59, 66, 89, 100, 165, 195, 260, 655, 745, 832, 999, 1230]
# 在列表中是否能快速找到999
# 首先我们可以通过for循环查找
# check_num = 999
# for i in l1:
#     if i == 999:
#         print('找到了', i)
#         break
# else:
#     print('没找到')
'''
虽然说使用for循环是可以是能够满足我们的需求的
但是for循环是从左到右一个一个提取并比对的
这样太浪费时间了 万一这个列表中的值非常多而查找的的也刚好很靠后
那么效率就会变低
'''
# 这个时候我们就能使用二分法了
'''
二分法就是先把列表中的值提取出来进行比对如果查找的值大了就会往右查找左边的值就可以直接去除
然后在找右边列表的中间值在做对比 然后在找中间值做对比 一直找到为止
'''

l1 = [11, 23, 39, 45, 59, 66, 89, 100, 165, 195, 260, 655, 745, 832, 999, 1230]


def target_num(l, check_num):
    if len(l) == 0:
        print('没有找到')
        return
    # 首先我们要提取列表的中间值
    middle_index = len(l) // 2  # 首先我们需要知道列表中间的索引值
    middle_num = l[middle_index]
    # 进行判断
    if check_num > middle_num:
        # 提取右边的列表
        right_l = l[middle_index + 1:]
        target_num(right_l, check_num)
    elif check_num < middle_num:
        lift_l = l[:middle_index]
        target_num(lift_l, check_num)
    else:
        print('找到了', check_num)
target_num(l1,99)
'''
利用递归函数就能编写出二分法就可以快速找到需要查找的值
但是二分法也有一定的缺陷 如果需要查找的值是在列表的末尾或则开头效率也会变低
所以一般的算法是没有完美的 只有不断的完善,优化
'''

三元表达式

def my_max1(a, b):
    if a > b:
        return a
    else:
        return b
res = my_max(10, 50)
print(res)  # 50 可以得出两个数的较大值

def my_max2(a, b):
    return a if a > b else b
res = my_max2(60, 20)
print(res)  # 60 这样的编写代码也是能够得出两个的较大值
'''但是这样编写明显简单 并且对于代码的行数也有减少'''

# 或则是判断用户登入
username = input('username>>>:').strip()
password = input('password>>>:').strip()
if username == 'jason' and password == '123':
    print('登入成功')
else:
    print('用户名或密码错误')
# 向上述的编写我们也可以编写成三元表达式
username = input('username>>>:').strip()
password = input('password>>>:').strip()
print('登入成功') if username == 'jason' and password == '123' else print('用户名或密码错误')
'''
向上述所编写的代码就是三元表达式
'''
# 三元表达式的语法结构为:
数据值1 if 条件 else 数据值2
'''
但是尽量不要嵌套三元表达式
因为嵌套会让代码可读性变差 不美观
'''

各种生成式

'''   列表生成式   '''
# 现在要把一个列表中的所有值加10并且放到两一个列表中
l1 = [1, 9, 32, 55, 66, 75]
# 我们首先可以想到要用for循环
new_list = []
for i in l1:
    j = i + 10
    new_list.append(j)
print(new_list)  # [11, 19, 42, 65, 76, 85]
# 我们现在可以用列表生成式来快速的编写
new_list = [i + 10 for i in l1]
print(new_list)  # [11, 19, 42, 65, 76, 85]
'''
两种方式都可以操作 但是列表生成式相对来说会简便许多代码的行数也会减少很多
上面的列表生成式可以理解为:
先执行for循环 然后把列表l1中的数据值一个一个取出来 然后再给前面的 i+10操作 
然后在一个一个放到列表中
'''

# 现在有一个列表现在要把列表中的值在末尾添加一个_nb 并且放到另一个列表中
l1 = ['jason', 'tony', 'kevin', 'jerry', 'oscar']
# 我们可以使用for循环
name_list = []
for name in l1:
    new_name = name + '_nb'
    name_list.append(new_name)
print(name_list)  # ['jason_nb', 'tony_nb', 'kevin_nb', 'jerry_nb', 'oscar_nb']
# 使用for循环是可以做到的 不过我们可以使用列表生成式可以是代码行数减少更简便
new_list = [name + '_nb' for name in l1]
print(new_list)  # ['jason_nb', 'tony_nb', 'kevin_nb', 'jerry_nb', 'oscar_nb']
'''
这样的话我们使用列表生成式会简便许多 代码可读性也可以
其实上面的列表生成式跟最上面的执行过程是一样的
首先执行for循环然后一个一个循环取出来 然后交给前面的表达式操作
最后在一个一个放到列表中
'''
l1 = ['jason', 'tony', 'kevin', 'jerry', 'oscar']
# 现在我们把列表除了jason其他都加上_nb
# 我们也可以直接使用列表生成式
new_list = [name + '_nb' for name in l1 if name != 'jason']
print(new_list)  # ['tony_nb', 'kevin_nb', 'jerry_nb', 'oscar_nb']
'''
这样使用列表生成式时可以很快的使用出来 不需要在使用for循环了
这个表达式的执行过程是
还是先执行for循环 把名字一个一个循环出来 然后交给if判断条件是否成立
如果成立就放到for循环前面的表达式继续操作 
然后在一个一个放到列表中
'''
'''
其实之前两个的代码的列表生成式 都有一个if判断的只不过是 if true 所以就简写了
列表生成式中只能出现 for 与 if 不能出现其他关键字
'''
'''   字典生成式   '''
# 其实字典生成式跟列表生成式差不多 就是字典需要两个参数 一个k一个v
user_dict = {i: 'jason' for i in range(6)}
print(user_dict)  # {0: 'jason', 1: 'jason', 2: 'jason', 3: 'jason', 4: 'jason', 5: 'jason'}
# 字典生成式的表达式也相当于快速生成一个字典 也可以加if判断
user_dict = {i: 'jason' for i in range(6) if i != 3}
print(user_dict)  # {0: 'jason', 1: 'jason', 2: 'jason', 4: 'jason', 5: 'jason'}
'''
其实就是首先for循环然后循环出来的值交给if判断 如果条件成立才会执行for循环前面的表达式
'''
'''   集合生成式   '''
# 集合生成式也跟列表差不多
set1 = {i for i in range(10)}
print(set1)  # {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
# 也是能够快速生成一个集合 也能够加判断
'''
new_tuple = (i for i in range(10))
print(new_tuple)  <generator object <genexpr> at 0x000001E62B8ED740>

而在python解释器中是没有元祖生成器的 元祖特性不能通过这种生成器生成
生成的是一个迭代器
'''

匿名函数

顾名思义就是没有名字的函数 我们之前编写的都是有名函数

# 匿名函数的语法结构
  lambda 形参: 返回值
lambda是关键字
形参跟有名函数一样可以传多个参数
返回值也跟有名函数一样写啥返回啥
(lambda x: x + 1)(10)  # 直接调用
res = (lambda x: x + 1)(10)
print(res)  # 命名调用

但是如果命名调用的话 就失去了匿名函数的独有风格了 如果要这样调用还不如直接命名一个函数

所以一般匿名函数都是跟一些内置函数来搭配使用的

匿名函数搭配各种内置函数

# 首先简绍一个函数 max() 这是python解释器的内置函数 它的功能就是计算一个列表中最大的值
l1 = [1, 12, 55, 66, 420, 452, 365, 214, 665, 668, 62, 745, 985, 125, 66, 2236, 225, 4222, 45]
res = max(l1)
print(res)  # 4222 可以计算一个列表中最大值
'''
其实就是for循环一个一个提取出来然后两两比较 大的留下 
然后在跟下一个比较始终都是两两比较 直到取完所有的值
'''
# 现在要计算出一个字典中那个人的薪资是最高的?
dic = {
    'jason': 1213,
    'alex': 4230,
    'egon': 999999,
    'Bean': 12143,
    'zone': 88
}
res = max(dic)
print(res)  # zone
'''
它会打印zone 因为max其实就是先for循环 但是字典参与for循环的只有k
而dic这个字典的k只有字符串而比较字符串的大小是一个一个比较的 如果是因为是根据
英文对应的ASCII表来做比较的 而因为小写z是最大的所以会打印zone 
而如何提取v做比较呢? 这就需要匿名函数了
'''
dic = {
    'jason': 1213,
    'alex': 4230,
    'egon': 999999,
    'Bean': 12143,
    'zone': 88
}
res = max(dic, key=lambda k: dic.get(k))
print(res)  # egon
'''
现在就可以打印最正确的值了
max函数时可以传key的 key后面可以传一个函数名
首先max的底层就是一个for循环 每次for循环出来的值交给函数去处理
但是被循环的数据类型是字典所以 每次循环都是循环字典的k 
max会把循环出来的k 交给后面的函数处理 而后面的函数的功能是
传一个参数 然后通过get方法提取这个参数的值 
比如传进去一个'jason'然后通过函数lambda的返回值dic.get(k)取出v1213
然后在循环下一个然后在两两继续比较 留大的跟下一个继续比较 直到取完
然后把最大的值按照当初for循环的值返回回去
'''
# 我们也可以编写一个有名函数传进去 只不过代码的函数会多出来 利用匿名函数会简便许多 其实用哪个都一样
def func(k):
    return dic.get(k)
dic = {
    'jason': 1213,
    'alex': 4230,
    'egon': 999999,
    'Bean': 12143,
    'zone': 88
}
res = max(dic, key=func)
print(res)  # egon

重要的一些内置函数

map

# map : 映射
'''
现在有个需求就是将列表中所有的值都自增10
我们可以用到for循环 列表生成式
现在有个内置函数也可以解决这个需求那就是map
'''
l1 = [1, 2, 3, 4, 5, 6]
res = map(lambda x: x + 20, l1)
print(list(res))  # [21, 22, 23, 24, 25, 26]
def index(x):
    return x + 20
res = map(index, l1)
print(list(res))  # [21, 22, 23, 24, 25, 26]
'''
map其实也是通过for循环一个一个取出列表中的值 
然后交给前面的函数处理 而前面的函数 是传进去一个参数然后返回一个 x+20
就会把传进去的数自增20 然后保存起来 然后在将第二个数传进去再自增20 
然后在保存到前面的数字后面 顺序就会一一对应 直到把列表中的值取完在返回出去
只不过是返回的是一个迭代器 所以在通过列表转换即可
同样的我们也可以吧匿名函数换成有名函数
'''

filter

''' filter '''
# 现在把列表中指定的值给去除 把'jason'去除掉
# 可以用for循环了、列表生成器现在可以用函数filter配合匿名函数

l1 = ['jason', 'tony', 'kevin', 'jerry', 'oscar', 'egon']
res = filter(lambda x: x != 'jason', l1)
print(list(res))  # ['tony', 'kevin', 'jerry', 'oscar', 'egon']

def func(a):
    return a != 'jason'
res = filter(func, l1)
print(list(res))  # ['tony', 'kevin', 'jerry', 'oscar', 'egon']

'''
filter其实也是通过for循环一个一个取出数据值 然后把数据值交给函数去处理
首先通过函数取出列表中的值 然后交给匿名函数lambda 匿名函数的返回值是 x != 'jason'
所以就可以除了'jason'的数据值保存起来 直到列表中的值被取完为止 返回出去
只不过filter返回的也是一个迭代器 需要通过列表转换
函数可以是匿名函数也可以是有名函数
'''

reduce

''' reduce '''
# 它可以将很多单体变成整体
# 现在需要取出列表的总数
'''
可以使用for循环、列表生成式、sum函数
现在还有一个reduce只不过reduce不能直接使用
需要通过模块导入
'''
# from functools import reduce

# l1 = [1, 2, 3, 4, 5]
# res = reduce(lambda x, y: x + y, l1)
# print(res)  # 15
# 我们还可以在reduce末尾在添加一个参数
# res1 = reduce(lambda x, y: x + y, l1, 100)
# print(res1)  # 115
# def func(x, y):
#     return x + y
# res2 = reduce(func, l1, 100)
# print(res2)  # 115
'''
reduce也是一个for循环一个一个取出所有值 然后交给函数处理
reduce会取出两个数据值然后 交个匿名函数匿名函数会返回两个数的和
然后reduce会在取出一个数据值再跟之前的和一起在给函数处理再返回这两个数的和
直到列表中的数据被取完 在返回出去 同样的函数可以是匿名函数也可以是有名函数
'''

zip

''' zip '''
# 将两个列表中的值一一对应组织成列表套元祖
# l1 = [1, 2, 3]
# l2 = ['tony', 'jason', 'egon']
# res = zip(l1, l2)  # 返回的是一个迭代器
# print(list(res))  # [(1, 'tony'), (2, 'jason'), (3, 'egon')]

l1 = [1, 2, 3]
l2 = ['jason', 'tony', 'kevin']
l3 = [4, 5, 6]
res = zip(l1, l2, l3)
print(list(res))  # [(1, 'jason', 4), (2, 'tony', 5), (3, 'kevin', 6)]
# zip可以多个列表一起

l1 = [1, 2, 3, 4, 5, 6, 7, 8, 9]
l2 = ['jason', 'kevin', 'tony', 'jerry']
l3 = 'jason'
res = zip(l1, l2, l3)
print(list(res))  # [(1, 'jason', 'j'), (2, 'kevin', 'a'), (3, 'tony', 's'), (4, 'jerry', 'o')]
# 如果其中一个列表的数据值跟其他的列表得值数量不一样那么就会把多的数据除去
# 必须要支持for循环的才行

 

这篇关于本周内容回顾的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!