且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Python 3 过滤器 - 错误还是功能?

更新时间:2022-10-15 18:30:30

根据 文档,Python 3.x 中的filter 返回一个迭代器,而不是2.x 版.这比预先生成整个列表更节省内存.如果您想要返回列表,可以将迭代器包装在 list() 调用中:

VALIDVALUES = list(filter(...))

或者,按照 Python 3.0 中的新功能,您可以将其重写为没有 lambda 的列表推导式:

VALIDVALUES = [x for x in [...] if re.search(r'^' + KEY + '=', x)]

Okay, I am a complete newbie to Python - and ***. I am coming from a ksh and Perl background.

The following in an interactive session with Python 2.7:


    Python 2.7.3 (default, Jan  2 2013, 16:53:07) 
    [GCC 4.7.2] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import re
    >>> KEY="REC_PAPER"
    >>> VALIDVALUES=filter(lambda x:re.search(r'^' + KEY + '=', x), [
    ... "REC_METAL=|YES|NO|",
    ... "REC_PAPER=|YES|NO|",
    ... "REC_GLASS=|YES|NO|",
    ... "REC_PLAST=|YES|NO|",
    ... "DEBUG_FLAG=|0|1|"
    ... ])  #End general list.
    >>> print(VALIDVALUES)
    ['REC_PAPER=|YES|NO|']
    >>> 

Which is what I would expect VALIDVALUES to return. However, Python 3.2's interactive session yields completely different results:


    Python 3.2.3 (default, Feb 20 2013, 17:02:41) 
    [GCC 4.7.2] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import re
    >>> KEY="REC_PAPER"
    >>> VALIDVALUES=filter(lambda x:re.search(r'^' + KEY + '=', x), [
        ... "REC_METAL=|YES|NO|",
        ... "REC_PAPER=|YES|NO|",
        ... "REC_GLASS=|YES|NO|",
        ... "REC_PLAST=|YES|NO|",
        ... "DEBUG_FLAG=|0|1|"
        ... ])  #End general list.
    >>> print(VALIDVALUES)
    &ltfilter object at 0xb734268c>
    >>> 

I have seen in several places (including ***) where Python's equivalent of Perl's grep against a list is to filter the list. That appeared to work in Python 2. However, assuming the above behaviour in Python 3 is "correct," that no longer seems to be the case.

First question: Is the above beahviour a bug or feature in Python 3?

Second question: Assuming it is a feature, how do I get the output that Python 2 was giving? For reasons I won't go into, I want to stay away from defining a function or subroutine, and do it "inline" like the current code.

Am I missing something obvious (quite possible for a newbie)? Thanks in advance.

As per the documentation, filter in Python 3.x returns an iterator, rather than a list as in version 2.x. This is more memory-efficient than generating the whole list up-front. If you want the list back, you can wrap the iterator in a list() call:

VALIDVALUES = list(filter(...))

Alternatively, and as recommended by What’s New In Python 3.0, you could rewrite it as a list comprehension without a lambda:

VALIDVALUES = [x for x in [...] if re.search(r'^' + KEY + '=', x)]