Python高级部分

函数部分

动态(万能)参数

动态参数分为两种:动态接受位置参数,动态接受关键字参数

动态接受位置参数

动态接收位置参数 *args 在参数位置用*表示接受任意参数

def eat(*args):

    print('我想吃',args)

eat('大米饭','中米饭','小米饭')  

这种传参方式实则是传入一个元组。

动态接受关键字参数

动态接受关键字参数**kwargs

def func(**kwargs):
    print(kwargs) # {'name': '太白金星', 'sex': '男'}
func(name='太白金星',sex='男')

由此,关键字参数传入的实则是一个字典。

需要注意的是当*args与 **args 一同使用时,其顺序唯一

def test(*args,**kwargs):
    print(args)
    print(kwargs)

    
#顺序只能是接收参数在关键字参数之前

聚合打散

聚合,则用*号 主要用于传入多个参数且不知道具体数量

打散,用于将三个可迭代对象逐个当参数传入。

s1 = 'alex'
l1 = [1, 2, 3, 4]
tu1 = ('武sir', '太白', '女神',)
def func(*args):
    print(args) # ('alex', [1, 2, 3, 4], ('武sir', '太白', '女神'))
func(s1,l1,tu1)

#解决办法
s1 = 'alex'
l1 = [1, 2, 3, 4]
tu1 = ('武sir', '太白', '女神',)
def func(*args):
    print(args) # ('a', 'l', 'e', 'x', 1, 2, 3, 4, '武sir', '太白', '女神')
func(*s1,*l1,*tu1)

其他用法

  1. 赋值

    • 元组列表中多余被赋值变量时。将多余的元素打包给被*修饰的变量

      a,*b = (1, 2, 3, 4,)
      print(a, b) # 1 [2, 3, 4]
      
      *rest,a,b = range(5)
      print(rest, a, b) # [0, 1, 2] 3 4
      
  2. 解包

    拆解可迭代对象

    print([1, 2, *[3, 4, 5]]) # [1, 2, 3, 4, 5]
    

参数的顺序

def func(位置参数,*args,默认参数,仅限关键字参数,**kwargs):
    pass

仅限关键字参数

仅限关键字参数要放在*args参数后面,与默认参数位置可交换

传入参数时,必须指定关键字,否则报错。

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

函数注释(属性)

def eat(food, drink, sex='男'):

    """

    这里描述这个函数是做什么的.例如这函数eat就是吃

    :param food:  food这个参数是什么意思

    :param drink: drink这个参数是什么意思

    :return:  执行完这个函数想要返回给调用者什么东西

    """

    print(food, drink,sex)

    return 666

eat('麻辣烫','肯德基')

# print(dir(eat))   dir() 获取函数所有的属性
['__annotations__', '__call__', '__class__', '__closure__', '__code__',
 '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__',
 '__eq__', '__format__', '__ge__', '__get__', '__getattribute__',
 '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__',
 '__kwdefaults__', '__le__', '__lt__', '__module__',
 '__name__', '__ne__', '__new__', '__qualname__', '__reduce__',
 '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
 '__subclasshook__']

# 常用的属性
print(eat.__doc__)  # str类型 获取函数的注释信息
print(eat.__name__)  # str类型 获取函数名
print(eat.__defaults__)  # tuple类型 获取默认参数的默认值
print(eat.__closure__)  # 与闭包函数相关,后面会涉及

名称空间,作用域

1aaf097d-864d-42ed-8b4d-869aada5698c.png

1. 全局作用域: 全局命名空间 + 内置命名空间

2. 局部作用域: 局部命名空间

**3. globals()函数 以字典的形式返回全局作用域所有的变量对应关系。 **

**4. locals()函数 以字典的形式返回当前作用域的变量的对应关系。 **

global、nonlocal

  • global
    • 在局部作用域中可以更改全局作用域的变量。
    • 利用global在局部作用域也可以声明一个全局变量。
  • nonlocal
    • 不能更改全局变量
    • 在局部作用域中,对父级作用域(或者更外层作用域非全局作用域)的变量进行引用和修改,并且引用的哪层,从那层及以下此变量全部发生改变。

字符串格式化 f-string

他的结构就是F(f)+ str的形式,在字符串中想替换的位置用{}展位,与format类似,但是用在字符串后面写入替换的内容,而他可以直接识别。碉堡了。

支持的写法:

  1. 变量
  2. 任意表达式
  3. 函数返回值
  4. 多行

迭代器

在Python中,但凡内部含有__iter__方法的对象,都是可迭代对象

在python中,内部含有Iter方法并且含有next方法的对象就是迭代器。

  • 可迭代对象:

    是一个私有的方法比较多,操作灵活(比如列表,字典的增删改查,字符串的常用操作方法等),比较直观,但是占用内存,而且不能直接通过循环迭代取值的这么一个数据集。

    应用:当你侧重于对于数据可以灵活处理,并且内存空间足够,将数据集设置为可迭代对象是明确的选择。

  • 迭代器:

    是一个非常节省内存,可以记录取值位置,可以直接通过循环+next方法取值,但是不直观,操作方法比较单一的数据集。

    应用:当你的数据量过大,大到足以撑爆你的内存或者你以节省内存为首选因素时,将数据集设置为迭代器是一个不错的选择。(可参考为什么python把文件句柄设置成迭代器)

生成器

构建生成器

将函数中的return改为yield即可。 此时函数会返回一个生成器。

def func():
    print(11)
    yield 22
ret = func()
print(ret)

# 运行结果:
<generator object func at 0x000001A575163888>
  • return一般在函数中只设置一个,他的作用是终止函数,并且给函数的执行者返回值。

  • yield在生成器函数中可设置多个,他并不会终止函数,next会获取对应yield生成的元素。

当构建一个列表(列表中的元素不会同时会用)时可使用生成器。

好处如下:

  • 节约内存
  • 保留上次的位置
#老板向楼下卖包子的老板订购了10000个包子.包子铺老板非常实在,一下就全部都做出来了
def eat():

    for i in range(1,10000):

        yield '包子'+str(i)

e = eat()

for i in range(200):
    next(e)

yield from

在python3中提供一种可以直接把可迭代对象中的每一个数据作为生成器的结果进行返回

yield from ['卫龙','老冰棍','北冰洋','牛羊配']
'''
等同于
    yield '卫龙'
    yield '老冰棍'
    yield '北冰洋'
    yield '牛羊配'
'''

小坑

def func():
    lst1 = ['卫龙', '老冰棍', '北冰洋', '牛羊配']
    lst2 = ['馒头', '花卷', '豆包', '大饼']
    yield from lst1
    yield from lst2


g = func()
for i in g:
    print(i)

返回的结果是将第一个列表的元素全部返回后,在返回第二个列表

闭包

所谓闭包就是在函数内在写一个函数

def wrapper(a,b):
    def inner():
        print(a)
        print(b)
    return inner
a = 2
b = 3
ret = wrapper(a,b)

闭包的作用:保存局部信息不被销毁,保证数据的安全性。

闭包的应用

  1. 可以保存一些非全局变量但是不易被销毁、改变的数据。
  2. 装饰器

装饰器

在不改变原被装饰的函数的源代码以及调用方式下,为其添加额外的功能。

def wrapper(func):
    def inner(*args,**kwargs):
        '''执行被装饰函数之前的操作'''
        ret = func
        '''执行被装饰函数之后的操作'''
        return ret
    return inner

示例:

def timer(func):  # func = home
    def inner(*args,**kwargs):
        start_time = time.time()
        func(*args,**kwargs)
        end_time = time.time()
        print(f'此函数的执行效率为{end_time-start_time}')
    return inner
@timer  # home = timer(home)
def home(name,age):
    time.sleep(3)  # 模拟一下网络延迟以及代码的效率
    print(name,age)
    print(f'欢迎访问{name}主页')
home('太白',18)

参数

def auth(x):
    def auth2(func):
        def inner(*args, **kwargs):
            if login_status['status']:
                ret = func()
                return ret
            
            if x == 'wechat':
                username = input('请输入用户名:').strip()
                password = input('请输入密码:').strip()
                if username == '太白' and password == '123':
                    login_status['status'] = True
                    ret = func()
                    return ret
            elif x == 'qq':
                username = input('请输入用户名:').strip()
                password = input('请输入密码:').strip()
                if username == '太白' and password == '123':
                    login_status['status'] = True
                    ret = func()
                    return ret
        return inner
    return auth2
    
@auth('wechat')  
def jitter():
    print('记录美好生活')

@auth('qq')
def pipefish():
    print('期待你的内涵神评论')

推荐阅读更多精彩内容