Python OOP(适用于 Java 开发者)

发布: (2026年2月16日 GMT+8 03:56)
9 分钟阅读
原文: Dev.to

I’m happy to translate the article for you, but I’ll need the text you’d like translated. Could you please paste the content (or the portion you want translated) here? I’ll keep the source line and all formatting exactly as you requested.

Java 版本

Square Shape。它由位置 (x, y) 和边长定义。

正方形继承自形状

abstract class Shape {
    abstract int area();
    abstract int perimeter();
}

public class Square extends Shape {
    private int x;
    private int y;
    private int side;

    public Square(int x, int y, int side) {
        this.x = x;
        this.y = y;
        this.side = side;
    }

    public Square(int x1, int y1, int x2, int y2) {
        if (Math.abs(x2 - x1) != Math.abs(y2 - y1)) {
            throw new IllegalArgumentException("Square must have equal sides");
        }
        x = x1;
        y = y1;
        side = Math.abs(x2 - x1);
    }

    @Override
    public int area() {
        return side * side;
    }

    @Override
    public int perimeter() {
        return 4 * side;
    }

    @Override
    public String toString() {
        return String.format("Square[x=%d,y=%d,side=%d]", x, y, side);
    }
}

本文面向 Java 开发者,因此对 Java 代码不作详细解释。欢迎在评论中提问。

Translating to Python

类定义

class Square(Shape):
    pass   # empty blocks are not allowed in Python, so we’ll fill it later

构造函数(Python 只有一个 __init__ 方法)

在 Python 中,声明和初始化在同一位置完成,所以我们在 __init__ 中声明字段。

def __init__(self, x, y, side):
    self.x = x
    self.y = y
    self.side = side

创建实例时使用 new 关键字:

s1 = Square(1, 3, 10)
s2 = Square(x=1, y=3, side=10)

Python 不支持方法重载,因此第二个 Java 构造函数(四个参数)无法用另一个 __init__ 表达。我们稍后会用 @classmethod 实现它。

封装

Python 没有 public / protected / private 关键字。按照约定,前导下划线 (_) 表示“私有”。

显式的 self 参数

所有实例方法的第一个参数都是实例本身,传统上命名为 self。这类似于 Java 的 this,但 self 不是 关键字。

def area(self):
    return self.side * self.side

def perimeter(self):
    return 4 * self.side

字符串表示

Python 使用 __str____repr__,而不是 Java 的 toString

  • __str__ – 面向用户的表示(printstr() 使用)。
  • __repr__ – 明确的表示,理想情况下可以用来重新创建对象。
def __str__(self):
    return f"Square [side={self.side}]"

def __repr__(self):
    return f"Square(side={self.side})"
sq = Square(5, 0, 5)
print(sq)               # Square [side=5]
print(str(sq) + ".")    # Square [side=5].
# print(sq + ".") would raise a TypeError because concatenation with a non‑string is not allowed.
方法用途调用者
__repr__返回类似构造函数的表达式repr() 或交互式解释器
__str__返回可读的字符串str()print()

静态方法和类方法

在 Java 中,static 方法属于类本身。Python 将 静态方法@staticmethod)和 类方法@classmethod)区分开来。

静态方法示例

public static double calcSideLength(double area) {
    return Math.sqrt(area);
}
import math

@staticmethod
def calc_side_length(area):
    return math.sqrt(area)   # `math` 是一个模块,而不是类

静态方法不接受 selfcls 参数,因为它既不依赖实例也不依赖类。

用于第二个构造函数的类方法

类方法的第一个参数是类本身 (cls),非常适合用作工厂方法

@classmethod
def from_points(cls, x1, y1, x2, y2):
    """Create a Square from two opposite corners."""
    if abs(x2 - x1) != abs(y2 - y1):
        raise ValueError("The points do not form a square")
    side = abs(x2 - x1)
    # Use the lower‑left corner as the origin (x1, y1)
    return cls(x1, y1, side)
sq = Square.from_points(0, 0, 3, 3)   # creates a 3×3 square

异常

Java 的 throw 对应 Python 的 raise。上面的 from_points 方法已经演示了在提供的点不构成正方形时抛出 ValueError

完整的 Python 实现

import math
from abc import ABC, abstractmethod

class Shape(ABC):
    @abstractmethod
    def area(self):
        pass

    @abstractmethod
    def perimeter(self):
        pass

class Square(Shape):
    def __init__(self, x, y, side):
        self.x = x
        self.y = y
        self.side = side

    @classmethod
    def from_points(cls, x1, y1, x2, y2):
        """Factory method that builds a Square from two opposite corners."""
        if abs(x2 - x1) != abs(y2 - y1):
            raise ValueError("The points do not form a square")
        side = abs(x2 - x1)
        return cls(x1, y1, side)

    @staticmethod
    def calc_side_length(area):
        """Return the side length for a given area."""
        return math.sqrt(area)

    def area(self):
        return self.side * self.side

    def perimeter(self):
        return 4 * self.side

    def __str__(self):
        return f"Square [side={self.side}]"

    def __repr__(self):
        return f"Square(side={self.side})"

现在你可以像使用 Java 版一样使用该类,只是采用了更符合 Python 风格的写法:

sq1 = Square(1, 2, 5)
sq2 = Square.from_points(0, 0, 5, 5)

print(sq1)                     # Square [side=5]
print(repr(sq2))               # Square(side=5)
print(Square.calc_side_length(25))  # 5.0

祝编码愉快! 如有任何不清楚的地方,请留言,我们会进一步说明。

使用 Square.make_square_from_points

try:
    sq = Square.make_square_from_points(4, 5, 7, 11)
except ValueError as ve:
    print(ve)

输出

ValueError: (4, 5, 7, 11)

错误层次结构

创建自定义异常

我们将通过继承 ValueError 来创建自己的错误 MalformedSquareException

class MalformedSquareException(ValueError):
    def __init__(self, x1, y1, x2, y2):
        self.x1 = x1
        self.y1 = y1
        self.x2 = x2
        self.y2 = y2

    # 注意 __str__ 的区别
    def __repr__(self):
        return "MalformedSquareException(%d, %d, %d, %d)" % (
            self.x1, self.y1, self.x2, self.y2
        )

    def __str__(self):
        return (
            "The points (%d, %d) and (%d, %d) are not the opposite corners of a square"
            % (self.x1, self.y1, self.x2, self.y2)
        )

try:
    sq = Square.make_square_from_points(4, 7, 5, 11)
except MalformedSquareException as ve:
    print(ve)

输出

The points (4, 5) and (7, 11) are not the opposite corners of a square

Source:

抽象类

Shape 抽象基类可以用 Python 如下编写:

import abc

# alternative: class Shape(abc.ABC)
class Shape(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def area(self):
        ...  # Python 抽象方法需要一个函数体

    @abc.abstractmethod
    def perimeter(self):
        ...

Python 抽象类的创建方式有两种:

  • ABCMeta 声明为元类,
  • 继承 ABC(其元类为 ABCMeta)。

和 Java 类似,Python 抽象类可以拥有构造函数和非抽象方法。它们也可以定义 静态 抽象方法。

示例:静态抽象方法

class Shape(metaclass=abc.ABCMeta):
    @staticmethod
    @abc.abstractmethod
    def nb_sides():
        ...

class Square(Shape):
    @staticmethod
    def nb_sides():
        return 4

注意: @staticmethod 必须位于 @abc.abstractmethod 之前

运算符重载

Python 支持通过特殊方法(如 __add____mul____lt____gt__ 等)进行运算符重载。相比之下,Java 只对 + 进行字符串连接的重载。

import abc
import math

class Square(metaclass=abc.ABCMeta):
    # sq2 = sq1 * 3 creates sq2 that's √3 times bigger than sq1
    def __mul__(self, n):
        return Square(self.x, self.y, self.side * math.sqrt(n))

    def __lt__(self, other):
        return self.side < other.side

s1 = Square(0, 0, 10)
s2 = s1 * 3          # calls __mul__
print(s1 < s2)       # calls __lt__

Source:

多重继承

Python 支持多重继承,而 Java 只允许单继承。当一个类拥有多个祖先时,解析顺序为:

  1. 直接祖先的优先级高于更远的祖先。
  2. 在同一层级的祖先中,类定义中的顺序决定优先级(左 → 更高,右 → 更低)。

示例图

Updated Shape, Rectangle, Rhombus & updated Square classes

代码

class Rectangle(Shape):
    def __init__(self, x, y, length, breadth):
        self.x, self.y = x, y
        self.length, self.breadth = length, breadth

    def area(self):
        return self.length * self.breadth

    def perimeter(self):
        return 2 * (self.length + self.breadth)

    @staticmethod
    def nb_sides():
        return 4

class Rhombus(Shape):
    def __init__(self, x, y, side, angle):
        self.x, self.y = x, y
        self.side, self.angle = side, angle

    def area(self):
        return self.side * self.side * math.sin(self.angle * math.pi / 180)

    def perimeter(self):
        return 4 * self.side

    @staticmethod
    @abc.abstractmethod
    def nb_sides():
        return 4

class Square(Rhombus, Rectangle):
    def __init__(self, side):
        # Rhombus expects (x, y, side, angle); we set x=y=0 and angle=90°
        super().__init__(0, 0, side, 90)

    def area(self):
        return super().area()

    @staticmethod
    def nb_sides():
        return 4

关键要点:

  • Square 同时继承自 RhombusRectangle
  • 方法解析顺序(MRO)遵循上述规则。
  • Square.__init__ 中的 super() 调用正确地将参数转发给 Rhombus.__init__(MRO 中的第一个父类)。

理解 Python 中的 super() 与构造函数调用

  • super() 调用 不会 自动调用父类构造函数;它仅提供对父对象的引用。因此,如果需要父类的初始化逻辑,必须显式调用 __init__
  • 由于 Square 的声明中先列出了 Rhombus 再是 Rectanglesuper() 将首先解析为 Rhombus
0 浏览
Back to Blog

相关文章

阅读更多 »

模块-01--面试题 _JAVA

1. Java 中有多少种数据类型?‑ 基本数据类型 共 8 种:byte、short、int、long、float、double、char、boolean ‑ 非基本引用数据类型:...

超级简易 Java Web Scraping (Jsoup)

添加 Jsoup xml org.jsoup jsoup 1.17.2 创建一个最小的爬虫 在本例中,我们将打印页面中所有链接的文本和 URL: java import org.jsoup.Jsoup; im...