generator\iterator 的奇怪行为
Strange behavior with generator\iterator
我为一些 OOP 练习创建的迭代器出现问题。
这是有问题的生成器:
def shapeIterator(listOfShapes):
print("Generator...")
print(listOfShapes)
listOfShapessoretedbyArea = shape.sortedByArea(listOfShapes)
for shapes in listOfShapessoretedbyArea:
yield str(shapes)
shape.sortedByArea(listOfShapes) 是一个静态方法,它需要一个参数,一个按计算面积排序的列表,返回给调用者。
此方法在这个主要功能中完美运行:
if __name__ == '__main__':
rect = rectangle(20, 5)
squa = square(2)
tri = equiTria(2, 5)
circ = circle(2)
pent = pentagon(5)
hexa = hexagon(3)
listOfShapes = [rect, squa, hexa, tri, circ, pent]
listOfShapessoretedbyArea = sorted(listOfShapes, key=lambda x: x.calculate_area())
listOfShapessoretedbyPeri = sorted(listOfShapes, key=lambda x: x.calculate_perimeter())
listOfShapessoretedbyArea2 = shape.sortedByArea(listOfShapes)
listOfShapessoretedbyPeri2 = shape.sortedByPerim(listOfShapes)
iterator = shapeIterator(listOfShapes)
for i in range(6):
sleep(1)
value = next(iterator)
print(value)
print("NOT SORTED")
for shape in listOfShapes:
print(str(shape))
print("\nSORTED BY AREA")
for shape in listOfShapessoretedbyArea:
print(str(shape))
print("\nSORTED BY PERIMETER")
for shape in listOfShapessoretedbyPeri:
print(str(shape))
print("\nSORTED BY AREA v2")
for shape in listOfShapessoretedbyArea2:
print(str(shape))
print("\nSORTED BY PERIMETER v2")
for shape in listOfShapessoretedbyPeri2:
print(str(shape))
但是当我移动这部分时:
iterator = shapeIterator(listOfShapes)
for i in range(6):
sleep(1)
value = next(iterator)
print(value)
在主体的最后,像这样:
if __name__ == '__main__':
rect = rectangle(20, 5)
squa = square(2)
tri = equiTria(2, 5)
circ = circle(2)
pent = pentagon(5)
hexa = hexagon(3)
listOfShapes = [rect, squa, hexa, tri, circ, pent]
listOfShapessoretedbyArea = sorted(listOfShapes, key=lambda x: x.calculate_area())
listOfShapessoretedbyPeri = sorted(listOfShapes, key=lambda x: x.calculate_perimeter())
listOfShapessoretedbyArea2 = shape.sortedByArea(listOfShapes)
listOfShapessoretedbyPeri2 = shape.sortedByPerim(listOfShapes)
print("NOT SORTED")
for shape in listOfShapes:
print(str(shape))
print("\nSORTED BY AREA")
for shape in listOfShapessoretedbyArea:
print(str(shape))
print("\nSORTED BY PERIMETER")
for shape in listOfShapessoretedbyPeri:
print(str(shape))
print("\nSORTED BY AREA v2")
for shape in listOfShapessoretedbyArea2:
print(str(shape))
print("\nSORTED BY PERIMETER v2")
for shape in listOfShapessoretedbyPeri2:
print(str(shape))
iterator = shapeIterator(listOfShapes)
for i in range(6):
sleep(1)
value = next(iterator)
print(value)
我收到这个错误:
TypeError: sortedByArea() takes 1 positional argument but 2 were given
这很奇怪。为了进行一些简单的调试,我在第二种情况下打印了在函数 sortedByArea() 中传递的参数,实际上我得到了两个参数。一个是每个语句最后打印的字符串值,第二个是列表本身。
每个语句的最后一个字符串值是指此:
for shape in listOfShapessoretedbyPeri2:
print(str(shape))
我还尝试更改列表的值,实际上传递给 shapeIterator 函数的参数的值 "concatenated" 是最后打印的字符串。
如果需要,这里是 类 和主要 .py 中使用的导入:
from math import pi
from math import sqrt
from time import sleep
class shape():
def calculate_area():
pass
def calculate_perimeter():
pass
def ltarea(self, other):
return self.calculate_area() < other.calculate_area()
def ltperim(self, other):
return self.calculate_perimeter() < other.calculate_perimeter()
def sortedByArea(shapes):
return sorted(shapes, key=lambda x: x.calculate_area())
def sortedByPerim(shapes):
return sorted(shapes, key=lambda x: x.calculate_perimeter())
def nametype(self):
return "shape"
def __str__(self):
return "{0}, area: {1}, perim: {2}".format(self.nametype(),
self.calculate_area(),
self.calculate_perimeter())
class rectangle(shape):
def __init__(self, side1, side2):
self.__side1 = side1
self.__side2 = side2
def calculate_area(self):
return self.__side1 * self.__side2
def calculate_perimeter(self):
return (self.__side1 * 2) + (self.__side2 * 2)
def nametype(self):
return "rectangle"
class square(rectangle):
def __init__(self, side):
self._rectangle__side1 = side
self._rectangle__side2 = side
def nametype(self):
return "square"
class equiTria(shape):
def __init__(self, side, height):
self.__side = side
def calculate_area(self):
self.__height = self.calculate_perimeter() / (2 * sqrt(3))
return (self.__side * self.__height)/2
def calculate_perimeter(self):
return self.__side * 3
def nametype(self):
return "equiTria"
class circle(shape):
def __init__(self, radius):
self.__radius = radius
def calculate_area(self):
return pi * pow(self.__radius, 2)
def calculate_perimeter(self):
return 2 * pi * self.__radius
def nametype(self):
return "circle"
class pentagon(shape):
def __init__(self, side):
self.__side = side
self.__apothem = side * 0.688
def calculate_perimeter(self):
return self.__side * 5
def calculate_area(self):
return (self.calculate_perimeter() * self.__apothem) / 2
def nametype(self):
return "pentagon"
class hexagon(shape):
def __init__(self, side):
self.__side = side
def calculate_area(self):
self.__apothem = self.__side * 0.866
return (self.calculate_perimeter() * self.__apothem) / 2
def calculate_perimeter(self):
return self.__side * 6
def nametype(self):
return "hexagon"
def shapeIterator(listOfShapes):
print("Generator...")
print(listOfShapes)
listOfShapessoretedbyArea = shape.sortedByArea(listOfShapes)
for shapes in listOfShapessoretedbyArea:
yield str(shapes)
你重新绑定 shape
在你的循环中,所以它不再是class,而是一个实例。
比如上面你对生成器的使用:
for shape in listOfShapessoretedbyPeri2:
print(str(shape))
__main__
部分中的变量仍然是全局变量,因此替换了生成器使用的 class。
您的选择是:
- 为循环变量使用不同的名称;
ashape
例如。
- 为 class 使用不同的名称。 Python 风格指南建议对 class 名称使用 CamelCase,因此在这里将其重命名为
Shape
会很好。
- 将
if __name__ == '__main__':
块下的所有代码放在一个函数中,这样循环目标之类的变量名就变成了locals.
就我个人而言,我会同时实施 2 和 3;避免污染你的全局命名空间总是一个好主意,遵循几乎普遍采用的 Python 风格指南也是如此;这有助于避免将来出现此类错误。
此外,如果 sortedByArea
是一个静态方法,请至少使用 @staticmethod
装饰器。这样即使在实例上它仍然可以用作静态方法:
class Shape:
# ...
@staticmethod
def sortedByArea(shapes):
return sorted(shapes, key=lambda x: x.calculate_area())
@staticmethod
def sortedByPerim(shapes):
return sorted(shapes, key=lambda x: x.calculate_perimeter())
您重复使用了 shape
变量,一次用于 shape
class,一次用于所有 for shape in
循环中的循环变量。
我为一些 OOP 练习创建的迭代器出现问题。
这是有问题的生成器:
def shapeIterator(listOfShapes):
print("Generator...")
print(listOfShapes)
listOfShapessoretedbyArea = shape.sortedByArea(listOfShapes)
for shapes in listOfShapessoretedbyArea:
yield str(shapes)
shape.sortedByArea(listOfShapes) 是一个静态方法,它需要一个参数,一个按计算面积排序的列表,返回给调用者。 此方法在这个主要功能中完美运行:
if __name__ == '__main__':
rect = rectangle(20, 5)
squa = square(2)
tri = equiTria(2, 5)
circ = circle(2)
pent = pentagon(5)
hexa = hexagon(3)
listOfShapes = [rect, squa, hexa, tri, circ, pent]
listOfShapessoretedbyArea = sorted(listOfShapes, key=lambda x: x.calculate_area())
listOfShapessoretedbyPeri = sorted(listOfShapes, key=lambda x: x.calculate_perimeter())
listOfShapessoretedbyArea2 = shape.sortedByArea(listOfShapes)
listOfShapessoretedbyPeri2 = shape.sortedByPerim(listOfShapes)
iterator = shapeIterator(listOfShapes)
for i in range(6):
sleep(1)
value = next(iterator)
print(value)
print("NOT SORTED")
for shape in listOfShapes:
print(str(shape))
print("\nSORTED BY AREA")
for shape in listOfShapessoretedbyArea:
print(str(shape))
print("\nSORTED BY PERIMETER")
for shape in listOfShapessoretedbyPeri:
print(str(shape))
print("\nSORTED BY AREA v2")
for shape in listOfShapessoretedbyArea2:
print(str(shape))
print("\nSORTED BY PERIMETER v2")
for shape in listOfShapessoretedbyPeri2:
print(str(shape))
但是当我移动这部分时:
iterator = shapeIterator(listOfShapes)
for i in range(6):
sleep(1)
value = next(iterator)
print(value)
在主体的最后,像这样:
if __name__ == '__main__':
rect = rectangle(20, 5)
squa = square(2)
tri = equiTria(2, 5)
circ = circle(2)
pent = pentagon(5)
hexa = hexagon(3)
listOfShapes = [rect, squa, hexa, tri, circ, pent]
listOfShapessoretedbyArea = sorted(listOfShapes, key=lambda x: x.calculate_area())
listOfShapessoretedbyPeri = sorted(listOfShapes, key=lambda x: x.calculate_perimeter())
listOfShapessoretedbyArea2 = shape.sortedByArea(listOfShapes)
listOfShapessoretedbyPeri2 = shape.sortedByPerim(listOfShapes)
print("NOT SORTED")
for shape in listOfShapes:
print(str(shape))
print("\nSORTED BY AREA")
for shape in listOfShapessoretedbyArea:
print(str(shape))
print("\nSORTED BY PERIMETER")
for shape in listOfShapessoretedbyPeri:
print(str(shape))
print("\nSORTED BY AREA v2")
for shape in listOfShapessoretedbyArea2:
print(str(shape))
print("\nSORTED BY PERIMETER v2")
for shape in listOfShapessoretedbyPeri2:
print(str(shape))
iterator = shapeIterator(listOfShapes)
for i in range(6):
sleep(1)
value = next(iterator)
print(value)
我收到这个错误:
TypeError: sortedByArea() takes 1 positional argument but 2 were given
这很奇怪。为了进行一些简单的调试,我在第二种情况下打印了在函数 sortedByArea() 中传递的参数,实际上我得到了两个参数。一个是每个语句最后打印的字符串值,第二个是列表本身。
每个语句的最后一个字符串值是指此:
for shape in listOfShapessoretedbyPeri2:
print(str(shape))
我还尝试更改列表的值,实际上传递给 shapeIterator 函数的参数的值 "concatenated" 是最后打印的字符串。
如果需要,这里是 类 和主要 .py 中使用的导入:
from math import pi
from math import sqrt
from time import sleep
class shape():
def calculate_area():
pass
def calculate_perimeter():
pass
def ltarea(self, other):
return self.calculate_area() < other.calculate_area()
def ltperim(self, other):
return self.calculate_perimeter() < other.calculate_perimeter()
def sortedByArea(shapes):
return sorted(shapes, key=lambda x: x.calculate_area())
def sortedByPerim(shapes):
return sorted(shapes, key=lambda x: x.calculate_perimeter())
def nametype(self):
return "shape"
def __str__(self):
return "{0}, area: {1}, perim: {2}".format(self.nametype(),
self.calculate_area(),
self.calculate_perimeter())
class rectangle(shape):
def __init__(self, side1, side2):
self.__side1 = side1
self.__side2 = side2
def calculate_area(self):
return self.__side1 * self.__side2
def calculate_perimeter(self):
return (self.__side1 * 2) + (self.__side2 * 2)
def nametype(self):
return "rectangle"
class square(rectangle):
def __init__(self, side):
self._rectangle__side1 = side
self._rectangle__side2 = side
def nametype(self):
return "square"
class equiTria(shape):
def __init__(self, side, height):
self.__side = side
def calculate_area(self):
self.__height = self.calculate_perimeter() / (2 * sqrt(3))
return (self.__side * self.__height)/2
def calculate_perimeter(self):
return self.__side * 3
def nametype(self):
return "equiTria"
class circle(shape):
def __init__(self, radius):
self.__radius = radius
def calculate_area(self):
return pi * pow(self.__radius, 2)
def calculate_perimeter(self):
return 2 * pi * self.__radius
def nametype(self):
return "circle"
class pentagon(shape):
def __init__(self, side):
self.__side = side
self.__apothem = side * 0.688
def calculate_perimeter(self):
return self.__side * 5
def calculate_area(self):
return (self.calculate_perimeter() * self.__apothem) / 2
def nametype(self):
return "pentagon"
class hexagon(shape):
def __init__(self, side):
self.__side = side
def calculate_area(self):
self.__apothem = self.__side * 0.866
return (self.calculate_perimeter() * self.__apothem) / 2
def calculate_perimeter(self):
return self.__side * 6
def nametype(self):
return "hexagon"
def shapeIterator(listOfShapes):
print("Generator...")
print(listOfShapes)
listOfShapessoretedbyArea = shape.sortedByArea(listOfShapes)
for shapes in listOfShapessoretedbyArea:
yield str(shapes)
你重新绑定 shape
在你的循环中,所以它不再是class,而是一个实例。
比如上面你对生成器的使用:
for shape in listOfShapessoretedbyPeri2:
print(str(shape))
__main__
部分中的变量仍然是全局变量,因此替换了生成器使用的 class。
您的选择是:
- 为循环变量使用不同的名称;
ashape
例如。 - 为 class 使用不同的名称。 Python 风格指南建议对 class 名称使用 CamelCase,因此在这里将其重命名为
Shape
会很好。 - 将
if __name__ == '__main__':
块下的所有代码放在一个函数中,这样循环目标之类的变量名就变成了locals.
就我个人而言,我会同时实施 2 和 3;避免污染你的全局命名空间总是一个好主意,遵循几乎普遍采用的 Python 风格指南也是如此;这有助于避免将来出现此类错误。
此外,如果 sortedByArea
是一个静态方法,请至少使用 @staticmethod
装饰器。这样即使在实例上它仍然可以用作静态方法:
class Shape:
# ...
@staticmethod
def sortedByArea(shapes):
return sorted(shapes, key=lambda x: x.calculate_area())
@staticmethod
def sortedByPerim(shapes):
return sorted(shapes, key=lambda x: x.calculate_perimeter())
您重复使用了 shape
变量,一次用于 shape
class,一次用于所有 for shape in
循环中的循环变量。