我对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
如何制作它以便给我价值/答案? 我真的不确定发生了什么。
答案 0 :(得分: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
答案 1 :(得分:1)
第一个问题是你的括号在错误的地方。您想在生成器表达式上调用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
不是那么简洁,也不是那么快,但没有使用尽可能多的内存。
答案 2 :(得分:0)
我会像这样尝试一些更明确的东西,这符合您的预期答案
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)])
答案 3 :(得分:0)
您的代码有两个问题。一个是由于@ 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
答案 4 :(得分:0)
我对你的问题也有点困惑,似乎你不是故意使用发电机而只是想要到外围?
我认为最好稍微清理函数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()
函数使用了生成器函数,但您也可以使用循环或其他方式执行此操作。每次调用它时,它基本上只返回列表中的新对。