python 生成器表达式

1.用生成器表达式初始化元组

虽然也可以用列表推导来初始化元组、数组或其他序列类型,但是生成器表达式是更好的选择。这是因为生成器表达式背后遵守了迭代器协议,可以逐个地产出元素,而不是先建立一个完整的列表,然后再把这个列表传递到某个构造函数里。前面那种方式显然能够节省内存。生成器表达式的语法跟列表推导差不多,只不过把方括号换成圆括号而已。

from collections import Iterator,Iterable
g = [i**2 for i in range(5)]
print(f"g={g}")
# g=[0, 1, 4, 9, 16]
h = (i**2 for i in range(5))
print(f"h={h}")
# h=<generator object <genexpr> at 0x7fc8d018cf50>
print(isinstance(g,Iterator))
# False
print(isinstance(g,Iterable))
# True
print(isinstance(h,Iterator))
# True
print(isinstance(h,Iterable))
# True

2. 使用生成器表达式计算笛卡儿积

colors=['white','black']
sizes=['M','S','L']
i=0
for tshirt in ('%s %s' % (c,s) for c in colors for s in sizes):
    print(f"i={i},tshirt={tshirt}")
    i+=1

# output:
# i=0,tshirt=white M
# i=1,tshirt=white S
# i=2,tshirt=white L
# i=3,tshirt=black M
# i=4,tshirt=black S
# i=5,tshirt=black L

3. 具名元组

collections.namedtuple是一个工厂函数,它可以用来构建一个带字段名的元组和一个有名字的类。这个带名字的类对调试有很大的帮助

from collections import namedtuple

# 创建一个City的具名元组类,含有name,country,population,coordinates属性
City = namedtuple('City',['name','country','population','coordinates'])

# 实例化一个tokyo具名元组,并将相关参数进行对应赋值
tokyo = City('tokyo','NY',100,(10,20))

# 通过属性名进行访问数据
tokyo_name = tokyo.name
print(f"tokyo_name={tokyo_name}")
# 通过坐标来访问数据
tokyo_1 = tokyo[1]
print(f"tokyo_1={tokyo_1}")
# _field可以查看具名元组类中所有属性段
print(f"tokyo._fields={tokyo._fields}")
# _asdict()表示以字典的形式显示namedtuple属性
print(f"tokyo._asdict()={tokyo._asdict()}")
# _replace可以改变属性中的值,产生一个新的namedtuple.不改变原来的namedtuple
print(f"tokyo_before={tokyo}")
# 新建一个namedtuple,原来的tokyo里面的元素值不变
tokyo_after = tokyo._replace(name="update_tokyo")
print(f"tokyo_after={tokyo_after}")
print(f"tokyo={tokyo}")
tokyo_name=tokyo
tokyo_1=NY
tokyo._fields=('name', 'country', 'population', 'coordinates')
tokyo._asdict()=OrderedDict([('name', 'tokyo'), ('country', 'NY'), ('population', 100), ('coordinates', (10, 20))])
tokyo_before=City(name='tokyo', country='NY', population=100, coordinates=(10, 20))
tokyo_after=City(name='update_tokyo', country='NY', population=100, coordinates=(10, 20))
tokyo=City(name='tokyo', country='NY', population=100, coordinates=(10, 20))

4. sys.argv

sys.argv是获取运行python文件的时候命令行参数

  1. 我们通过命令行创建一个a.py文件
vim a.py
  1. 在文件中输入如下代码:
import sys
# a 获取所有的命令行参数
a = sys.argv
b = len(sys.argv)
# a_1 获取命令行列表中第0位参数
a_1 = sys.argv[0]
# a_2 获取命令行列表中第1位参数
a_2 = sys.argv[1]
# a_3 获取命令行列表中最后1位参数
a_3 = sys.argv[-1]
print(f"a={a}")
print(f"a_1={a_1}")
print(f"a_2={a_2}")
print(f"a_3={a_3}")
print(f"b={b}")
  1. 命令行输入如下命令来运行 a.py
python a.py hello my friends!
  1. 得到相关结果:
    我们发现,sys.argv将我们输入的命令进行分割后保存为列表形式后赋值给 a
a=['a.py', 'hello', 'my', 'friends!']
a_1=a.py
a_2=hello
a_3=friends!
b=4

5. bisect

5.1 bisect相关函数测试

  • 代码
import bisect

# 新建一个列表list
a = [1,4,6,8,15,17,18,20]
# bisect表示的是将元素13插入到a中,返回13在a中的位置
# position为列表的序号,左边小于13,右边大于13
position = bisect.bisect(a,13)
# 我们看出来13可以插入到 a 中第 4 位置,
# 所以positon=4
print(f"position={position}")
print(f"a={a}")
# 将13按照指定的位置插入到列表list中
a.insert(position,13)
print(f"a={a}")

b = [1,4,6,8,12,15,16,20]
print(f"b={b}")
# 直接调用bisect.insort可以将13直接插入到指定的位置
# 可以保证前后列表的顺序不变
bisect.insort(b,13)
print(f"b={b}")
  • 结果
position=4
a=[1, 4, 6, 8, 15, 17, 18, 20]
a=[1, 4, 6, 8, 13, 15, 17, 18, 20]
b=[1, 4, 6, 8, 12, 15, 16, 20]
b=[1, 4, 6, 8, 12, 13, 15, 16, 20]

5.2 bisect_left,bisect_right

  • 如果列表中没有x,那么bisect_left(ls,x)和bisect_right(ls,x)返回相同的位置值,该值是x在ls中合适的插入点索引,使得数组有序,保证 ls[index2] > x,ls[index3] > x
import bisect
ls = [1,5,9,13,17]
# 7不在列表ls中,所以不管是bisect_left还是bisect_right
# 返回的索引 index 是一致的index1=index2=index3=2
# 这样当我们将7插入到ls[2]位置的时候,ls中排序也是保持不变的
index1 = bisect.bisect(ls,7)
index2 = bisect.bisect_left(ls,7)
index3 = bisect.bisect_right(ls,7)
print("index1 = {}, index2 = {}, index3 = {}".format(index1, index2, index3))
# index1 = 2, index2 = 2, index3 = 2
  • 如果列表中有x,那么就可以看出来bisect_left表示当前元素位置的左边,bisect_right表示当前元素位置的右边
import bisect
ls = [1,5,9,13,17]
# 因为 9 也在 ls 中,所以bisect_left是返回的x=9中左边的位置
# bisect_right是返回的x=9中右边的位置
# bisect=bisect_right,所以index1=3
index1 = bisect.bisect(ls,9)
# bisect_left表示x=9的左边位置,所以index2=2
index2 = bisect.bisect_left(ls,9)
# bisect_right表示右边,所以index3=3
index3 = bisect.bisect_right(ls,9)
print("index1 = {}, index2 = {}, index3 = {}".format(index1, index2, index3))
# index1 = 3, index2 = 2, index3 = 3

5.3 案例

import bisect
import sys

HAYSTACK = [1,2,4,5,6,8,12,15,20,21,23,23,26,29,30]
NEEDLES = [0,1,2,5,8,10,22,23,29,30,31]
# reversed(NEEDLES)=[31,30,29,23,22,10,8,5,2,1,0]

# 定义format格式
# {0:}   表示传入第 0 个参数 宽度为 2
# {1:}   表示传入第 1 个参数 宽度为 2 
# {2}{0:<2d}表示传入第 2 个参数,填充右边 宽度为 2
# {0:}{1:}{2}{0:}
ROW_FMT = '{0:2d} @ {1:2d}   {2}{0:<2d}'

def demo(bisect_fn):
    for needle in reversed(NEEDLES):
    	# 将needle每一个值跟列表HAYSTACK对比得到插入的位置position
        position = bisect_fn(HAYSTACK,needle)
        offset = position * '  |'
        print(ROW_FMT.format(needle,position,offset))
        
if __name__ == '__main__':
    # 如果我们用命令行的形式运行此文件并且命令行中最后输入了left
    # if True 我们就调用 bisect.bisect_left;
    # if False 我们就调用 bisect.bisect
    if sys.argv[-1]=='left':
        bisect_fn=bisect.bisect_left
    else:
        bisect_fn=bisect.bisect
    # 打印选中的抬头函数,到底是bisect_left 还是 bisect(bisect_right 默认为 bisect)
    print('DEMO:',bisect_fn.__name__)
    print('haystack->',' '.join('%2d' % n for n in HAYSTACK))
    demo(bisect_fn)
  • 结果:
/root/.local/share/jupyter/runtime/kernel-5632752f-4fed-413b-aa39-507d059d85d3.json
DEMO: bisect_right
haystack->  1  2  4  5  6  8 12 15 20 21 23 23 26 29 30
31 @ 15     |  |  |  |  |  |  |  |  |  |  |  |  |  |  |31
30 @ 15     |  |  |  |  |  |  |  |  |  |  |  |  |  |  |30
29 @ 14     |  |  |  |  |  |  |  |  |  |  |  |  |  |29
23 @ 12     |  |  |  |  |  |  |  |  |  |  |  |23
22 @ 10     |  |  |  |  |  |  |  |  |  |22
10 @  6     |  |  |  |  |  |10
 8 @  6     |  |  |  |  |  |8 
 5 @  4     |  |  |  |5 
 2 @  2     |  |2 
 1 @  1     |1 
 0 @  0   0 

6. setdefault

7. map

8. filter

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值