为了账号安全,请及时绑定邮箱和手机立即绑定

尝试理解面向对象编程。如何使用对象组合?

尝试理解面向对象编程。如何使用对象组合?

翻翻过去那场雪 2022-09-27 10:40:31
是两个类,定义如下:Point()Circle()class Point:    def __init__(self, x, y):        self._x = x        self._y = y    @property    def x(self):        return self._x    @x.setter    def x(self, x):        self._x = x    @property    def y(self):        return self._y    @y.setter    def y(self, y):        self._y = y    def __repr__(self):        return f"{self._x}, {self._y}"    def move(self, x, y):        self._x = x        self._y = y        return self._x, self._yclass Circle:    def __init__(self, radius, x, y):        self._radius = radius        self.x = x        self.y = y    def move(self, x, y):        Point.move(self, x, y)    def __repr__(self):        return f"radius = {self._radius}, \nx = {self.x},\ny = {self.y}"point1 = Point(12, 3)print(point1)point1.y = 0print(point1)point1.move(55, 7)print(point1)circle1 = Circle(4, 1, 1)print(circle1)circle1.move(2, 2)print(circle1)我试图在 Circle 中开发方法,从类 Point 调用方法 move(x,y),而不使用继承。首先初始化一个对象:move(x,y)circle1 = Circle(4,1,1)但是当你使用圆圈位置仍然是(1,1):有什么问题?我想使用_x和_y来模拟私有变量!circle1.move(2,2)
查看完整描述

4 回答

?
繁花如伊

TA贡献2012条经验 获得超12个赞

问题在于你没有使用“组合” - 你只是从你的圈子类中的方法中随机调用。该调用将失败,因为如果将其放置在其他任何位置都会失败:是一个实例方法,它需要一个点的实例来工作。Point.movePoint.move


对于“组合”,您需要具有作为类属性的其他类的实例 - 然后在需要时调用这些实例上的方法。


例如,您的“圆圈”可能具有一个“.center”属性,即一个点。然后,您只需调用一个实例 - 或者,如果您希望在 circle 类本身中使用一个方法:circle.center.move.move



class Circle:

    def __init__(self, radius, x, y):

        self._radius = radius

        self.center = Point(x, y)


    def move(self, x, y):

        self.center.move(x, y)


    def __repr__(self):

        return f"Circle center at ({self.point}), radius: {self.radius}"

你想做什么

您的代码试图在传递 的实例时调用方法。虽然Python 3允许这样做,但它几乎起作用是一个纯粹的巧合(如果Circle中的“x”和“y”名称与“Point”相同,它将像Dani的答案中演示的那样工作) - 但这不是“OOP”也不是“组合”,只是没有引发运行时错误,因为Python 3将类中的实例方法视为函数。PointCircle

“圆”不是“点”。考虑到几何学,你可以说“圆”和“点”分享了一些属性和方法 - Python允许您通过使用多重继承来共享它们,以及我们称之为“mixins” - 因此您可以拥有一个具有“x”和“y”属性的“LocationMixin”类,以及“移动”方法,并且是“点”和“圆”的祖先, 这将起作用。

简化代码

除了你的组合问题之外,重要的是要注意,在Python中,尝试使属性“私有”并不重要,并且为公共连接定义gotter和setters - 如果你的点类简单地写成:

class Point:

    def __init__(self, x, y):

        self.x = x

        self.y = y


    def __repr__(self):

        return f"{self.x}, {self.y}"


    def move(self, x, y):

        self.x = x

        self.y = y

        return self.x, self.y

如果要验证 x 和 y ae 设置为数字,或者验证值范围,则 getter 和 setter 将有意义 - 否则,它们只是多余的。


有趣的是,Python设计了它的“属性”,以便您可以更改属性以拥有获取器和设置器,并在以后添加这些验证,而不会破坏与以前版本的类(Point)的任何兼容性。


查看完整回答
反对 回复 2022-09-27
?
扬帆大鱼

TA贡献1799条经验 获得超9个赞

将类更改为:Circle


class Circle:

    def __init__(self, radius, x, y):

        self._radius = radius

        self._x = x

        self._y = y


    def move(self, x, y):

        Point.move(self, x, y)


    def __repr__(self):

        return f"radius = {self._radius}, \nx = {self._x},\ny = {self._y}"


circle1 = Circle(4, 1, 1)

print(circle1)

circle1.move(2, 2)

print(circle1)

输出


radius = 4, 

x = 1,

y = 1

radius = 4, 

x = 2,

y = 2

否则,在执行 时,将创建两个新字段 (),请参阅:Point.move_x, _y


circle1 = Circle(4, 1, 1)

circle1.move(2, 2)

print(circle1._x, circle1._y)

输出


2 2


查看完整回答
反对 回复 2022-09-27
?
qq_遁去的一_1

TA贡献1725条经验 获得超7个赞

您没有操作正确的变量。
你圈出类的用途,但在调用你操纵和self.xself.yPoint.move(self, x, y)self._xself._y

查看完整回答
反对 回复 2022-09-27
?
不负相思意

TA贡献1777条经验 获得超10个赞

如果您继续使用 Point.move(), 则使用 move() 作为静态方法,而不是实例方法。这会将圆“自我”对象传递给点.move() 方法。如果您按照其他帖子的建议将self.x更改为self._x等,它将起作用,但这是一个非常糟糕的设计。它之所以有效,是因为它将 Point 内部的“self”变量视为与 x 和 y 一起的第三个参数,而不是实际的 Point 对象。例如,您可以将 Point.move() 方法重写为如下所示的内容,该方法仍可用于移动 Circle 对象,但设计得很糟糕:


def move2(foo,x,y):

    foo._x = x

    foo._y = y

    print(foo._x,foo._y)

    return foo._x,foo._y

此外,下面是一个链接,我在尝试回答您的问题时发现了静态方法与类方法的差异:)类方法与静态方法 2020


查看完整回答
反对 回复 2022-09-27
  • 4 回答
  • 0 关注
  • 83 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信