欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

python中的高级特性

程序员文章站 2024-01-25 16:05:23
...

#高级特性
内容梗概: python中的高级特性

01生成式详解

列表生成式就是一个用来生成列表的特定语法形式的表达式。是Python提供的一种生
成列表的简洁形式, 可快速生成一个新的list。
• 普通的语法格式:[exp for iter_var in iterable]
result = [random.randint(1,50) for count in range(100)]
• 带过滤功能语法格式: [exp for iter_var in iterable if_exp]
result = [num for num in range(1,100) if num%3 == 0]
• 循环嵌套语法格式: [exp for iter_var_A in iterable_A for iter_var_B in iterable_B]
nums = [item1+item2 for item1 in ‘abc’ for item2 in ‘123’]

字典生成式:用来快速生成字典;
集合生成式:用来快速生成集合;
s = {1,2,3,4,5,6,7}
#集合生成式
print({i2 for i in s})
#字典生成式
print({i:i
2 for i in s})

练习1:求1—100之间所有的质数

def is_prime(num):
    if num > 1:
        for i in range(2,num+1):
            if (num%i) == 0:
                break
        if num == i:
            return True
        else:
            return False
result = [k for k in range(1,101) if is_prime(k)]
print(result)

练习2:将字典中所有的key值和value值替换

def swap_key_value(dictionary):
    return {value:key for key,value in dictionary.items()}
if __name__ == '__main__':
    d = {
        'user1':'name',
        'user2':'westos'
    }
    d1 = swap_key_value(d)
print(d1)

练习3:字典key值大小写计数合并 : 已知字典{‘A’:10, ‘b’:5, ‘a’:2}, 合并后为{‘a’:12, ‘b’:5}注意: key值最终全部为小写.
d = dict(a=2,b=1,c=2,B=9,A=10)
print({x.lower():(d.get(x.lower(),0)+d.get(x.upper(),0)) for x in d.keys()})

生成器

• 什么叫生成器?
在Python中,一边循环一边计算的机制,称为生成器:Generator。
• 什么时候需要使用生成器?
性能限制需要用到,比如读取一个10G的文件,如果一次性将10G的文件加载到内存处理的话(read方法),内存肯定会溢出;但使用生成器把读写交叉处理进行,比如使用(readline和readlines)就可以再循环读取的同时不断处理,这样就可以节省大量的内存空间.
• 如何创建生成器?
第一种方法: 列表生成式的改写。 []改成()
nums_gen = (num for num in range(1, 10001) if num % 8 == 0)
print(nums_gen)
第二种方法: yield关键字。
Yield生成fib()数列

def fib2(num):
    count = 0
    a=b=1
    while True:
        if count < num:
            count += 1
            yield a
            a=b
            b=a+b
        else:
            break
print(fib2(2))
print(next(fib2(2)))
print(next(fib2(2)))

• 如何打印生成器的每一个元素呢?
第一种方法:通过for循环, 依次计算并生成每一个元素。
#查看一个对象是否可以for循环?
from collections.abc import Iterable
print(“生成器是否为可迭代对象?”, isinstance(nums_gen, Iterable))
for num in nums_gen:
if num > 50:
break
print(num)
第二种方法:如果要一个一个打印出来,可以通过next()函数获得生成器的下一个返回值。
print(next(nums_gen)) # 执行一次next生成一个值
print(next(nums_gen))
print(next(nums_gen))
生成器的特点是什么?
• 解耦. 爬虫与数据存储解耦;
• 减少内存占用. 随时生产, 即时消费, 不用堆积在内存当中;
• 可不终止调用. 写上循环, 即可循环接收数据, 对在循环之前定义的变量,可重复使用;
• 生成器的循环, 在 yield 处中断, 没那么占 cpu.

生成器的应用案例: 生产者-消费者模型
python中的高级特性
生产者消费者问题是多线程并发中一个非常经典的问题,也是在互联网面试求职中会经常
问到的一个题。顾名思义,单生产者-单消费者模型中只有一个生产者和一个消费者,生产者不停地往队列库中放入产品,消费者则从队列库中取走产品。

生产者-消费者模型有如下几个特点:
1、队列库容积有一定的限制,只能容纳一定数目的产品。
2、如果生产者生产产品的速度过快,则需要等待消费者取走产品之后,产品库
不为空才能继续往产品库中放如新的产品。
3、如果消费者取走产品的速度过快,则可能面临产品库中没有产品可使用的情
况,此时需要等待生产者放入一个产品后,消费者才能继续工作。
专业术语描述:
1、当队列元素已满的时候,阻塞插入操作;
2、当队列元素为空的时候,阻塞获取操作;

python中return关键字和yield关键字的区别?
• return:在程序函数中返回某个值,返回之后函数不在继续执行,彻底结束。
• yield: 带有yield的函数是一个迭代器,函数返回某个值时,会停留在某个位
置,返回函数值后,会在前面停留的位置继续执行,直到程序结束
生成器的send方法:

def grep(kw):
    while True:
        response = ''
        request = yield response
        if kw in request:
            print(request)
if __name__ == '__main__':
    grep_gen = grep('python')
    next(grep_gen)   #当程序执行到yield语句时,程序被挂起
    grep_gen.send('I love python') #指定yield response的返回值为'I love #python',即request为'I love python'
    grep_gen.send('I love java')

注意:在执行send方法前,程序必须被挂起,不然会报错,send方法有一个参数,该参数指定的是上一次被挂起yield函数的返回值
https://segmentfault.com/a/1190000016880292?utm_source=tag-newest
https://www.cnblogs.com/lanyinhao/p/9137956.html

03 生成器、迭代器、可迭代对象

迭代是访问容器元素的一种方式。迭代器是一个可以记住遍历的位置的对象。
迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。
可迭代对象:可以直接作用于for循环的对象(如何判断是否可以迭代?)
一类是集合数据类型,如list, tuple,dict, set,str等;
一类是generator,包括生成器和带yield的generator function。
• 可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。
• 生成器都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator。
• 把list、dict、str等Iterable变成Iterator可以使用iter()函数
python中的高级特性

生成器: generator, 一边循环一边计算的工具。
迭代器: iterator, 可以调用next方法访问元素的对象.
可迭代对象: Iterable, 可以实现for循环的
生成器都是迭代器么? Yes, 生成器内部实现了迭代器的协议。
生成器都是可迭代对象吗? Yes
可迭代对象都是迭代器吗? Not Always, 比如: str,list,tuple,set,dict.
如何将可迭代对象转换成迭代器? iter()内置函数

04 闭包

• 什么是闭包?如何实现闭包?
闭包就是指有权访问另一个函数作用域中的变量的函数。
创建闭包最常见方式,就是在一个函数内部创建另一个函数。
常见形式: 内部函数使用了外部函数的临时变量,且外部函数的返回值是内部函数的引用。
闭包的一个常用场景就是装饰器。

python中的高级特性

05装饰器

器指的是工具,而程序中的函数就是具备某一功能的工具,所以装饰器指的是为被装饰器
对象添加额外功能的工具/函数。
为什么使用装饰器?
如果我们已经上线了一个项目,我们需要修改某一个方法,但是我们不想修改方法的使用方法,这个时候可以使用装饰器。因为软件的维护应该遵循开放封闭原则,即软件一旦上线运行后,软件的维护对修改源代码是封闭的,对扩展功能指的是开放的。
装饰器的实现必须遵循两大原则:
• 封闭: 对已经实现的功能代码块封闭。 不修改被装饰对象的源代码
• 开放: 对扩展开发
装饰器其实就是在遵循以上两个原则的前提下为被装饰对象添加新功能。

如何实现装饰器?
装饰器本质上是一个函数,该函数用来处理其他函数,它可以让其他函数在不需要修改代
码的前提下增加额外的功能,装饰器的返回值也是一个函数对象。
装饰器的应用场景?
装饰器经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、
权限校验等应用场景。
装饰器的应用1:插入日志

# logging:专门做日志记录或者处理的模块。
import logging
# 日志的基本配置
# 官方符网站基本配置及使用: https://docs.python.org/zh-cn/3/howto/logging.html#logging-basic-tutorial
logging.basicConfig(
    level=logging.DEBUG,  # 控制台打印的日志级别
    filename='message.log',  # 日志文件位置
    filemode='a',  # 写入文件的模式,a是追加模式,默认是追加模式
    #日志格式
format='%(asctime)s-%(pathname)s[line:%(lineno)d]- %(levelname)s: %(message)s'
)
#logging.debug('Network start Ok')
#logging.warning('Network start Failed')
#1). 定义装饰器
from functools import wraps

def logger(func):
    """插入日志的装饰器"""
    # wraps装饰器, 用来保留func函数原有的函数名和帮抓文档。
    @wraps(func)
    def wrapper(*args, **kwargs):  # args, kwargs是形参, args是元组, kwargs是字典.
        """闭包函数"""
        logging.debug("函数%s开始执行" % (func.__name__))
        result = func(*args, **kwargs)  # args, kwargs是实参, *args, **kwargs解包
		logging.debug("函数%s执行结束" % (func.__name__))
        return result

    return wrapper
# 2). 如何使用装饰器?
#  1). @logger语法糖,  login = logger(login), python解释器遇到语法糖就直接执行
#   2). login函数目前指向logger(login)函数的返回值wrapper, login=wrapper
@logger
def login(username, password):
    """用户登录"""
    if username == 'root' and password == 'redhat':
        print('LOGIN OK')
        logging.debug('%s LOGIN OK' % (username))
    else:
        print('LOGIN FAILED')
        logging.error('%s LOGIN FAILED' % (username))
# 实质上执行的是装饰器里面的wrapper函数
login('root', 'westos')
# print(login.__name__)
# print(login.__doc__)

装饰器应用2:性能测试

from functools import wraps
import time
def timeit(func):
    """计算被装饰函数运行总时间的装饰器"""
    @wraps(func)
    def wrapper(*args,**kwargs):
        start_time = time.time()
        result = func(*args,**kwargs)
        end_time = time.time()
        print('函数%s运行总时间为%.2f秒' %(func.__name__,end_time-start_time))
        return result
    return wrapper
@timeit
def download_videos(name,dirname):
    time.sleep(2)
    print('download %s movie to %s' %(name,dirname))
download_videos('python','/mnt/python')

装饰器应用3:事务处理

from functools import wraps
import json
import string
def json_result(func):
    @wraps(func)
    def wrapper(*args,**kwargs):
        result = func(*args,**kwargs)
        return json.dumps(result)
    return wrapper
@json_result
def get_users():
    return {'user' + item:'passwd' + item for item in string.digits}
result = get_users()
print(result)
print(type(result))

装饰器应用4:fib数列缓存
functools.lru_cache的作用主要是用来做缓存,把相对耗时的函数结果进行保存,避免传入相同的参数重复计算。同时,缓存并不会无限增长,不用的缓存会被释放。

from functools import wraps
def fib_cache(func):
    caches = {1:1,2:1,3:2,4:3}
    @wraps(func)
    def wrapper(num):
        if num in caches:
            return caches[num]
        result = func(num)
        caches[num] = result
        return result
    return wrapper
import time
def timeit(func):
    """计算被装饰函数运行总时间的装饰器"""
    @wraps(func)
    def wrapper(*args,**kwargs):
        start_time = time.time()
        result = func(*args,**kwargs)
        end_time = time.time()
        print('函数%s运行总时间为%f秒' %(func.__name__,end_time-start_time))
        return result
    return wrapper

@fib_cache
def fib1(num):
    if num in (1,2):
        return 1
    else:
        return fib1(num-1)+fib1(num-2)


def fib2(num):
    if num in (1, 2):
        return 1
    else:
        return fib2(num - 1) + fib2(num - 2)
@timeit
def use_cache():
    result = fib1(20)
    print(result)
@timeit
def no_cache():
    result = fib2(20)
    print(result)
if __name__ == '__main__':
    use_cache()
    no_cache()

装饰器应用5:权限验证与多装饰器

from functools import wraps
db = {
    'root':{
        'name':'root',
        'passwd':'westos',
        'is_super':0
    },
    'admin': {
            'name': 'admin',
            'passwd': 'westos',
            'is_super': 1  # 0-不是 1-是
    }
}
login_user_session = {}

def is_login(func):
    @wraps(func)
    def wrapper1(*args,**kwargs):
        if login_user_session:
            result = func(*args,**kwargs)
            return result
        else:
            print('未登陆,请先登录')
            print('跳转登陆'.center(50,'*'))
            user = input('user:')
            passwd = input('passwd:')
            if user in db:
                if db[user]['passwd'] == passwd:
                    login_user_session['username'] = user
                    print('登录成功')
                    # ***** 用户登录成功, 执行buy的操作;
                    result = func(*args, **kwargs)
                    return result
                else:
                    print("密码错误")
            else:
                print("用户不存在")

    return wrapper1
def is_permission(func):
    """判断用户是否有权限的装饰器"""

    # @wraps保留被装饰函数的函数名和帮助文档, 否则是wrapper的信息.
    @wraps(func)
    def wrapper2(*args, **kwargs):
        print("判断是否有权限......")
        current_user = login_user_session.get('username')
        permissson = db[current_user]['is_super']
        if permissson == 1:
            result = func(*args, **kwargs)
            return result
        else:
            print("用户%s没有权限" % (current_user))
    return wrapper2
# 多个装饰器装饰的顺序是自下而上(就近原则),而调用/执行的顺序是自上而下(顺序执行)。
"""
被装饰的过程: 
1). @is_permission:  buy = is_permission(buy)  ===> buy=wrapper2
2). @is_login: buy = is_login(buy)  ===> buy = is_login(wrapper2)   ===> buy=wrapper1
"""
@is_login
@is_permission
def buy():
    print("购买商品........")
"""
判断用户是否登录..........
判断用户是否有权限..........
购买商品........
调用的过程: 
    1). buy() ===>  wrapper1()  print("判断用户是否登录..........")
    2). wrapper2()              print("判断用户是否有权限..........")
    3). buy()                   print("购买商品........")                 
"""
buy()

有参装饰器

无参装饰器只套了两层,有参装饰器: 套三层的装饰器,实现一个用户登录的装饰器。

from functools import  wraps
def auth(type):
    print("认证类型为: ", type)
    def desc(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            if type == 'local':
                user = input("User:")
                passwd = input("Passwd:")
                if user == 'root' and passwd == 'westos':
                    result = func(*args, **kwargs)
                    return result
                else:
                    print("用户名/密码错误")
            else:
                print("暂不支持远程用户登录")
        return  wrapper
    return  desc

"""
结论: @后面跟的是装饰器函数的名称, 如果不是名称, 先执行,再和@结合。
1). @auth(type='local') 
2). desc = auth(type='local')
3). @desc
4). login = desc(login)
4). login = wrapper
"""
@auth(type='remote')
def home():
    print('网站主页')
home()

06高阶内置函数

函数式编程的一个特点就是,允许把函数本身作为参数传入另一个函数,还允许返
回一个函数!Python对函数式编程提供部分支持。

什么是高阶函数?
把函数作为参数传入,这样的函数称为高阶函数,函数式编程就是指这种高度抽象的编程范式。
1、map() 会根据提供的函数对指定序列做映射。
python中的高级特性
2、当序列多于一个时,map可以并行(注意是并行)地对每个序列执行如下图所示的过程:
python中的高级特性

#1).map的传递函数名可以是内置函数
#map_object = map(int,['1','2','3'])  #返回的是一个map对象,生成器对象
#print(list(map_object))
#for item in map_object:
#     print(item,type(item))
#print(next(map_object))
#print(next(map_object))
#print(next(map_object))
#2).map的传递函数名可以是匿名函数
#iterator_object = (int(item) for item in ['1','2','3'])
#for item in iterator_object:
#     print(item,type(item))
#map_object = map(lambda x:x**2,[1,2,3,4])
#print(list(map_object))

#3).map的传递函数名可以是非匿名函数
#def data_process(x):
#     return x+4
#map_object = map(data_process,[1,2,3,4])
#print(list(map_object))

#4).map的传递的可迭代对象可以是多个
map_object = map(lambda x,y:x**2+y,[1,2,3],[1,2,3])
print(list(map_object))

3、reduce() 函数会对参数序列中元素进行累积。
python中的高级特性

from functools import reduce
nums_add = reduce(lambda x,y:x+y,list(range(1,100)))
print(nums_add)
N = 5
result = reduce(lambda x,y:x*y,list(range(1,N+1)))
print(result)

4、filter() 函数用于过滤序列,过滤掉不符合条件的元素,返回由符合条件元素组成的新列表。
python中的高级特性

# result = filter(lambda x:x%3 == 0,list(range(1,11)))
# print(list(result))
#
# result = [item for item in range(1,11) if item%3 == 0]
# print(result)

def is_prime(x):
“””判断是否是质数”””
    if x >= 2:
        for i in range(2,x+1):
            if x%i == 0:
                break
        if i == x:
            return True
    else:
        return True
result = filter(is_prime,list(range(1,101)))
print(list(result))

5、sorted() 函数对所有可迭代的对象进行排序操作。返回重新排序的列表。
sorted(iterable, key=None, reverse=False)
key: 主要是用来进行比较的元素,只有一个参数,
reverse: 排序规则,True 降序 ,False 升序(默认)

python排序sort()和sorted()的区别是什么?

  1. 排序对象不同: sort 是应用在 list 上的方法,sorted 可以对所有可迭代的对象进行排序操作。
  2. 返回值不同:
    list 的 sort 方法返回的是对已经存在的列表进行操作,无返回值,
    内建函数 sorted 方法返回的是一个新的 list,而不是在原来的基础上进行的操作。
import random
def is_odd(x):
    return x % 2 == 0
# 需求:偶数排在前,奇数排在后
nums = list(range(10))
random.shuffle(nums)
print('排序前:',nums)
nums.sort(key=lambda x:0 if is_odd(x) else 1)
print('排序后:',nums)
#sorted可以对所有可迭代的对象进行排序操作
result = sorted({2,3,4,5,1})
print(result)