python高级特性

限于喜欢 提交于 2019-12-22 00:10:25

生成式

  • 列表生成式:用来生成列表的特定语法形式的表达式。是Python提供的一种生成列表的简洁形式, 可快速生成一个新的list
    普通的语法格式:[exp for iter_var in iterable]
#列表生成式:生成100个1~50之间的随机数值。
#先使用空列表 循环100次 每循环一次在random.randint(1,50)中选一个值保存到[]中
print([random.randint(1,50) for i in range(1,100)])

执行结果:
[42, 8, 22, 16, 34, 8, 37, 39, 31, 30, 7, 3, 11, 17, 39, 4, 8, 8, 16, 5, 12, 27, 15, 35, 1, 9, 5, 17, 41, 9, 14, 22, 29, 16, 30, 30, 44, 40, 32, 30, 20, 2, 28, 35, 19, 21, 38, 35, 12, 42, 30, 35, 9, 35, 34, 25, 44, 6, 8, 26, 26, 13, 19, 15, 37, 40, 15, 44, 1, 16, 27, 38, 15, 44, 5, 39, 23, 25, 7, 5, 43, 40, 16, 42, 20, 47, 14, 11, 9, 27, 36, 9, 43, 8, 20, 28, 14, 34, 17]

带过滤功能语法格式: [exp for iter_var in iterable if_exp]

#带过滤功能语法格式  1~100之间能被3整除的数
print([i for i in range(1,101) if i %3==0])

执行结果:
[3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51, 54, 57, 60, 63, 66, 69, 72, 75, 78, 81, 84, 87, 90, 93, 96, 99]

循环嵌套语法格式: [exp for iter_var_A in iterable_A for iter_var_B in iterable_B]

print([i+j for i in 'abc'for j in '123'])


执行结果:
['a1', 'a2', 'a3', 'b1', 'b2', 'b3', 'c1', 'c2', 'c3']
  • 字典生成式:用来快速生成字典;
生成100个用户字典 用户名:密码
 import  pprint
 pprint.pprint({'user'+str(x+1):'passwd'+str(x+1) for x in range(100)})


执行结果:
{'user1': 'passwd1',
 'user10': 'passwd10',
 'user100': 'passwd100',
 'user11': 'passwd11',
 'user12': 'passwd12',
 'user13': 'passwd13',
 'user14': 'passwd14',
 'user15': 'passwd15',
 'user16': 'passwd16',
 'user17': 'passwd17',
 'user18': 'passwd18',
 'user19': 'passwd19',
 'user2': 'passwd2',
 'user20': 'passwd20',
 'user21': 'passwd21',
 'user22': 'passwd22',
 'user23': 'passwd23',
 'user24': 'passwd24',
 'user25': 'passwd25',
 'user26': 'passwd26',
 'user27': 'passwd27',
 'user28': 'passwd28',
 'user29': 'passwd29',
 'user3': 'passwd3',
 'user30': 'passwd30',
 'user31': 'passwd31',
 'user32': 'passwd32',
 'user33': 'passwd33',
 'user34': 'passwd34',
 'user35': 'passwd35',
 'user36': 'passwd36',
 'user37': 'passwd37',
 'user38': 'passwd38',
 'user39': 'passwd39',
 'user4': 'passwd4',
 'user40': 'passwd40',
 'user41': 'passwd41',
 'user42': 'passwd42',
 'user43': 'passwd43',
 'user44': 'passwd44',
 'user45': 'passwd45',
 'user46': 'passwd46',
 'user47': 'passwd47',
 'user48': 'passwd48',
 'user49': 'passwd49',
 'user5': 'passwd5',
 'user50': 'passwd50',
 'user51': 'passwd51',
 'user52': 'passwd52',
 'user53': 'passwd53',
 'user54': 'passwd54',
 'user55': 'passwd55',
 'user56': 'passwd56',
 'user57': 'passwd57',
 'user58': 'passwd58',
 'user59': 'passwd59',
 'user6': 'passwd6',
 'user60': 'passwd60',
 'user61': 'passwd61',
 'user62': 'passwd62',
 'user63': 'passwd63',
 'user64': 'passwd64',
 'user65': 'passwd65',
 'user66': 'passwd66',
 'user67': 'passwd67',
 'user68': 'passwd68',
 'user69': 'passwd69',
 'user7': 'passwd7',
 'user70': 'passwd70',
 'user71': 'passwd71',
 'user72': 'passwd72',
 'user73': 'passwd73',
 'user74': 'passwd74',
 'user75': 'passwd75',
 'user76': 'passwd76',
 'user77': 'passwd77',
 'user78': 'passwd78',
 'user79': 'passwd79',
 'user8': 'passwd8',
 'user80': 'passwd80',
 'user81': 'passwd81',
 'user82': 'passwd82',
 'user83': 'passwd83',
 'user84': 'passwd84',
 'user85': 'passwd85',
 'user86': 'passwd86',
 'user87': 'passwd87',
 'user88': 'passwd88',
 'user89': 'passwd89',
 'user9': 'passwd9',
 'user90': 'passwd90',
 'user91': 'passwd91',
 'user92': 'passwd92',
 'user93': 'passwd93',
 'user94': 'passwd94',
 'user95': 'passwd95',
 'user96': 'passwd96',
 'user97': 'passwd97',
 'user98': 'passwd98',
 'user99': 'passwd99'}

  • 集合生成式:用来快速生成集合;
# 需求: 生成100个1~200之间的随机且不重复数值。
import random
print({random.randint(1, 200) for count in range(100)})

执行结果:
{3, 4, 7, 10, 14, 15, 17, 18, 19, 21, 23, 25, 26, 28, 31, 33, 36, 37, 40, 42, 44, 48, 51, 54, 56, 58, 62, 67, 68, 71, 79, 81, 84, 86, 87, 88, 89, 93, 95, 96, 100, 101, 102, 105, 106, 109, 110, 114, 116, 119, 123, 127, 131, 137, 140, 141, 149, 150, 151, 153, 154, 159, 162, 163, 165, 166, 168, 169, 172, 175, 177, 179, 184, 187, 190, 195, 196, 198}

生成式小案例

  1. 求以r为半径的圆的面积和周长(r的范围从1到10)。
import math
print({'s='+str(math.pi*r**2) :'C='+str(math.pi*2*r)for r in range(1,11)})

执行结果:
{'s=3.141592653589793': 'C=6.283185307179586', 's=12.566370614359172': 'C=12.566370614359172', 's=28.274333882308138': 'C=18.84955592153876', 's=50.26548245743669': 'C=25.132741228718345', 's=78.53981633974483': 'C=31.41592653589793', 's=113.09733552923255': 'C=37.69911184307752', 's=153.93804002589985': 'C=43.982297150257104', 's=201.06192982974676': 'C=50.26548245743669', 's=254.46900494077323': 'C=56.548667764616276', 's=314.1592653589793': 'C=62.83185307179586'}
  1. 找出1~100之间所有的质数。
def is_prime(x):
    for j in range(2,x):
          if x % j == 0 :
              return False #函数一旦遇到return 就不会i执行后面的代码 相当于break
    else: #x%j!=0不执行任何操作,直到遍历完j的值return true
         return  True
print([i for i in range(1,101) if is_prime(i)])


执行结果:
[1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]


  1. 将字典的key值和value值调换。
import  pprint
num={'user'+str(x+1):'passwd'+str(x+1) for x in range(100)}
pprint.pprint({value:key for key,value in num.items()})#调换

执行结果:
{'passwd1': 'user1',
 'passwd10': 'user10',
 'passwd100': 'user100',
 'passwd11': 'user11',
 'passwd12': 'user12',
 'passwd13': 'user13',
 'passwd14': 'user14',
 'passwd15': 'user15',
 'passwd16': 'user16',
 'passwd17': 'user17',
 'passwd18': 'user18',
 'passwd19': 'user19',
 'passwd2': 'user2',
 'passwd20': 'user20',
 'passwd21': 'user21',
 'passwd22': 'user22',
 'passwd23': 'user23',
 'passwd24': 'user24',
 'passwd25': 'user25',
 'passwd26': 'user26',
 'passwd27': 'user27',
 'passwd28': 'user28',
 'passwd29': 'user29',
 'passwd3': 'user3',
 'passwd30': 'user30',
 'passwd31': 'user31',
 'passwd32': 'user32',
 'passwd33': 'user33',
 'passwd34': 'user34',
 'passwd35': 'user35',
 'passwd36': 'user36',
 'passwd37': 'user37',
 'passwd38': 'user38',
 'passwd39': 'user39',
 'passwd4': 'user4',
 'passwd40': 'user40',
 'passwd41': 'user41',
 'passwd42': 'user42',
 'passwd43': 'user43',
 'passwd44': 'user44',
 'passwd45': 'user45',
 'passwd46': 'user46',
 'passwd47': 'user47',
 'passwd48': 'user48',
 'passwd49': 'user49',
 'passwd5': 'user5',
 'passwd50': 'user50',
 'passwd51': 'user51',
 'passwd52': 'user52',
 'passwd53': 'user53',
 'passwd54': 'user54',
 'passwd55': 'user55',
 'passwd56': 'user56',
 'passwd57': 'user57',
 'passwd58': 'user58',
 'passwd59': 'user59',
 'passwd6': 'user6',
 'passwd60': 'user60',
 'passwd61': 'user61',
 'passwd62': 'user62',
 'passwd63': 'user63',
 'passwd64': 'user64',
 'passwd65': 'user65',
 'passwd66': 'user66',
 'passwd67': 'user67',
 'passwd68': 'user68',
 'passwd69': 'user69',
 'passwd7': 'user7',
 'passwd70': 'user70',
 'passwd71': 'user71',
 'passwd72': 'user72',
 'passwd73': 'user73',
 'passwd74': 'user74',
 'passwd75': 'user75',
 'passwd76': 'user76',
 'passwd77': 'user77',
 'passwd78': 'user78',
 'passwd79': 'user79',
 'passwd8': 'user8',
 'passwd80': 'user80',
 'passwd81': 'user81',
 'passwd82': 'user82',
 'passwd83': 'user83',
 'passwd84': 'user84',
 'passwd85': 'user85',
 'passwd86': 'user86',
 'passwd87': 'user87',
 'passwd88': 'user88',
 'passwd89': 'user89',
 'passwd9': 'user9',
 'passwd90': 'user90',
 'passwd91': 'user91',
 'passwd92': 'user92',
 'passwd93': 'user93',
 'passwd94': 'user94',
 'passwd95': 'user95',
 'passwd96': 'user96',
 'passwd97': 'user97',
 'passwd98': 'user98',
 'passwd99': 'user99'}
  1. 字典key值大小写计数合并 : 已知字典{‘A’:10, ‘b’:5, ‘a’:2}, 合并后为{‘a’:12, ‘b’:5}
    注意: key值最终全部为小写.
d={'A':10, 'b':5, 'a':2}
print({x.lower():d.get(x.lower(),0)+d.get(x.upper(),0) for x in d.keys()})

执行结果:
{'a': 12, 'b': 5}

生成器

定义:一边循环一边计算的机制,称为生成器:Generator。当读取一个10G的文件,如果一次性将10G的文件加载到内存处理的话(read方法),内存肯定会溢出;但使用生成器把读写交叉处理进行,比如使用(readline和readlines)就可以再循环读取的同时不断处理,这样就可以节省大量的内存空间.
生成器的特点:节省大量的内存空间、解耦. 爬虫与数据存储解耦、 可不终止调用. 写上循环, 即可循环接收数据, 对在循环之前定义的变量, 可重复使用、生成器的循环, 在 yield 处中断, 没那么占 cpu.
创建生成器方法
第一种方法: 列表生成式的改写。 []改成()

 num=(nums for nums in range(1,100))
 print(type(num))
 print(num)

执行结果:
<class 'generator'>
<generator object <genexpr> at 0x00000247784CAE48>

第二种方法: yield关键字。


#生成器创建方法2:yield关键字。 print改为yield,函数中包含yield关键字,返回值为生成器对象
def fib2(num):
    count=0
    a=b=1
    while True:
        if count<=num:
            count+=1
            yield a
            a,b=b,a+b
        else:
            break
result=fib2(100) #100以内的fib数列
print(result)

执行结果:
<generator object fib2 at 0x0000024CE7A2ADC8>

打印生成器的每一个元素的方法:
方法一:通过for循环, 依次计算并生成每一个元素。

# #访问生成器的元素1:for循环法 依次生成每一个元素
for i in result: #打印50以内的fib数列
    if i > 50:
        break
    print(i)

执行结果:
1
1
2
3
5
8
13
21
34

方法二:如果要一个一个打印出来,可以通过next()函数获得生成器的下一个返回值。

生成器小案例

聊天机器人(掌握yield工作原理和生成器的常用方法)

import requests #HTTP库 用于爬虫
import json #将python字符串转换为字典
def rebot_api(word):
    #青云提供的聊天机器人api地址
    url='http://api.qingyunke.com/api.php?key=free&appid=0&msg=%s'%(word)
    try:
        response_text=requests.get(url).text#访问url,获取网页响应内容:.text
        return json.loads(response_text).get('content','无响应')#网页返回json字符串类型内容 '{"result":0,"content":"你好,我就开心了"}',将json字符串转换为字典,并获取content的value值
    except Exception as e:
        #访问有错误,返回空
        return ''
def chatboot():
    response='' #设置一个机器人空回复
    while True:
        request=yield response #函数返回response或send接收值给request
        if '姓名' in request:
            response='not tell'
        elif '你好' in request:
            response='hello'
        else:
            response=rebot_api(request)
if __name__ == '__main__':
    rebot=chatboot() #调用函数返回生成器对象response,赋给rebot,此时生成器没有执行
    next(rebot) #执行生成器对象进而访问函数体
    while True: #设置与机器人互动的死循环
        request=input('me>>>')
        if request=='bye':
            break
        response1=rebot.send(request) #yield接收request给函数中的request,通过if判断之后将response传给yield,返回response赋给response1
        print('robot>>>',response1)


执行结果:
me>>>西安天气
robot>>> [12月21日] 西安天气:阴转晴,白天 6℃,夜晚 -2℃,东风转西南风,<3级
me>>>姓名
robot>>> not tell
me>>>bye

生产者-消费者模型

单生产者-单消费者模型中只有一个生产者和一个消费者,生产者不停地往队列 库中放入产品,消费者则从队列库中取走产品。
生产者-消费者模型有如下几个特点:
1、队列库容积有一定的限制,只能容纳一定数目的产品。
2、如果生产者生产产品的速度过快,则需要等待消费者取走产品之后,产品库 不为空才能继续往产品库中放如新的产品。
3、如果消费者取走产品的速度过快,则可能面临产品库中没有产品可使用的情 况,此时需要等待生产者放入一个产品后,消费者才能继续工作。
专业术语描述: 1、当队列元素已满的时候,阻塞插入操作; 2、当队列元素为空的时候,阻塞获取操作;
注意:python中return关键字和yield关键字的区别:
return:在程序函数中返回某个值,返回之后函数不在继续执行,彻底结束。
yield: 带有yield的函数是一个迭代器,函数返回某个值时遇到return,会停留在某个位置,返回函数值后,会在前面停留的位置继续执行,直到程序结束

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

可迭代对象:可以直接作用于for循环的对象
一类是集合数据类型,如list, tuple,dict, set,str等;
一类是generator,包括生成器和带yield的generator function。
迭代器:可以被next()函数调用并不断返回下一个值的对象:Iterator。
生成器:都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator。
把list、dict、str等Iterable变成Iterator可以使用iter()函数
生成器是迭代器(next访问)、可迭代对象(for 访问),迭代器是可迭代对象,可迭代对象使用iter()转换为迭代器。

闭包

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

#小案例 画出ax+b的图像
import matplotlib.pyplot as plt
#line_conf提供a,b值,固定x值,line求ax+b的值,line为一个闭包
def line_conf(a,b):
    def line(x):
        return a*x+b #内部函数使用了外部函数的临时变量a,b
    return line #外部函数的返回值是内部函数的调用
#line1为函数名
line1=line_conf(1,1) #将外部函数的返回值-->内部函数line赋给line1,返回a*x+b
line2=line_conf(2,1)
line3=line_conf(3,1)
#固定x的值
x=list(range(1,100,2))
y1=[line1(item)for item in x]#由x的值根据x+1求y值。line1(item):返回ax+b
y2=[line2(item)for item in x]#由x的值根据2x+1求y值
y3=[line3(item)for item in x]#由x的值根据3x+1求y值
#画折线图
plt.plot(x,y1,label='y=x+1')
plt.plot(x,y2,label='y=2x+1')
plt.plot(x,y3,label='y=3x+1')
plt.title('line display')
plt.legend()
plt.show()

在这里插入图片描述

装饰器

定义:为被装饰器对象添加额外功能的函数。照片与相框的关系。
为什么要使用装饰器:如果我们已经上线了一个项目,我们需要修改某一个方法,但是我们不想修改方法的使用方法,这个时
候可以使用装饰器。因为软件的维护应该遵循开放封闭原则,即软件一旦上线运行后,软件的维护对修改源代码是封闭的,对扩展功能指的是开放的。
装饰器的实现必须遵循两大原则:
• 封闭: 对已经实现的功能代码块封闭。 不修改被装饰对象的源代码
• 开放: 对扩展开发
装饰器其实就是在遵循以上两个原则的前提下为被装饰对象添加新功能。
实现装饰器:装饰器本质上是一个函数,该函数用来处理其他函数,它可以让其他函数在不需要修改代码的前提下增加额外的功能,装饰器的返回值也是一个函数对象。
装饰器的应用场景::插入日志、性能测试、事务处理、缓存、权限校验等应用场景。

  • 插入日志场景:
import logging
#日志的基本设置
logging.basicConfig(
    level=logging.DEBUG,#控制台打印日志的级别 warning和warning以上的级别写入日志
    filename='message.log',#日志文件位置
    filemode='a',#写入文件的模式为追加
    #日志格式
    format='%(asctime)s - %(pathname)s[line:%(lineno)d] - %(levelname)s: %(message)s'
)
from functools import wraps
def logger(func): #定义装饰器
    '''插入日志的装饰器'''
    @wraps(func) #wraps的形参func 保留func函数原有的函数名和帮助文档
    def wrapper(*args,**kargs): #闭包  args元组 kargs字典
        logging.debug('函数%s starting'%(func.__name__))#func.__name__输出函数名 logger(login) 此时func为login
        result=func(*args,**kargs) #调用函数  实参  *args,**kargs 参数解包
        logging.debug('函数%s ending'%(func.__name__))
        return result
    return wrapper
@logger #使用装饰器 login=logger(login) login函数指向logger(login)函数的返回值wrapper;python遇到语法糖直接执行
def login(name,passwd):
    if name=='root' and passwd=='redhat':
        print('login ok')
        logging.debug('%s login ok '%(name)) #生成debug类型日志,控制台级别为debug时才可以将登陆正确信息写入日志
    else:
        print(' login failed')
        logging.error('%s failed'%(name)) #生成error日志将登陆错误信息存入文件
if __name__ == '__main__':
    #实质上执行的是装饰器里面的wrapper函数
    login('root','wesat')
  • 性能测试场景:
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('函数运行时间为%.2fs'%(func.__name__,end_time-start_time))
        return result
    return wrapper
  • 事务处理场景:
from functools import wraps
import json
def json_result(func):
    @wraps(func)
    def wrapper(*args,**kwargs):
        result=func(*args,**kwargs)
        return json.dumps(result)
    return wrapper
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!