繁体   English   中英

试图了解面向 object 的编程。 如何使用 object 排版?

[英]Trying to understand object oriented programming. How to use object composing?

成为下面定义的两个类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._y


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}"


point1 = Point(12, 3)
print(point1)
point1.y = 0
print(point1)

point1.move(55, 7)
print(point1)

circle1 = Circle(4, 1, 1)
print(circle1)
circle1.move(2, 2)
print(circle1)

我尝试在 Circle 中开发方法move(x,y) (x,y),从 class 点调用方法 move(x,y),而不使用 inheritance。 首先初始化一个 object:

circle1 = Circle(4,1,1)

但是当您使用circle1.move(2,2)时,圆 position 仍然是 (1,1):怎么了? 我想用_x和_y来模拟私有变量!

问题在于您没有使用“组合” - 您只是在您的圈子 class 中的一个方法中随机调用Point.move 该调用将失败,因为如果将其放在其他任何地方都会失败: Point.move是一个实例方法,它需要一个 point 的实例才能工作。

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

例如,您的“Circle”可能有一个“.center”属性,它是一个点。 然后,您只需在实例中调用circle.center.move - 或者,如果您想要在圆 class 本身中使用.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}"

你想做什么

您的代码试图在Point中调用一个方法,传递Circle的一个实例。 虽然 Python 3 允许这样做,但这完全是巧合,它几乎可以工作(如果 Circle 中的“x”和“y”名称与“Point”中的名称相同,它会像 Dani 的回答中所展示的那样工作) - 但是这不是“OOP”也不是“Composition”,并且不会引发运行时错误,因为 Python 3 将类中的实例方法视为函数。

“圆”不是“点”。 考虑几何,您可以说“圆”和“点”具有一些属性和方法 - Python 允许您通过使用多个 inheritance 以及我们所谓的“mixins”来共享这些属性和方法 - - 所以你可以有一个“LocationMixin”ZA7FED3411FAF832174EF1F040028B2C21Z - - 所以你可以有一个“LocationMixin”ZA26BB4EBDC2DCC40ABBB4这将具有“x”和“y”属性,以及“move”方法并且是“Point”和“Circle”的祖先,这将起作用。

简化代码

除了您的组合问题之外,重要的是要注意,在 Python 中,尝试将属性设置为“私有”并为公共 consunption 定义 getter 和 setter 并不重要 - 如果您将观点 class 简单地写为:

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 设计了它的“属性”,以便您可以更改属性以具有 getter 和 setter,并在稍后添加这些验证,而不会破坏与之前版本的 class (Point) 的任何兼容性。

Circle class 更改为:

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)

Output

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)

Output

2 2

您没有操纵正确的变量。
你圈出 class 使用self.xself.y但在调用Point.move(self, x, y)你操纵self._xself._y

@jsbueno 有最明智的设计正确答案。 如果您提前使用 go 并使用 Point.move() 您正在使用 move() 作为 static 方法,而不是实例方法。 这会将 Circle 'self' object 传递给 Point.move() 方法。 如果您按照其他帖子的建议将 self.x 更改为 self._x 等,它会起作用,但这是一个非常糟糕的设计。 它之所以有效,是因为它将 Point 内的“self”变量与 x 和 y 一起视为第三个参数,而不是实际的 Point object。 例如,您可以将 Point.move() 方法重写为类似的方法,该方法仍可用于移动 Circle object,但设计不当:

def move2(foo,x,y):
    foo._x = x
    foo._y = y
    print(foo._x,foo._y)
    return foo._x,foo._y

Also the following is a link where I found the difference in static methods vs class methods while trying to answer your question:) CLASS METHOD VS STATIC METHOD 2020

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM