basicPython-2

函数参数

# 函数参数的类型提示:name:str, age:int, 返回值->int
# 补充>>> 提示信息可以是中文等, 使用函数时候不按照提示信息也能正常运行(即:随意)

def func(name: str, age: int) -> str:
    print(f"姓名>>>{name}")
    print(f"年龄>>>{age}")
    return "信息已展示"


if __name__ == '__main__':
    print(func("Tony", 18))
    print(func.__annotations__)

三元表达式

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


# 以上的代码可用‘三元表达式’实现
x = 6
y = 3
res = x if x > y else y

生成器

"""生成器"""
"""普通方法"""
g = []
for x in range(10 + 1):
    g.append(x)
# 结果内存中一下子占满了10个数 尽管你还没用到 g ---> [0, 1, 2, 3, ..., 10]

"""使用"生成器"方法(用多少数字生成多少数字)"""


def generator():
    for i in range(10 + 1):
        yield i


aa = generator()
next(aa)  # 生成第一个数
next(aa)  # 生成第二个数
# ...

"""生成器原理介绍"""


def generator_1():
    print("函数开始...")
    while True:
        res = yield 666
        print("当前的res为--->", res)


tt = generator_1()
print(next(tt))  # 每调用一次next,就执行一次yield | 依靠这种需要才生产的工作机制,大大的节省资源
print("——" * 10)
print(next(tt))

"""
程序执行过程解析:
1.程序开始执行以后,因为函数中有yield关键字,所以函数并不会真的执行,而是先得到一个生成器tt(相当于一个对象)

2.直到调用next方法,函数正式开始执行,先执行函数中的print方法,然后进入while循环

3.程序遇到yield关键字,然后把yield当成return,return了一个666之后,程序停止,并没有执行赋值给res操作,
此时next(tt)语句执行完成,所以输出666

4.程序执行print("——"*10),输出10个——

5.又开始执行下面的print(next(tt)),这个时候和上面那个差不多,
不过不同的是,这个时候是从刚才那个next程序停止的地方开始执行的,
也就是要执行res的赋值操作,
这时候要注意,这个时候赋值操作的右边是没有值的,
因为刚才那个是return出去了,并没有给赋值操作的左边传参数,
所以这个时候res赋值是None,所以接着下面的输出就是当前的res为---> None,

6.程序会继续在while里执行,又一次碰到yield,这个时候同样return出666,然后函数暂停,print函数输出的666

 

到这里你可能就明白yield和return的关系和区别了,
带yield的函数是一个生成器,而不是一个函数了,
这个生成器有一个函数就是next函数,
next就相当于“下一步”生成哪个数,
这一次的next开始的地方是接着上一次的next停止的地方执行的,
所以调用next的时候,生成器并不会从函数的头部开始执行,
而是接着上一步停止的地方开始,然后遇到yield后,return出要生成的数,然后暂停...
"""


def generator_2():
    print("函数开始...")
    while True:
        res = yield 666
        print("当前的res为--->", res)


mm = generator_2()
print()
next(mm)
print("*" * 20)
next(mm)
mm.send(520)
# send是发送一个参数给res的,因为上面讲到,return的时候,并没有把666赋值给res,
# 下次执行的时候只好继续执行赋值操作,只好赋值为None了,而如果用send的话,开始执行的时候,
# 先接着上一次执行,先把520赋值给了res,然后执行next的作用,遇见下一回的yield,return出结果后结束

迭代器

"""迭代器"""
"""

1.
迭代器对象从集合的第一个元素开始访问,
直到所有的元素被访问完结束。
迭代器只能往前不能后退

2.
迭代器是Python中的容器类的数据类型,
可以同时存储多个数据,取迭代器中的数据只能一个一个地取,
而且取出来的数据在迭代器中就不存在了。

3.
迭代器有两个基本的方法:iter() 和 next()

4.
所有的序列都可以转换成迭代器,
包括字符串、列表、元组、字典对象等

"""

"""创建迭代器(iterate:迭代)"""
# 字符串转换成迭代器
iter1 = iter('abcd')  # 创建部分
for index, date in enumerate(iter1):  # 使用部分
    print(index, date)

# 列表转换成迭代器
iter2 = iter([1, 2, 3, 4])  # 创建部分
for i in iter2:  # 使用部分
    print(i)

# 字典转换成迭代器
iter3 = iter({'name': 'aaa'})  # 创建部分
print(iter3)  # 迭代器的内存地址

"""通过next()方法取迭代器中的元素(iterate:迭代)"""
iter4 = iter([10, 5, 2])
print(next(iter4, 0))  # 默认'取'元素,没得取,将返回后面备胎‘0’
print(next(iter4, 0))
print(next(iter4, 0))
print(next(iter4, 'end'))
# print(next(iter4))  # 取不到,又没有备用的,将引发StopIteration异常!

可变长参数

"""可变长度参数"""
'''
约定成俗 *args **kwargs
'''


def func1(a, b, *c, **d):
    # *c-->将多余的 非"键值对"类型的 数据 以元组形式"打包"存放到c里面
    # **d-->将多余的 "键值对"类型的 数据 以字典形式"打包"存放到d里面
    print(a)
    print(b)
    print(type(c), c)  # c为元组
    print(type(d), d)  # d为字典
    return None


func1(1, 2, 3, 4, name="王强")


def func2(a, b, *c, **d):
    print(a)
    print(b)
    print(*c)  # *c-->将元组c进行解包
    print(d.get("name"))  # **d-->将字典d进行解包
    return None


func2(5, 4, 3, 2, name="小明")

递归函数

"""函数的递归"""


# 从0累加到i
def the_sum(i):
    if i == 0:
        return 0
    return i + the_sum(i - 1)


print(the_sum(10))


# 汉诺塔
def hano(n, A, B, C):
    """注释:
    整体法 + 树状图反推法 ---> 汉诺塔算法
    A:start_position
    B:wait_position
    C:end_position
    """
    if n == 1:
        print(f"{A} ---> {C}")
    else:
        hano(n - 1, A, C, B)
        print(f"{A} ---> {C}")
        hano(n - 1, B, A, C)


num = int(input("请输入盘子个数>>>"))
hano(num, "A", "B", "C")

匿名函数

"""匿名函数"""


# 有名函数(需要重复调用)
def func(x, y):
    return x + y


# 匿名函数(临时调用一次)
res = (lambda x, y: x + y)(2, 5)
print(res)

"""匿名函数的应用"""

""" 应用1:找出薪资最高的那个人的名字 """
info = {
    'jack': 5000,
    'tony': 2500,
    'andy': 8000,
    'amy': 6000,
    'lucy': 11000
}
# max()函数实现以上功能:
res = max(info, key=(lambda k: info[k]))
print(res)
# 对max()函数的补充:
# max()函数用于获得给定的可迭代对象中的最大值。
# key是max()函数的一个参数,它辅助max函数找到最大元素。
# 当max() 函数中有 key 参数时,求的是 value 的最大值,
# 当没有 key 参数时,求的是 key 的最大值

# 反之
res = min(info, key=lambda k: info[k])
print(res)

""" 应用2:给列表内的所有元素添上一个后缀 --->  _老坛酸菜 """
# 普通方法:
list_info = [
    '康师傅',
    '景观狼',
    '大今野',
    '白象叶',
]
list_new = [name + "_老坛酸菜" for name in list_info]
print(list_new)

# 匿名函数:
res = map(lambda name: name + '_老坛酸菜', list_info)  # map 为映射
print(next(res))
# 这个map函数的结果为一个生成器!
# 所以,print(res) 只能找到它的地址!

装饰器

无参装饰器

"""装饰器(无参)"""
import time

"""我的世界~Game"""


# 游戏源代码:
def minecraft(name, ability):
    print("\n欢迎来到————我的世界!")
    print("你好,%s,欢迎回来!" % name)
    print("你的%s技能得到了10点提升\n" % ability)


# 游戏源代码~调用
minecraft("史蒂夫", "锋利II")

"""完美世界~Game"""


# 游戏在线时长统计
def time_statistics(func):
    def wrapper(*args, **kwargs):
        t1 = time.time()
        res = func(*args, **kwargs)  # 完美世界游戏源代码
        t2 = time.time()
        print("游戏已结束...")
        print("在线游戏时间:%.1f" % (t2 - t1))
        return res

    return wrapper


# 游戏源代码:
@time_statistics
def perfectworld(name, behavior):
    time.sleep(1)
    print("欢迎来到————完美世界!")
    time.sleep(1)
    print("玩家 >%s< 正在%s" % (name, behavior))
    time.sleep(1)


# 调用装饰后的函数
# 方法1: time_statistics(perfectworld)("荒天帝", "战斗")
# 方法2:游戏源代码处,在‘ def XXX ’的头顶上加上一个  @ (装饰器名称) time_statistics
# 即可起到以下作用
# 1. 将 XXX 这个被装饰的函数 的‘函数名’ 当成参数 传入装饰器(time_statistics)中 以供(装饰器)日后使用
# 2. 同时起到了重命名的作用
# 以上两个作用都是由 @time_statistics 引起的 功能等效于 perfectworld = time_statistics(perfectworld)
perfectworld("荒天帝", "战斗")

含参装饰器

"""装饰器(含参)"""
import time
from functools import wraps  # 导入工具模块,为下面的调用‘完美伪装’做准备


def game_time(account, address):
    def out_wrapper(func):
        @wraps(func)  # 完美装饰!
        def wrapper(*args, **kwargs):
            print(f"欢迎{account}来到《时间猎人》游戏")
            print(f"{account}前往了游戏{address}区")

            t1 = time.time()
            res = func(*args, **kwargs)
            t2 = time.time()

            print(f"\n\n{account}已退出游戏...")
            print("游戏时长>>> %.2f秒" % (t2 - t1))
            return res

        return wrapper

    return out_wrapper


# 时间猎人~源代码
@game_time(25988, 1)
def time_hunter(name, ability, blood):
    print(f"\n时间猎人 >%s< 正遭受攻击" % name)
    print(f"{name}正在使用{ability}进行反击")
    for i in range(blood, -1, -1):
        print(f"\r当前血条>>> {i}", end="")
        time.sleep(0.05)


time_hunter("雷鸣", "时间冻结", 100)

案例演示

import time


# 装饰器部分:
def outer_1(func):
    def wrapper_1():
        while True:
            name = input('\r请输入账号:').strip()
            password = input('请输入密码:').strip()
            if name == '叶寻' and password == '123':
                res = func()
                return res
            else:
                print('账号或密码错误!')

    return wrapper_1


def outer_2(func):
    def wrapper_2(*args, **kwargs):
        print('''\r正在打开登录系统,请稍等...''', end='')
        for i in range(5 + 1):
            time.sleep(1)
            print(f'\r倒计时  ————)))-  {5 - i}秒', end='')
        res = func(*args, **kwargs)
        return res

    return wrapper_2


def outer_3(func):
    def wrapper(*args, **kwargs):
        p = '正在前往登录系统'
        k = p.center(2, '*')
        print(k, end='')
        time.sleep(2)
        res = func(*args, **kwargs)
        return res

    return wrapper


# 原始功能被‘三层装饰器’装饰

@outer_3
@outer_2
@outer_1
def login():
    print('登录成功!')
    return 520


# 执行功能
login()

记忆函数

"""带有记忆功能的函数"""


def outer():
    x = 0
    y = 0

    def inner(x1, y1):
        nonlocal x, y  # 记忆功能核心!
        x = x + x1
        y = y + y1
        print("当前坐标位置为(%s,%s)" % (x, y))

    return inner


move = outer()  # 将inner内存地址传给了move变量

while True:
    s = input("Q退出").strip()
    if (s == "Q" or s == "q"):
        break
    x = int(input("沿着X方向走>>>").strip())
    y = int(input("沿着y方向走>>>").strip())
    move(x, y)  # 等价于inner内存地址+()

# 若看不懂,请认真复习‘装饰器’中‘地址传递’的原理

你可能感兴趣的:(Python基础,python)