第六章:python中的函数详解

函数

一、函数介绍

(一) 什么是函数

    函数就是一个盛放代码的容器
    具备某一功能的工具----》函数
    事先准备工具的过程====》函数的定义
    遇到应用场景拿来就用==》函数的调用

(二) 为何要有函数

1)、程序的组织结构不清晰、可读性差
    (2)、代码冗余
    (3)、程序的可维护性差

(三) 如何使用函数

    使用基本原则:先定义,后调用

    定义函数的语法:
        def 函数名(参数1,参数2,参数3,...):  # 先定义
            """文档注释"""
            代码1
            代码2
            代码3
            ...
            return 返回值

    调用函数
        函数名(1,2,3,...)  # 后调用
# 一:先定义
def func(n,msg):  # func=函数的内存地址
    print('-'*n)
    print(msg)
    print('-'*n)


# 二:后调用
func(10,'hello')
func(5,'world')


# 三:
# 定义阶段:只检测语法,不执行代码
def func():
    xxx


# 调用阶段:根据函数名找到函数的内存地址,然后配合()触发函数体代码的运行
func()


(四) 实例

# 示例1
def bar():
    print('from bar')

def foo():
    print('from foo')
    bar()

foo()

# 示例2
def foo():
    print('from foo')
    bar()

def bar():
    print('from bar')

foo()

(五) 定义函数的三种形式

#(1):无参函数
def login():
    name= input('username>>>: ').strip()
    pwd = input('username>>>: ').strip()
    if name == 'egon' and pwd == "123":
        print('login successful')
    else:
        print('username or password error')

login()

#(2):有参函数
def max2(x,y):
    # x = 10
    # y = 20
    if x > y:
        print(x)
    else:
        print(y)

max2(10,20)
max2(111,222)

#(3):空函数
def func():
    pass

(六) 调用函数的三种形式

# (1) 语句形式
input("please input your name: ")

def max2(x,y):
    # x = 10
    # y = 20
    if x > y:
        print(x)
    else:
        print(y)

max2(11,22)


# (2) 表达形式
name = input("please input your name: ")

def max2(x,y):
    if x > y:
        return x
    else:
        return y

res=max2(111,222) * 12




# (3) 当作参数传给另外一个函数
def max2(x,y):
    if x > y:
        return x
    else:
        return y

print(max2(111,222))

print(max2(max2(111,222),333))

(七) 函数返回值return

# (1) return是函数结束的标志,函数内可以有多个return,但只要执行一次整个函数就会立即终止,并且会将return后的结果当作本次调用的返回值返回
def func():
    print('hello1')
    return 111
    print('hello2')
    return 222
    print('hello3')
    return 333

func()


# (2) return可以返回的值的个数
#   return 值:返回一个值
#   return 值1,值2,值3: 把多个值放到一个元组内返回
def func():
    return 1,33.3,[1,2,3]

res=func()
print(res)

 # 没有return或者就一个单独的return:默认返回的是None
def func():
    pass

res=func()
print(res)

四、函数中的参数

(一) 函数中的参数分为形参与实参

# (1) 形参: 在函数定义阶段,括号内定义的参数(变量名),称之为形式参数,简称形参
def func(x,y):
    print(x,y)
# (2) 实参: 在函数调用阶段,括号内传入的值(变量值),称之为实际参数,简称实参
func(1,2)

(二) 形参与实参详细介绍

一、位置参数

# (1) 位置形参:在函数定义阶段,按照从左到右的顺序依次定义的形参
#       特点: 必须被传值
def func(x,y):
    print(x,y)

func(1,2)
func(1,2,3)
func(1)


# (2) 位置实参:在函数调用阶段,按照从左到右的顺序依次传入的值
#       特点:按照位置与形参一一对应
def func(x, y):
    print(x, y)
func(1,2) 

二、关键字实参

# 2 关键字实参: 在函数调用阶段,按照key=value的形式传值
#       特点: 可以打破传值的顺序,但仍能指名道姓地为形参赋值
def func(y=2,x=1)

#       注意:可以混用位置实参与关键字实参,但是
#              (1)位置实参必须放在前面
#              (2)不能为同一个形参重复赋值
func(111,y=2)
func(y=2,111)
func(111,x=222,y=333)

三、默认形参

# 在定义函数时,就已经为某个形参赋值了,该形参称之为默认形参
# 特点:定义时已经赋值了,意味着调用时可以不用为其赋值


def func(x, y=222):
    print(x)
    print(y)

func(111)
func(111, 333)

def register(name, age, gender="male"):
    print(name, age, gender)

register('tom', 18)
register('jack',29)
register('wuchangwen',19)
register('lili',19,"female")
# 注意:
# 1、可以混用位置形参与关键字形参,但是位置的肯定要在前
# 2、默认形参的值只在函数定义阶段赋值一次,拿到的是值的内存地址
# 3、默认形参的值通常应该是不可变类型


m=100
def func(x,y=m):  # y=100的内存地址
    print(x)
    print(y)
m=200
func(1)


m=[1,2,3]
def func(x,y=m):  # y=[1,2,3]的内存地址
    print(x)
    print(y)
m=200
func(1)

m.append(444)
func(1)


def register(name,hobby,hobbies=None):  # hobbies = None
    if hobbies is None:
        hobbies = []
    hobbies.append(hobby)
    print("%s 的爱好是 %s" %(name,hobbies))

register('egon','read')
register('jack','music')
register('lili','play')

四 关键字实参

# 在调用函数时,按照key=value的形式定义的实参,称之为关键字实参
# 特点:
#    1 可以打乱顺序,但是仍然能够为指定的形参赋值
def func(x,y):
    print(x,y)

func(y=222,x=111)

# 可以混用位置实参与关键字实参,但是
#    1 但是位置实参必须在关键字参数前
#    2 不能对一个形参重复赋值
func(111,y=222)
func(y=222,111)
func(1111,222,y=333)
func(x=111,y=222,x=333)

五 可变长参数

# 在函数调用时,传入的参数个数不固定,而调用函数时实参形式无非两种:位置实参
# 与关键字实参
# 实参一定是为形参赋值的,实参的个数不固定,对应着必须有特殊格式的形参来专门
# 接收溢出的位置实参与关键字实参


# 5.1 在形参中出现*: *会将溢出的位置实参汇总成元组然后赋值给紧跟其后的那个变量名
def func(x,y,*args):
    print(x)
    print(y)
    print(args)

func(1,2,3,4,5)

def my_sum(*args):
    res = 0
    for v in args:
        res+=v
    return res

print(my_sum(1,2,3,4))


# 5.2 在形参中出现**: **会将溢出的关键字实参汇总成字典然后赋值给紧跟其后的那个变量名
def func(x,y,**kwargs):
    print(x)
    print(y)
    print(kwargs)

func(1,y=2,a=1,b=2,c=3)

# 总结:*与**出现在形参中,是一种汇总操作


# 5.3 在实参中出现*:*后跟的必须是一个可以被for循环循环的类型,*会将其打散成位置实参
def func(x,y):
    print(x)
    print(y)

func(*[111,222])  # func(111,222)
func(*"he")  # func("h","e")
func(*"hel")  # func("h","e","l")
func(*{
    
    "k1":1111,"k2":2222})  # func("k1","k2")


# 5.4 在实参中出现**:**后跟的必须是一个字典,**会将其打散成关键字实参

func(**{
    
    "y":111,"x":2222})  # func(y=111,x=2222)

# 总结:*与**出现在实参中,是一种打撒操作

def index(x,y,z):
    print(x)
    print(y)
    print(z)

def wrapper(*args,**kwargs):  # args=(1,2,3,4,5)  kwargs={'a':1,"b":2,"c":3}
    # print(args)
    # print(kwargs)
    index(*args,**kwargs)  # index(*(1,2,3,4,5),**{'a':1,"b":2,"c":3})
                           # index(1,2,3,4,5,a=1,b=2,c=3)

wrapper(1,2,3,4,5,a=1,b=2,c=3)
wrapper(1,z=3,y=2)


# 非常重要的一种格式
def index(x,y):
    print('index===>',x,y)

def wrapper(*args,**kwargs):  # args=(1,2,3)  kwargs={"a":1,'b':2,'c':3}
    index(*args,**kwargs)  # index(*(1,2,3).**{"a":1,'b':2,'c':3})
                          #  index(1,2,3,a=1,b=2,c=3)

    # index(1,y=2)

wrapper(1,y=2)

六 了解

def func(x,y=666,*args,m=777,n,**kwargs):
    print(x)
    print(y)
    print(args)
    print(m)
    print(n)
    print(kwargs)

# func(1,2,3,4,5,6,n=3,m=4,a=1,b=2)


# def func(*args,x):
#     print(args)
#     print(x)
#
# func(1,2,3,4,5)

五、函数对象

# 函数是第一个等公民:可以把函数当变量去用
def func():  # func=函数的内存地址
    print('from func')

x=10 # x=10的内地址
#1、可以被赋值
# f=func
# f()

#2、可以当作参数传给另外一个函数
# def foo(f):
#     print(f)
#     f()
#
# foo(func)

#3、可以当作函数的返回值
# def foo(f):
#     return f
# res=foo(func)
# print(res)

#4、可以当作容器类型的元素
# l=[func,]
# print(l)
# l[0]()


应用

def login():
    print('登录...')

def register():
    print('注册...')

def tranfer():
    print('转账...')

def withdraw():
    print("提现功能。。。")

func_dic={
    
    
    "1":["登录",login],
    "2":["注册",register],
    "3":["转账",tranfer],
    "4":["提现",withdraw]
}

while True:
    for k,v in func_dic.items():
        print(k,v[0])
    choice = input("请输入您的命令编号,输入0退出:").strip()
    if choice == "0":
        break
    if choice in func_dic:
        func_dic[choice][1]()
    else:
        print("输入的指令错误")

补充

def add(x:int,y:int) -> int:
    return x+y


res=add("aaa","bbbb")
print(res)

help(add)

六、函数嵌套

1、函数的嵌套调用:在调用一个函数的过程中又调用了其他函数

def bar():
    print('from bar')

def foo():
    print('from foo')
    bar()

foo()

应用实例

def max2(x,y):
    if x > y:
        return x
    else:
        return y

def max4(a,b,c,d):
    res1=max2(a,b)
    res2=max2(res1,c)
    res3=max2(res2,d)
    return res3

print(max4(1,2,3,4))

2、函数的嵌套定义:在一个函数内部又定义了其他函数

# 特点:定义在函数内的函数通常情况只能函数内部使用,这是一种封闭的效果
def f1():
    def f2():
        print('from f2')

    x = 111
    # print(x)
    # print(f2)
    f2()
f1()

应用示例

from math import pi

def circle(radius,action=1):
    def perimeter(radius):
        return 2 * pi * radius

    def area(radius):
        return pi * (radius * radius)

    if action == 1:
        return perimeter(radius)
    elif action == 2:
        return area(radius)

print(circle(10,1))
print(circle(10,2))

3.函数嵌套定义+函数对象

def f1():
    def f2():
        print('from f2')

    return f2

res=f1()
print(res)

res()

七、名称空间与作用域

(一) 名称空间

# 名称空间:就是用来存放名字的内存空间
# 名称空间分为三大类:
# 1、内置名称空间:存放python解释器提供的名字
#          生命周期:python解释器启动则产生,python解释器关闭则销毁
# 2、全局名称空间:顶级的名字
#          生命周期:开始python程序则启动,python程序运行完毕则销毁
x = 1
y = 2
if True:
    z = 3

while True:
    bbb = 44


# 3、局部名称空间:在函数内部定义的名字
#          生命周期:调用函数则产生,函数调用结束则会立即销毁
def f1(aaa):
    # aaa=555
    def f2():
        ccc = 666

f1(555)

例1

# 名字访问的优先级:基于当前所在的位置向上查找(局部-》全局-》内置)

# len=111

def f1():
    # len=222
    def f2():
        # len=333
        print(len)
    f2()

f1()

例2

def f1():
    print(len)

# f1()
len=111
# f1()

def foo():
    len=333333
    f1()


def bar():
    len=44444
    f1()

foo()
bar()

例3

aaa=333

def f1():
    # print(aaa)
    # print(len)
    x=111
    def ff1():
        print("fff1===>x: ",x)
    ff1()

def f2():
    # print(aaa)
    # print(len)
    y=222

f1()
f2()

例4

len=111

def f1():
    print(len)



def f2():
    len=33333333333333333333
    f1()

f2()

# 名称空间的嵌套关系是在函数定义阶段扫描语法的时候生成的
x=111

def func():
    print(x)
    y=2222

func()

(二) 作用域

# 全局作用域:内置名称空间,全局名称空间
#         全局存活,全局有效
# 局部作用域:局部名称空间
#         临时存活,局部有效

y=222

def f1():
    x=111
    def ff1():
        print(x)

def f2():
    pass

def f3():
    pass

f1()
f2()
f3()

(三) global、nonlocal

# 3.1 global:在函数内声明名字是来自于全局的
# l=[1,2,3]
# def func():
#     l[0]=111
# func()
# print(l)

# x=10
# def func():
#     global x
#     x=20
# func()
# print(x)

# 3.2 nonlocal在函数内声明名字是来自于外层函数的
# x=333
# def f1():
#     # x=111
#     def f2():
#          # global x
#          nonlocal x
#          x=222
#     f2()
#     print(x)
#
# f1()



def f1():
    x=111
    def f2():
        print('from f2',x)
    return f2


res=f1()

def foo():
    x=222
    res()

foo()

(四) LEG

LEGB含义解释:
	L-Local(function);函数内的名字空间
	E-Enclosing function locals;外部嵌套函数的名字空间(例如closure)
	G-Global(module);函数定义所在模块(文件)的名字空间
	B-Builtin(Python);Python内置模块的名字空间

注意: Python的命名空间是一个字典,字典内保存了变量名称与对象之间的映射关系,因此,查找变量名就是在命名空间字典中查找键-值对。
Python有多个命名空间,因此,需要有规则来规定,按照怎样的顺序来查找命名空间,LEGB就是用来规定命名空间查找顺序的规则。

LEGB规定了查找一个名称的顺序为:L–>E–>G–>B

例子

a = 1


def foo():
    a = 2

    def innerfoo():
        a = 3
        print('locals ', a)

    innerfoo()
    print('enclosing function locals ', a)


foo()
print('global ', a)


# locals  3
# enclosing function locals  2
# global  1

对例子进行改进

a = 1


def foo():
    a = 2

    def innerfoo():
        # a = 3  # 注释该行,可以发现当a=3被注释后,函数innerfoo()查找的a=2
        print('locals ', a)

    innerfoo()
    print('enclosing function locals ', a)


foo()
print('global ', a)


# locals  2
# enclosing function locals  2
# global  1

八、闭包函数

# 闭包函数=函数嵌套定义+名称空间与作用域+函数对象
# 闭:指的是该函数是一个定义在函数内部的函数
# 包:闭函数访问了一个来自于外层函数中的名字

# def f1():
#     x = 111
#     def f2():
#         print('from f2: ',x)
#
#     return f2  # 千万不要加括号
#
# res=f1()
#
# def foo():
#     x=222
#     res()
#
# foo()

# 为函数体传参的解决方案:
# 方案一:直接定义形参
# def f2(x):
#     print(x)
#
# f2(111)
# f2(222)
# f2(333)

# 闭包函数是一种为函数体传参的解决方案
# def f1(x):
#     # x=111
#     def f2():
#         print(x)
#
#     return f2  # return f1.locals.f2的内存地址
#
# f2=f1(111)
# f2()


# 写死?
# 专用?
# 传值?

def outter(x):
    # x =2222
    def wrapper():
        print(x)

    return wrapper

f=outter(333)
# print(f)
f()

九、装饰器

(一) 什么是装饰器

=》工具=》函数
    装饰=》指的是为被装饰者添加新功能

(二) 为何要用装饰器

    开放封闭原则:
        封闭指的是对修改源代码是封闭的
        开放指的是对拓展新功能是开放的

    装饰器就是一个函数,该函数就是在不修改被装饰对象源代码以及调用的方式的前提下,为被装饰对象添加额外的功能

(三) 如何使用装饰器

如何实现装饰器=》闭包函数
    装饰器的目标:为被装饰对象添加额外的新功能
    装饰器的实现应该遵循的原则:
        1、不该被装饰对象的源代码
        2、不该被装饰对象的调用方式

例1

import time

def index():
    start=time.time()
    print("index===>")
    time.sleep(0.5)
    stop=time.time()
    print("run time is : %s" %(stop - start))

index()

例2

import time

def index():
    print("index===>")
    time.sleep(0.5)


start=time.time()
index()
stop=time.time()
print("run time is : %s" %(stop - start))

例3

import time

def index():
    print("index===>")
    time.sleep(0.5)


def wrapper():
    start=time.time()
    index()
    stop=time.time()
    print("run time is : %s" %(stop - start))

wrapper()

例4:直接通过参数为函数体传参

import time

def index():
    print("index===>")
    time.sleep(0.5)


def wrapper(func):
    start=time.time()
    func()
    stop=time.time()
    print("run time is : %s" %(stop - start))

wrapper(index)

例5:直接通过参数为函数体传参

import time

def index():
    print("index===>")
    time.sleep(0.5)


def outter(func):
    # func=index的内存地址
    def wrapper():
        start=time.time()
        func()
        stop=time.time()
        print("run time is : %s" %(stop - start))
    return wrapper  # 千万不要加括号

index=outter(index)

index() # wrapper()

例6

import time

def index(x,y,z):
    print("index===>",x,y,z)
    time.sleep(0.5)
    return 123

def home(name):
    print('welcome %s to home page' %name)
    time.sleep(1)

# index(1,2,3)
# home("egon")

def outter(func):
    # func=index的内存地址
    def wrapper(*args,**kwargs):
        start=time.time()
        res=func(*args,**kwargs)
        stop=time.time()
        print("run time is : %s" %(stop - start))
        return res
    return wrapper  # 千万不要加括号

index=outter(index)
res=index(1,2,3) # wrapper(1,2,3)
print(res)

home=outter(home)
res=home("egon")
print(res)

例7:语法糖

import time
from functools import wraps

def timmer(func):
    @wraps(func)
    def wrapper(*args,**kwargs):
        start=time.time()
        res=func(*args,**kwargs)
        stop=time.time()
        print("run time is : %s" %(stop - start))
        return res
    # wrapper.__name__=func.__name__
    # wrapper.__doc__=func.__doc__
    return wrapper  # 千万不要加括号

@timmer  # index=timmer(index)
def index(x,y,z):
    """
    index的文档注释
    """
    print("index===>",x,y,z)
    time.sleep(0.5)
    return 123

@timmer  # home=timmer(home)
def home(name):
    """
    home的文档注释
    """
    print('welcome %s to home page' %name)
    time.sleep(1)

# res=index(1,2,3) # wrapper(1,2,3)
# print(res)
#
# res=home("egon")
# print(res)


# help(index)
print(index.__name__)

例8

def auth(func):
    def wrapper(*args, **kwargs):
        name = input("username>>: ").strip()
        pwd = input("password>>: ").strip()
        if name == "egon" and pwd == "123":
            print('login successful')
            res = func(*args, **kwargs)
            return res
        else:
            print("username or password error")

    return wrapper


@auth
def index():
    print('from index')


index()

(四) 有参装饰器

def auth(x,engine = "file"):
    def outter(func):
        def wrapper(*args, **kwargs):
            x
            name = input("username>: ").strip()
            pwd = input("password>: ").strip()

            if engine == "file":
                if name == "egon" and pwd == "123":
                    print('login successful'.center(50,'='))

                    res = func(*args, **kwargs)
                    return res
                else:
                    print('username or password error')
            elif engine == "mysql":
                print("基于mysql的认证")
            elif engine == "ldap":
                print("基于ldap的认证")
            else:
                print('engine不存在')
        return wrapper
    return outter

@auth(11,"file")  # @outter函数的内存地址  # index=outter函数的内存地址(index函数的内存地址)
def index():
    print('from index')
@auth(11,"mysql")
def home(name):
    print('welcome %s to home page' %name)

# index=auth(index,"file")
# home=auth(index,"ldap")

index()
home("egon")

# 模板

def outter2(x):
    def outter1(func):
        def wrapper(*args, **kwargs):
            res = func(*args, **kwargs)
            return res

        return wrapper
    return outter1


@outter2(x=1)
def index():
    pass

(五) 叠加多个装饰器

# def deco1(func1):  # func1 = wrapper2的内存地址
#     def wrapper1(*args, **kwargs):
#         print('====>wrapper1')
#         res1 = func1(*args, **kwargs)
#         return res1
#     return wrapper1
#
# def deco2(func2):  # func2 = wrapper3的内存地址
#     def wrapper2(*args, **kwargs):
#         print('====>wrapper2')
#         res2 = func2(*args, **kwargs)
#         return res2
#     return wrapper2
#
# def deco3(func3):  # func3 = index函数的内存地址
#     def wrapper3(*args, **kwargs):
#         print('====>wrapper3')
#         res3 = func3(*args, **kwargs)
#         return res3
#     return wrapper3
#
# # 加载/得到wrapper函数的顺序是自下而上的
# # 我们运行wrapper函数的顺序是:
#
#         # index=wrapper1的内存地址
# @deco1  # deco1(wrapper2的内存地址) => wrapper1的内存地址
# @deco2  # deco2(wrapper3的内存地址) => wrapper2的内存地址
# @deco3  # deco3(index函数的内存地址) => wrapper3的内存地址
# def index():
#     print('from index')
#
# # print(index)
# res=index()
# """
# ====>wrapper1
# ====>wrapper2
# ====>wrapper3
# from index
# """


import time

def timmer(func):
    def wrapper(*args,**kwargs):
        start=time.time()
        res=func(*args,**kwargs)
        stop=time.time()
        print("run time is : %s" %(stop - start))
        return res
    return wrapper  # 千万不要加括号

def auth(x,engine = "file"):
    def outter(func):
        def wrapper(*args, **kwargs):
            x
            name = input("username>: ").strip()
            pwd = input("password>: ").strip()

            if engine == "file":
                if name == "egon" and pwd == "123":
                    print('login successful'.center(50,'='))

                    res = func(*args, **kwargs)
                    return res
                else:
                    print('username or password error')
            elif engine == "mysql":
                print("基于mysql的认证")
            elif engine == "ldap":
                print("基于ldap的认证")
            else:
                print('engine不存在')
        return wrapper
    return outter

@auth(111,"file")
@timmer
def index():
    print("index=====>")
    time.sleep(3)

index()

十、迭代器

(一) 什么是迭代器

'''
器=>工具
迭代:迭代是一个重复的过程,但是每次重复都是基于上一次的结果而来的
    count =  1
    while count < 5:
        print(count)
        count+=1

迭代器:迭代取值的工具
'''

(二) 为甚要用迭代器

'''
为了找到一种可以不依赖索引的迭代取值方式
优点:
    1、迭代器是一种通用的、不依赖于索引的迭代取值方式
    2、节省内存

缺点:
    1、取值不灵活,只能往后取,不能取指定的值
    2、无法预知长度,只能取一次
    '''

(三) 如何使用迭代器

'''
python为一些类型内置了__iter__方法,调用了__iter__方法就会将原类型转换成一个迭代器

可迭代对象:内置有__iter__
迭代器对象:内置有__next__,__iter__
'''

例1

names=["tong","jack","tom"]
names="abcdefg"

i=0
while i < len(names):
    print(names[i])
    i+=1

例2

c="hello".__iter__
d=["a",'B','C'].__iter__
e=("a",'B','C').__iter__
a={
    
    "k1":111}.__iter__
g={
    
    111,222,333}.__iter__
f=open("a.txt",'w')
f.__iter__
f.__next__


dic={
    
    'k1':111,"k2":222,'k3':333}
dic={
    
    111,222,333}
iter_dic=dic.__iter__()

print(iter_dic.__iter__() is iter_dic)
print(iter_dic)

res=iter_dic.__next__()
print(res)

res=iter_dic.__next__()
print(res)

res=iter_dic.__next__()
print(res)

res=iter_dic.__next__()
print(res)
dic={
    
    111,222,333}
iter_dic=dic.__iter__()

while True:
    try:
        print(iter_dic.__next__())
    except StopIteration:
        break
print('='*50)
iter_dic=dic.__iter__()
while True:
    try:
        print(iter_dic.__next__())
    except StopIteration:
        break

for循环的底层工作原理

# 1、dic.__iter__()拿到一个迭代器
# 2、k=迭代器.__next__(),循环往复直到抛出异常
# 3、for循环会捕捉异常,然后结束循环


dic = {
    
    'k1': 111, "k2": 222, 'k3': 333}
for k in dic:
    print(k,dic[k])
print('='*50)
for k in dic:
     print(k,dic[k])


f=open("a.txt",'w')
for k in f:
    print(k)

十一、生成器

# 生成器:自定义的迭代器
# 函数内但凡出现yield关键字,再调用函数,不会触发函数体代码的运行
# 会得到一个返回值,该返回值就是一个生成器对象,也就是自定义的迭代器

# yield与return
# 相同点:都能返回值
# 不同点:yield能返回多次值,而return只能返回一次值函数就立即结束
def func():
    print("first")
    yield
    print("second")
    yield 222
    return 777777777777777777
    print("third")
    yield 333
    print('fourth')

g=func()
# print(g)
# iter(g)  # g.__iter__()
# next(g)  # g.p__next__()

# res=next(g)
# print(res)
#
# res=next(g)
# print(res)
#
# res=next(g)
# print(res)
#
# next(g)


#range(1,5,2)
def my_range(start,stop,step=1):
    while start < stop:
        yield start
        start += step


for i in my_range(1,5,2):
    print(i)

十二、递归

例1

# 递归调用:在调用一个函数的过程中又直接或者间接地调用函数自己
def foo():
    print('from foo')
    foo()
    

foo()


import sys
print(sys.getrecursionlimit())
sys.setrecursionlimit(2000)

例2

def foo():
    print('from foo')
    bar()


def bar():
    print('from bar')
    foo()


foo()

# 递归调用有两个阶段
# 1、回溯:一层一层地递归调用下去
# 2、递推:在某一层结束递归调用,开始向上一层一层地返回

# age(5) = age(4) + 10
# age(4) = age(3) + 10
# age(3) = age(2) + 10
# age(2) = age(1) + 10
# age(1) = 18

# n = 1: age(1) = 18
# n > 1: age(n) = age(n-1) + 10


def age(n):
    if n == 1:
        return 18
    return age(n-1) + 10


res=age(5)
print(res)

应用实例1

nums=[1,[2,[3,[4,[5,[6,[7,[8,[9]]]]]]]]]

def func(list1):
    for item in list1:
        if type(item) is list:
            func(item)
        else:
            print(item)

func(nums)

应用实例2:二分法

nums = [-3, 11, 13, 25, 37, 39, 43, 52, 77, 84, 91]


def search(list1, find_num):
    print(list1)
    if len(list1) == 0:
        print('not exists')
        return

    mid_index = len(list1) // 2
    if find_num > list1[mid_index]:
        # on the right
        search(list1[mid_index + 1:], find_num)
    elif find_num < list1[mid_index]:
        # on the left
        search(list1[:mid_index], find_num)
    else:
        print('find it')


search(nums, 85)

十三、匿名函数

# 匿名函数:没有名字的函数,意味着只能调用一次就被回收了
# 应用场景:临时调用一次的场景


# res=(lambda x,y:x+y)(1,2)
# print(res)

# 匿名函数应用示例
salaries = {
    
    
    "wuchangwen": 3000,
    "tom": 5000,
    "tony": 1000,
}

# def func(k):
#     return salaries[k]

# res = max(salaries,key=lambda k:salaries[k])
# print(res)

# print(max([11,10,44,9]))

# res = min(salaries,key=lambda k:salaries[k])
# print(res)

# res=sorted([11,10,44,9],reverse=True)
# print(res)

# res=sorted(salaries,key=lambda k:salaries[k],reverse=True)
# print(res)

# 了解
# map
# filter
# reduce

十四、面向过程编程

'''
面向过程编程
    核心是过程二字,过程即做事的步骤,即先干什么、再干什么、然后干什么...
    基于该思想写程序就好比是在设计一条条的流水线

优点:复杂问题流程化、进而简单化
缺点:扩展性差

'''

十五、三元表达式

def max2(x,y):
    if x > y:
        return x
    else:
        return y

# res =条件成立时运行的表达式 if 条件 else 条件不成立时运行的表达式
x=11
y=22

res=x*12 if x > y else y*100
print(res)

十六、生成器

案例

l = []
for i in range(1, 6):
    if i > 3:
        l.append(i)

print(l)
# 1、列表生成式
res = [i for i in range(1, 6) if i > 3]
print(res)

# 2、集合生成式
res = {
    
    i for i in range(1, 6) if i > 3}
print(res, type(res))

# 3、字典生成式
items = [("name", "egon"), ('age', 18), ('gender', 'male')]
dict(items)
res = {
    
    k: v for k, v in items if k != "age"}
print(res, type(res))

# 4、生成器表达式
res = (i for i in range(1, 6) if i > 3)
print(res)

print(next(res))
print(next(res))
print(next(res))


def my_sum(nums, res=0):
    for num in nums:
        res += num
    return res


with open(r'D:\weekend_s7\day06\02 叠加多个装饰器.py', mode='rt', encoding="utf-8") as f:
    # print(len(f.read()))  # 2061

    # res=0
    # for line in f:
    #     res+=len(line)

    res = sum(len(line) for line in f)
    print(res)

    # g=(len(line) for line in f)
    # res=my_sum(g)

    # print(res)

了解:map、filter、reduce

# 1、map函数
salaries = [1000, 2000, 3000, 4000, 5000]
res = map(lambda num: num * 12, salaries)
print(res)
print(list(res))

print((num * 12 for num in salaries))

# 2、filter函数
names = ['egon', "alex_dsb", "liuqingzheng_dsb"]
res = filter(lambda n: n.endswith("dsb"), names)
print(res)

print([name for name in names if name.endswith('dsb')])

# 3、reduce函数
from functools import reduce

res = reduce(lambda x, y: x + y, [1, 2], 100)
print(res)

作业

# 1.编写文件修改功能,调用函数时,传入三个参数(修改的文件路径,要修改的内容,修改后的内容)既可完成文件的修改

# 2.编写tail工具

# 3.编写登录功能

# 4.编写注册功能

# 5.写函数:用户传入修改的文件名,与要修改的内容,执行函数,完成批量修改操作

# 6.写函数:计算传入字符串中【数字】、【字母】、【空格] 以及 【其他】的个数

# 7.写函数:判断用户传入的对象(字符串、列表、元组)长度是否大于5。

# 8.写函数:检查传入列表的长度,如果大于2,那么仅保留前两个长度的内容,并将新内容返回给调用者。

# 9.写函数:检查获取传入列表或元组对象的所有奇数位索引对应的元素,并将其作为新列表返回给调用者。

# 10.写函数:检查字典的每一个value的长度,如果大于2,那么仅保留前两个长度的内容,并将新内容返回给调用者。

# 11.函数对象优化多分支if的代码练熟

# 12.编写计数器功能,要求调用一次在原有的基础上加一

# 13.编写ATM程序实现下述功能,数据来源于文件db.txt
'''
0.注册功能:用户输入账号名、密码、金额,按照固定的格式存入文件db.txt
1.登录功能:用户名不存在,要求必须先注册,用户名存在&输错三次锁定,登录成功后记录下登录状态(提示:可以使用全局变量来记录)
下述操作,要求登录后才能操作
1.充值功能:用户输入充值钱数,db.txt中该账号钱数完成修改
2.转账功能:用户A向用户B转账1000元,db.txt中完成用户A账号减钱,用户B账号加钱
3.提现功能:用户输入提现金额,db.txt中该账号钱数减少
4.查询余额功能:输入账号查询余额

答案

# 1.编写文件修改功能,调用函数时,传入三个参数(修改的文件路径,要修改的内容,修改后的内容)既可完成文件的修改


def update(address, old_content, new_content):
    with open(address, 'r+', encoding='utf-8') as f:
        t = f.read().replace(old_content, new_content)
        f.seek(0, 0)
        f.write(t)


addr = input('请输入文件地址:')
old = input('请输入原内容:')
new = input('请输入替换内容:')

update(addr, old, new)



# 2.编写tail工具
import time  # 导入时间模块


def input_info():
    with open('access.log', mode='at', encoding='utf-8') as f1:  # at为追加写模式
        inp_info = input('请输入要存入的信息:\n')
        f1.write('{}\n'.format(inp_info))


def watch():
    with open('access.log', mode='rb') as f:
        f.seek(0, 2)  # 把指针移动到结尾
        while True:
            line = f.readline()
            input_info()
            if len(line) == 0:
                time.sleep(1)
            else:
                print(line.decode('utf-8'), end='')


watch()



# 3.编写登录功能


def login(username, password):
    with open(r'userinfo.txt', 'r', encoding='utf-8') as f:
        for line in f:
            usr, pwd = line.strip().split(':')
            if username == usr and password == pwd:
                print('登录成功!')
                break
            else:
                print('用户名或密码错误!')


usr = input('请输入帐号:').strip()
pwd = input('请输入密码:').strip()
login(usr, pwd)


# 4.编写注册功能
def register(username, password):
    with open(r'userinfo.txt', 'a+t', encoding='utf-8') as f:
        for line in f:
            usr, pwd = line.strip().split(':')
            if username == usr:
                print('该帐号已存在!')
                break
            else:
                f.write('{}:{}\n'.format(username, password))
                print('登录成功!')


usr = input('请输入帐号:').strip()
pwd = input('请输入密码:').strip()
register(usr, pwd)



# 5.写函数:用户传入修改的文件名,与要修改的内容,执行函数,完成批量修改操作
def update(address, **kwargs):
    import os
    if not os.path.exists(r'{}'.format(address)):
        print('当前路径下不存在该文件!')
        return
    with open(r'{}'.format(address), mode='rb') as r, \
            open(r'{}.swap'.format(address), mode='wb') as w:
        for line in r:
            line = line.decode('utf-8')
            if kwargs['old_content'] in line:
                w.write(line.replace(kwargs['old_content'], kwargs['new_content']).encode('utf-8'))
            else:
                w.write(line.encode('utf-8'))
    os.remove('{}'.format(address))
    os.rename('{}.swap'.format(address), '{}'.format(address))


address = input('请输入文件名:').strip()
old_content = input('请输入要修改的内容:').strip()
new_content = input('请输入修改后的内容:').strip()

update(address, old_content=old_content, new_content=new_content)


# 6.写函数:计算传入字符串中【数字】、【字母】、【空格] 以及 【其他】的个数
def count_some():
    num = 0
    letter = 0
    space = 0
    other = 0
    inp_str = input('请输入要检测的字符串:')
    for line in inp_str:
        if line.isdigit():
            num += 1
        elif 65 <= ord(line) <= 90 or 97 <= ord(line) <= 122: # 在ASCII码表中,A-Z对应65-90,a-z对应97-122
            letter += 1
        elif ord(line) == 32:   # 在ASCII码表中,32对应空格(space)
            space += 1
        else:
            other += 1
    print('数字{}个\n字母{}个\n空格{}个\n其他字符{}个'.format(num,letter,space,other))

count_some()


# 7.写函数:判断用户传入的对象(字符串、列表、元组)长度是否大于5。
def morethan_five():
    inp_sth = input('请输入要检测的对象:')
    if inp_sth.startswith('[') and inp_sth.endswith(']'):
        inp_sth = inp_sth.strip('[').strip(']').replace(',','')
        res = len(inp_sth)
    elif inp_sth.startswith('(') and inp_sth.endswith(')'):
        inp_sth = inp_sth.strip('(').strip(')').replace(',', '')
        res = len(inp_sth)
    else:
        res = len(inp_sth)
    print(res)

morethan_five()


# 8.写函数:检查传入列表的长度,如果大于2,那么仅保留前两个长度的内容,并将新内容返回给调用者。
def morethan_two(x, y, *args):
    return x, y
x, y = morethan_two(*[1, 2, 3, 4, 5, '6'])
print(x,y)


# 9.写函数:检查获取传入列表或元组对象的所有奇数位索引对应的元素,并将其作为新列表返回给调用者。
def return_single(old_list):
    if type(old_list)==list or type(old_list)==tuple:
        new_list = []
        for i in old_list:
            if  old_list.index(i)%2 == 1:
                new_list.append(i)
    else:
        print("输入的类型不是列表或元组,请重新输入!")
    return new_list
res = return_single([1,2,3,4,5])
print(res)


# 10.写函数:检查字典的每一个value的长度,如果大于2,那么仅保留前两个长度的内容,并将新内容返回给调用者。
dic = {
    
    "k1": "v1v1", "k2": [11,22,33,44]}
# PS:字典中的value只能是字符串或列表

dic = {
    
    "k1": "v1v1", "k2": [11,22,33,44]}
def morethan_two_plus(a):
    for i in a:
        if len(a[i]) > 2:
            a[i] = a[i][0:2]
    return a
res = morethan_two_plus(dic)
print(res)


# 11.函数对象优化多分支if的代码练熟
def exit():
    print('退出')
    # break

def login():
    print('登录功能')


def transfer():
    print('转账功能')


def check_banlance():
    print('查询余额')


def withdraw():
    print('提现')


def register():
    print('注册')


func_dic = {
    
    
    '1': login,
    '2': transfer,
    '3': check_banlance,
    '4': withdraw,
    '5': register
}

while True:
    print("""
    0 退出
    1 登录
    2 转账
    3 查询余额
    4 提现
    5 注册
    """)
    choice = input('请输入命令编号:').strip()
    if not choice.isdigit():
        print('必须输入编号,傻叉')
        continue

    if choice == '0':
        break

    if choice in func_dic:
        func_dic[choice]()
    else:
        print('输入的指令不存在')
        

# 12.编写计数器功能,要求调用一次在原有的基础上加一
def take_num():
    x = 0
    def counte():
        nonlocal x
        x+=1
        return x
    return counte

couter = take_num()
print(couter())
print(couter())
print(couter())
print(couter())
print(couter())


# 13.编写ATM程序实现下述功能,数据来源于文件db.txt
'''
0.注册功能:用户输入账号名、密码、金额,按照固定的格式存入文件db.txt
1.登录功能:用户名不存在,要求必须先注册,用户名存在&输错三次锁定,登录成功后记录下登录状态(提示:可以使用全局变量来记录)
下述操作,要求登录后才能操作
1.充值功能:用户输入充值钱数,db.txt中该账号钱数完成修改
2.转账功能:用户A向用户B转账1000元,db.txt中完成用户A账号减钱,用户B账号加钱
3.提现功能:用户输入提现金额,db.txt中该账号钱数减少
4.查询余额功能:输入账号查询余额
'''import os
login_user = None

# 注册模块
def register():
    inp_usr = input("请输入账号:").strip()
    inp_pwd = input("请输入密码:").strip()
    inp_money = input("请输入预存金额:").strip()
    if not (inp_usr or inp_pwd or inp_money):
        print("输入不能为空")
        # continue
    with open(r'userinfo.txt', mode='at', encoding='UTF-8') as w_register, \
            open(r'userinfo.txt', mode='rt', encoding='UTF-8') as r_register, \
            open(r'money.txt', mode='at', encoding='UTF-8') as a_money:
        res = r_register.read()
        if inp_usr not in res:
            w_register.write(f'{inp_usr}:{inp_pwd}\n')
            a_money.write(f'{inp_usr}:{inp_money}\n')
            print('注册成功!')
        else:
            print('该用户已存在,注册失败!')


# 登录模块
def login():
    global login_user
    count = 0
    while True:
        inp_usr = input("请输入账号:").strip()
        if os.path.exists(r'locked\{}.txt'.format(inp_usr)):
            print("该账号已被锁定")
            count = 0
            continue
        elif login_user == inp_usr:
            print('您处于已登录状态,请勿重复登录!')
            break
        inp_pwd = input("请输入密码:").strip()
        with open(r'userinfo.txt', mode='rt', encoding='UTF-8') as r_login:
            for line in r_login:
                usr, pwd = line.strip().split(':')
                if inp_usr == usr and inp_pwd == pwd:
                    login_user = inp_usr
                    print('登录成功,请选择')
                    break
                else:
                    res = r_login.read()
                    print(res)
                    print(count)

                    if inp_usr not in res:
                        print("该账号不存在")
                    else:
                        if count == 2:
                            print("错误次数过多,账号已被锁定")
                            with open(r'locked\{}.txt'.format(inp_usr), mode='wt', encoding='UTF-8') as f:
                                f.write('')
                            continue
                        else:
                            print("密码错误,剩余次数:{}".format(2 - count))
                            count += 1
        break


# 余额查询模块
def balance():
    inp_usr = input("请输入要查询余额账号:").strip()
    if inp_usr == login_user:
        with open(r'money.txt', mode='rt', encoding='UTF-8') as f_balance:
            usr, money = f_balance.readline().strip().split(':')
            if inp_usr == usr and money:
                print('尊敬的用户{},您的余额为{}元'.format(inp_usr, money))
    else:
        print('请先登录')
        login()


# 提现模块
def withdrawal():
    inp_usr = input("请输入要提现的账号:").strip()
    if inp_usr == login_user:
        dic = {
    
    }
        with open(r'money.txt', mode='rt', encoding='UTF-8') as r_withdrawal:
            for line in r_withdrawal:
                usr, money = line.strip().split(':')
                dic[usr] = int(money)
        while True:
            money = input('请输入要提现的金额:').strip()
            if not money.isdigit():
                print('必须输入数字!')
                continue
            money = int(money)
            dic[inp_usr] -= money
            with open(r'money.txt', mode='wt', encoding='UTF-8') as w_withdrawal:
                for usr, money in dic.items():
                    w_withdrawal.write(f'{usr}:{money}\n')
            with open(r'money.txt', mode='rt', encoding='UTF-8') as f_balance:
                usr, money = f_balance.readline().strip().split(':')
                if inp_usr == usr and money:
                    print('提现成功,您的余额为{}元'.format(money))
            break
    else:
        print('请先登录')
        login()

# 提现模块
def recharge():
    inp_usr = input("请输入要充值的账号:").strip()
    if inp_usr == login_user:
        dic = {
    
    }
        with open(r'money.txt', mode='rt', encoding='UTF-8') as r_recharge:
            for line in r_recharge:
                usr, money = line.strip().split(':')
                dic[usr] = int(money)
        while True:
            money = input('请输入要提现的金额:').strip()
            if not money.isdigit():
                print('必须输入数字!')
                continue
            money = int(money)
            dic[inp_usr] += money
            with open(r'money.txt', mode='wt', encoding='UTF-8') as w_withdrawal:
                for usr, money in dic.items():
                    w_withdrawal.write(f'{usr}:{money}\n')
            with open(r'money.txt', mode='rt', encoding='UTF-8') as f_balance:
                usr, money = f_balance.readline().strip().split(':')
                if inp_usr == usr and money:
                    print('充值成功,您的余额为{}元'.format(money))
            break
    else:
        print('请先登录')
        login()


# 转账模块
def transfer():
    inp_usr = input("请输入您的账号:").strip()
    if inp_usr == login_user:
        inp_usr2 = input("请输入对方账号:").strip()
        t_money = input("请输入转账金额:").strip()
        if not t_money.isdigit():
            print('必须输入数字!')
        else:
            t_money = int(t_money)
            dic = {
    
    }
            with open(r'money.txt', mode='rt', encoding='UTF-8') as f_balance:
                for line in f_balance:
                    usr, money = line.strip().split(':')
                    dic[usr] = int(money)
            if inp_usr2 not in dic:
                print('对方账户不存在,请重新输入')
                return
            print('转账前:', dic[inp_usr])
            if dic.get(inp_usr) >= t_money:
                dic[inp_usr] -= t_money
                dic[inp_usr2] -= t_money
                print('转账后:', dic[inp_usr])
                with open(r'money.txt', mode='wt', encoding='UTF-8') as f:
                    for usr, money in dic.items():
                        f.write(f'{usr}:{money}\n')
    else:
        print('请先登录')
        login()


func_dic = {
    
    
    '1': login,
    '2': transfer,
    '3': balance,
    '4': withdrawal,
    '5': register
}

while True:
    print("""
    0 退出
    1 登录
    2 转账
    3 查询余额
    4 提现
    5 注册
    """)
    choice = input('请输入命令编号:').strip()
    if not choice.isdigit():
        print('必须输入编号,傻叉')
        continue

    if choice == '0':
        break

    if choice in func_dic:
        func_dic[choice]()
    else:
        print('输入的指令不存在')

作者:吴常文
出处:https://blog.csdn.net/qq_41405475
本文版权归作者和CSDN共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。

猜你喜欢

转载自blog.csdn.net/qq_41405475/article/details/113773751