免责声明:这不是家庭作业或任何与学校作业相关的内容。这纯粹是我试图更好地理解如何使用类编程(以及制作类实例的浅/深副本)。
所以我写了两个课程:Point
和Rectangle
。在这里,我创建了两个Rectangle对象:box
和new_box
。
当我调用move_rectangle(rect, dx, dy)
方法并运行我的代码(我将尝试在此处发布)时,它应该返回box
的深层副本(其返回值)被分配到new_box
)。
当我检查:box is new_box
时,它会返回False
(我的预期),但当我检查box
和new_box
的x坐标时,< strong>两个的x值都发生了变化。
这就是我的预期:
box.corner.x = 3
new_box.corner.x = 6
相反,我得到了:
box.corner.x = 6
new_box.corner.x = 6
如果框应该是new_box
的单独对象,那该怎么办?
非常感谢任何帮助/提示/建议!
这是我的代码:
import math
import copy
class Point (object):
""" Represent a point in a 2-D space """
x = 0.0
y = 0.0
def distance(p1, p2):
return math.sqrt((p2.x-p1.x)**2 + (p2.y-p1.y)**2)
def print_point(p):
print('(%g, %g)' % (p.x, p.y))
class Rectangle(object):
"""represent a rectangle.
attributes: width, height, corner."""
width = 0.0
height = 0.0
corner = Point()
def grow_rectangle(rect, dwidth, dheight):
rect.width += dwidth
rect.height += dheight
def move_rectangle(rect, dx, dy):
new_rect = copy.deepcopy(rect)
new_rect.corner.x += dx
new_rect.corner.y += dy
return new_rect
def findCenter(box):
p = Point()
p.x = box.corner.x + box.width/2.0
p.y = box.corner.y + box.height/2.0
return p
box = Rectangle()
box.corner.x = 3
box.corner.y = 8
new_box = Rectangle.move_rectangle(box, 3, 5)
print(new_box is box.corner)
print(box.corner.x)
print(new_box.corner.x)
答案 0 :(得分:1)
copy.deepcopy
函数只知道如何深度复制实现复制协议(或酸洗协议)的类型。列表和dicts等内置容器当然会实现它,但是Rectangle
没有。
通常,“默认”行为才有效。但它不适合你,因为你实际上并没有使用Point
的实例属性;相反,您依赖于提供默认值的class属性。这对于0.0
等不可变值非常有用,但对Point()
等可变值没有那么多。
以便copy.deepcopy(self)
返回一个新的Rectangle
corner
:
>>> box1 = Rectangle
>>> box1
<__main__.Rectangle at 0x155c9e5c0>
>>> box1.corner
<__main__.Point at 0x155c9e5f8>
>>> box2 = copy.deepcopy(box1)
>>> box2
<__main__.Rectangle at 0x155c670f0>
>>> box2.corner
<__main__.Point at 0x155c9e5f8>
>>> box2 is box1
False
>>> box2.corner is box1.corner
True
所以,你有两个选择:
copy
docs。deepcopy
,只需手动执行。第二个更简单:
def move_rectangle(rect, dx, dy):
new_rect = Rectangle()
new_rect.corner = Point()
new_rect.corner.x = rect.corner.x + dx
new_rect.corner.y = rect.corner.y + dy
return new_rect
虽然我们在这里,你在这里做一些奇怪的事情。
首先,将self
参数命名为self
以外的其他内容,如rect
,违反了一个非常重要的习惯用法。任何熟悉Python的人都会进行双重操作,开始阅读代码,然后在解析代码所做的事情之前再做一次双重考虑。
其次,对于这样的类型,您通常希望能够将值传递给构造函数,如下所示:
class Point:
def __init__(self, x=0.0, y=0.0):
self.x, self.y = x, y
如果您按照这种方式设计,move_rectangle
方法会变得更简单:
def move_rectangle(self, dx, dy):
return Rectangle(Point(self.corner.x+dx, self.corner.y+dy))
最后,您有一个名为grow_rectangle
的方法,该方法在就地增长self
,而另一个名为move_rectangle
的方法会单独留下self
,而是返回一个不同的矩形。那令人困惑;没有明显的理由让任何人阅读这些名称,一个人应该改变,另一个人应该改变。
在Python 3.7中,使用新的dataclass
功能可能更好。 3.7目前仍处于测试阶段,但是您可以使用第三方attrs
库获得类似的功能,或者,如果您希望这些对象在构建后是不可变的,只需使用namedtuple
。