翻译:《实用的 Python 编程》02_06_List_comprehension - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
codists
V2EX    Python

翻译:《实用的 Python 编程》02_06_List_comprehension

  •  1
     
  •   codists
    codists 2021-02-25 14:27:50 +08:00 1564 次点击
    这是一个创建于 1694 天前的主题,其中的信息可能已经有所发展或是发生改变。

    2.6 列表推导式

    一个常见的任务是处理列表中的项(译注:元素)。本节介绍列表推导式,完成此任务的强大工具。

    创建新列表

    列表推导式通过将操作应用于序列的每一个元素来创建新列表。

    >>> a = [1, 2, 3, 4, 5] >>> b = [2*x for x in a ] >>> b [2, 4, 6, 8, 10] >>> 

    再如:

    >>> names = ['Elwood', 'Jake'] >>> a = [name.lower() for name in names] >>> a ['elwood', 'jake'] >>> 

    列表推导式的一般语法是:[ <expression> for <variable_name> in <sequence> ]

    过滤

    也可以在列表推导式中对元素进行过滤。

    >>> a = [1, -5, 4, 2, -2, 10] >>> b = [2*x for x in a if x > 0 ] >>> b [2, 8, 4, 20] >>> 

    用例

    列表推导式超级有用。例如,可以收集特定字典字段的值:

    stocknames = [s['name'] for s in stocks] 

    在序列上执行类数据库查询:

    a = [s for s in stocks if s['price'] > 100 and s['shares'] > 50 ] 

    也可以把列表推导式与序列缩减合并在一起:

    cost = sum([s['shares']*s['price'] for s in stocks]) 

    一般语法

    [ <expression> for <variable_name> in <sequence> if <condition>] 

    上面语法的含义:

    result = [] for variable_name in sequence: if condition: result.append(expression) 

    历史题外话

    列表推导式来自于数学(集合构建符号)。

    a = [ x * x for x in s if x > 0 ] # Python a = { x^2 | x ∈ s, x > 0 } # Math 

    这在其它几种语言中也实现了,虽然大部分的程序员可能已经想不起他们的数学课了。所以,可以将其视为很酷的列表快捷方式。

    练习

    首先运行 report.py 程序,以便能够在交互模式下中加载股票投资组合。

    bash % python3 -i report.py 

    现在,在 Python 交互提示符下,输入语句以执行下述操作。这些操作对投资组合数据执行各类缩减,转换和查找。

    练习 2.19:列表推导式

    尝试一些简单的列表推导式来熟悉语法:

    >>> nums = [1,2,3,4] >>> squares = [ x * x for x in nums ] >>> squares [1, 4, 9, 16] >>> twice = [ 2 * x for x in nums if x > 2 ] >>> twice [6, 8] >>> 

    请注意列表推导式是如何通过适当转换或过滤的数据创建一个新列表的。

    练习 2.20:序列缩减

    使用单个 Python 语句计算投资组合的总价。

    >>> portfolio = read_portfolio('Data/portfolio.csv') >>> cost = sum([ s['shares'] * s['price'] for s in portfolio ]) >>> cost 44671.15 >>> 

    完成后,展示如何使用单个语句计算投资组合的当前值。

    >>> value = sum([ s['shares'] * prices[s['name']] for s in portfolio ]) >>> value 28686.1 >>> 

    上面的两个操作都是映射缩减的列子。列表推导式将操作映射到整个列表。

    >>> [ s['shares'] * s['price'] for s in portfolio ] [3220.0000000000005, 4555.0, 12516.0, 10246.0, 3835.1499999999996, 3254.9999999999995, 7044.0] >>> 

    然后,sum() 函数对所有结果进行缩减。

    >>> sum(_) 44671.15 >>> 

    有了这些知识,你现在就可以准备成立一家大数据创业公司了。

    练习 2.21:数据查询

    请尝试以下各种数据查询示例。

    首选是创建一个列表,存储持有 100 股以上的股票投资组合。

    >>> more100 = [ s for s in portfolio if s['shares'] > 100 ] >>> more100 [{'price': 83.44, 'name': 'CAT', 'shares': 150}, {'price': 51.23, 'name': 'MSFT', 'shares': 200}] >>> 

    持有 MSFT 和 IBM 股票的所有投资组合。

    >>> msftibm = [ s for s in portfolio if s['name'] in {'MSFT','IBM'} ] >>> msftibm [{'price': 91.1, 'name': 'IBM', 'shares': 50}, {'price': 51.23, 'name': 'MSFT', 'shares': 200}, {'price': 65.1, 'name': 'MSFT', 'shares': 50}, {'price': 70.44, 'name': 'IBM', 'shares': 100}] >>> 

    持有总价超过 $10000 的所有股票投资组合。

    >>> cost10k = [ s for s in portfolio if s['shares'] * s['price'] > 10000 ] >>> cost10k [{'price': 83.44, 'name': 'CAT', 'shares': 150}, {'price' 51.23, 'name': 'MSFT', 'shares': 200}] >>> 

    练习 2.22:数据提取

    展示如何构建元组 (name, shares) 列表,名称(name )和 股数(shares)从股票投资组合(portfolio)中获取:

    >>> name_shares =[ (s['name'], s['shares']) for s in portfolio ] >>> name_shares [('AA', 100), ('IBM', 50), ('CAT', 150), ('MSFT', 200), ('GE', 95), ('MSFT', 50), ('IBM', 100)] >>> 

    如果将方括号([,])更改为花括号({, }),那么将得到集合推导式。这会得到独一无二的的或无重复的值。

    例如,这将确定集合中的股票名称是独一无二的:

    >>> names = { s['name'] for s in portfolio } >>> names { 'AA', 'GE', 'IBM', 'MSFT', 'CAT' } >>> 

    如果指定键值对(key:value),则可以构建一个字典。例如,构建一个将股票名称映射到持有的股票数量的字典:

    >>> holdings = { name: 0 for name in names } >>> holdings {'AA': 0, 'GE': 0, 'IBM': 0, 'MSFT': 0, 'CAT': 0} >>> 

    后面的特性就是众所皆知的字典推导式。让我们将其表格化:

    >>> for s in portfolio: holdings[s['name']] += s['shares'] >>> holdings { 'AA': 100, 'GE': 95, 'IBM': 150, 'MSFT':250, 'CAT': 150 } >>> 

    请尝试以下示例,该示例将 prices 字典过滤出仅在 portfolio 中出现的名称( name ):

    >>> portfolio_prices = { name: prices[name] for name in names } >>> portfolio_prices {'AA': 9.22, 'GE': 13.48, 'IBM': 106.28, 'MSFT': 20.89, 'CAT': 35.46} >>> 

    练习 2.23: 从 CSV 文件提取数据

    在各类数据处理中,知道如何将列表,集合,字典推导式联合使用会非常有用。这里有一个示例,展示如何从 CSV 文件中提取所选择的列。

    首先,从 CSV 文件读取一行标题信息:

    >>> import csv >>> f = open('Data/portfoliodate.csv') >>> rows = csv.reader(f) >>> headers = next(rows) >>> headers ['name', 'date', 'time', 'shares', 'price'] >>> 

    接着,定义一个变量列出实际需要的列:

    >>> select = ['name', 'shares', 'price'] >>> 

    现在,在 CSV 源文件中找到以上各列的索引。

    >>> indices = [ headers.index(colname) for colname in select ] >>> indices [0, 3, 4] >>> 

    最后,使用字典推导式读取数据的一行并把其转换为字典。

    >>> row = next(rows) >>> record = { colname: row[index] for colname, index in zip(select, indices) } # dict-comprehension >>> record {'price': '32.20', 'name': 'AA', 'shares': '100'} >>> 

    如果你对前面的操作感到满意,那么请读取文件的剩余部分:

    >>> portfolio = [ { colname: row[index] for colname, index in zip(select, indices) } for row in rows ] >>> portfolio [{'price': '91.10', 'name': 'IBM', 'shares': '50'}, {'price': '83.44', 'name': 'CAT', 'shares': '150'}, {'price': '51.23', 'name': 'MSFT', 'shares': '200'}, {'price': '40.37', 'name': 'GE', 'shares': '95'}, {'price': '65.10', 'name': 'MSFT', 'shares': '50'}, {'price': '70.44', 'name': 'IBM', 'shares': '100'}] >>> 

    天啊,已经把 read_portfolio() 函数简化为单个语句了。

    说明

    列表推导式在 Python 中常用作转换,过滤和收集数据的有效方法。由于语法的原因,请不要走极端应该让每个列表推导式尽可能简单。可以将事情分解为多个步骤。例如,不清楚你会不会把最后一个例子强加给毫不知情的同事。

    也就是说,知道如何快速处理数据是一项非常有用的技能。在很多情况下,可能必须解决某种一次性的问题,包括数据导入,导出,提取等。成为列表推导式的大师可以大大减少设计方案所花费的时间。另外,不要忘记 collections 模块。

    注:完整翻译见 https://github.com/codists/practical-python-zh

    2 条回复    2021-02-26 22:23:38 +08:00
    no1xsyzy
        1
    no1xsyzy  
       2021-02-25 15:41:27 +08:00
    sum([ *comp* ]) 可以去掉方括号变成 sum( *comp* )
    从列表推导式变为生成器推导式,节约空间( O(n) => O(1) )。

    另一点,如果推导式内有多层 for 的话需要按这个顺序写:
    [ element for vector in matrix for element in vector ]
    多个 for 的顺序与循环写法顺序一致。

    _result = []
    for vector in matrix:
       for element in vector:
        _result.append(element)
    codists
        2
    codists  
    OP
       2021-02-26 22:23:38 +08:00
    @no1xsyzy
    生成器在后面才介绍,现在还不能用。再次感谢大佬的指导。
    关于     帮助文档     自助推广系统     博客     a href="/help/api" class="dark" target="_self">API     FAQ     Solana     5253 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 34ms UTC 07:18 PVG 15:18 LAX 00:18 JFK 03:18
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86