Python基础(四)

生成器

创建生成器

方法1
In [7]: nums = (x*2 for x in range(10))

In [8]: nums
Out[8]: <generator object <genexpr> at 0x7fb2a6137fc0>	#生成器对象

In [9]: for num in nums:
   ...:     print(num)
   ...:
0
2
4
6
8
10
12
14
16
18
方法2

定义一个函数,让这个函数变成生成器

定义一个函数实现斐波那契数列:1 1 2 3 5 8 13…

 def fib(num):
    a,b,count = 0,1,1
    while count <= num:
        print(b)
        a,b = b,a+b
        count +=1

fib(10)

如果在调用函数的时候,发现这个函数中有yeild
那么此时,也就不是调用函数了,而是创建了一个生成器对象

def creat_num(all_num):
    print('~~~~~~~~~~~~1~~~~~~~~~~~')
    a, b = 0, 1
    current_num = 0
    while current_num < all_num:
        print('~~~~~~~~~~~~2~~~~~~~~~~~')
        # 相当于暂停程序
        yield b	
        print('~~~~~~~~~~~~3~~~~~~~~~~~')
        a, b = b, a + b
        current_num += 1
        print('~~~~~~~~~~~~4~~~~~~~~~~~')
    
obj = creat_num(5)
# 返回生成器对象
print(obj)

# 用for循环不断调用yield,生成数列
for num in obj:
    print(num)

# 调用next()分步执行,遇到yield就中断
ret = next(obj)
print(ret)
ret1 = next(obj)
print(ret1)
ret2 = next(obj)
print(ret2)
ret3 = next(obj)
print(ret3)
ret4 = next(obj)
print(ret4)
# 执行5次yield后,已经没有yield可执行了,所以第6次调用next()会报错
# ret5 = next(obj)
# print(ret5)

while True:
    try:
        ret = next(obj)
        print(ret)
    except Exception as red:
        print(red.value)
        break

# 两个生成器对象之间并没有任何关系
obj2 = creat_num(5)
ret6 = next(obj2)
print(ret6)

生成器_send

使用send唤醒程序
使用send()函数来唤醒程序执行,
使用send()函数的好处是:可以在唤醒的同时向断点中传入一个附加的数据

def creat_num(all_num):
    a, b = 0, 1
    current_num = 0
    while current_num < all_num:
        ret = yield b
        print('>>>>>> ret >>>>>>',ret)
        a, b = b, a + b
        current_num += 1

obj = creat_num(10)

# next()不传递值
red = next(obj)
print(red)

# send传递值
red = obj.send('hello')
print(red)

#
red = obj.send(None)
print(red)

next和send得到的都是yield后面的值
不同的是:send传递值而next不传递值
在这里插入图片描述
注意:
不能把send放在第一个,会报错,因为第一次执行程序是从开始执行并没有值来接收send
在这里插入图片描述
如果你非要把send放在第一个,那么传递的值应该是None
在这里插入图片描述

生成器应用

实现多任务

并行(真的):有两个任务,两个cpu,一个任务占一个cpu
并发(假的):有四个任务,两个cpu,四个任务交替占有cpu执行

import time

def task1():
    while True:
        print('~~~~~~1~~~~~~')
        time.sleep(0.1)
        yield


def task2():
    while True:
        print('~~~~~~2~~~~~~')
        time.sleep(0.1)
        yield


def main():
    t1 = task1()
    t2 = task2()
    """
    类似于两个while True一起执行
    先让t1运行一会,当t1遇到yield的时候,再返回到task2()
    然后执行t2,当它遇到yield的时候,再次切换到t1中
    这样t1/t2/t1/t2的交替运行,最终实现了多任务---->协程
    """
    while True:
        next(t1)
        next(t2)

main()

在这里插入图片描述

实现单线程并发

利用了关键字yield一次性返回一个结果,阻塞,重新开始
send 唤醒

import time

def consumer(name):
    print('%s 准备学习了~' %(name))
    while True:
        lesson = yield
        print('开始[%s]了,[%s]老师来讲课了~' %(lesson,name))

def producer():
    c1 = consumer('A')
    c2 = consumer('B')
    c1.__next__()
    c2.__next__()
    print('同学们开始上课了~')
    for i in range(3):
        time.sleep(1)
        print('到了两个同学')
        c1.send(i)
        c2.send(i)

producer()

在这里插入图片描述

使用greenlet完成多任务

为了更好的使用协程来完成多任务,python中的greeblet模块对其进行的封装

下载greenlet:/usr/local/python3/bin/pip3 install greenlet

from greenlet import greenlet
import time


def test1():
    while True:
        print('~~~~~1~~~~~')
        gr2.switch()
        time.sleep(0.5)


def test2():
    while True:
        print('~~~~~2~~~~~')
        gr1.switch()
        time.sleep(0.5)

# greenlet这个类对yield进行的封装
gr1 = greenlet(test1)
gr2 = greenlet(test2)

gr1.switch()

在这里插入图片描述

使用gevent完成多任务

使用greenlet时需要 gr1.switch( ) 和 gr1.switch( ) 手动切换
gevent则不需要

import gevent


def f1(n):
    for i in range(n):
        print(gevent.getcurrent(), i)
        gevent.sleep(0.5)


def f2(n):
    for i in range(n):
        print(gevent.getcurrent(), i)
        gevent.sleep(0.5)


def f3(n):
    for i in range(n):
        print(gevent.getcurrent(), i)
        gevent.sleep(0.5)


g1 = gevent.spawn(f1, 5)
g2 = gevent.spawn(f2, 5)
g3 = gevent.spawn(f3, 5)

g1.join()
g2.join()
g3.join()

gevent:三个任务同时进行
在这里插入图片描述

gevent实现多张图片同时下载

下载图片:

import urllib.request

def main():
    req = urllib.request.urlopen('https://img3.doubanio.com/view/photo/m/public/p2528834770.jpg')
    img_content = req.read()
    with open('1.jpg','wb') as f:
        f.write(img_content)

main()

下载多张图片:

import urllib.request
import gevent
   
def downloder(img_name,img_url):
    req = urllib.request.urlopen(img_url)
    img_content = req.read()
    with open(img_name,'wb') as f:
        f.write(img_content)
def main():
    gevent.joinall([
    			      # 图片名	图片地址链接
        gevent.spawn(downloder,'2.jpg','https://img3.doubanio.com/view/photo/m/public/p2528834770.jpg'),
        gevent.spawn(downloder,'3.jpg','https://img1.doubanio.com/view/photo/l/public/p2541840518.jpg'),
        gevent.spawn(downloder,'4.jpg','https://img3.doubanio.com/view/photo/l/public/p2540519750.jpg'),
        gevent.spawn(downloder,'4.jpg','https://ss0.bdstatic.com/94oJfD_bAAcT8t7mm9GUKT-xh_/timg?image&quality=100&size=b4000_4000&sec=1544239785&di=0dac6c76bd63b935147a034cbf1ff1aa&src=http://image11.m1905.cn/uploadfile/2018/ss/1023/20181023110107782.jpg')
    ])
    
main()

高阶函数

高阶函数
----实参是一个函数名
----函数的返回值是一个函数

函数本身也可以赋值给变量 变量可以指向函数

# abs() 是求绝对值的函数
print(abs(-11))

f = abs
print(f(-10))

在这里插入图片描述
传递的参数包含函数名

def fun(x,y,f):
    return f(x),f(y)

print(fun(-10,34,abs))

在这里插入图片描述

内置高阶函数_map

map( )函数接收两个参数,一个是函数,一个是序列
map( )将传入的函数依次作用到序列的每个元素,并且把结果作为新的序列返回

import random

# 需求1:对于序列[-1,3,-4,-5]的每个元素求绝对值
print(list(map(abs,[1,-3,-4,5])))

# 需求2:对于序列的每个元素求阶乘
def f(x):
    res = 1
    for i in range(1,x+1):
        res = res * i
    return res

s = [random.randint(1,6) for i in range(10)]
print(s)
print(list(map(f,s)))

# 需求3:用户接收遗传数字,将该字符串中的所有数字转化为整型并以列表格式输出
def f1(s):
    s = int(float(s))
    return s
print(list(map(f1,input().split(' '))))

在这里插入图片描述
练习:
题目描述:
现在IPV4下用一个32位无符号整数来表示,一般用点分方式来显示,点将IP地址分成4个部分,每个部分为8位,表示成一个无符号整数(因此不需要用正号出现);
如10.137.17.1,是我们非常熟悉的IP地址,一个IP地址串中没有空格出现(因为要表示成一个32数字);
现在需要你用程序来判断IP是否合法。

输入描述:
输入一个ip地址
输出描述:
返回判断的结果YES or NO

示例1:
输入
10.138.15.1
输出
YES

代码:

num = list(map(int, input().split('.')))
count = 0
for i in num:
    if i >= 0 or i <= 255:
        count += 1
if count == 4:
    print('YES')
else:
    print('NO')

运行结果:
在这里插入图片描述

内置高阶函数_reduce

reduce( )函数:这个函数必须接收两个参数,一个是函数,一个是序列
reduce( )把一个函数作用在一个序列上
reduce( )把结果继续和序列的下一个元素做累积计算
----reduce(f,[x1,x2,x3,x4]) = f(f(f(x1,x2),x3),x4)

from functools import reduce
"""
python2:reduce为内置函数
python3:from functools import reduce
"""

# 累乘
def multi(x,y):
    return x*y

print(reduce(multi,range(1,4)))

# 累加
def add(x,y):
    return x+y

print(reduce(add,[1,2,3,4,5]))

在这里插入图片描述

内置高阶函数_filter

filter( ):过滤函数
和map( )类似,filter( )也接收一个函数和一个序列
但是和map ( )不同的是,filter( )把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素

拿出1~100之间的所有偶数

# 函数只能有一个形参,函数的返回值只能是True或者False
def f(n):
    if n % 2 == 0:
        return True
    else:
        return False
print(list(filter(f,range(100))))

在这里插入图片描述
拿出1~100之间的所有素数

def f1(n):
    for i in range(2,n):
        if n % i ==0:
            return False
    return True
print(list(filter(f1,range(2,101))))

在这里插入图片描述

内置高阶函数_sorted

sort( )和sorted( ):

li = [1,2,4,6,3]
# sort()函数直接在原列表进行排序
li.sort()
print(li)
# sorted()函数对所有可迭代的对象进行排序操作,返回新的列表
a = sorted(li)
print(a)

# 默认sort()和sorted()方法由小到大进行排序,reverse=True 由大到小进行排序
a = sorted(li,reverse=True)
print(a)

sorted( )函数也是接收两个参数,一个是序列,一个是函数
不同的是,sorted( )先写序列,再写函数

Info = [
    #商品名称 商品数量 商品单价
    ['apple1', 100, 35],
    ['apple3', 50, 55],
    ['apple4', 50, 25],
    ['apple2', 200, 45]
]

# 默认按商品名称进行排序
print(sorted(Info))

# 按商品数量进行排序
def sorted_by_count(x):
    return x[1]
# key代表排序的关键字
print(sorted(Info, key=sorted_by_count))

# 按商品单价进行排序
def sorted_by_price(x):
    return x[2]  
print(sorted(Info, key=sorted_by_price))

# 先按商品数量进行排序,如果商品数量一致,则按商品单价进行排序
def sorted_by_count_price(x):
    return x[1], x[2]   
print(sorted(Info, key=sorted_by_count_price))

在这里插入图片描述
练习:
题目需求:
给定一个整型数组, 将数组中所有的0移动到末尾, 非0项保持不变;
在原始数组上进行移动操作, 勿创建新的数组;
输入:
第一行是数组长度, 后续每一行是数组的一条记录;
4
0
7
0
2
输出:
调整后数组的内容;
7
2
0
0
代码:

n = int(input('数组长度:'))
str = [int(input()) for i in range(n)]

def move_zero(item):
    #给0项赋值1,非0项赋值0
    if item == 0:
        return 1
    else:
        return 0

print('输出:')
#将赋值后的列表进行升序排序,则0项移至末尾,非0项不变,然后逐个输出
for i in sorted(str,key=move_zero):
    print(i)

运行结果:
在这里插入图片描述

匿名函数

匿名函数:
关键字为lambda
冒号前面是形参,冒号后面是返回值

和高阶函数结合使用

reduce

from functools import reduce

# reduce()函数实现累加
def add(x, y):
    return x + y   
print(reduce(add, [1, 2, 3, 4, 5]))

# 匿名函数结合reduce()函数实现累加
print(reduce(lambda x, y: x + y, [1, 2, 3, 4, 5]))

map

# map()函数求序列内元素的平方
def mypow(x):
    return x ** 2    
print(list(map(mypow, range(5))))

# 匿名函数结合map()函数求序列内元素的平方
print(list(map(lambda x: x ** 2, range(5))))

filter

# filter()函数找序列中的偶数
def is_odd(x):
    return x % 2 == 0    
print(list(filter(is_odd, range(10))))

# 匿名函数结合filter()函数找序列中的偶数
print(list(filter(lambda x: x % 2 == 0, range(10))))

sorted

# 匿名函数结合sorted()函数对序列进行排序
Info = [
    # 商品名称 商品数量 商品单价
    ['apple1', 100, 35],
    ['apple3', 50, 55],
    ['apple4', 50, 25],
    ['apple2', 200, 45]
]

# 默认按商品名称进行排序
print(sorted(Info))
# 按商品数量进行排序
print(sorted(Info, key=lambda x: x[1]))
# 按商品单价进行排序
print(sorted(Info, key=lambda x: x[2]))
# 先按商品数量进行排序,如果商品数量一致,则按商品单价进行排序
print(sorted(Info, key=lambda x:(x[1],x[2])))

# 对于字典里面嵌套字典进行排序
d = {
    '003':{
        'name':'apple1',
        'count':100,
        'price':10
    },
    '002':{
        'name':'apple2',
        'count':200,
        'price':2
    }

}
 
print(d.items())	# [('key',{}),(),()]

# x:('003', {'name': 'apple1', 'count': 100, 'price': 10})
# 
print(sorted(d.items(),key=lambda x:x[1]['count']))
print(sorted(d.items(),key=lambda x:x[1]['price']))

在这里插入图片描述
在这里插入图片描述
练习_奇偶数排序
问题描述:
有一个整数列表(10个元素), 要求调整元素顺序,把所有的奇数放在前面, 偶数放在后面。

代码:

import random
# 方法一:
li = [random.randint(1,10) for i in range(10)]
print(sorted(li,key=lambda n:(n%2==0)))

# 方法二:
print(sorted(list(map(lambda x:random.randint(1,10),range(10))),key=lambda n:n%2==0))

运行结果:
在这里插入图片描述

装饰器

装饰器:

把一个函数当作参数,返回一个替代版的函数
本质上就是一个返回函数的函数

在不改变原函数的基础上,给函数增加功能

def outer(func):
   def inner(age):
       if age<0:
           age = 0
       func(age)
   return inner

@outer	   # 语法糖,相当于 say = outer(say)
def say(age):
    print('man is %s years old' %age)

# say = outer(say)
say(-1)

在这里插入图片描述

装饰器的应用
多个函数使用一个装饰器
 def desc(fun):  # 需要传递一个函数,要装饰的函数
    def add_info():  # 装饰器函数里要嵌套函数
        print('元旦快乐~')
        fun()
        print('欢迎光临西部开源~')
    return add_info    # 返回值是嵌套的函数对象

@desc   # 如何调用装饰器(两种方式)
def login():
    print('login....')

# login = desc(login)  # 返回值是一个函数
# login()
@desc
def logout():
    print('logout...')

@desc
def savemoney():
    print('存钱...')

@desc
def transfermoney():
    print('转账...')


login()
logout()
savemoney()
transfermoney()

在这里插入图片描述

装饰器实现一个计时器
 import time
import string
import random
import functools

li = [random.choice(string.ascii_letters) for i in range(10)]


# 问题1:装饰的函数有返回值
# 问题2:如何保留被装饰函数的函数名和帮助信息文档
def timeit(fun):
    """这是一个装饰器timeit"""

    @functools.wraps(fun)  # 可以保留被装饰函数的函数名和帮助信息文档
    def add_time(*args, **kwargs):  # 接收可变参数和关键字参数
        """这是一个add_time函数"""
        # 在函数执行之前计时
        start_time = time.time()
        # 执行函数
        # 函数有返回值时,将函数赋给res
        res = fun(*args, **kwargs)
        # 在函数执行之后计时
        end_time = time.time()
        print('运行时间:%.6f' % (end_time - start_time))
        # 返回res
        return res

    return add_time


@timeit
def con_add():
    """这是con_add函数,被timeit装饰"""
    s = ''
    for i in li:
        s += i + ','
    print(s)


@timeit
def join_add():
    """这是join_add函数,被timeit装饰"""
    print(','.join(li))


@timeit
def fun_list(n):
    # 函数有返回值
    return (i for i in range(n) if n % 2 == 0)


@timeit
def fun_filter(n):
    return (filter(lambda x: (x % 2 == 0), range(n)))


def func():
    """这是func函数"""
    print('hello')


con_add()
join_add()

print(fun_list(5000))
print(fun_filter(5000))

print(func.__doc__)
print(func.__name__)

print(con_add.__doc__)
print(con_add.__name__)

print(join_add.__doc__)
print(join_add.__name__)

在这里插入图片描述
问题2的解决:
在这里插入图片描述

装饰器实现对用户权限的判断
import functools
import inspect


def is_admin(fun):
    @functools.wraps(fun)
    def wrapper(*args, **kwargs):
        # inspect.getcallargs返回一个字典,key值:形参,value值:对应的实参
        inspect_res = inspect.getcallargs(fun, *args, **kwargs)
        print('inspect的返回值:%s' % inspect_res)
        if inspect_res.get('name') == 'admin':
            res = fun(*args, **kwargs)
            return res
        else:
            print('not admin user,no permisson!')

    return wrapper


@is_admin
def add_student(name):
    print('添加学生信息~')

@is_admin
def del_student(name):
print('删除学生信息~')

add_student('admin')
del_student('student')

在这里插入图片描述

练习_创建装饰器

创建装饰器,要求如下:
1.创建add_log装饰器,被装饰的函数打印日志信息
2.日志格式为:[字符串时间] 函数名:xxx, 运行时间:xxx, 运行返回值结果:xxx

代码:

import time
import functools


def add_log(fun):
    @functools.wraps(fun)
    def print_Info(*args, **kwargs):
        start_time = time.time()
        res = fun(*args, **kwargs)
        end_time = time.time()
        print('字符串时间:[%s] 函数名:%s 运行时间:%.6f 运行返回值结果:%s'
              %(time.ctime(),fun.__name__,end_time - start_time,res))
        return res

    return print_Info


@add_log
def fun_filter(n):
    time.sleep(1)
    return list(filter(lambda x: (x % 2 == 0), range(n)))

fun_filter(5)

运行结果:
在这里插入图片描述

多个装饰器

有多个装饰器的时候,函数从上到下执行的

def decorator_a(fun):
    print('Get in decorator_a')
    def inner_a(*args,**kwargs):
        print('Get in inner_a')
        return fun(*args,**kwargs)
    return inner_a

def decorator_b(fun):
    print('Get in decorator_b')
    def inner_b(*args,**kwargs):
        print('Get in inner_b')
        return fun(*args,**kwargs)
    return inner_b
    
"""
当有多个装饰器的时候,装饰器decorator是从下到上调用
但真实的inner函数内容是从上到下执行的
"""
@decorator_b
@decorator_a
def f():
    print('Get in f')
    
f()

在这里插入图片描述

应用
用多个装饰器先验证用户是否登陆成功,再验证是否有权限
import functools
import inspect


def is_admin(fun):
    @functools.wraps(fun)
    def wrapper(*args, **kwargs):
        inspect_res = inspect.getcallargs(fun, *args, **kwargs)
        if inspect_res.get('name') == 'admin':
            res = fun(*args, **kwargs)
            return res
        else:
            print('%s not admin user,no permisson!' % args[0])

    return wrapper


login_session = ['admin', 'root', 'westos']


def is_login(fun):
    @functools.wraps(fun)
    def wrapper(*args, **kwargs):
        if args[0] in login_session:
            res = fun(*args, **kwargs)
            return res
        else:
            print('%s not login!' % args[0])

    return wrapper


@is_login
@is_admin
def add_student(name):
    print('添加学生信息~')


add_student('redhat')
add_student('westos')
add_student('admin')

在这里插入图片描述

练习_创建装饰器

编写装饰器required_ints,条件如下:
1.确保函数收到的每一个参数都是整数
2.如果参数不是整型数,打印 TypeError:参数必须为整型

代码:

import functools


def required_ints(fun):
    @functools.wraps(fun)
    def wrapper(*args, **kwargs):
        for i in args:
            if not isinstance(i, int):
                print('TypeError:参数必须为整型')
                return
        else:
            res = fun(*args, **kwargs)
            return res

    return wrapper


@required_ints
def add(x, y):
    print(x+y)

add(1, 2)
add(1, 2.5)

运行结果:
在这里插入图片描述

带参数的装饰器

应用
import time
import functools

def log(kind):	# kind = 'debug'
    def add_log(fun):
        @functools.wraps(fun)
        def print_Info(*args, **kwargs):
            start_time = time.time()
            res = fun(*args, **kwargs)
            end_time = time.time()
            print('字符串格式:<%s> 字符串时间:[%s] 函数名:%s 运行时间:%.6f 运行返回值结果:%s'
                  %(kind,time.ctime(),fun.__name__,end_time - start_time,res))
            return res

        return print_Info

    return add_log


@log('debug')
# log('debug') ====> 返回值:add_log
def add(x,y):
    time.sleep(1)
    return x+y

add(5,6)

在这里插入图片描述

练习_创建装饰器

编写装饰器required_types,条件如下:
1.当装饰器为@required_types(int,float)时,确保函数接收到的每一个参数都是int或者float类型;
2.当装饰器为@required_types(list)时,确保函数接收到的每一个参数都是list类型;
3.当装饰器为@required_types(str,int)时,确保函数接收到的每一个参数都是str或者int类型;
4.如果参数不满足条件,打印 TypeError:参数必须为xxxx类型

代码:

import functools


def required_types(*kind):
    def required(fun):
        @functools.wraps(fun)
        def wrapper(*args, **kwargs):
            for i in args:
                if not isinstance(i, kind):
                    print('TypeError:参数必须为:',kind)
                    return
            else:
                res = fun(*args, **kwargs)
                return res

        return wrapper

    return required


@required_types(int,float)
def add(x, y):
    print(x , y)


add(1.5,3)
add('westos', 2.5)

运行结果:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值