学习python-周总结03


周总结

一、 * 与 ** 在实参和形参的作用

* **
形参作用 位置参数多余的部分传值给*后面的变量名 关键字参数多余的部分传值给**后面的变量名
实参作用 利用for循环将每个列表的数据值、字符串的字符、字典的k值分开再组织成元组的形式传值给函数体代码 就是将字典的每个K:V键值对取出转化成关键字实参的方式。

二、命名关键字参数(冷门了解)

1. def func(a,b,*args,c):
    	print(a,b,args,c)
   func(1,2,3,4,5)#报错
   func(1,2,3,4,c=5) # 1 2 (3,4) 5

命名关键字-变量名可以放在*args的后面。不过在实参的时候,该变量名要以关键字实参的方式传值到形参。

def func(a,b,*args,c,**kwargs):
    pass
func(1,2,3,4,5,6,c=123,name='xz')
注意该变量不能放在**kwargs的后面,不然会报错。

三、名称空间

1.定义:就是存放变量名与数据值之间绑定关系的地方。

name = 'xz'
del name  (删除不是数据值,而是变量名与数据值之间的绑定关系)

名称空间 内置名称空间 全局名称空间 局部名称空间
定义 python解释器运行就会立刻创建空间 py文件代码运行过程中产生的名字会存在这个空间 函数体代码一运行过程中产生的名字都会存入该空间
用法 直接拿来用的内置函数 普通代码里面的变量名(分支结构,循环结构,定义函数的函数名,定义类的类名) 函数体运行后的变量名。
2.名称空间的存活周期
创建 销毁
内置名称空间 解释器运行 解释器关闭
全局名称空间 py文件运行 py文件结束
局部名称空间 函数体代码运行 函数体代码结束
3.名字查找顺序

名字查找顺序之前一定要清楚自己所在的名称空间是什么。

当前处于全称名称空间时: 全称名称空间 >>>  局部名称空间
	就在全称名称空间找那个名字,如果没有就去内置名称空间里面找。
当前处于局部名称空间时: 局部名称空间 >>> 全称名称空间 >>> 局部名称空间  
	就在当前的局部名称空间找名字,如果没有就去全称名称空间找,还没有最后去内置名称空间找。如果内置都找不到,那就报错!
4.局部名称空间复杂情况

注意:各自局部名称空间默认下情况下不能彼此共享名字。

函数嵌套情况就很特殊。

? 它可以在内存局部名称空间调用外存名称空间。外层名称空间调用最外层名称空间。最后没有局部名称空间后调用全局名称空间。

x = 1
def func1():
    x = 2
    def func2():
        x = 3
        def func3():
            x = 4
         func3()
     func2()
func3()

    
5.global与nonlocal关键字

global 就是将全局名称空间的变量名变成局部名称空间里的变量名(可变类型可以不用关键字,不变类型需要关键字)

nonlocal 就是内层局部名称空间的变量名修改外层局部名称空间里的变量名(不可类型)。

四、函数名的多种使用方式

函数名使用方式
1.函数名可以被用来多次赋值(函数名与变量名使用一致)
2.函数名可以当做函数实参
3.函数名可以当做函数名的返回值
4.函数名可以当做容器类型里面的数据值:l1 = [1,2,3,4,func]

五、闭包函数

1.闭包函数简介:
  1. 定义在函数内部的函数
  2. 内部函数使用了外部函数名称空间里的名字

注意:如果有内部函数情况下,运行外部函数不会立马结束,而是等内部函数全部结束才结束。

2.闭包函数的实际应用:

函数体代码传值的方式有两种:

  1. 形参
  2. 闭包函数
def index():
    username = 'xz'
    def func():
        print(username)
        return func
res = index()
res()
            

六、装饰器

1.装饰器的简介
  • 在不改变被装饰器对象原来的调用方式内部代码的情况下给被装饰对象的添加新的功能。
2.装饰器的原则
  • 不能修改代码,只能扩展代码

时间戳:

import time
print(time.time())
'''时间戳(秒数):当前距离1970年1月1日0时0分0秒'''
time.sleep(3)
print('3秒后我出来了')
'''让程序原地等待三秒'''
3.装饰器的前期推导
  1. index()前后加个时间戳是不改变它的调用方式和内部代码。

    import time
    def index():
        print('运行index函数体代码')
    start_time = time.time()
    index()
    end_time = time.time()
    print('函数执行的时间:',end_time - start_time)
    
    

    注意:不利于多个index函数需要统计时间。

  2. 多个相同函数需要统计时间,需要封装成函数。

    import time
    def index():
        print('运行index函数体代码')
    
    def get_time():
        start_time = time.time()
        index()
        end_time = time.time()
        print('函数的执行时间是:', end_time - start_time)
    get_time()
    

    注意:封装后,但是不能满足不同函数的统计时间。

  3. 多个不同的函数需要统计时间,可以封装后调用形参(动态传参)

    import time
    def index():
        print('运行index函数体代码')
       
    def home():
        print('运行home函数体代码')
       
    def get_time(a):
        start_time = time.time()
        a()
        end_time = time.time()
        print('函数的执行时间是:', end_time - start_time)
       
    get_time(index)
    get_time(home)
    
    
    '''传参的过程中我们要注意形参的个数问题:引用* 与 **'''
    如果在a(*args, **kwargs)的话会报错,原因是get_time函数没法识别a()里面是什么东西。
    
    

    注意:这样会改变之前的调用方式!!!如果不能直接用形参的方式,那就用闭包函数。

4.装饰器各个版本

如果index和home都有形参,则就不能用形参的方式传值,而是用闭包函数来做。

def outer(a):
    def get_time(*args, **kwargs)
        start_time = time.time()
        a(*args, **kwargs)
        end_time = time.time()
        print('函数的执行时间是:', end_time - start_time)
    return get_time
res = outer(index)
res()

res1 = outer(home)
res1()

'''注意:这样还有不满足装饰器的条件,调用方式改变。'''

我们可以将变量名重命名和函数名一样解决了调用方式不一样问题。

def outer(a):
    def get_time():
        start_time = time.time()
        a()
        end_time = time.time()
        print('函数的执行时间是:', end_time - start_time)
        return get_time
index = outer(index)
index()

home = outer(home)
home()
5.装饰器的固定模板
from functools import wraps
def outer(func_name):
    #@wraps(func_name)  # 仅仅是为了让装饰器不容易被别人发现 做到真正的以假乱真
    def inner(*args, **kwargs):
        print('执行被装饰对象之前可以做的额外操作')
        res = func_name(*args, **kwargs)
        print('执行被装饰对象之后可以做的额外操作')
        return res
    return inner

inner = outer()
inner()
6.装饰器语法糖

语法糖的功能就是紧挨着的函数名(装饰对象)当做参数传递给@符号后面的函数名(加括号调用)

#装饰器语法糖
import time
@outer
def home():
    print('from home')
    return 'home的返回值'
home()
7.help
def index():
    pass

help(index)



8.多层装饰器
def outer1(func1):
    print('加载outer1')
    def wrapper1(*args, **kwargs):
        print('执行了wrapper1')
        res1 = func1(*args, **kwargs)
        return res1
    return wrapper1

def outer2(func1):
    print('加载outer2')
    def wrapper1(*args, **kwargs):
        print('执行了wrapper2')
        res2 = func21(*args, **kwargs)
        return res2
    return wrapper2

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

@outer1  # index = outer1(wrapper2)
@outer2  # wrapper2 = outer2(wrapper3)
@outer3  # wrapper3 = outer3(index)
def index():
    print('hello world!')
    
index()
9.有参装饰器
def transfor(condition, type_user):
    def outer(func_name):
        def inner(*args, **kwargs)
        if type_user == 'xz':print('VIP')
        if condition == '权限1':
        	print('可以打开权限1,进入其中使用其功能。')
        elif condition == '权限2':
            print('可以打开权限2,进入其中使用其功能。')
        elif condition == '权限3':
             print('可以打开权限3,进入其中使用其功能。')
        else:
            print('没有别的方式!')
        return inner
    return outer

@transfor('权限1', type_user)
def inner():
    print('执行inner函数体代码')
    
inner()

'''目的给装饰器传递更多额外的数据'''

四、算数二分法

就是解决问题的方法。

就是将有序数组一分为二,取中间那个数值与目标数值比较。目标数值大,则在这中间的数往右半边找。目标数小则往左半边找。再从左半边/右半边取中间的数值与目标数值比较,以此类推,缩短查找的空间,步步接近与目标数相近的数值最后找到目标数值。

五、三元表达式

主要减少了代码的行数

'缩短单横的条件语句'
eg:
if username == 'xz':print('欢迎')
else:print('抱歉!')
'三元表达式:仅限于二选一情况(if...else)并且不建议嵌套使用'
eg:
print('欢迎') if username == 'xz' else print('抱歉')
'''
三元表达式语法结构:
	值1 if 条件 else 值2
如果if后面的条件成立,则使用if前面的值
如果if后面的条件不成立,则使用else后面的值
'''

六、生成式

1.列表生成式/字典生成式/集合生成式
#列表生成式
name_list = ['xz', 'wyb', 'bx', 'yyds']
#给上述列表所有的数据值加上s的后缀
#先执行for循环,然后将一个个数据值交给for循环前面的拼接处理,最后在整理成一个新列表。
new_list = [name + 's' for name in name_list]
print(new_list)
#如果有if判断语句就for循环之后先if判断。
new_list = [name + 's' for name in name_list if name != 'xz']
print(new_list)

----------------
#字典生成式
#for循环将i作为K值,然后将每个K值循环到后面的if判断,判断后的值返回到for循环前面的代码中执行。
new_dict = {i: 'xz' for i in range(10) if i == 6}
print(new_dict) #{6:'xz'}
#集合生成式
 new_set = {i for i in range(10) if i == 6}
  print(new_set) 
4.元组

元组没有生成式,只有生成器就是迭代器。

七、匿名函数

  1. 匿名函数就是没有函数名的函数

  2. 语法结构: lambda 形参 : 返回值

  3. 直接调用: (lambda x : x + 1)(123)

  4. 命名调用:res = lambda x : x + 1

  5. 应用场景:

    通常要配合其他函数一起使用,用于减少代码。

八、匿名函数在内置函数中是使用

  1. max() 最大值/min()最小值

    min()'方法返回字符串中最小的字母'
    max()'会根据提供的函数对指定序列做映射'
    l1 = [1,2,3,4,5]
    res = max(l1)
    print(res)  # 5
    
    
    dict1 = {
        'jason': 100,
        'aj': 123,
        'Bason': 9999,
        'zero': 888
    }
    #方式一:直接用函数
    #传入一个形参K
    def index(k):
        return dict1.get(k)
    res = max(dict1, key = index)
    print(res)
    
    #方式二:用匿名函数
    #得到K值对应的V值,然后将数据传到前面的dict1中比较大小。
    res = max(dict1, key = lambda k: dict1.get(k))
    print(res)
    
    
    

九、重要的内置函数

  1. reduce() 求和

    函数会对参数序列中元素进行累积。

    l2 = [1, 2, 3]
    # 需求:求列表中所有数据值的和
    

    方式1 : for循环

    s = 0
    for i in l2:
        s += i
    print(s)
    

    方式2 : sum()

    res = sum(l2)
    print(res)
    

    方式3 : reduce()

    from functools import reduce
    #用匿名函数,l2后面是可以添加数据值的。
    res = reduce(lambda x, y: x + y, l2, 100)
    print(res)
    
  2. map()映射

    
    l1 = [11, 22, 33, 44, 55, 66]
    # 需求:将列表中所有的数据值自增20
    

    方式1:for循环

    new_list = []
    for i in l1:
        i += 10
        new_list.append(i)
    print(new_list)
    

    方式2:列表生成式

    new_list = [i+10 for i in l1]
    print(new_list)
    

    方式3:map函数

    res = map(lambda i : i = 10, l1)
    print(res)
    
    ----------
    def index(a):
        return a + 10
    res = map(index,l1)
    print(list(res))
    
  3. filter() 过滤

    用于过滤序列,过滤掉不符合条件的元素,返回由符合条件元素组成新的列表

    l1 = ['xz', 'wyb', 'bx', 'yyds']
    # 需求:移除数据值里面的yyds
    

    方式1:for循环

    for i in l1:
        if i == 'yyds':
            l1.remove(i)
    print(l1)
    

    方式2:列表生成式

    new_list = [i for in l1 if i != 'yyds']
    print(new_list)
    

    方式3:filter()

    res = filter(lambda a : a != 'xz', l1)
    print(res)#迭代器形式
    print(list(res))#这里需要转换成列表形式
    
  4. zip()

    1. 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的对象。
    2. 如果各个迭代器的元素个数不一样,则返回列表长度与最短的对象相同,利用*操作符可将元组解压成列表
    >>> a = [1,2,3]
    >>> b = [4,5,6]
    >>> a1, a2 = zip(*zip(a,b))  
    >>> list(a1)
    [1, 2, 3]
    >>> list(a2)
    [4, 5, 6]
    
    1. 元组根据一一对应然后组成一个元组,再用list转化成列表里的元组。

      l1 = [1, 2, 3]
      l2 = ['xz','wyb','bx']
      res = zip(n1, n2)
      print(res)  # 
      print(list(res))
      '运行结果:
          
          [(1, 'xz'), (2, 'wyb'), (3, 'bx')]'
      
    2. 字符串拆开成一个个字符对应。

      l1 = [1, 2, 3]
      l2 = ['xz','wyb','bx']
      s = 'wyb'
      res = zip(l1,l2,s)
      print(list(res))
      '运行结果:
          [(1, 'xz', 'w'), (2, 'wyb', 'y'), (3, 'bx', 'b')]'
      
    3. 元素个数与最短的列表一致。

      l1 = [1, 2, 3]
      l2 = ['xz','wyb','bx']
      s1 = 'xz'
      res = zip(l1, l2, s1)
      print(list(res))
      '运行结果:
         [(1, 'xz', 'x'), (2, 'wyb', 'z')]'
      

十、递归函数

1.概念:函数可以直接或者间接调用自己>>>>递归调用
def index():
    print('oooooo')
    index()
index()
'''超过了系统给定的调用次数会报错'''

def index();
	print('oooo')
    func()
def func():
    print('000000')
    index()
func()
'''相互间接调用'''

2.递归函数真正的应用场景

递归:一层层忘下寻找答案

回溯:根据已知条件退出最终结果

递归函数

  1. 每次调用的时候都比上一次更接近结果
  2. 递归函数最终都需要有个明确的结束条件。