02函数整合篇

前言

本篇博客整合了以下与函数有关的知识点

函数

函数的简介

# 函数:以功能(完成一件事)为导向,登录,注册,len,一个函数就是一个功能。 随调随用。
# 减少代码的重复性。
# 增强了代码的可读性。

函数的结构与调用

定义一个函数
def len_num(a):
    return len(a)
b=len_num([123,1,2])
print(b)

# 结构:
#def 关键字,定义函数。
#len_num 函数名:与变量设置相同,具有可描述性。
#函数体 :缩进。函数中尽量不要出现print

函数可以没有return 但没有return返回值就没有意义
# return后面是返回值(len(a)) 在函数中遇到return直接结束函数。
	# return 将数据返回给函数的执行者,调用者 len_num()。
    # return 返回单个元素 是返回原有数据类型的形式返回
    # return 返回多个元素 是以元组的形式返回给函数的执行者。

函数的返回值

# return 将数据返回给函数的执行者,简单来说谁调用返回谁
# return 返回单个元素 是返回原有数据类型的形式返回
# return 返回多个元素 是以元组的形式返回给函数的执行者。

函数的参数

# 写一个函数,只接受两个int的参数,函数的功能是将较大的数返回。
# def compile(a,b): #行参  1.位置参数 2. 默认参数(经常使用的参数)
#     c = 0
#     if a > b:
#         return c
#     else:
#         return c
# compile(10,20)#实参 位置参数  关键字参数,
# 形参角度:
# 1. 位置参数
# 2. 默认参数  (经常使用的参数)

# 实参角度:
# 1. 位置参数 按照顺序,一一对应
# 2. 关键字参数, 一一对应
# 3. 混合参数:位置参数一定要在关键字参数的前面。

万能参数,仅限关键字参数

# 万能参数: *args, 约定俗称:args,
# 函数定义时,*代表聚合。 他将所有的位置参数聚合成一个元组,赋值给了 args。
# 写一个函数:计算你传入函数的所有的数字的和。
# def func(*args):
#     count = 0
#     for i in args:
#         count += i
#     return count
# print(func(1,2,3,4,5,6,7))
# **kwargs
# 函数的定义时: ** 将所有的关键字参数聚合到一个字典中,将这个字典赋值给了kwargs.
# 形参角度:仅限关键字参数 (了解) 可以在默认参数前也可以在后面 一定要传参数,不传报错
# 形参角度最终的顺序:位置参数,*args,默认参数,仅限关键字参数,**kwargs

# *的魔性用法
# **在函数的调用时,*代表打散。
def func(*args,**kwargs):
    print(args) # (1,2,3,22,33)
    print(kwargs)
# func(*[1,2,3],*[22,33])  # func(1,2,3,22,33)
# func(*'fjskdfsa',*'fkjdsal')  # func(1,2,3,22,33)
func(**{'name': '太白'},**{'age': 18})  #func(name='太白',age='18')

*的魔性用法。

# *在函数的调用时,*代表打散。
**{'name': '太白'}打散为name='太白' 
*[1,2,3]打散为1,2,3
# 函数外:处理剩余元素
# a,b,*c = [1,2,3,4,5]
# a,*c,b, = [1,2,3,4,5]
# a,*c = range(5)
# a,*c,b = (1,2,3,4,5,6)
# print(a,c,b)

名称空间作用域

# 内置名称空间:python源码给你提供的一些内置的函数,print input
# python分为三个空间:
    # 内置名称空间(builtins.py)
    # 全局名称空间(当前py文件)
    # 局部名称空间(函数,函数执行时才开辟)

# 加载顺序:
# 内置名称空间 ---> 全局名称空间  ----> 局部名称空间(函数执行时)
# 取值顺序(就近原则) 单向不可逆
# (从局部找时)局部名称空间  ---> 全局名称空间  --->  内置名称名称空间

# 作用域:
# 两个作用域:
    # 全局作用域 :内置名称空间 全局名称空间
    # 局部作用域:局部名称空间(函数等)
# 局部作用域可以引用全局作用域的变量
# 局部作用域不能改变全局变量。 可以使用可以,不能改变
# 注意 python中不可以先引用 后定义

高阶函数

# 就是函数的嵌套
# 例1:
def func1():
    print('in func1')
    print(3)

def func2():
    print('in func2')
    print(4)

func1()
print(1)
func2()
print(2)
# in func1 3 1 in func2 4 2



# 例2:
def func1():
    print('in func1')
    print(3)

def func2():
    print('in func2')
    func1()
    print(4)

print(1)
func2()
print(2)


# 例3:
def fun2():
    print(2)

    def fun3():
        print(6)

    print(4)
    fun3()
    print(8)

print(3)
fun2()
print(5)

内置函数 globals locals

# 内置函数:globals locals
a = 1
b = 2
def func():
    name = 'alex'
    age = 73
    print(globals())  # 返回的是字典:字典里面的键值对:全局作用域的所有内容。
    print(locals())  # 返回的是字典:字典里面的键值对:当前作用域的所有的内容。
# print(globals())  # 返回的是字典:字典里面的键值对:全局作用域的所有内容。
# print(locals())  # # 返回的是字典:字典里面的键值对:当前作用域的所有的内容。
func()

global nonlocal关键字

# global
# 1, 在局部作用域声明一个全局变量 声明后就可以修改全局变量

# nonlocal 存在于双层嵌套中
# 1. 不能够操作全局变量。
# 2. 作用局部作用域:内层函数对外层函数的局部变量进行修改。

函数名的应用

# 函数名是一个特殊的变量。
# 函数名指向的是函数的内存地址,加上()就执行这个函数。
# 3. 函数名可以作为容器类类型的元素。
# 4. 函数名可以作为函数的实参。
# 5. 函数名可以作为函数的返回值。

默认参数的坑

# 陷阱只针对于默认参数是可变的数据类型:
# 如果你的默认参数指向的是可变的数据类型,那么你无论调用多少次这个默认参数,都是同一个。
# 本质是闭包
# def func(name,alist=[]):
#     alist.append(name)
#     return alist
# ret1 = func('alex')
# print(ret1,id(ret1))  # ['alex']
# ret2 = func('太白金星')
# print(ret2,id(ret2))  # ['太白金星']

# 局部作用域的坑
# 在函数中,如果你定义了一个变量,但是在定义这个变量之前对其引用了,那么解释器认为:语法问题。
# 你应该在使用之前先定义。
# 列题
# count = 1
# def func():
#     count += 1
#     print(count)
# func()

可迭代对象和迭代器

# 可以进行循环更新的一个实实在在值。
# 如何判断一个对象是否是可迭代对象: 利用内置函数:dir()可以查看对象内部方法
# 有__iter__方法的对象,都是可迭代对象。
# print('__iter__' in dir(str))


# 如何判断一个对象是迭代器: 可更新迭代的工具
# 在python中,内部含有'__iter__'方法并且含有'__next__'方法的对象就是迭代器。
# print('__iter__' in dir(str) and '__next__' in dir(str))

# 可迭代对象转化成迭代器:
# 利用内置函数iter()
# obj = iter(l1)
# object.__iter__()

# 迭代器可以迭代取值。利用next()进行取值(节省内存)或者转为list 元祖等等取值
# 一个next()取一个值 且会记录位置
# 迭代器一条路走到底,不走回头(记录位置)。
# 取完了再next()会报错(StopIteration) 我们可以用try处理 万能异常(Exception)

while模拟for循环

s = 'gkffdsa;lfkdsk;lafkds;laldgjfd'
obj = iter(s)
while 1:
    try:
        print(next(obj))
    except StopIteration:
        break

可迭代对象与迭代器的对比

可迭代对象与迭代器的对比

  • 可迭代对象是一个操作方法比较多,比较直观,存储数据相对少(几百万个对象,8G内存是可以承受的)的一个数据集。
  • 当你侧重于对于数据可以灵活处理,并且内存空间足够,将数据集设置为可迭代对象是明确的选择。
  • 是一个非常节省内存,可以记录取值位置,可以直接通过循环+next方法取值,但是不直观,操作方法比较单一的数据集。
  • 当你的数据量过大,大到足以撑爆你的内存或者你以节省内存为首选因素时,将数据集设置为迭代器是一个不错的选择。

生成器

# return作用 返回值 单个或多个 终止函数
# 结束函数,给函数的执行者返回值(多个值通过元组的形式返回)。
# 将return换为yield就是生成器函数
# 只要函数中出现了yield那么他就不是函数,它是生成器函数。
# 不结束函数,对应着给 next 返回值(多个值通过元组的形式返回)。 会记录位置
def func():
    yield 2,4,5
    print(11)
    yield 3
    print(22)
    print(33)
    yield 4
    yield 5
ret = func()  # 生成器对象
# print(ret)
# print(next(ret))
# print(next(ret))
# print(next(ret))
# yield : 对应next给next返回值

yield from

# yield from 将一个可迭代对象的每一个元素返回给next
# yield from 节省代码,提升效率(代替了for循环)
# def func():
#     l1 = [1, 2, 3]
#     yield from l1#就是下面的简写
#     '''
#     yield 1
#     yield 2
#     yield 3
#     '''
# ret = func()
# print(next(ret))

出错题

def eat_baozi_gen():
    for i in range(1,5):
        yield f'{i}号包子'
        print(11)
ret1 = eat_baozi_gen()
for i in ret1:
    print(i)

生成器表达式,列表推导式,字典推导式

# 两种构建方式:
# 1.循环模式: [变量(加工后的变量) for 变量 in iterable]
# print([i**2 for i in range(1, 11)])
# 2.筛选模式: [变量(加工后的变量) for 变量 in iterable if 条件]
# print([i**2 for i in range(1, 11)])

# 列表推导式的优缺点:
# 优点:
    # 1, 简单,快捷,装b。
# 缺点:
    # 2. 可读性不高,不好排错。
# 慎用,不要入迷。

# 生成器表达式: 小括号
# 与列表推导式几乎一模一样。
# 循环模式,筛选模式。
# obj = (i for i in range(1, 11))
# 字典推导式,集合推导式:  两种模式: 循环模式,筛选模式
l1 = ['小潘', '怼怼哥','西门大官人', '小泽ml亚']
# {0: '小潘', 1: '怼怼哥', 2: '西门大官人'}
# dic = {}
# for index in range(len(l1)):
#     dic[index] = l1[index]
# print(dic)
# print({i:l1[i] for i in range(len(l1))})

匿名函数

一句话函数 一般与内战函数结合

# 匿名函数:没有名字的函数
# 匿名函数只能构建简单的函数,一句话函数。
# func2 = lambda 形参: 返回值
# func2 = lambda x,y: x + y

小练习

i改变了指向
func_list = []
for i in range(10):
    func_list.append(lambda x:x+i)
v1 = func_list[0](2)
v2 = func_list[5](1)
print(v1,v2)

func_list = []
for i in range(10):
    func_list.append(lambda x:x+i)
for i in range(0,len(func_list)):
    result = func_list[i](i)
    print(result)
 
 
 
result = []
for i in range(10):
    func = lambda : i      # 注意:函数不执行,内部代码不会执行。
    result.append(func)
print(i)#9
print(result)
v1 = result[0]()
v2 = result[9]()
print(v1,v2)

def func(num):
    def inner():
        print(num)
    return inner
result = []
for i in range(10):
    f = func(i)
    result.append(f)
print(i)
print(result)
v1 = result[0]()
v2 = result[9]()
print(v1,v2)

如 10.3.9.12 转换规则为二进制:
        10            00001010
         3            00000011
         9            00001001
        12            00001100
再将以上二进制拼接起来计算十进制结果:00001010 00000011 00001001 00001100 = ?
# IP地址转换为int
# 思路IP按照split进行分隔成4个部分,然后每个部分都转换为二进制类型.
# 然后将这些二进制进行拼接成一个32位的大的二进制字符串.
# 最后将这个二进制数,转换成对应的int类型
def ipToInt(ip_str):
    # 分隔
    ip_list = ip_str.split('.')
    # 拼接
    bin_str = ""
    # 遍历,然后求出每一个二进制数,(注意切割,舍弃0b),还要把它弄成8位.再相加
    for i in ip_list:
        part = bin(int(i))[2:]
        # 将part前面补充0
        part = part.zfill(8)
        bin_str += part
    # 最后将这个二进制数转换为整数
    ip_int = int(bin_str, 2)
    return ip_int
    

v = [lambda :x for x in range(10)]
print(v)
print(v[0])
print(v[0]())

v = (lambda :x for x in range(10))
print(v)
print(next(v))
print(next(v)())

def num():
    return [lambda x:i*x for i in range(4)]
print([m(2)for m in num()])

内置函数

内置函数 I 了解

# all()  any()  bytes() callable() chr() complex() divmod() eval() exec() format() frozenset() globals() hash() help()
# id() input() int()  iter() locals() next()  oct()  ord()  pow()    repr()  round()
# eval 剥去字符串的外衣,返回里面的本质
# s1 = "{1: 'alex'}"
# ret = eval(s1)

# exec 代码流,过程。
# s3 = '''
# for i in range(3):
#     print(i)
# '''
# exec(s3)

# hash:获取一个对象(可哈希对象:int,str,Bool,tuple)的哈希值。
# print(hash(12322))
# help:函数用于查看函数或模块用途的详细说明。
# print(help(list))
# print(help(str.split))

# int:函数用于将一个字符串或数字转换为整型。
# print(int('0100',base=2))  # 将2进制的 0100 转化成十进制。结果为 4
# float:函数用于将整数和字符串转换成浮点数。
# complex:函数用于创建一个值为 real + imag * j 的复数或者转化一个字符串或数为复数。如果第一个参数为字符串,则不需要指定第二个参数。。

# divmod:计算除数与被除数的结果,返回一个包含商和余数的元组(a // b, a % b)。
# round:保留浮点数的小数位数,默认保留整数。
# pow:求x**y次幂。(三个参数为x**y的结果对z取余)
# bytes:用于不同编码之间的转化。
# ord 输入字符找该字符编码的位置
# chr 输入位置数字找出其对应的字符
# repr:返回一个对象的string形式(原形毕露)。
# print(repr('{"name":"alex"}'))
# print('{"name":"alex"}')
# %r  原封不动的写出来
# name = 'taibai'
# print('我叫%r'%name)

callable 判断是否可调用

# callable:函数用于检查一个对象是否是可调用的。如果返回True,object仍然可能调用失败;
# 但如果返回False,调用对象ojbect绝对不会成功。
# name = 'alex'
# def func():
#     pass
# print(callable(name))  # False
# print(callable(func))  # True

bin oct hex进制转换

# bin:将十进制转换成二进制并返回。
# oct:将十进制转化成八进制字符串并返回。
# hex:将十进制转化成十六进制字符串并返回。
# 二进制 to 十进制: 
int(str,n=10) 

all any判断是否全部为真或假

# all  可迭代对象中,全都是True才是True
# any  可迭代对象中,有一个True 就是True
# print(all([1,2,True,0]))
# print211444(any([1,'',0]))

内置函数II 重要

# abs() enumerate() filter()  map() max()  min() open()  range() print()  len()  list()
# dict() str()  float() reversed()  set()  sorted()  sum()    tuple()  type()  zip()  dir()


bytes() #把字符串转换成bytes类型

sep 设定分隔符。

print(1, 2, 3, sep='|')

end去除默认换行

print(1, 2, end=' ')

abs() 获取绝对值

print(abs(-10))

sum() 数字相加求和

# sum() 数字相加求和 会for循环里面元素 必须里面都是由int组成 注意列表 sum(iterable,)
print(sum([1, 2, 3, 4], 100))

min max()可以加功能

# min 可以加功能 key 与匿名函数结合
# min 可以加功能
# print(min([22, 11, 45, 2]))
# l1 = [(73, 'alex'), (35, '武大'), (18, '太白')]
# print(min(l1,key=lambda x: x[0]))
# print(min(l1,key=lambda x: x[0])[0])
# 第一步 循环遍历l1 将里面的元素以形参的方式传给匿名函数得到返回值
# 第2步  利用内置函数比较返回值 得到想要的结果,在将传进去的元素返回

reversed() 将一个序列翻转

# reversed() 将一个序列翻转, 返回翻转序列的迭代器 reversed 示例:
# l = reversed('123')  # l 获取到的是一个生成器 注意字符串转list会分隔
# print(list(l))

sorted排序函数 可以加key

# lst = [{'id': 1, 'name': 'alex', 'age': 18},
#        {'id': 2, 'name': 'wusir', 'age': 17},
#        {'id': 3, 'name': 'taibai', 'age': 16}, ]
# # 按照年龄对学生信息进行排序
# print(sorted(lst, key=lambda e: e['age']))
l = ['班级24','班级15','班级3','班级5','班级25']#,按照数字的顺序从大到小排序,不改变原列表,请以最少代码量实现。(3分)
print(sorted(l, key=lambda e: int(e[2:]),reverse=False))

map对元素进行映射

# map(function,iterable) 可以对可迭代对象中的每一个元素进行映射,分别取执行function
# 计算列表中每个元素的平方,返回新列表
# lst = [1,2,3,4,5]
# def func(s):
#     return  s*s
# mp = map(func,lst)
# print(mp)#对象
# print(list(mp))
# # 改写成lambda
# print(list(map(lambda s:s*s,lst)))

zip() 拉链方法

# zip() 拉链方法。函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,
# 然后返回由这些元祖组成的内容,如果各个迭代器的元素个数不一致,则按照长度最短的返回
# lst1 = [1,2,3]
# lst2 = ['a','b','c','d']
# lst3 = (11,12,13,14,15)
# for i in zip(lst1,lst2,lst3):
#     print(i)

filter筛选过滤 返回迭代器

filter筛选过滤 返回迭代器
ls = filter(lambda e:e['age'] > 16,lst)

闭包

定义:

默认参数就是闭包原理

  1. 闭包是嵌套在函数中的函数。
  2. 闭包必须是内层函数对外层函数的变量(非全局变量)的引用。
# 引用的变量就是自由变量,自由变量不会随着函数的执行结束之后而消失
# 如何判断判断闭包
# 如果此函数拥有自由变量,那么就可以侧面证明其是否是闭包函数了
# 利用 函数名.__code__.co_freevars 查看函数的自由变量

# 闭包的作用:保存局部信息不被销毁,保证数据的安全性。
# 闭包的应用:
# 可以保存一些非全局变量但是不易被销毁、改变的数据。
# 装饰器。

装饰器

开放封闭原则:

装饰器:装饰,装修,房子就可以住,如果装修,不影响你住,而且体验更加,让你生活中增加了很多功能:洗澡,看电视,沙发。
器:工具。
开放封闭原则:
开放:对代码的拓展开放的, 更新地图,加新枪,等等。
封闭:对源码的修改是封闭的。

装饰器:完全遵循开放封闭原则。
装饰器: 在不改变原函数的代码以及调用方式的前提下,为其增加新的功能。
装饰器就是一个函数。

推导见代码

标准版的装饰器;

标准版的装饰器;

def wrapper(f):
    f = zz  # 第2步
    def inner(*args, **kwargs):  # 第5步
        ret = f(*args,**kwargs)#第7步
        return ret
    return inner  # 第3步
@wrapper  # zz=weapper(zz) 第一步
def zz(): # 第4步 此时zz 为 inner
    pass

带参数的装饰器

def wrapper_out(n,*args,sex="男")
    def wrapper(f):
        def inner(*args,**kwargs):
            ret = f(*args,**kwargs)  # 这边执行的是func1()
            return ret
        return inner
    return wrapper

def func1():
    print("in func1")
func = wrapper_out(1)  # wrapper函数名
ly = fun(func1)  # inner = wrapper(func1)
ly()  # inner()
def wrapper_out(n):
    def wrapper(f):
        def inner(*args,**kwargs):
            if n == "qq":
                username = input("请输入用户名:").strip()
                password = input("请输入密码:").strip()
                with open("qq",encoding="tuf-8") as f1:
                    for line in f1:
                        user,pwd = line.strip().split("|")
                        if username == user and password == pwd:
                            print("登陆成功")
                            ret = f(*args,**kwargs)
                            return ret
                        return False
            
            elif n == "yiktok":
                username = input("请输入用户名:").strip()
                password = input("请输入密码:").strip()
                with open("qq",encoding="tuf-8") as f1:
                    for line in f1:
                        user,pwd = line.strip().split("|")
                        if username == user and password == pwd:
                            print("登陆成功")
                            ret = f(*args,**kwargs)
                            return ret
                        return False
 

def wrapper_out(n):
    def wrapper(f):
        def inner(*args,**kwargs):                     
            username = input("请输入用户名:").strip()
            password = input("请输入密码:").strip()
            with open(n,encoding="tuf-8") as f1:
                    for line in f1:
                        user,pwd = line.strip().split("|")
                        if username == user and password == pwd:
                            print("登陆成功")
                            ret = f(*args,**kwargs)
                            return ret
                        return False
        return inner
    return wrapper

@ wrapper_out("qq")
def qq():
    print("成功访问qq")
qq()
# 看到带参数的装饰器分两步执行:

@ wrapper_out("腾讯")
    # 1.执行wrapper_out("腾讯"),把相应的参数传给n,并且得到返回值wrapper函数名
    # 2.将@与wrapper结合,得到我们之前熟悉的标准版装饰器,按照装饰器的执行流程执行
    
@ wrapper_out("qq")
def qq():
    print("成功访问qq")
    
@ wrapper_out("tiktok")
def tiktok():
    print("成功访问抖音")
    
qq()
tiktok()
# 开发思路:增强耦合性

多个装饰器装饰一个函数

 def wrapper1(func1):  # func1 = f原函数
    def inner1():
        print('wrapper1 ,before func')  # 2
        func1()
        print('wrapper1 ,after func')  # 4
    return inner1

def wrapper2(func2):  # func2 == inner1
    def inner2():
        print('wrapper2 ,before func')  # 1
        func2()  # inner1
        print('wrapper2 ,after func')  # 5
    return inner2


@wrapper2  # f = wrapper2(f) 里面的f == inner1  外面的f == inner2
@wrapper1  # f = wrapper1(f) 里面的f == func1   外面的f == inner1  先看下面
def f():
    print('in f')  # 3

f()  # inner2()  看外层f

递归

# 官网规定:默认递归的最大深度1000次。
# 如果你递归超过100次还没有解决这个问题,那么执意使用递归,效率很低。  递归比起循环来说更占用内存
# 修改递归的最大深度
    # import sys
    # sys.setrecursionlimit(1000000000)
# 递归就是自己调自己
# 递归函数是怎么停下来的?递归3次结束整个函数
# 一个递归函数要想结束,必须在函数内写一个return,并且return的条件必须是一个可达到的条件
# --注意---并不是函数中有return,return的结果就一定能够在调用函数的外层接收到  谁调用最后一个函数返回给谁
# 加上return tet
# def func(count):
#     count += 1
#     print(count)
#     if count == 5 : return 5#这个5其实是返回给下面的func()
#     ret = func(count)#要想把这个5返回给最外层 所以逐层returt
#     return ret
# 精简版
def func(count):
    count += 1#这里是代码思路
    if count == 5 :
        return 5#这个5其实是返回给下面的func()
    return  func(count)#精简了上面的过程

# 1.计算阶乘 100! = 100*99*98*97*96....*1
def fin(n):
    if n ==1 :
        return n
    else:
        return n*fin(n-1)
ret = fin(7)
print(ret)
l2 = [1, 3, 5, ['太白','元宝', 34, [33, 55, [11,33]]], [77, 88],66]
# # 错误方法
# for i in l2:
#     if type(i) == list:
#         for j in i:
#             print(j)
#     else:
#         print(i)
# 递归
# def func(alist):
#     for i in alist:
#         if type(i) == list:
#             func(i)  # func(['太白','元宝',34])
#         else:
#             print(i)
# func(l2)
# 5.三级菜单 可能是n级
# 2.os模块:查看一个文件夹下的所有文件,这个文件夹下面还有文件夹,不能用walk
# 3.os模块:计算一个文件夹下所有文件的大小.这个文件夹下面还有文件夹,不能用 walk
# 4.计算斐波那契数列
    # 找第100个数
# 1.计算阶乘 100! = 100*99*98*97*96....*1

原文地址:https://www.cnblogs.com/saoqiang/p/12111370.html