函数

一. global与nonlocal关键字

1.1 global

"""
如果想要在局部修改全局的不可变类型, 需要提前加关键字global申明

如果想要在局部修改全局的可变类型, 不需要加关键字global申明
"""

# 不可变数据类型
    x = 111
    def index():
        x = 222                # 并不是在修改全局的x 而是在局部名称空间中创建了一个新的x

                               # 如果想要在局部名称空间中修改全局名称空间中的名字 那么需要使用关键字申明
        global x               # 申明 修改的是全局x而不是产生新的x
        x = 666
    index()
    print(x)                   # 不使用 global 则是 111, 否则是 666

# 可变数据类型
    l1 = [111, 222, 333]
    def index():
        l1.append(444)
    index()
    print(l1)

1.2 nonlocal


"""
局部名称空间嵌套的情况下 内层如果想要修改外层
    情况1数据是不可变类型
        需要使用关键字nonlocal
    情况2数据是可变类型
        不需要使用关键字nonlocal
"""

# 不可变数据类型
    def index():
        x = 111             # 在index的局部产生一个x=111
        def f1():
            x = 222         # 在f1的局部产生一个x=222
            print(x)
            nonlocal x
            x = 333
        f1()
        print(x)
        print(l1)
    index()

# 可变数据类型
    def index():
        l1 = [11, 22, 33]
        def f1():
            l1.append(44)
        f1()
        print(x)
        print(l1)
    index()

二. 闭包函数

2.1 特性

    1. 函数嵌套函数;
    2. 函数内部可以引用函数外部的参数和变量;
    3. 参数和变量不会被垃圾回收机制回收.

2.2 优缺点

优点是:
    1. 变量被保存起来没有被销毁,随时可以被调用
    2. 只有函数内部的子函数才能读取局部变量,可以避免全局污染

缺点是:
    1. 如果闭包使用不当,就会导致变量不会被垃圾回收机制回收,造成内存泄露

三. 装饰器

3.1 简易版装饰器

  def get_time(func):
      start_time = time.time()      # 函数执行之前获取一个时间戳
      func()
      end_time = time.time()        # 函数执行之后获取一个时间戳
      print(end_time - start_time)  # 两个时间戳的差值就是函数的执行时间

  def home():
      time.sleep(3)
      print('from home')

  get_time(home)

3.2 进阶版本装饰器

# 解决参数问题

    def outer(func_name):
        def get_time(*args, **kwargs):

            start_time = time.time()
            func_name(*args, **kwargs)
            end_time = time.time()

            print(end_time - start_time)
        return get_time

3.3 完整版本装饰器

# 解决返回值问题

    def outer(func_name):
        def get_time(*args, **kwargs):

            start_time = time.time()
            res = func_name(*args, **kwargs)          # 执行真正的index函数
            end_time = time.time()
            print(end_time - start_time)

            return res                                # return '不要急躁' # 如何在此处返回真正index函数的返回值
        return get_time

3.4 装饰器模板(重要)

'''编写装饰器其实有一套固定的代码 不需要做任何理解'''

def outer(func_name):                                 # func_name用于接收被装饰的对象(函数)
    def inner(*args, **kwargs):
        print('执行被装饰函数之前 可以做的额外操作')
        res = func_name(*args, **kwargs)              # 执行真正的被装饰函数
        print('执行被装饰函数之后 可以做的额外操作')
        return res                                    # 返回真正函数的返回值
    return inner

3.5 装饰器修复技术

# 做到比真的还要真  但是本质其实没有变

from functools import wraps                                # 导入模块

    def outer(func_name):
        @wraps(func_name)
        def inner(*args, **kwargs):
            print('执行被装饰对象之前可以做的操作')
            res = func_name(*args, **kwargs)
            return res
        return inner
    @outer
    def index():
        print('from index')
    @outer
    def home():
        '''这是home函数的注释'''
        print('from home')
    # help(home)  # help可以查看指定函数的注释信息
    # help(len)
    # index()  # 目前的以假乱真 有瑕疵
    # print(index)
    # help(home)
    # help(index)
    # print(home)
    # print(index)
    home()
    index()

3.6 多层装饰器

# 判断七句print执行顺序
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
@outter2
@outter3
def index():
    print('from index')


index()

# 结果:
"""
加载了outter3
加载了outter2
加载了outter1
执行了wrapper1
执行了wrapper2
执行了wrapper3
from index
"""

3.7 有参装饰器

def outer(source_data):
    def login_auth(func_name):                            # 不能修改  只能接收一个被装饰对象名字
        def inner(*args, **kwargs):                       # 不能修改  是专门用来给被装饰的对象传参的

            username = input('username>>>:').strip()
            password = input('password>>>:').strip()

            # 校验用户数据  数据的来源可以有很多 比如全局字典 全局列表 文本文件 数据库
            # 数据的来源不同 处理方式就不同 对应的代码编写就不一样
            # 分支结构处理 然后根据不同的参数提示 匹配不同的流程

            if source_data == '1':
                print('使用字典的方式处理数据')
            elif source_data == '2':
                print('使用列表的方式处理数据')
            elif source_data == '3':
                print('使用文件操作处理数据')
            else:
                print('其他操作情况')
            res = func_name(*args, **kwargs)
            return res
        return inner
    return login_auth

@outer('3')
def index():
    print('from index')


3.8 装饰器语法糖

def outer(func_name):  # func_name用于接收被装饰的对象(函数)
    def inner(*args, **kwargs):
        a = 1
        if a > 2:
            res = func_name(*args, **kwargs)  # 执行真正的被装饰函数
            return res  # 返回真正函数的返回值

    return inner

方式一:
@outer
def index():
    print('index')

方式二:
def index():
    print('index')
index = outer(index)

四. 三元表达式

值1 if 条件 else 值2
条件如果成立则使用值1 (if前面的数据)
条件如果不成立则使用值2 (else后面的数据)
username = input('username>>>:').strip()
res = '管理员' if username == 'kiven' else 'DSB'

五. 各种生成式

>>>没有元组生成式<<<

5.1 列表生成式

"""列表生成式中值允许出现for和if 不能出现else 因为会产生歧义(for和if都能结合else)"""


# 需求:将列表中所有的人名后面加上_DSB
name_list = ['kunkun', 'kevin', 'tony', 'oscar', 'jerry']

# 列表生成式完成需求
res = [name+'_SB' for name in name_list]
print(res)                                                            # ['kunkun_SB', 'kevin_SB', 'tony_SB', 'oscar_SB', 'jerry_SB']  

# 列表生成式复杂用法:具备筛选能力

res = [name+'_SB' for name in name_list if name == 'kunkun']
print(res)

res = [name+'_SB' for name in name_list if name != 'kunkun']
print(res)

5.2 字典生成式

# 需求:将下面两个列表分别制作成字典的键值
l1 = ['name', 'age', 'pwd']
l2 = ['jason', 18, 123]

res = {l1[i]: l2[i] for i in range(len(l1))}
print(res)                                                           # {'name': 'jason', 'age': 18, 'pwd': 123}

res = {l1[i]: l2[i] for i in range(len(l1)) if i == 1}
print(res)                                                           # {'age': 18}

5.3 集合生成式

res = {i for i in range(10)}
print(res, type(res))

res = {i for i in range(10) if i != 2}
print(res, type(res))

六. 常见内置函数(重要)

6.1 map映射

# 需求:元素全部自增10
l1 = [11, 22, 33, 44, 55]

1. 方式一:(列表生成式)
    res = [item + 10 for item in l1]
    print(res)


2. 方式二:(内置函数)

    def index(n):
        return n + 10
    res = map(index, l1)
    print(res)                           # <map object at 0x000001F3064EEE80>
    print(list(res))                     # [21, 32, 43, 54, 65]
            ||
            ||
           相当于
            ||
            \/
    res = map(lambda x: x + 10, l1)      # lambda 自带的内置函数
    print(res)                           # <map object at 0x000001F3064EEE80>
    print(list(res))                     # [21, 32, 43, 54, 65]

6.2 zip拉链

# 需求:将两个列表中的元素一一对应成对即可----------------> 生成器也可以
l1 = [11, 22, 33, 44]
l2 = ['jason','kevin','tony','oscar']

res = zip(l1,l2)                         # 结果是一个迭代器
print(res)                               # 目前想看里面的数据 用list转换一下即可
print(list(res))                         # [(11, 'jason'), (22, 'kevin'), (33, 'tony'), (44, 'oscar')]


'''zip可以整合多个数据集, 如果数据集之间个数不一致 那么依据短的'''

l1 = [11, 22, 33, 44]
l2 = ['jason','kevin','tony','oscar']
l3 = [1,2,3,4]
l4 = [55,66,77,88]
res = zip(l1,l2,l3,l4)
print(list(res))                         # [(11, 'jason', 1, 55), (22, 'kevin', 2, 66), (33, 'tony', 3, 77), (44, 'oscar', 4, 88)]

6.3 filter过滤

# 需求:筛选出大于30的元素
l1 = [11, 22, 33, 44, 55, 66]



def index(x):
    return x > 30
res = filter(index,l1)
print(list(res))                   # [33, 44, 55, 66]
            ||
            ||
           相当于
            ||
            \/
res = filter(lambda x:x>30, l1)
print(list(res))                   # [33, 44, 55, 66]

6.4 reduce归总

以前是内置函数 现在是某个模块下面的子函数

from functools import reduce               # 导入

# 需求:讲列表中所有的元素相加
l1 = [11, 22, 33]

def index(x,y):
    return x + y
res = reduce(index,l1)
print(res)                               # 66
            ||
            ||
           相当于
            ||
            \/
res = reduce(lambda x, y: x + y, l1)
print(res)                                 # 66
res = reduce(lambda x, y: x + y, l1, 100)
print(res)                                 # 166

6.5 常见内置函数 1

# 1.abs()  获取绝对值(不考虑正负号)
# print(abs(-123))
# print(abs(123))

# 2.all()与any()
# l1 = [0, 0, 1, 0, True]
# print(all(l1))  # False  数据集中必须所有的元素对应的布尔值为True返回的结果才是True
# print(any(l1))  # True   数据集中只要所有的元素对应的布尔值有一个为True 返回的结果就是True

# 3.bin() oct() hex()  产生对应的进制数
# print(bin(100))
# print(oct(100))
# print(hex(100))

# 4.bytes()  类型转换
# s = '你好啊 hello world!'
# print(s.encode('utf8'))  # b'\xe4\xbd\xa0\xe5\xa5\xbd\xe5\x95\x8a hello world!'
# print(bytes(s, 'utf8'))  # b'\xe4\xbd\xa0\xe5\xa5\xbd\xe5\x95\x8a hello world!'
'''针对编码解码 可以使用关键字encode与decode  也可以使用bytes和str'''
# s1 = '天黑了 抓紧进屋吧!!!'
# 编码
# res = bytes(s1, 'utf8')
# print(res)
# 解码
# res1 = str(res, 'utf8')
# print(res1)

# 5.callable()  判断当前对象是否可以加括号调用
# name = 'jason'
# def index():pass
# print(callable(name))  # False  变量名不能加括号调用
# print(callable(index))  # True  函数名可以加括号调用

# 6.chr()、ord()  字符与数字的对应转换
# print(chr(65))  # A  根据数字转字符  依据ASCII码
# print(ord('A'))  # 65  根据字符转数字  依据ASCII码

# 7.dir()  返回数据类型可以调用的内置方法(查看对象内部可调用的属性)
# print(dir(123))
# print(dir('jason'))

# 8.divmod()
"""
可以使用在网站的分页制作上
    问
        总共250条数据 每页展示25条 需要多少页   10页
        总共251条数据 每页展示25条 需要多少页   11页
        总共249条数据 每页展示25条 需要多少页   10页
"""
# print(divmod(250,25))  # (10, 0)  第一个参数是整数部分 第二个是余数部分
# print(divmod(251,25))  # (10, 1)
# print(divmod(249,25))  # (9, 24)
# def get_page_num(total_num,page_num):  # 后面django分页器使用
#     more,others = divmod(total_num, page_num)
#     if others:
#         more += 1
#     print('需要%s页'%more)
# get_page_num(1000,30)


# 9.enumerate()  枚举
# name_list = ['jason', 'kevin', 'oscar', 'tony']
# for name in name_list:
#     print(name)

# for i,j in enumerate(name_list):
#     print(i,j)  # i类似于是计数 默认从0开始

# for i,j in enumerate(name_list,start=1):
#     print(i,j)  # 还可以控制起始位置

# 10.eval() exec()  识别字符串中的python代码  使用频率很低
# print('print("有点饿了")')
# eval('print("有点饿了111")')
# exec('print("有点饿了222")')
res = """
for i in range(10):
    print(i)
"""
# eval(res)  只能识别简单逻辑的python代码
# exec(res)  能够识别具有与一定逻辑的python代码

6.6 常见内置函数 2

# 1.help()  查看注释信息
# help(len)

# 2.id()  返回一串相当于内存地址的数字
# print(id('jason'))

# 3.int()  类型转换、机制转换

# 4.isinstance()  判断数据类型
# print(type('jason') is str)  # 类型判断 别扭的很 不推荐
# print(isinstance('jason', str))  # True
# print(isinstance('jason', int))  # False

# 5.pow()  幂指数
# print(pow(10,2))

# 6.round()  四舍五入
# print(round(11, 1))  # 第二个参数控制需要保留几位小数部分
# print(round(11.29, 1))
# print(round(11.59, 1))

# 7.sum()求和
# print(sum([11,2,2,3,4,3,2]))

七. 函数与方法

1. 函数:就是普通函数,有几个值就要传几个值

2. 方法[面向对象]:是绑定给对象,类,绑定给谁谁来调用,会自动传值,谁来调用就会把谁传入

3. 总结:只要能自动传值,就是方法,有几个值传几个值就是函数

区分方法和函数

# 导入
from types import MethodType, FunctionType

def add(a, b):
    return a + b


class Person:
    # 方法:绑定给对象的【不一定是方法】
    def speak(self):
        print('人说话')

    @classmethod
    def test(cls):
        print('类的绑定方法')


    @staticmethod
    def ttt():
        print('static')

p = Person()


print(isinstance(add, MethodType))             # False
print(isinstance(add, FunctionType))           # True

print(isinstance(p.speak, MethodType))         # True
print(isinstance(p.speak, FunctionType))       # False

print(isinstance(Person.speak, FunctionType))  # True
print(isinstance(Person.speak, MethodType))    # False

print(isinstance(Person.test, FunctionType))   # False
print(isinstance(Person.test, MethodType))     # True

print(isinstance(p.test, FunctionType))        # False
print(isinstance(p.test, MethodType))          # True

# 静态方法,本质就是个函数,有几个值就要传几个值
print(isinstance(p.ttt, FunctionType))
print(isinstance(p.ttt, MethodType))

八. 偏函数

1. python内置给咱们一个偏函数,可以把函数包裹一下,提前传参

from functools import partial

def add(a, b, c):
    return a / b + c


# 正常使用
res=add(4,5,6)
print(res)


# 使用偏函数,提前传值
res = partial(add, 4, 5)
print(res)  # functools.partial(<function add at 0x000002C4025C71F0>, 4)
print(res(6))
posted @ 2023-05-05 12:40  codegjj  阅读(0)  评论(0编辑  收藏  举报