python初学之高级特性(包含练习题)

这篇博客详细介绍了Python的高级特性,包括生成式、生成器、闭包和装饰器的概念、语法和应用场景。通过实例展示了生成式的列表、集合和字典生成式,以及如何创建和使用生成器。还讨论了生成器和迭代器的关系,闭包的定义和实现,并给出装饰器的定义、实现方式和应用场景。最后,探讨了Python内置的高阶函数,如map、reduce、filter和sorted,并给出了相应的练习题和解答。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、生成式

1.什么是生成式?

答:是指快速生成对象的公式。一般包括(列表生成式,集合生成式,字典生成式)。

  1. 列表生成式:用来生成列表的特定语法形式的表达式。是Python提供的一种生成列表的简洁形式, 可快速生成一个新的list。
  2. 集合生成式:用来快速生成集合(set)。
  3. 字典生成式:用来快速生成字典(dir)。

1.列表生成式:

例如:生成100个1-50之间的随机值

1)最原始的办法:(定义列表)

import random
nums = []                    #定义一个空列表,用来装随机产生的随机数
for count in range(100):
    num = random.randint(1,50)
    nums.append(num)
print(nums)
print(len(nums))                 #可写可不写


#运行结果:
[39, 30, 30, 40, 48, 34, 39, 14, 11, 6, 47, 27, 35, 26, 6, 7, 37, 37, 18, 14, 40, 48, 4, 20, 18, 14, 4, 26, 12, 25, 12, 34, 22, 35, 45, 7, 14, 32, 47, 20, 17, 14, 14, 2, 3, 16, 40, 23, 17, 30, 44, 32, 38, 3, 28, 39, 29, 27, 34, 32, 1, 41, 39, 31, 15, 37, 33, 5, 5, 34, 50, 20, 42, 26, 2, 15, 50, 21, 26, 50, 13, 48, 13, 25, 22, 5, 19, 50, 49, 13, 17, 10, 38, 17, 9, 13, 19, 5, 31, 20]
100

2)用列表生成式:

import random
nums = [random.randint(1,50) for count in range(100)]            #列表生成式
print(nums)
print(len(nums))         #可写可不写


#运行结果:
[49, 37, 39, 9, 22, 22, 41, 40, 49, 15, 16, 38, 33, 11, 18, 14, 43, 43, 27, 50, 22, 40, 48, 5, 19, 48, 13, 25, 48, 32, 42, 39, 4, 35, 18, 48, 49, 27, 31, 10, 12, 19, 13, 42, 8, 35, 17, 17, 16, 30, 22, 46, 14, 16, 42, 25, 12, 44, 5, 45, 5, 23, 22, 45, 27, 20, 3, 49, 43, 12, 50, 40, 3, 5, 7, 32, 7, 42, 49, 45, 14, 4, 36, 47, 38, 11, 18, 29, 25, 3, 21, 33, 10, 1, 45, 37, 14, 35, 1, 21]
100

基于以上 两种方法,可以进一步生成其函数模块,可以直接调用函数的方法,如下:

1)循环方法的函数模块(def use_loop())
import random
def use_loop():           #定义use_loop()函数
    nums = []
    for count in range(100):
        num = random.randint(1,50)
        nums.append(num)
    return nums
print(use_loop())           #调用函数


#运行结果:
[6, 19, 3, 48, 5, 39, 4, 20, 48, 40, 36, 32, 31, 10, 17, 16, 40, 12, 6, 18, 4, 40, 9, 36, 1, 35, 14, 33, 6, 12, 45, 2, 40, 16, 10, 34, 21, 30, 12, 29, 40, 34, 38, 44, 32, 16, 37, 31, 15, 38, 8, 9, 31, 17, 47, 11, 37, 39, 6, 27, 11, 1, 8, 33, 32, 10, 29, 26, 25, 44, 47, 23, 36, 8, 33, 15, 36, 2, 4, 9, 41, 10, 46, 28, 13, 31, 29, 25, 40, 2, 21, 26, 27, 35, 33, 40, 10, 26, 13, 2]     

2)列表生成式的函数模块(use_list_expression())

import random
def use_list_expression():               #定义函数模块
    return [random.randint(1,50) for count in range (100)]
print(use_list_expression())            #调用函数

#运行结果:
[2, 24, 31, 21, 45, 19, 20, 38, 46, 9, 38, 14, 46, 40, 21, 31, 35, 37, 48, 5, 30, 35, 26, 35, 8, 24, 26, 5, 50, 15, 22, 49, 6, 2, 50, 28, 10, 41, 35, 25, 22, 5, 48, 38, 2, 14, 30, 35, 48, 3, 3, 48, 37, 4, 49, 20, 28, 39, 41, 28, 22, 6, 3, 29, 34, 38, 33, 50, 4, 38, 1, 4, 1, 12, 34, 41, 41, 28, 23, 20, 33, 26, 2, 40, 2, 49, 14, 17, 9, 15, 13, 34, 31, 17, 3, 36, 24, 37, 30, 46]

可见,使用生成式更加简洁,代码量也少了很多,对于以上两个函数模块,还可以进一步优化,可以使生成的数字量更加的灵活,如下:

1)循环方法的函数模块:

import random
def use_loop(count=100,start=0,end=50):
    nums = []
    for count in range(count):
        num = random.randint(start,end)
        nums.append(num)
    return nums
print(use_loop(count=10))           #调用函数,指定生成个数为10
print(use_loop(count=15))           #指定生成个数为15


#运行结果:
[45, 49, 9, 21, 10, 32, 5, 0, 36, 20]
[13, 11, 39, 34, 11, 21, 39, 10, 45, 20, 9, 4, 15, 25, 48]

2)列表生成式的函数模块:

import random
def use_list_expression(count=100,start=0,end=50):
    return [random.randint(1,50) for count in range(count)]
print(use_list_expression(count=8))
print(use_list_expression(count=14))

#运行结果:
[41, 1, 4, 5, 4, 27, 28, 23]
[28, 42, 14, 45, 35, 18, 2, 30, 14, 29, 42, 15, 20, 11]

可见,使用生成式快速又简洁,节省很多代码量。

2)集合生成式:

例如:生成100个1-200之间随机且不重复数值

import random
nums = {random.randint(1,200) for count in range(100)}    #其实就是把列表的方括号变成了花括号
print(nums)

#运行结果:
{1, 3, 5, 6, 7, 13, 14, 16, 19, 20, 22, 23, 25, 26, 27, 28, 29, 34, 38, 41, 44, 45, 46, 49, 52, 55, 57, 59, 64, 65, 67, 69, 72, 74, 75, 78, 82, 83, 87, 88, 89, 94, 95, 96, 99, 103, 110, 118, 124, 125, 128, 129, 132, 133, 138, 139, 140, 143, 144, 148, 150, 152, 156, 158, 159, 160, 162, 165, 168, 172, 173, 174, 176, 178, 184, 185, 190, 192, 194, 196, 199}

3)字典生成式:

例如:生成10个用户字典, key是用户名userx(x=1, 2, 3, ....), value是密码passwordx(x=1, 2, 3...)

import  pprint             #pprint模块只是为了打印结果更加的友好性
users_info = {'user' + str(x+1) : 'password'+ str(x+1) for x in range(10)}
pprint.pprint(users_info)


#运行结果:
{'user1': 'password1',
 'user10': 'password10',
 'user2': 'password2',
 'user3': 'password3',
 'user4': 'password4',
 'user5': 'password5',
 'user6': 'password6',
 'user7': 'password7',
 'user8': 'password8',
 'user9': 'password9'}

2、生成式语法格式

  1. 普通的语法格式:[exp for iter_var in iterable]
  2. 带过滤功能语法格式: [exp for iter_var in iterable if_exp]
  3. 循环嵌套语法格式: [exp for iter_var_A in iterable_A for iter_var_B in iterable_B

例如:这里统一用列表生成式举例说明

1)普通的语法格式:([random.randint(start,end) for count in range (count)])

如:生成任意个数<=100个,1~50之间的随机数值(如20个)

import random
def use_list_expression(count=100,start=0,end=50):
    return [random.randint(start,end) for count in range (count)]
print(use_list_expression(count=20))


#运行结果:
[13, 38, 4, 12, 43, 35, 32, 24, 47, 34, 5, 49, 30, 49, 13, 3, 17, 12, 18, 10]

2)带过滤功能的语法格式:([num for num in range(start, end + 1) if num % div_num == 0])

如:找出1-100之间能被3整除的数值

def use_list_expression(start=1, end=100, div_num=3):
    """使用列表生成式实现需求"""
    return [num for num in range(start, end + 1) if num % div_num == 0]
print(use_list_expression())
#或者:
print(use_loop(div_num=50))       (1到100之间能被50整除的数)

#运行结果:
[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]
[50]

3)循环嵌套的语法格式:([item1+ item2 for item1 in 'abc' for item2 in '123'])

如:快速生成['a1', 'a2', 'a3', 'b1', 'b2', 'b3', 'c1', 'c2', 'c3']

nums = [item1+ item2 for item1 in 'abc' for item2 in '123']
print(nums)

#运行结果:
['a1', 'a2', 'a3', 'b1', 'b2', 'b3', 'c1', 'c2', 'c3']

3、生成式练习:

1). 求以r为半径的圆的面积和周长(r的范围从1到10)。
 
import math
def circle_example():
    S = lambda r: math.pi * pow(r,2)
    C = lambda r : 2 * math.pi * r
    return [(S(r), C(r)) for r in range(1, 11)]
print(circle_example())

#运行结果:
[(3.141592653589793, 6.283185307179586), (12.566370614359172, 12.566370614359172), (28.274333882308138, 18.84955592153876), (50.26548245743669, 25.132741228718345), (78.53981633974483, 31.41592653589793), (113.09733552923255, 37.69911184307752), (153.93804002589985, 43.982297150257104), (201.06192982974676, 50.26548245743669), (254.46900494077323, 56.548667764616276), (314.1592653589793, 62.83185307179586)]

2). 找出1~100之间所有的质数。

质数:指在大于1的自然数中,除了1和该数自身外,无法被其他自然数整除的数。

def is_prime(num):
    """判断是否为质数,如果是质数,返回True,如果不是,返回False"""
    for i in range(2, num):
        if num % i == 0:
            return False
    else:
        return True

def find_prime():
    """找出1~100之间所有的质数"""
    return [num for num in range(1, 101) if is_prime(num)]

if __name__ == '__main__':
    result = find_prime()
print(result)

#运行结果:
[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]

3). 将字典的key值和value值调换。

def swap_key_value(dictObj):
    return {value: key for key, value in dictObj.items()}

if __name__ == '__main__':
    d = {
        'user1': 'passwd1',
        'user2': 'passwd2',
    }
    result = swap_key_value(d)
    print(result)

#运行结果:
{'passwd1': 'user1', 'passwd2': 'user2'}

4). 字典key值大小写计数合并 : 已知字典{'A':10, 'b':5, 'a':2}, 合并后为{'a':12, 'b':5} 注意: key值最终全部为小写.

dict = {'A':10, 'b':5, 'a':2}
d = {key.lower(): (dict.get(key.lower(), 0) + dict.get(key.upper(), 0)) for key, value in dict.items()}
print(d)

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

二、生成器  

1、什么是生成器?

答:Python,一边循环一边计算的机制,称为生成器:Generator

2、生成器应用场景?

性能限制需要用到,比如读取一个10G的文件,如果一次性将10G的文件加载到内存处理的话 (read方法),内存肯定会溢出;
 
但使用生成器把读写交叉处理进行,比如使用(readlinereadlines) 就可以在循环读取的同时不断处理,这样就可以节省大量的内存空间.
 

3、生成器的特点:

  1. 解耦. 爬虫与数据存储解耦;  
  2. 减少内存占用. 随时生产, 即时消费, 不用堆积在内存当中;
  3. 可不终止调用. 写上循环, 即可循环接收数据, 对在循环之前定义的变量,
  4. 可重复使用; 生成器的循环, yield 处中断, 没那么占 cpu.

4、如何创建生成器?

  1.  列表生成式的改写。将 [ ]改成()。
  2. 使用 yield关键字。

举例如下:

1)生成器创建方法1:将 [ ]改成()
# 列表生成式
nums = [num for num in range(1, 10001) if num % 8 == 0]
print(nums)
print(type(nums))                       #<class 'list'>

# 生成器创建方法一(将列表生成式的[]改成()就可以了)
nums_gen = (num for num in range(1, 10001) if num % 8 == 0)
print(nums_gen)                    # <generator object <genexpr> at 0x000002375E0987C8>
print(type(nums_gen))              # <class 'generator'>

#运行结果:
[8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120, 128, 136, 144, 152, 160, 168, 176, 184, 192, 200, 208, 216, 224, 232, 240, 248, 256, 264, 272, 280, 288, 296, 304, 312, 320, 328, 336, 344, 352, 360, 368, 376, 384, 392, 400, 408, 416, 424, 432, 440, 448, 456, 464, 472, 480, 488, 496, 504, 512, 520, 528, 536, 544, 552, 560, 568, 576, 584, 592, 600, 608, 616, 624, 632, 640, 648, 656, 664, 672, 680, 688, 696, 704, 712, 720, 728, 736, 744, 752, 760, 768, 776, 784, 792, 800, 808, 816, 824, 832, 840, 848, 856, 864, 872, 880, 888, 896, 904, 912, 920, 928, 936, 944, 952, 960, 968, 976, 984, 992, 1000, 1008, 1016, 1024, 1032, 1040, 1048, 1056, 1064, 1072, 1080, 1088, 1096, 1104, 1112, 1120, 1128, 1136, 1144, 1152, 1160, 1168, 1176, 1184, 1192, 1200, 1208, 1216, 1224, 1232, 1240, 1248, 1256, 1264, 1272, 1280, 1288, 1296, 1304, 1312, 1320, 1328, 1336, 1344, 1352, 1360, 1368, 1376, 1384, 1392, 1400, 1408, 1416, 1424, 1432, 1440, 1448, 1456, 1464, 1472, 1480, 1488, 1496, 1504, 1512, 1520, 1528, 1536, 1544, 1552, 1560, 1568, 1576, 1584, 1592, 1600, 1608, 1616, 1624, 1632, 1640, 1648, 1656, 1664, 1672, 1680, 1688, 1696, 1704, 1712, 1720, 1728, 1736, 1744, 1752, 1760, 1768, 1776, 1784, 1792, 1800, 1808, 1816, 1824, 1832, 1840, 1848, 1856, 1864, 1872, 1880, 1888, 1896, 1904, 1912, 1920, 1928, 1936, 1944, 1952, 1960, 1968, 1976, 1984, 1992, 2000, 2008, 2016, 2024, 2032, 2040, 2048, 2056, 2064, 2072, 2080, 2088, 2096, 2104, 2112, 2120, 2128, 2136, 2144, 2152, 2160, 2168, 2176, 2184, 2192, 2200, 2208, 2216, 2224, 2232, 2240, 2248, 2256, 2264, 2272, 2280, 2288, 2296, 2304, 2312, 2320, 2328, 2336, 2344, 2352, 2360, 2368, 2376, 2384, 2392, 2400, 2408, 2416, 2424, 2432, 2440, 2448, 2456, 2464, 2472, 2480, 2488, 2496, 2504, 2512, 2520, 2528, 2536, 2544, 2552, 2560, 2568, 2576, 2584, 2592, 2600, 2608, 2616, 2624, 2632, 2640, 2648, 2656, 2664, 2672, 2680, 2688, 2696, 2704, 2712, 2720, 2728, 2736, 2744, 2752, 2760, 2768, 2776, 2784, 2792, 2800, 2808, 2816, 2824, 2832, 2840, 2848, 2856, 2864, 2872, 2880, 2888, 2896, 2904, 2912, 2920, 2928, 2936, 2944, 2952, 2960, 2968, 2976, 2984, 2992, 3000, 3008, 3016, 3024, 3032, 3040, 3048, 3056, 3064, 3072, 3080, 3088, 3096, 3104, 3112, 3120, 3128, 3136, 3144, 3152, 3160, 3168, 3176, 3184, 3192, 3200, 3208, 3216, 3224, 3232, 3240, 3248, 3256, 3264, 3272, 3280, 3288, 3296, 3304, 3312, 3320, 3328, 3336, 3344, 3352, 3360, 3368, 3376, 3384, 3392, 3400, 3408, 3416, 3424, 3432, 3440, 3448, 3456, 3464, 3472, 3480, 3488, 3496, 3504, 3512, 3520, 3528, 3536, 3544, 3552, 3560, 3568, 3576, 3584, 3592, 3600, 3608, 3616, 3624, 3632, 3640, 3648, 3656, 3664, 3672, 3680, 3688, 3696, 3704, 3712, 3720, 3728, 3736, 3744, 3752, 3760, 3768, 3776, 3784, 3792, 3800, 3808, 3816, 3824, 3832, 3840, 3848, 3856, 3864, 3872, 3880, 3888, 3896, 3904, 3912, 3920, 3928, 3936, 3944, 3952, 3960, 3968, 3976, 3984, 3992, 4000, 4008, 4016, 4024, 4032, 4040, 4048, 4056, 4064, 4072, 4080, 4088, 4096, 4104, 4112, 4120, 4128, 4136, 4144, 4152, 4160, 4168, 4176, 4184, 4192, 4200, 4208, 4216, 4224, 4232, 4240, 4248, 4256, 4264, 4272, 4280, 4288, 4296, 4304, 4312, 4320, 4328, 4336, 4344, 4352, 4360, 4368, 4376, 4384, 4392, 4400, 4408, 4416, 4424, 4432, 4440, 4448, 4456, 4464, 4472, 4480, 4488, 4496, 4504, 4512, 4520, 4528, 4536, 4544, 4552, 4560, 4568, 4576, 4584, 4592, 4600, 4608, 4616, 4624, 4632, 4640, 4648, 4656, 4664, 4672, 4680, 4688, 4696, 4704, 4712, 4720, 4728, 4736, 4744, 4752, 4760, 4768, 4776, 4784, 4792, 4800, 4808, 4816, 4824, 4832, 4840, 4848, 4856, 4864, 4872, 4880, 4888, 4896, 4904, 4912, 4920, 4928, 4936, 4944, 4952, 4960, 4968, 4976, 4984, 4992, 5000, 5008, 5016, 5024, 5032, 5040, 5048, 5056, 5064, 5072, 5080, 5088, 5096, 5104, 5112, 5120, 5128, 5136, 5144, 5152, 5160, 5168, 5176, 5184, 5192, 5200, 5208, 5216, 5224, 5232, 5240, 5248, 5256, 5264, 5272, 5280, 5288, 5296, 5304, 5312, 5320, 5328, 5336, 5344, 5352, 5360, 5368, 5376, 5384, 5392, 5400, 5408, 5416, 5424, 5432, 5440, 5448, 5456, 5464, 5472, 5480, 5488, 5496, 5504, 5512, 5520, 5528, 5536, 5544, 5552, 5560, 5568, 5576, 5584, 5592, 5600, 5608, 5616, 5624, 5632, 5640, 5648, 5656, 5664, 5672, 5680, 5688, 5696, 5704, 5712, 5720, 5728, 5736, 5744, 5752, 5760, 5768, 5776, 5784, 5792, 5800, 5808, 5816, 5824, 5832, 5840, 5848, 5856, 5864, 5872, 5880, 5888, 5896, 5904, 5912, 5920, 5928, 5936, 5944, 5952, 5960, 5968, 5976, 5984, 5992, 6000, 6008, 6016, 6024, 6032, 6040, 6048, 6056, 6064, 6072, 6080, 6088, 6096, 6104, 6112, 6120, 6128, 6136, 6144, 6152, 6160, 6168, 6176, 6184, 6192, 6200, 6208, 6216, 6224, 6232, 6240, 6248, 6256, 6264, 6272, 6280, 6288, 6296, 6304, 6312, 6320, 6328, 6336, 6344, 6352, 6360, 6368, 6376, 6384, 6392, 6400, 6408, 6416, 6424, 6432, 6440, 6448, 6456, 6464, 6472, 6480, 6488, 6496, 6504, 6512, 6520, 6528, 6536, 6544, 6552, 6560, 6568, 6576, 6584, 6592, 6600, 6608, 6616, 6624, 6632, 6640, 6648, 6656, 6664, 6672, 6680, 6688, 6696, 6704, 6712, 6720, 6728, 6736, 6744, 6752, 6760, 6768, 6776, 6784, 6792, 6800, 6808, 6816, 6824, 6832, 6840, 6848, 6856, 6864, 6872, 6880, 6888, 6896, 6904, 6912, 6920, 6928, 6936, 6944, 6952, 6960, 6968, 6976, 6984, 6992, 7000, 7008, 7016, 7024, 7032, 7040, 7048, 7056, 7064, 7072, 7080, 7088, 7096, 7104, 7112, 7120, 7128, 7136, 7144, 7152, 7160, 7168, 7176, 7184, 7192, 7200, 7208, 7216, 7224, 7232, 7240, 7248, 7256, 7264, 7272, 7280, 7288, 7296, 7304, 7312, 7320, 7328, 7336, 7344, 7352, 7360, 7368, 7376, 7384, 7392, 7400, 7408, 7416, 7424, 7432, 7440, 7448, 7456, 7464, 7472, 7480, 7488, 7496, 7504, 7512, 7520, 7528, 7536, 7544, 7552, 7560, 7568, 7576, 7584, 7592, 7600, 7608, 7616, 7624, 7632, 7640, 7648, 7656, 7664, 7672, 7680, 7688, 7696, 7704, 7712, 7720, 7728, 7736, 7744, 7752, 7760, 7768, 7776, 7784, 7792, 7800, 7808, 7816, 7824, 7832, 7840, 7848, 7856, 7864, 7872, 7880, 7888, 7896, 7904, 7912, 7920, 7928, 7936, 7944, 7952, 7960, 7968, 7976, 7984, 7992, 8000, 8008, 8016, 8024, 8032, 8040, 8048, 8056, 8064, 8072, 8080, 8088, 8096, 8104, 8112, 8120, 8128, 8136, 8144, 8152, 8160, 8168, 8176, 8184, 8192, 8200, 8208, 8216, 8224, 8232, 8240, 8248, 8256, 8264, 8272, 8280, 8288, 8296, 8304, 8312, 8320, 8328, 8336, 8344, 8352, 8360, 8368, 8376, 8384, 8392, 8400, 8408, 8416, 8424, 8432, 8440, 8448, 8456, 8464, 8472, 8480, 8488, 8496, 8504, 8512, 8520, 8528, 8536, 8544, 8552, 8560, 8568, 8576, 8584, 8592, 8600, 8608, 8616, 8624, 8632, 8640, 8648, 8656, 8664, 8672, 8680, 8688, 8696, 8704, 8712, 8720, 8728, 8736, 8744, 8752, 8760, 8768, 8776, 8784, 8792, 8800, 8808, 8816, 8824, 8832, 8840, 8848, 8856, 8864, 8872, 8880, 8888, 8896, 8904, 8912, 8920, 8928, 8936, 8944, 8952, 8960, 8968, 8976, 8984, 8992, 9000, 9008, 9016, 9024, 9032, 9040, 9048, 9056, 9064, 9072, 9080, 9088, 9096, 9104, 9112, 9120, 9128, 9136, 9144, 9152, 9160, 9168, 9176, 9184, 9192, 9200, 9208, 9216, 9224, 9232, 9240, 9248, 9256, 9264, 9272, 9280, 9288, 9296, 9304, 9312, 9320, 9328, 9336, 9344, 9352, 9360, 9368, 9376, 9384, 9392, 9400, 9408, 9416, 9424, 9432, 9440, 9448, 9456, 9464, 9472, 9480, 9488, 9496, 9504, 9512, 9520, 9528, 9536, 9544, 9552, 9560, 9568, 9576, 9584, 9592, 9600, 9608, 9616, 9624, 9632, 9640, 9648, 9656, 9664, 9672, 9680, 9688, 9696, 9704, 9712, 9720, 9728, 9736, 9744, 9752, 9760, 9768, 9776, 9784, 9792, 9800, 9808, 9816, 9824, 9832, 9840, 9848, 9856, 9864, 9872, 9880, 9888, 9896, 9904, 9912, 9920, 9928, 9936, 9944, 9952, 9960, 9968, 9976, 9984, 9992, 10000]
<class 'list'>
<generator object <genexpr> at 0x000002375E0987C8>
<class 'generator'>

从这里就可以很直观的看出生成器的优势了, 减少了大量的内存占用。

 2)生成器创建方法2:使用 yield关键字。

#Fib数列的案例理解生成器的创建

def fib1(num):
    """递归实现Fib数列"""
    if num in (1, 2):
        return 1
    else:
        return fib1(num - 1) + fib1(num - 2)
print(fib1(15))

# 第二种方法: 函数中包含yield关键字
def fib2(num):
    """不使用递归方式实现Fib数列"""
    count = 0
    a = b = 1
    while True:
        if count < num:
            count += 1
            yield a
            a, b = b, a + b
        else:
            break
# 如果函数中有yield关键字, 那么函数的返回值是生成器对象.
result = fib2(15)
print(result)

#运行结果:
610
<generator object fib2 at 0x000002AE978E88B8>

 5、如何访问(打印)生成器的每一个元素呢?

  1. 通过for循环, 依次计算并生成每一个元素。
  2. 如果要一个一个打印出来,可以通过next()函数获得生成器的下一个返回值。

    例如:                                                                                                                                                                                                               1)通过for循环:

def fib2(num):
    """不使用递归方式实现Fib数列"""
    count = 0
    a = b = 1
    while True:
        if count < num:
            count += 1
            yield a
            a, b = b, a + b
        else:
            break
# 如果函数中有yield关键字, 那么函数的返回值是生成器对象.
result = fib2(15)
print(result)

# 访问生成器对象元素的方法一: 通过for循环, 依次计算并生成每一个元素。
for num in result:
    if num > 50:
        break
    print(num)

#运行结果:
<generator object fib2 at 0x0000020B96DD88B8>
55
89
144
233

  2)通过next()函数获得生成器的下一个返回值:

def fib2(num):
    """不使用递归方式实现Fib数列"""
    count = 0
    a = b = 1
    while True:
        if count < num:
            count += 1
            yield a
            a, b = b, a + b
        else:
            break
# 如果函数中有yield关键字, 那么函数的返回值是生成器对象.
result = fib2(100)
print(result)

# 访问生成器对象元素的方法二: 如果要一个一个打印出来,可以通过next()函数获得生成器的下一个返回值。
print(next(result))       # 执行一次next生成一个值
print(next(result))
print(next(result))        #三次next,所以只生成前三个值

#运行结果:
<generator object fib2 at 0x0000019C63A888B8>
1
1
2

6、 比较pythonreturn关键字和yield关键字的区别?

return: 遇到return, 在程序函数中返回某个值,函数到此就执行结束。后面的代码不会执行。

如:

def return_example():
	print('step 1')   #打印 'step 1'
	return True     
 	print('step 2')   # 不执行
yield: 带有yield的函数是一个迭代器,函数返回某个值时,会停留在某个位 置,
返回函数值后,会在前面停留的位置继续执行,直到程序结束。
 
如:
 
def yield_example():          
    for count in range(100):  # 3  # 7
        yield 'step' + str(count + 1)   # 4 停止  # 8 停止
        print("success")      # 6   从上次停止的地方开始执行

if __name__ == '__main__':
   result = yield_example()   # 1 
   print(next(result))        # 2 执行函数yield_example
   print(next(result))        # 5 


#运行结果:
step1
success
step2

7、生成器的send 方法:     

  • send方法和next方法唯一的区别是在执行send方法会首先把上一次挂起的yield语句的返回值通过参数设定,从而实现与生成器方法的交互。
  • 但是需要注意,在一个生成器对象没有执行next方法之前,由于没有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)
    # send方法可以给生成器传递数据, 并一直执行, 遇到yield停止。
    grep_gen.send('I love python')
    grep_gen.send('I like Java')

运行结果:

I love python

8、生成器的应用案例: 聊天机器人                                                                                                       

1)简易版的(傻瓜式机器人)

def chatRobot():
    response = ''
    while True:
        request = yield  response
        if '姓名' in request:            # 判断关键字是否在用户的输入中
            response = '姓名暂时保密'      # 如果在,将字符串赋给response,并用response来接收,打印Robot: response
        elif '你好' in request:
            response = 'hello'
        else:
            response = '我不知道你在说些什么, 请换种说法'

if __name__ == '__main__':
    Robot = chatRobot()    # 生成器对象
    next(Robot)            # 调用next方法
    while True:
        request = input("Me:  ")
        if request == '再见':
            print("欢迎下次聊天.....")
            break
        response = Robot.send(request)   #将用户输入的request传给生成器,用request来接收
        print("Robot:  ", response)

运行结果:

Me:  hello
Robot:   我不知道你在说些什么, 请换种说法
Me:  你好
Robot:   hello
Me:  年龄
Robot:   我不知道你在说些什么, 请换种说法
Me:  姓名
Robot:   姓名暂时保密
Me:  再见
欢迎下次聊天.....

   2)升级版聊天机器人

#注意:代码需要联网运行

# requests库是python实现的最简单易用的HTTP库,多用于网络爬虫。
import requests
# json库是python中实现json的序列化与反序列化的模块。
import json
def robot_api(word):
    # 青云提供的聊天机器人API地址
    url = 'http://api.qingyunke.com/api.php?key=free&appid=0&msg=%s' %(word)
    try:
        # 访问URL, 获取网页响应的内容。
        response_text = requests.get(url).text
        # 将json字符串转成字典, 并获取字典的‘content’key对应的value值
        # eg: {'result': 0, 'content': '有做广告的嫌疑,清静点别打广告行么'}
        return  json.loads(response_text).get('content', "无响应")
    except Exception as e:
        # 如果访问失败, 响应的内容为''
        return  ''
    
def chatRobot():
    response = ''
    while True:
        # yield  response: response就是生成器执行next方法或者send方法的返回值。
        # request = yield
        request = yield  response
        if '姓名' in request:
            response = '姓名暂时保密'
        elif '你好' in request:
            response = '你好!Hello'
        else:
            response = robot_api(request)

if __name__ == '__main__':
    # 生成器对象
    Robot = chatRobot()
    # 调用next方法
    next(Robot)
    while True:
        request = input("Me: >> ")
        if request == '再见':
            print("欢迎下次聊天.....")
            break
        response = Robot.send(request)
        print("Robot: >> ", response)

  运行结果:

Me: >> 你好
Robot: >>  你好!Hello
Me: >> 天气
Robot: >>  先告诉菲菲您在哪个城市,让我帮您查天气吧
Me: >> 西安天气
Robot: >>  [12月24日] 西安天气:多云转阴,白天 4℃,夜晚 0℃,东北风,<3级
Me: >> 你真漂亮
Robot: >>  {face:74}我就是人称超级可爱美少女菲菲也!
Me: >> 性别
Robot: >>  女
Me: >> 再见
欢迎下次聊天.....

三、生成器、迭代器、可迭代对象总结 (重要)

1)通俗理解:
生成式:快速生成列表,集合,字典的公式。
生成器( generator):一边循环一边计算的机制。
迭代器(iterator): 可以调用next方法访问元素的对象.
可迭代对象( Iterable): 可以实现for循环的对象

生成器都是迭代器,生成器内部实现了迭代器的协议。
生成器都是可迭代对象
可迭代对象并不都是迭代器, 比如: str,list,tuple,set,dict.
如何将可迭代对象转换成迭代器? 用iter()内置函数

2)官方一点的理解:
 
迭代是访问容器元素的一种方式。迭代器是一个可以记住遍历的位置的对象。
迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。
可迭代对象:可以直接作用于for循环的对象(如何判断是否可以迭代?)
一类是集合数据类型,listtupledictsetstr;
一类是generator,包括生成器和带yieldgenerator function
 
可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator
生成器都是Iterator对象,listdictstr虽然是Iterable,却不是Iterator
listdictstrIterable变成Iterator可以使用iter()函数
 



四、闭包 

1、定义

闭包就是指有权访问另一个函数作用域中的变量的函数。

2、如何实现闭包:

创建闭包最常见实现方式:就是在一个函数内部创建另一个函数。

3.闭包的常见形式:

(1)函数嵌套
(2)内部函数使用了外部函数的临时变量并且外部函数的返回值是内部函数的名称

闭包主要应用场景:装饰器
闭包优点:提高代码可复用性                                                                                                              

例如1):内部函数使用了外部函数的临时变量,外部函数的返回值是内部函数的名称

"""
line_conf:是外部函数
line: 是内部函数
line是一个闭包, line调用了line_conf的局部变量a和b
"""
def line_conf(a, b):
    """y = ax + b """
    def line(x):
        return a * x + b
    return line          #返回的line 是一个函数

# line1是一个函数名
line1 = line_conf(2, 3)  # 调用函数, a=2, b=3
line2 = line_conf(3, 3)  # 调用函数, a=3, b=3
line3 = line_conf(4, 3)  # 调用函数, a=4, b=3

# x = [1, 3, 5, 7 ,9]
x = list(range(1, 10, 2))
y1 = [line1(item) for item in x]
y2 = [line2(item) for item in x]
y3 = [line3(item) for item in x]

print(y1)
print(y2)
print(y3)
函数line与变量a,b构成闭包,在创建闭包的时候,通过line_conf的参数a,b说明了这两个变量的取值,这样,我们就确定了函数的最终形式

 打印结果:

[5, 9, 13, 17, 21]
[6, 12, 18, 24, 30]
[7, 15, 23, 31, 39]

扩展:用来画图:

"""
line_conf:是外部函数
line: 是内部函数
line是否为闭包? Yes, line调用了line_conf的局部变量a和b
"""
import matplotlib.pyplot as plt

def line_conf(a, b):        # a=2, b=3
    """y = ax + b """
    def line(x):
        return a * x + b
    return line

# line1是一个函数名
line1 = line_conf(2, 3)  # 调用函数, a=2, b=3
line2 = line_conf(3, 3)  # 调用函数, a=3, b=3
line3 = line_conf(4, 3)  # 调用函数, a=4, b=3

# x = [1, 3, 5, 7 .....99]
x = list(range(1, 100, 2))
y1 = [line1(item) for item in x]
y2 = [line2(item) for item in x]
y3 = [line3(item) for item in x]

#1) plot:折线图
plt.plot(x, y1, label='y=2x+3')
plt.plot(x, y2, label='y=3x+3')
plt.plot(x, y3, label='y=4x+3')

# 2)scatter: 散点图
# plt.scatter(x, y1, label='y=2x+3')
# plt.scatter(x, y2, label='y=3x+3')
# plt.scatter(x, y3, label='y=4x+3')

# 显示绘制的图形
plt.title('line display')   # 添加标题
plt.legend()                # 添加图例
plt.show()

1)折线图:

2)散点图:

用来画图只用注意导入画图模块即可:import matplotlib.pyplot as plt

五、装饰器

1、定义:

(1)首先:指的是工具,而程序中的函数就是具备某一功能的工具,所以装饰器指的是为被装饰对象添加额外功能的工具/函数

2、使用装饰器的意义(原因):

如果我们已经上线了一个项目,我们需要修改某一个方法,但是我们不想修改方法的使用方法,这个时 候可以使用装饰器。因为软件的维护应该遵循开放封闭原则,即软件一旦上线运行后,软件的维护对修改源代码是封闭的,对扩展功能指的是开放的。

3、装饰器的实现必须遵循两大原则:

  1. 封闭: 对已经实现的功能代码块封闭。 不修改被装饰对象的源代码
  2. 开放: 对扩展开发 装饰器其实就是在遵循以上两个原则的前提下为被装饰对象添加新功能。

4、如何实现装饰器?

装饰器本质上是一个函数,该函数用来处理其他函数,它可以让其他函数在不需要修改代码的前提下增加额外的功能,装饰器的返回值也是一个函数对象。

*******饰器的通用模板*******(很重要)

from functools import wraps

def function(func): #func===被装饰的函数
    @wraps(func) #保留被装饰函数的名字和帮助文档
    def wrapper(*args, **kwargs): #形参,可变参数(元组),关键字参数(字典)
        """被装饰函数前需要添加的内容"""

        result = func(*args, **kwargs) # 实参,解包
        """被装饰函数后需要添加的内容"""

        return result
    return wrapper

5、装饰器的应用场景:

装饰器经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、 权限校验等应用场景。
 
装饰器典型应用场景:
Django框架装饰器应用http://y.tsutsumi.io/dry-principles-through-python-decorators.html
 
(1)插入日志
 
#logging模块:专门做日志记录和处理
import logging
from functools import wraps

#日志的基本配置
logging.basicConfig(
    level= logging.DEBUG,     # 控制台打印的日志级别
    filename='message.log',   # 日志文件位置
    filemode='a',             # 写入文件的模式,a是追加模式,默认是追加模式
    # 日志的格式
    format='%(asctime)s - %(pathname)s[line:%(lineno)d] - %(levelname)s: %(message)s'
)

#定义装饰器
def logger(func):
    """插入日志的装饰器"""
    def wrapper(*args, **kwargs):
        logging.debug("函数%s开始执行" %(func.__name__))
        result = func(*args, **kwargs)
        logging.debug("函数%s执行结束" %(func.__name__))
        return result
    return wrapper

#使用装饰器
@logger  #语法糖 执行: login = logger(login) 将login通过logger函数进行装饰,返回wrapper
def login(username, password):
    if username == 'root' and password == '123':
        print('login ok')
        logging.debug('%s login ok' %(username))
    else:
        print('login failed')
        logging.error('%s login failed' %(username))

if __name__ == '__main__':
    login('root','123')   # 实质执行的是wrapper函数

运行结果:

LOGIN FAILED

我们查看日志文件messag.log可以看到每次运行的日志情况:如:

 (2)性能测试

比如:计算代码运行时间

from functools import  wraps
import time

def timeit(func):   # 2   func=download_music
    """打印被装饰函数运行总时间的装饰器"""
    # @wraps保留被装饰函数的函数名和帮助文档, 否则是wrapper的信息.
    @wraps(func)
    def wrapper(*args, **kwargs):   # 5     args=('Music', ), kwargs={}
        start_time = time.time()
        result = func(*args, **kwargs)  # 6 func('Music')=download_music('Music')
        end_time = time.time()
        print("%s函数运行总时间为%fs" %(func.__name__, end_time-start_time))
        return  result                  # 7
    return  wrapper     # 3

@timeit         # 1 @timeit实质上执行的内容: download_music = timeit(download_music) = wrapper
def download_music(name):   # 7
    time.sleep(0.4)
    print('[Download]: ', name)
    return  True

# 调用download_music函数时实质上调用的是wrapper函数。
download_music('Music') # 4

运行结果:

[Download]:  Music
download_music函数运行总时间为0.420078s

(3)事务处理

import pprint
import json
from functools import wraps
import string
def json_result(func):                
    """被装饰函数的返回值序列化成json格式字符串"""

    # 保留被装饰函数的函数名和帮助文档。
    @wraps(func)
    def wrapper(*args, **kwargs):      
        result = func(*args, **kwargs)  
        return json.dumps(result)             #python to json               
    return wrapper                      

@json_result                            
def get_users():                       
    return {'user' + item: 'passwd' + item for item in string.digits}

result = get_users()                   
pprint.pprint(result)                          

 运行结果:

('{"user0": "passwd0", "user1": "passwd1", "user2": "passwd2", "user3": '
 '"passwd3", "user4": "passwd4", "user5": "passwd5", "user6": "passwd6", '
 '"user7": "passwd7", "user8": "passwd8", "user9": "passwd9"}')

(4)缓存

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

from functools import lru_cache
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函数运行的时间是%fs" %(func.__name__,end_time-start_time))
        return result
    return wrapper

def fib_cache(func):
    """实现缓存的装饰器"""
    chaches = {}
    @wraps(func)
    def wrapper(num):
        if num in chaches:            #判断是否在缓存字典中
            return chaches.get(num)   #在,直接返回
        else:
            result = func(num)        #不在,计算斐波那契数列
            chaches[num]= result      #并将结果存入字典
            return result
    return wrapper

@fib_cache                            # 使用了缓存装饰器的fib函数
def fib1(num):
    if num in (1,2):
        return 1
    else:
        return fib1(num-1) + fib1(num-2)

def fib2(num):			      #没有使用缓存装饰器的fib函数
    if num in (1,2):
        return 1
    else:
        return fib2(num-1) + fib2(num-2)

@timeit                              #计算使用了缓存装饰器的函数运行的时间
def use_cache():
    result = fib1(30)
    print(result)

@timeit                             #计算没有使用缓存装饰器的函数运行的时间
def no_cache():
    result = fib2(30)
    print(result)

if __name__ == '__main__':
    use_cache()
    no_cache()

 运行结果:

832040
use_cache函数运行的时间是0.000000s
832040
no_cache函数运行的时间是0.210037s

3、多装饰器

一般情况下,在函数中可以使用一个装饰器,但是有时也会有两个或两个以上的装饰器。 多个装饰器装饰的顺序是自下而上(就近原则),而调用的顺序是自上而下(顺序执行)

from functools import wraps

#定义装饰器
def is_login(func):
    @wraps(func)
    def wrapper1(*args, **kwargs):
        print("判断用户是否登录")
        result = func(*args, **kwargs)
        return result
    return wrapper1
#定义装饰器
def is_permission(func):
    @wraps(func)
    def wrapper2(*args, **kwargs):
        print("判断用户是否有权限")
        result = func(*args, **kwargs)
        return result
    return wrapper2
"""
被装饰的过程:自下而上
(1)@is_permission: buy() = is_permission(buy()) buy()==wrapper2
(2)@is-login: buy() = is_login(buy()) 但是现在的buy()是wrapper2 ,所以 wrapper2 = is_login(wrapper2) buy==wrapper2 = wrapper1
         buy == wrapper2 == wrapper1
"""
#使用装饰器
@is_login
@is_permission
def buy():
    print("购买商品")

"""
调用的过程: 自上而下
(1)调用函数buy(),目前buy() = wrapper1,所以调用wrapper1,print("判断用户是否登录"),再执行函数func,此时传给is_login的参数func是wrapper2
(2)所以去执行wrapper2,print(判断用户是否有权限"),再执行函数func,此时传给is_permission的参数func是buy()
(3)所以执行buy()
"""
if __name__ == '__main__':
    buy()

运行结果:

判断用户是否登录
判断用户是否有权限
购买商品

典型案例:实现 权限校验+多装饰器

from functools import wraps

#系统中的用户信息数据库
db = {
    'root':{
             'name':'root',
             'password':'123',
             'is_super': 0    # 0表示没有权限
            },
    'admin':{
             'name':'admin',
             'password':'123',
             'is_super': 1   # 1表示有权限
            }
}
#存储当前登录用户的信息
login_user_info = {}

#定义装饰器
def is_login(func):
    """判断用户是否登录的装饰器"""
    @wraps(func)
    def wrapper1(*args, **kwargs):
        if login_user_info:           #判断当前登录的用户信息是否存在
            result = func(*args, **kwargs)  # 存在,执行函数buy()
            return result
        else:                         # 不存在,登录用户
            print("未登录,请先登录")
            user = input("User:")
            password = input("Passwoed:")
            if user in db:
                if db[user]['password'] == password:
                    print("登录成功")                       # 用户在用户数据库中,且密码正确,登录成功
                    login_user_info['username'] = user    # 并将用户添加到用户数据库中
                    result = func(*args, **kwargs)        # 执行被装饰函数
                    return result
                else:
                    print("密码错误")
            else:
                print("用户不存在")
    return wrapper1

def is_permission(func):
    """判断用户是否有权限的装饰器"""
    @wraps(func)
    def wrapper2(*args, **kwargs):
        print("判断用户是否有权限")
        current_user = login_user_info.get('username')   # 获取当前登录的用户名
        permission = db[current_user]['is_super']        # 获取当前用户的权限信息
        if permission == 1:                              # 如果有权限 执行函数
            result = func(*args, **kwargs)
            return result
        else:
            print("用户%s没有权限" %(current_user))
    return wrapper2

@is_login
@is_permission
def buy():
    print("购买商品....")

if __name__ == '__main__':
    buy()

运行结果:

#1)未登录,请先登录
User:浅浅
Password:20191224
登录成功
判断用户是否有权限
用户浅浅没有权限

#2)未登录,请先登录
User:cat
Password:61616
登录成功
判断用户是否有权限
购买商品....

4、有参装饰器

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

例如:

from functools import wraps

def auth(type):
    print("认证类型:",type)
    def desc(func):
        def wrapper(*args, **kwargs):
            if type == 'local':
                user = input("User:")
                password = input("Password:")
                if user == 'root' and password == '123':
                    result = func(*args, **kwargs)
                    return result
                else:
                    print("用户名/密码错误")
            else:
                print("不支持远程用户登录")
        return wrapper
    return desc

@auth('local')
def home():
    print("网站主页")

if __name__ == '__main__':
    home()

运行结果:

认证类型: local
User:浅浅
Password:1234
网站主页

需要 注意的是:@后面跟的是装饰器函数的名称, 如果不是名称, 先执行,再和@结合。

  • 1). @auth(type='local')
  • 2). desc = auth(type='local')
  • 3). @desc 4). login = desc(login)
  • 4). login = wrapper

六、内置高阶函数

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

1.什么是高阶函数?

函数作为参数传入,这样的函数称为高阶函数,函数式编程就是指这种高度抽象的编程范式。

2、高阶函数主要有哪些?

map()、reduce()、filter()、sorted()
 

1)map() 函数(map(function, *iterable)

**map() 函数会根据提供的函数对指定序列做映射。即:

  1. map的传递函数名可以是内置函数
  2. map的传递函数名可以是匿名函数
  3. map的传递函数名可以是非匿名函数
  4. map的传递的可迭代对象可以是多个

**当序列多于一个时,map可以并行(注意是并行)地对每个序列执行如下图所示的过程:
 

例如:

# 1). map的传递函数名可以是内置函数
map_object = map(int, ['1', '2', '3'])
for item in map_object:
    print(item, type(item))

# 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))  

def data_process(x):
    return x + 4

# 3). map的传递函数名可以是非匿名函数
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))

运行结果:

1 <class 'int'>
2 <class 'int'>
3 <class 'int'>
1 <class 'int'>
2 <class 'int'>
3 <class 'int'>
[1, 4, 9, 16]
[5, 6, 7, 8]
[2, 6, 12]

2)reduce() 函数(reduce(function, sequence[, initial]) -> value

reduce() 函数可以对参数序列中元素进行累积

  • 在python2中,reduce是内置高阶函数
  • 在python3中,reduce函数需要导入:from functools import reduce

 例如:

1)redue()实现累加:

from functools import reduce

nums_add = reduce(lambda x, y: x + y, list(range(1, 101)))
print(nums_add)

 运行结果:

5050

2)redue()实现阶乘:

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

运行结果:

120

3)filter() 函数 

filter() 函数用于过滤序列,过滤掉不符合条件的元素,返回由符合条件元素组成的新列表。
 
 

 例如:

1)找出1--10之间能被3整除的数:(用filter()和列表生成式实现):

# filter() 函数用于过滤序列,过滤掉不符合条件的元素,返回由符合条件元素组成的新列表。
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)

运行结果:

[3, 6, 9]
[3, 6, 9]

2)判断100以内的质数:质数是指在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数。

def is_prime(num):
    for i in range(2,num):
        if num % i == 0:
            return False
    else:
        return True
result = filter(is_prime, list(range(2, 101)))
print(list(result))

 运行结果:

[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]

4、sorted() 函数(sorted(iterable, key=None, reverse=False)

1)sorted() 函数对所有可迭代的对象进行排序操作。返回重新排序的列表。
sorted(iterable, key=None, reverse=False)
key: 主要是用来进行比较的元素,只有一个参数,
reverse: 排序规则,True 降序 ,False 升序(默认)。
 
2)python排序sort()和sorted()的区别是什么?
1. 排序对象不同: sort 是应用在 list 上的方法,sorted 可以对所有可迭代的对象进行排序操作。
2. 返回值不同:
list sort 方法返回的是对已经存在的列表进行操作,无返回值,
内建函数 sorted 方法返回的是一个新的 list,而不是在原来的基础上进行的操作。

 

例如:1)列表有sort()方法:

import random

def is_odd(x):
    """判断是否为偶数"""
    return x % 2 == 0

# 排序需求: 偶数排前面, 奇数排后面
nums = list(range(20))    #20以内的整数
random.shuffle(nums)
print("排序前: ", nums)
nums.sort(key=lambda x: 0 if is_odd(x) else 1)
print("排序后: ", nums)

运行结果:

排序前:  [15, 12, 19, 7, 18, 2, 16, 10, 1, 3, 13, 0, 6, 14, 17, 4, 9, 5, 11, 8]
排序后:  [12, 18, 2, 16, 10, 0, 6, 14, 4, 8, 15, 19, 7, 1, 3, 13, 17, 9, 5, 11]

2)sorted 可以对所有可迭代的对象进行排序操作(以集合为例)

result = sorted({2, 3, 4, 5, 1})
print(list(result))

运行结果:

[1, 2, 3, 4, 5]

七:内置高阶函数练习题:

1. 对于序列每个元素求绝对值;
思路:1)选择map()函数
           2) 绝对值:对于小于0的数乘以-1输出,对于大于等于0的数直接输出即可。
代码:
import math

def abs(x):
    if x >= 0:
        return x
    else:
        return x * -1
    
result = map(abs, [1, -2, 3, -5])
print(list(result))

 测试结果:

[1, 2, 3, 5]

2. 接收用户输入的数字 ; 依次将接收的数转换为整形

思路:python 的 input() 方法可以获取用户输入的一行内容,用 float() 来把这行内容转化成数字, 再用 int() 把小数部分丢弃掉

代码:

import sys

print('请输入数字:')
input_string = input()

try:
    number = float(input_string)
except ValueError:
    print('输入的不是数字!')
    sys.exit(0)

item = int(number)
print('转化后的数字为: %s' % item)

测试结果:

请输入数字:
3.3
转化后的数字为: 3

请输入数字:
abc
输入的不是数字!

3. 拿出1~100之间所有的素数(素数又叫质数(prime number)质数是指在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数。

思路:根据素数的定义,再用filter()函数过滤:

代码:

def is_prime(num):
    if num == 1:
        return True
    for i in range(2,num):
        if num % i == 0:
            return False
    else:
        return True

result = filter(is_prime, list(range(1,101)))
print(list(result))

测试结果:

[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]

总结: 熟练掌使用生成器和高阶函数,可以节省大量 代码空间。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值