文档章节

Python中的 List Comprehension 以及 Generator

小致dad
 小致dad
发布于 2016/07/20 17:57
字数 989
阅读 12
收藏 0

11行代码就写出了一个配置文件的解析器。

def loadUserInfo(fileName):
    userinfo = {}
    file = open(fileName, "r")
    while file:
        line = file.readline()
        if len(line) == 0:
            break
        if line.startswith('#'):
            continue
        key, value = line.split("=")
        userinfo[key.strip()] = value.strip()

  return userinfo

最近正在跟同事学习python在数据挖掘中的应用,又专门学习了一下python本身,然后用list comprehension简化了以下上面的代码:

def loadUserInfo(file):
    return dict([line.strip().split("=")
        for line in open(file, "r")
            if len(line) > 0 and not line.startswith("#")])

这个函数和上面的函数的功能一样,都是读取一个指定的key=value格式的文件,然后构建出来一个映射(当然,在Python中叫做字典)对象,该函数还会跳过空行和#开头的行。

比如,我想要查看一下.wgetrc配置文件:

if __name__ == "__main__":
    print(loadUserInfo("/Users/jtqiu/.wgetrc"))

假设我的.wgetrc文件配置如下:

http-proxy=10.18.0.254:3128
ftp-proxy=10.18.0.254:3128
#http_proxy=10.1.1.28:3128
use_proxy=yes

则上面的函数会产生这样的输出:

{'use_proxy': 'yes', 'ftp-proxy': '10.18.0.254:3128', 'http-proxy': '10.18.0.254:3128'}

list comprehension(列表推导式)

在python中,list comprehension(或译为列表推导式)可以很容易的从一个列表生成另外一个列表,从而完成诸如mapfilter等的动作,比如:

要把一个字符串数组中的每个字符串都变成大写:

names = ["john", "jack", "sean"]

result = []
for name in names:
    result.append(name.upper())

如果用列表推导式,只需要一行:

[name.upper() for name in names]

结果都是一样:

['JOHN', 'JACK', 'SEAN']

另外一个例子,如果想要过滤出一个数字列表中的所有偶数:

numbers = [1, 2, 3, 4, 5, 6]

result = []
for number in numbers:
    if number % 2 == 0:
        result.append(number)

如果写成列表推导式:

[x for x in numbers if x%2 == 0]

结果也是一样:

[2, 4, 6]

显然,列表推导更加短小,也更加表意。

迭代器

在了解generator之前,我们先来看一个迭代器的概念。有时候我们不需要将整个列表都放在内存中,特别是当列表的尺寸比较大的时候。

比如我们定义一个函数,它会返回一个连续的整数的列表:

def myrange(n):
    num, nums = 0, []
    while num < n:
        nums.append(num)
        num += 1
    return nums

当我们计算诸如myrange(50)或者myrange(100)时,不会有任何问题,但是当获取诸如myrange(10000000000)的时候,由于这个函数的内部会将数字保存在一个临时的列表中,因此会有很多的内存占用。

因此在python有了迭代器的概念:

class myrange(object):
    def __init__(self, n):
        self.i = 0
        self.n = n

    def __iter__(self):
        return self

    # for python 3
    def __next__(self):
        return self.next()

    def next(self):
        if self.i < self.n:
            i = self.i
            self.i += 1
            return i
        else:
            raise StopIteration()

这个对象其实实现了两个特殊的方法:__iter__(对于python3来说,是__next__)和next方法。其中next每次只返回一个值,如果迭代已经结束,就抛出一个StopIteration的异常。实现了这两个方法的类都可以算作是一个迭代器,他们可以被用于可迭代的上下文中,比如:

>>> from myrange import myrange
>>> x = myrange(10)
>>> x.next()
0
>>> x.next()
1
>>> x.next()
2

但是可以看到这个函数中有很多的样板代码,因此我们有了生成器表达式来简化这个过程:

def myrange(n):
    num = 0
    while num < n:
        yield num
        num += 1

注意此处的yield关键字,每次使用next来调用这个函数时都会求值一次num并返回,具体的细节可以参考这里。

区别

简单来说,两者都可以在迭代器上下文中使用,看起来几乎是一样的。不同的地方是generator可以节省内存空间,从而提高执行速度。generator更适合一次性的列表处理,比如只是需要一个中间列表作为转换。而列表推导则更适合要将列表保存下来,以备后续使用的场景。

这里也有一些讨论,可以一并参看。

参考

  1. Iterators & Generators
  2. Generators Wiki

© 著作权归作者所有

小致dad

小致dad

粉丝 165
博文 543
码字总数 584211
作品 0
济南
技术主管
私信 提问
Python中yield的理解和用法

【简单总结】 generator(生成器) 是一次性的iterator(迭代器,例如:list、string、files),但只能遍历迭代一次。好处是,只在迭代(调用)的时候占用临时内存,每一次迭代完成之后,下一...

Goopand
01/18
0
0
notes on python

iterator Behind the scenes, the for statement calls iter() on the container object. The function returns an iterator object that defines the method next() which accesses element......

leo-H
2014/12/20
0
0
Python Tips, Tricks, and Hacks

一、快速技巧 1.1、4 种引号 ' ''' " """ print """I wish that I'd never heard him say, '''She said, "He said, 'Give me five dollars'"'''""" 1.2、对象/变量的真与假 my_object ...

大数据之路
2013/07/23
0
0
一些Python的惯用法和小技巧:Pythonic

Pythonic其实是个模糊的含义,没有确定的解释。网上也没有过多关于Pythonic的说明,我个人的理解是更加Python,更符合Python的行为习惯。本文主要是说明一些Python的惯用法和小技巧,其实与上...

熟悉的防守
2016/03/29
26
0
Python 递推式构造列表(List Comprehensions)

你需要构造一个新的列表,列表中的元素是从一个已知列表中的元素计算而得到的. 比如你要创建一个列表,里面的元素是另一个列表中的元素加23后得到的.使用递推式构造列表是最理想的方法: thene...

阿豪boy
2017/11/19
0
0

没有更多内容

加载失败,请刷新页面

加载更多

利用mybatis generator生成实体类、Mapper接口以及对应的XML文件

项目中通常会遇到数据的持久化,如果是采用mybatis的orm,就会涉及到生成xml的问题,刚好mybatis官网提供了这么个插件MyBatis Generator,效果简直是棒呆。 1. 首先需要在build.gradle文件中...

啊哈关关
今天
2
0
SpringSocial相关的知识点

使用SprigSocial开发第三方登录 核心类 ServiceProvider(AbstractOauth2ServiceProvider):主要负责实现server提供商(例如QQ,微信等共有的东西),默认实现类是AbstractOauth2ServiceProvider...

chendom
今天
2
0
Java并发之AQS详解

一、概述   谈到并发,不得不谈ReentrantLock;而谈到ReentrantLock,不得不谈AbstractQueuedSynchronizer(AQS)!   类如其名,抽象的队列式的同步器,AQS定义了一套多线程访问共享资源...

群星纪元
昨天
2
0
Fabric-sdk-java最新教程

Fabric Java SDK是Fabric区块链官方提供的用于Java应用开发的SDK,全称为Fabric-sdk-java,网上可用资料不多,本文列出了精心整理的针对Fabric Java SDK的最新精选教程。 如果希望快速掌握F...

汇智网教程
昨天
3
0
react 子组件监听props 变化

componentWillReceiveProps //已经被废弃 getDerivedStateFromProps// 推荐使用//如果条件不存在必须要返回null static getDerivedStateFromProps(props, current_stat...

一箭落旄头
昨天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部