【问题标题】:Getting a Generator Object returned when I want the data当我想要数据时返回一个生成器对象
【发布时间】:2016-10-13 00:12:36
【问题描述】:

我对 Python 3 非常陌生,所以请善待。

我已经查看了我能找到的所有相关文档 - 似乎确实有很多,只是我仍然不知道该怎么做。

这是我的代码:

poly = [[36606.0,53223.0],[37332.0,52224.0],[39043.0,53223.0],
[41603.0,53223.0],[42657.0,53278.0],[43123.0,52060.0],
[44054.0,51156.0],[45806.0,51498.0],[46751.0,53237.0],
[46983.0,54606.0],[45861.0,57057.0],[44971.0,58836.0],
[44054.0,60616.0],[43451.0,58138.0],[41850.0,59179.0],
[40850.0,60370.0],[39906.0,59233.0],[38674.0,59179.0],
[35566.0,56249.0],[37592.0,57536.0]]

def perimeter():
     return (sum((abs((x1 - x0)**2)+abs((y1 - y0)**2))**.5)
                        for ((x0, y0), (x1, y1)) in parts1(poly))

def parts1(poly):
    return poly[0:] + [poly[0]]

print(perimeter())

它正在运行 没有任何错误,但我得到了以下结果:

generator object perimeter.locals.genexpr at 0x7f47d8671c50

我怎样才能让它给我价值/答案? 我真的不知道发生了什么。

【问题讨论】:

  • 我假设您所追求的值/答案是多边形的周长?
  • 提示:find a text editor 了解 Python 语法并具有 brace matching。使用这样的编辑器将帮助您在以后避免此错误。
  • 题外话:取abs()(x1 - x0)**2 是不必要的,因为它总是会产生一个正值(即使(x1 - x0) 是负值)。
  • 我得到了我的答案,吐出 41095.327,忘记通过匹配最后一个点与第一个点来关闭形状

标签: python python-3.x generator


【解决方案1】:

item for item in iterable 构造在括号中使其成为惰性生成器表达式,具有您所看到的外观。现在,它这样做而不是给你一个错误,你会因为尝试向sum() 发送不可迭代而得到的原因是因为它不评估任何东西。如果您将此生成器表达式发送到 list() 以对其进行评估,则会收到错误消息。

你需要移动一些括号:

sum((abs((x1 - x0)**2)+abs((y1 - y0)**2))**.5
                        for ((x0, y0), (x1, y1)) in parts1(poly))

现在你有 sum(expression for element in parts1(poly)) 而不是 (sum(expression) for element in parts1(poly))

小测试:

>>> x1, x0, y1, y0 = 3, 1, 5, 4
>>> sum((abs((x1 - x0)**2)+abs((y1 - y0)**2))**.5
...     for ((x0, y0), (x1, y1)) in [((x0,y0), (x1, y1))])
2.23606797749979

【讨论】:

  • 感谢您的快速回复!
  • TypeError: 'float' object is not iterable
【解决方案2】:

第一个问题是括号放错了地方。您想在生成器表达式上调用sum(),但您已经使用sum() 编写了生成器表达式。所以你可以试试这个:

def perimeter():
    return sum(((x1 - x0) ** 2) + ((y1 - y0) ** 2) ** .5
                 for (x0, y0), (x1, y1) in parts1(poly))

(我还删除了您的abs() 电话,因为对数字进行平方会使其为正数,使abs() 无关紧要,并删除了一些不必要的括号。)

但这仍然不起作用:现在你得到'float' object is not iterable

这是因为您试图从列表的每个元素中解压缩四个值,但每个元素只包含两个。 Python 将每个元素解压缩为两个浮点数,然后尝试将每个浮点数解压缩为两个变量。这就是错误消息出现的地方。

因此您需要更改parts1() 以返回列表列表列表的列表。也就是说,列表中的每一项都是一个列表,其中包含两个列表,每个列表都包含一个点(给定点及其后继点)的坐标。一种方法是使用内置的 zip() 函数和列表的偏移或旋转副本。

def parts1(poly):
    return zip(poly, poly[1:] + poly[:1])

最后,您实际上并不需要单独的函数parts1()——它可以直接放在perimeter() 函数中。你应该将poly 传递给perimeter()

def perimeter(poly):
    return sum(((x1 - x0) ** 2) + ((y1 - y0) ** 2) ** .5
                 for (x0, y0), (x1, y1) in zip(poly, poly[1:] + poly[:1]))

您可以通过遍历poly 中的坐标并跟踪您看到的最后一个项目来完成此操作,而无需额外的列表副本。但是你不能把它写成生成器表达式。相反,您将使用常规的 for 循环。

def perimeter(poly):
    x0, y0 = poly[-1][0], poly[-1][1]
    per = 0.0
    for x1, y1 in poly:
        per += ((x1 - x0) ** 2) + ((y1 - y0) ** 2) ** .5
        x0, y0 = x1, y1
    return per 

没有那么简洁,也没有那么快,但不会占用太多内存。

【讨论】:

    【解决方案3】:

    您的代码有两个问题。一个是由于@TigerhawkT3 指出的括号,另一个是你没有正确地遍历这些点。下面的代码解决了这两个问题。

    poly = [[36606.0,53223.0],[37332.0,52224.0],[39043.0,53223.0],
            [41603.0,53223.0],[42657.0,53278.0],[43123.0,52060.0],
            [44054.0,51156.0],[45806.0,51498.0],[46751.0,53237.0],
            [46983.0,54606.0],[45861.0,57057.0],[44971.0,58836.0],
            [44054.0,60616.0],[43451.0,58138.0],[41850.0,59179.0],
            [40850.0,60370.0],[39906.0,59233.0],[38674.0,59179.0],
            [35566.0,56249.0],[37592.0,57536.0]]
    
    def pairwise(iterable):
        "s -> (s0,s1), (s1,s2), (s2, s3), ..."
        a, b = iter(iterable), iter(iterable)
        next(b, None)
        return zip(a, b)
    
    def parts1(poly):
        return poly[0:] + [poly[0]]
    
    def perimeter():
        return sum((abs((x1 - x0)**2)+abs((y1 - y0)**2))**.5
                        for ((x0, y0), (x1, y1)) in pairwise(parts1(poly)))
    
    print(perimeter())  # -> 41095.327046386046
    

    另请注意,您可以使用内置的math.hypot() 函数来简化(并加快)您正在执行的计算:

    import math
    
    def perimeter2():
        return sum(math.hypot(x1-x0, y1-y0) 
                    for ((x0, y0), (x1, y1)) in pairwise(parts1(poly)))
    
    print(perimeter2())  # -> 41095.327046386046
    

    【讨论】:

    • 我现在遇到的唯一问题是答案出来不正确,我相信答案应该是:41095.327,但是试试这个方法还是@Selecsosi的方法推荐是给彼此不同的答案和真正的答案...
    • 没关系,我用的是这个方法:
    • 'def perimeter(): return sum((((x1 - x0) ** 2) + ((y1 - y0) ** 2)) **.5 for (x0, y0) , (x1, y1) in parts1(poly)) def parts1(poly): return zip(poly,poly[1:] + [poly[0]]) print(perimeter())' 但必须多放一些括号,因为整个批次不是平方根(或提高到 0.5)。
    • 对上面的问题感到抱歉 - 我以为我已将其标记为代码。
    • math.hypot() 计算您传递的两个值的平方和的平方根。所以代码应该计算多边形中每对点之间的距离之和。为了使测试更容易,我建议您尝试使用简单的矩形或正方形作为输入。
    【解决方案4】:

    我会尝试一些像这样更明确的东西,这符合您的预期答案

    import itertools
    
    def calculate_length(x0, x1, y0, y1):
        return ((x1 - x0)**2+(y1 - y0)**2)**.5
    
    def make_point_pairs(poly):
        pairs = zip(poly, poly[1:])
        # Close the shape
        chain = itertools.chain(pairs, [[poly[-1],poly[0]]])
        return chain
    
    def perimeter(poly):
         return sum([calculate_length(x0, x1, y0, y1) for ((x0, y0), (x1, y1)) in make_point_pairs(poly)])
    

    【讨论】:

      【解决方案5】:

      我也对你的问题有点困惑,看来你不是故意使用生成器,只是想得到周长? 我认为最好稍微清理一下函数perimeter(),而不是在那里使用生成器,而是简单地遍历列表poly,并获取每个相邻的对并以这种方式计算。

      poly = [[36606.0,53223.0],[37332.0,52224.0],[39043.0,53223.0],
      [41603.0,53223.0],[42657.0,53278.0],[43123.0,52060.0],
      [44054.0,51156.0],[45806.0,51498.0],[46751.0,53237.0],
      [46983.0,54606.0],[45861.0,57057.0],[44971.0,58836.0],
      [44054.0,60616.0],[43451.0,58138.0],[41850.0,59179.0],
      [40850.0,60370.0],[39906.0,59233.0],[38674.0,59179.0],
      [35566.0,56249.0],[37592.0,57536.0]]
      
      def perimeter():
          #return (sum((abs((x1 - x0)**2)+abs((y1 - y0)**2))**.5) \
                              #for ((x0, y0), (x1, y1)) in parts1(poly))
          peri=0
          for [x0, y0], [x1, y1] in get_pair(poly):
              peri+=((x1-x0)**2 + (y1-y0)**2)**0.5
          return peri
      
      def get_pair(poly):
          i=0
          while i<len(poly):
              yield [poly [i],poly [(i+1)%len(poly)]] #The modulo takes the pair of last and first coordinates into account
              #So that when poly [i] is the last coordinate it is returned with the first coordinate
              i+=1
      
      print(perimeter())
      

      我为get_pair() 函数使用了生成器函数,但您也可以使用循环或其他方式来实现。每次调用它时,它基本上只是在列表中返回一个新的对。

      【讨论】:

        猜你喜欢
        • 2012-08-22
        • 1970-01-01
        • 1970-01-01
        • 2021-06-02
        • 2020-12-04
        • 1970-01-01
        • 2016-10-15
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多