【问题标题】:Understanding this Python code from 2014's new year challenge从 2014 年的新年挑战中理解这个 Python 代码
【发布时间】:2015-01-01 05:21:44
【问题描述】:

我刚刚浏览了这个页面 here 并找到了这个条目:

print sum(ord(c) for c in 'Happy new year to you!')

它是 python 代码,执行时打印 2014。有人可以帮助 Java 开发人员准确了解这里发生了什么吗?

【问题讨论】:

  • 现在我知道为什么人们似乎对此重新产生了兴趣。此外,@Frg 想出了如何在 2015 年更新它。“祝你新年快乐!”
  • 作为 Java 开发人员,您可能也会喜欢这个:stackoverflow.com/questions/10363927/…

标签: python


【解决方案1】:

需要了解的几点:

  • 默认情况下,字符串是可迭代的,因此可以简单地迭代字符串中的每个元素:

    for c in 'Hello there':
        print c
    
  • ord 是一个内置函数,可返回字符的实际数字代码点。

  • 表达式ord(c) for c in 'Happy new year to you!'generator expression。此结果返回一个生成器函数,该函数在随后调用__next__() 时检索整个生成器表达式的结果。这既发生在我们的幕后,又以一种懒惰的方式完成;如果未调用 __next__() 片段,则不会生成下一个值。如果您要生成的表达式包含 很多 个值,这将非常有用。

    这其实是sn-p代码的症结所在;它表达了一些必须以更简洁的方式用 Java 更笨拙地编写的东西。

  • sum 将列表作为参数并返回其内容的总数值。

【讨论】:

    【解决方案2】:
    int s = 0;
    
    for (char c: "Happy new year to you!".toCharArray())
      s += (int) c;
    
    System.out.println(s);
    

    【讨论】:

    • 你没有new String,你知道的。你让我担心了一会儿。
    • plusOne。一定要喜欢转换:)
    • @Makoto:耸耸肩我的 Java 有点生疏了。
    【解决方案3】:

    ord() 将字符转换为其 ASCII 值。 sum() 将定义了加法运算的对象集合相加,在这种情况下为数学标量加法。

    sum() 中的表达式是生成器表达式,这是一种可迭代语句,在 Java 中没有明确的等效项,但类似于 .NET 中的 LINQ。本质上,它是一个内联的 for-each 循环,循环遍历字符串“Happy new year to you!”中的每个字符,用ord 计算字符的 ASCII 值,并将这些数值相加。

    【讨论】:

      【解决方案4】:

      1) 内置函数ord返回char的整数值。

      >>> help(ord)
      Help on built-in function ord in module __builtin__:
      
      ord(...)
          ord(c) -> integer
      
          Return the integer ordinal of a one-character string.
      

      2) for 循环对字符串'Happy new year to you!'的每个字符进行迭代

      >>> for c in 'Happy new year to you':
      ...     print ord(c)
      ...
      72
      97
      112
      112
      ...
      

      3) (ord(c) for c in 'Happy new year to you!') 是 python 中的 generator 表达式。

      >>> result = (ord(c) for c in 'Happy new year to you!')
      >>> result.next()
      72
      >>> result.next()
      97
      

      4) sum 内置函数返回每个字符的整数值的总和:

      >>> help(sum)
      Help on built-in function sum in module __builtin__:
      
      sum(...)
          sum(sequence[, start]) -> value
      
          Returns the sum of a sequence of numbers (NOT strings) plus the value
          of parameter 'start' (which defaults to 0).  When the sequence is
          empty, returns start.
      

      所以组合所有这些表达式的结果是:

      >>> sum(ord(c) for c in 'Happy new year to you!')
      2014
      

      另一种可能的解决方案是:

      >>> sum(map(lambda c:ord(c), 'Happy new year to you!'))
      2014
      

      【讨论】:

        【解决方案5】:

        print 是一个语句(在 Python 2.x 中),它将打印它后面的表达式。

        (请注意,在 Python 3.x 中,print() 是一个打印其参数的函数。)

        表达式是对内置函数sum() 的调用。不管是什么总和,结果都是 2014,所以print 打印出2014

        sum() 正在传递一个称为“生成器表达式”的特殊构造。这类似于“列表理解”,但效率更高。 [1]生成器表达式的基本格式是:

        iterable变量

        表达式

        这里,变量citerable 是一个字符串,'Happy new year to you!' expression 是对内置函数 ord() 的调用,它返回一个整数,表示它传递的字符;例如,ord('A') 返回65

        所以,这将字符串中所有字符的序数值相加;总和是 2014 年并打印出来。

        [1] 列表推导式构建一个值列表。生成器表达式不构建任何内容,但可以重复调用以一次生成一个值。 Python 中接受迭代的函数能够接受生成器表达式并从中获取值。

        您可以使用生成器表达式编写此代码以构建一个列表,然后对列表求和。但如果你这样做,列表将被构建,查看一次,然后进行垃圾收集。当您只想对值求和时,为什么要浪费精力分配和销毁列表对象?因此,生成器表达式。

        【讨论】:

          【解决方案6】:

          在这段代码 sn-p 中找到并被“裸”( ) 包围的形式的表达式称为生成器推导。它产生一种特定类型的迭代,称为 Python 中的生成器。

          还有其他类型的理解。被裸括号包围的表达式将是一个列表推导。示例:

          [char for char in "string"] 
          

          这将产生一个列表:

          ['s','t','r','i','n','g']
          

          而“裸”大括号(又名集合推导式)产生一个集合:

          {char for char in "string"} 
          

          这使得集合:

          {'s','t','r','i','n','g'}
          

          (也有字典推导式。)

          正如我一开始所说,在这种something for something in something_else 形式的语句周围只使用括号会产生一种特殊的迭代器,称为 Python 中的生成器(而不是像上面的示例那样的列表或集合) .

          然而,在 Python 中,很多其他的东西都是可迭代的,包括字符串。在生成器内部,每个字符在字符串被迭代时被检索,一次一个,因为它被依次调用,st,...等等。检索到的字符然后是引用的对象char 用于该迭代。

          ord(char) 部分将ord 函数依次应用于每个char,因为字符串被迭代。 ord 函数只是查找从字符串中检索到的特定字符的 unicode 编号。然后,该 unicode 值是当前迭代的整体生成器的结果。

          要从生成器中获取值,您必须以某种方式对其进行迭代 - 例如使用 next()for...in 语句。但通常您也可以将生成器作为参数应用到任何接收可迭代参数的函数。在这种情况下,sum()(这显然是为了将一系列连续的参数添加在一起)被应用于生成器的所有结果。生成器的每个产生的结果都是系列的成员。

          所以代码的整体效果是将字符串字符的所有 unicode 值加在一起。 2014 年的总体结果似乎只是巧合。那里没有发生任何神秘或神奇的事情。

          【讨论】:

          • 你对理解的解释很奇怪而且令人困惑。我不知道您所说的“裸”括号或方括号是什么意思。对于任何对解释感到困惑的人,这里是对列表推导和生成器表达式的一个很好的参考:docs.python.org/2/howto/… 我还想说你有迭代器和生成器:生成器是一种迭代器,但你不能真的说迭代器是“又名”生成器。至于 2014 年的结果,我猜是有人小心翼翼地把这句话弄出来了。
          • 我的意思是,2014 年特定消息的出现纯属巧合。我敢肯定有人故意把它放在一起。感谢 cmets。
          • 在重读我的回答后,我同意这令人困惑。我这里的术语错误。我想我在 3 周内学到了很多东西。
          • 我没有对你投反对票,但有人投了反对票。您可能只想删除答案,从而消除反对票。我们一直在这里学习(当然包括我),您可以回答更多问题。三个星期吧?欢迎使用 StackOverflow!
          • 不,已经完成了。我尝试修复它。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-01-21
          • 1970-01-01
          • 1970-01-01
          • 2020-12-07
          • 1970-01-01
          相关资源
          最近更新 更多