【问题标题】:Python loop of strings - why the 'none' comes?字符串的 Python 循环 - 为什么会出现“无”?
【发布时间】:2016-12-09 03:44:13
【问题描述】:

我在使用 python 循环时有一个奇怪的问题。这对我来说可能很容易但很奇怪。假设我有一个字符串列表:

seqs=['AA', 'AT']

然后我想打印出列表中的元素。一种方式(方法一)是使用for循环:

for seq in seqs:
    print seq

效果很好。同时,我定义了一个'print'函数(方法2)来打印:

def print0(s):
    print s

[print0(s) for s in seqs]

如果我使用 'print0' 函数打印出值,输出如下:

AA
AT
[None, None]

我想知道为什么这里有两个“无”值,因为当我使用方法 1 时这两个值没有出现?我想通过使用并行技术来执行 for 循环,但是使用 'None' 值,joblib 包中的 delayed 函数无法工作。谢谢。 更新:如果我想并行:

Parallel(n_jobs=2)(delayed(print0)(seq) for seq in seqs)

它会给出一个错误信息:

TypeError: expected string or Unicode object, NoneType found

【问题讨论】:

  • ...因为你不返回任何东西...
  • 两个 sn-ps 在语义上是不同的:一个只是带有 print 语句的 for 循环,而另一个是使用不返回任何内容(无)的函数创建具有列表理解的列表跨度>
  • 除了答案中提出的内容之外,如果您不想看到Nones,请丢弃表达式的值:_=[print0(s) for s in seqs]

标签: python for-loop parallels


【解决方案1】:

由于您使用的是交互式解释器,默认情况下会为返回到顶层的任何对象打印repr(),您会看到None 对象的列表,这是从您的@987654323 调用中返回的@ 功能。这就是为什么仅仅为了它的副作用而创建一个列表不是一个好习惯,除了所有这些对象都存储在内存中的事实(尽管只有一个 None 对象,并且该列表将被垃圾收集为只要您将其他内容返回到顶层 - 在此之前,它会存储在特殊变量 _) 中。

您将了解解释器如何显示返回到顶层的任何对象的repr()

>>> 'hello'
'hello'

显示以下文字列表是有意义的:

>>> [print()]

[None]

理解也一样:

>>> [print(num) for num in range(3)]
0
1
2
[None, None, None]

但最好使用普通循环。单线很有趣,但并不总是理想的。

>>> for num in range(3):
...     print(num)
...
0
1
2

请注意,如果函数打印一件事并返回另一件事,您可能会得到奇怪的结果:

>>> def f():
...     print(1)
...     return 2
...
>>> [f() for num in range(3)]
1
1
1
[2, 2, 2]
>>> for num in range(3):
...     f()
...
1
2
1
2
1
2

这是“副作用”的演示。尽量避免同时在两个不同位置进行更改的代码(在这种情况下,交互式解释器的显示结果和函数的本地操作)。

【讨论】:

  • None 不是单例,正如你所说,所以我不明白你关于列表/内存占用的观点。
  • 这是一个很好的答案,因为它很深入,但它无法消除发帖者的任何困惑。我认为他们对垃圾收集或良好的列表做法不感兴趣。
  • @CharlesAddis - 如果他们使用返回一些他们不感兴趣的非单例数据的函数,那将使用 O(n) 内存。当您不关心结果时,这只是编写正确循环而不是理解的另一个原因。
  • @BrandonIbbotson - 我添加了更多解释。
  • 删除了反对票,因为答案已经过编辑并且是一个很好的答案......但即使返回字符串或整数列表,内存占用也不是 O(n) - 请检查for _ in comprehension: print id(_) 的输出——你会看到字符串被保留,python 只存储每个唯一整数的一个实例 @TigerhawkT3
【解决方案2】:

[print0(s) for s in seqs] 的语法是 List Comprehension

它将为seq 中的每个元素调用print0(s) 并将结果放入列表中。因为print0 没有返回任何内容,所以您会得到一个包含 2 个Nones 的列表。

【讨论】:

    【解决方案3】:

    我经常看到这样的问题,应该有一些最终答案,只要printNone都出现在一个问题中,就会自动触发...... p>

    虽然问题本身的答案很简单,但我认为您需要真正理解的是side effect返回值 之间的区别。例如:

    a = 10
    def three(x):
        global a
        a += x #side effect
        print x #side effect
        return 3 #returning
    

    我们的three()函数返回的值是3。它还有两个副作用:修改一个全局变量a和打印。这些被称为副作用,因为它们修改了函数之外的东西:分别是a 变量和屏幕状态。

    在你的例子中:

    def print0(s):
        print s
    

    没有明确的返回值,只有副作用(打印)。换句话说,它会在屏幕上打印一些东西,然后什么都不返回nothing 在 Python 中称为 None。如果你这样称呼它:

    a = print0(3)
    

    它将 3 打印到控制台中。但是a现在的价值是多少?

    >>> print a
    None
    

    现在到列表理解。它是从函数式编程(Lisp 等)中借用的概念,称为map。 Python中还有map函数,所以下面两行是等价的:

    [print0(s) for s in seqs]
    map(print0, seqs)
    

    他们所做的是一个接一个地获取输入列表 (seqs) 的元素,将函数 (print0) 应用于每个元素,并将结果(返回值)一个接一个地放入,到他们返回的输出列表中。每次他们调用您的print0 函数时,它都会在屏幕上打印其参数s(副作用),然后什么都不返回(None),通过列表理解或map 将其放入输出列表中。如果您在 Python 交互式控制台中执行此操作,则该结果将出现在输出 ([None, None]) 中,否则 - 它仍由解释器生成并立即丢弃,除非您将其作为参数传递给另一个语句。这将我们引向您的最后一行代码和TypeError 消息。您将函数传递给另一个函数,该函数需要一个字符串,它并不关心您的函数可能产生的副作用。上下文对我来说并不完全清楚,但您可能应该像这样定义您的函数:

    def print0(s):
        return str(s)
    

    现在,不是在屏幕上打印s,而是将其转换为string,然后返回它。请注意,如果您像 print0(s) 那样在交互式解释器中调用它们,它们似乎会产生相同的效果,这可能会造成混淆。但是,如果您执行a = print0(s),您会发现a 是不同的。在某些语言中,最后计算的值会自动成为返回值,但在 Python 中,常规函数并非如此:

    def times_three(x):
        x*3
    

    返回None。但是,也有 lambda 函数, 就是这种情况:

    times_three = lambda x: x*3
    times_three(5) #returns 15
    

    【讨论】:

      【解决方案4】:

      Noneprint0(s) 的返回值。使用 print 时,结果将仅显示在标准输出中,但不会作为函数的结果返回。所以理解列表将函数评估为None。 你的功能应该是:

      def print0(s):
          return s
      

      【讨论】:

        【解决方案5】:

        另一种方式,如果您想在单行中以交互方式进行操作,请使用.join

        text = ['28', '43', '6f', '72', '65', '20', '64', '6f', '6d', '70', '65', '64', '29', '0a']
        
        ''.join(chr(int(x, 16)) for x in text)
        

        【讨论】:

          猜你喜欢
          • 2017-01-31
          • 1970-01-01
          • 1970-01-01
          • 2018-11-06
          • 1970-01-01
          • 2016-08-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多