4、Python面向对象编程 - 从Java到Python的OOP转变

55 阅读8分钟

Python面向对象编程 - 从Java到Python的OOP转变

1. Python面向对象编程概述

作为Java开发者,您已经熟悉面向对象编程(OOP)的核心概念。Python也是一种支持面向对象编程的语言,但其实现方式与Java有一些显著差异。

2. 类的定义与实例化

基本类定义

Python使用class关键字定义类,与Java类似:

# Python类定义
class Person:
    # 类变量(相当于Java的静态字段)
    species = "Homo Sapiens"
    
    # 构造方法
    def __init__(self, name, age):
        # 实例变量(相当于Java的实例字段)
        self.name = name
        self.age = age
    
    # 实例方法
    def introduce(self):
        return f"我叫{self.name},今年{self.age}岁"
    
    # 类方法(相当于Java的静态方法,但可以访问类变量)
    @classmethod
    def get_species(cls):
        return cls.species
    
    # 静态方法(与Java的静态方法类似)
    @staticmethod
    def is_adult(age):
        return age >= 18

对比Java:

// Java类定义
public class Person {
    // 静态字段
    private static final String SPECIES = "Homo Sapiens";
    
    // 实例字段
    private String name;
    private int age;
    
    // 构造方法
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    // 实例方法
    public String introduce() {
        return "我叫" + this.name + ",今年" + this.age + "岁";
    }
    
    // 静态方法
    public static String getSpecies() {
        return SPECIES;
    }
    
    // 静态方法
    public static boolean isAdult(int age) {
        return age >= 18;
    }
}

实例化与使用

# 创建实例
person = Person("张三", 30)

# 访问实例变量
print(person.name)  # 输出: 张三
print(person.age)   # 输出: 30

# 调用实例方法
print(person.introduce())  # 输出: 我叫张三,今年30岁

# 访问类变量
print(Person.species)  # 输出: Homo Sapiens
print(person.species)  # 也可以通过实例访问类变量

# 调用类方法
print(Person.get_species())  # 输出: Homo Sapiens

# 调用静态方法
print(Person.is_adult(20))  # 输出: True
print(person.is_adult(15))  # 也可以通过实例调用静态方法,输出: False

3. Python与Java的OOP差异

self参数

Python的实例方法必须显式声明第一个参数(通常命名为self),表示实例本身:

class MyClass:
    def instance_method(self, arg1, arg2):
        # self相当于Java中的this
        pass

访问修饰符

Python没有Java那样的publicprivateprotected访问修饰符:

  • Python使用命名约定来表示访问控制:
    • 单下划线前缀(_name)表示"受保护"(相当于Java的protected
    • 双下划线前缀(__name)表示"私有"(相当于Java的private
    • 无前缀表示"公开"(相当于Java的public
class Account:
    def __init__(self, owner, balance):
        self.owner = owner          # 公开
        self._account_type = "储蓄"  # 受保护
        self.__balance = balance    # 私有
    
    def deposit(self, amount):
        if amount > 0:
            self.__balance += amount
            return True
        return False
    
    def get_balance(self):
        return self.__balance

注意:Python的"私有"属性实际上是通过名称改写实现的(名称修饰),而不是真正的访问控制。

属性访问

Python提供了@property装饰器,可以将方法转换为属性访问语法:

class Person:
    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name
    
    @property
    def full_name(self):
        return f"{self.first_name} {self.last_name}"
    
    @property
    def age(self):
        return self._age
    
    @age.setter
    def age(self, value):
        if value < 0:
            raise ValueError("年龄不能为负数")
        self._age = value

# 使用
person = Person("张", "三")
print(person.full_name)  # 输出: 张 三

person.age = 30  # 调用setter
print(person.age)  # 调用getter,输出: 30

try:
    person.age = -5  # 引发ValueError
except ValueError as e:
    print(e)  # 输出: 年龄不能为负数

这类似于Java的getter和setter,但语法更简洁。

4. 继承与多态

类继承关系图

classDiagram
    Animal <|-- Dog
    Animal <|-- Cat
    Animal <|-- Duck
    Flyable <|-- Duck
    Swimmable <|-- Duck
    
    class Animal {
        +name: str
        +__init__(name)
        +speak()
    }
    
    class Dog {
        +speak()
    }
    
    class Cat {
        +speak()
    }
    
    class Flyable {
        +fly()
    }
    
    class Swimmable {
        +swim()
    }
    
    class Duck {
        +speak()
        +fly()
        +swim()
    }

基本继承

Python支持类继承,语法比Java更简洁:

# 基类
class Animal:
    def __init__(self, name):
        self.name = name
    
    def speak(self):
        raise NotImplementedError("子类必须实现这个方法")

# 派生类
class Dog(Animal):
    def speak(self):
        return f"{self.name}说:汪汪!"

class Cat(Animal):
    def speak(self):
        return f"{self.name}说:喵喵!"

# 使用
dog = Dog("旺财")
cat = Cat("咪咪")

print(dog.speak())  # 输出: 旺财说:汪汪!
print(cat.speak())  # 输出: 咪咪说:喵喵!

对比Java:

// 基类
public abstract class Animal {
    protected String name;
    
    public Animal(String name) {
        this.name = name;
    }
    
    public abstract String speak();
}

// 派生类
public class Dog extends Animal {
    public Dog(String name) {
        super(name);
    }
    
    @Override
    public String speak() {
        return name + "说:汪汪!";
    }
}

public class Cat extends Animal {
    public Cat(String name) {
        super(name);
    }
    
    @Override
    public String speak() {
        return name + "说:喵喵!";
    }
}

多重继承

与Java不同,Python支持多重继承:

class Flyable:
    def fly(self):
        return "我能飞!"

class Swimmable:
    def swim(self):
        return "我能游泳!"

class Duck(Animal, Flyable, Swimmable):
    def speak(self):
        return f"{self.name}说:嘎嘎!"

# 使用
duck = Duck("唐老鸭")
print(duck.speak())  # 输出: 唐老鸭说:嘎嘎!
print(duck.fly())    # 输出: 我能飞!
print(duck.swim())   # 输出: 我能游泳!

Java只支持单继承,但可以实现多个接口:

public interface Flyable {
    String fly();
}

public interface Swimmable {
    String swim();
}

public class Duck extends Animal implements Flyable, Swimmable {
    public Duck(String name) {
        super(name);
    }
    
    @Override
    public String speak() {
        return name + "说:嘎嘎!";
    }
    
    @Override
    public String fly() {
        return "我能飞!";
    }
    
    @Override
    public String swim() {
        return "我能游泳!";
    }
}

方法解析顺序(MRO)

Python使用C3线性化算法来确定多重继承中的方法解析顺序:

class A:
    def who_am_i(self):
        return "I am A"

class B(A):
    def who_am_i(self):
        return "I am B"

class C(A):
    def who_am_i(self):
        return "I am C"

class D(B, C):
    pass

# 查看MRO
print(D.__mro__)  # 输出: (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)

d = D()
print(d.who_am_i())  # 输出: I am B

super()函数

Python的super()函数用于调用父类方法:

class Animal:
    def __init__(self, name):
        self.name = name

class Pet:
    def __init__(self, owner):
        self.owner = owner

class Dog(Animal, Pet):
    def __init__(self, name, owner, breed):
        Animal.__init__(self, name)  # 显式调用父类构造方法
        Pet.__init__(self, owner)    # 显式调用父类构造方法
        self.breed = breed

class Cat(Animal, Pet):
    def __init__(self, name, owner, color):
        super().__init__(name)       # 使用super()调用第一个父类的构造方法
        Pet.__init__(self, owner)    # 显式调用第二个父类构造方法
        self.color = color

5. 特殊方法(魔术方法)

Python的特殊方法(以双下划线开头和结尾)允许自定义类的行为:

class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    # 字符串表示
    def __str__(self):
        return f"Vector({self.x}, {self.y})"
    
    # 调试表示
    def __repr__(self):
        return f"Vector({self.x}, {self.y})"
    
    # 加法运算符
    def __add__(self, other):
        return Vector(self.x + other.x, self.y + other.y)
    
    # 减法运算符
    def __sub__(self, other):
        return Vector(self.x - other.x, self.y - other.y)
    
    # 相等比较
    def __eq__(self, other):
        return self.x == other.x and self.y == other.y
    
    # 长度(向量的模)
    def __len__(self):
        import math
        return int(math.sqrt(self.x ** 2 + self.y ** 2))
    
    # 使对象可调用
    def __call__(self, scalar):
        return Vector(self.x * scalar, self.y * scalar)

# 使用
v1 = Vector(3, 4)
v2 = Vector(1, 2)

print(v1)          # 输出: Vector(3, 4)
print(v1 + v2)     # 输出: Vector(4, 6)
print(v1 - v2)     # 输出: Vector(2, 2)
print(v1 == v2)    # 输出: False
print(len(v1))     # 输出: 5
print(v1(2))       # 输出: Vector(6, 8)

这些特殊方法在Java中通常通过重写toString()equals()等方法或实现特定接口来实现。

6. 抽象基类

Python 3.4+提供了abc模块来定义抽象基类,类似于Java的抽象类:

from abc import ABC, abstractmethod

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

class Circle(Shape):
    def __init__(self, radius):
        self.radius = radius
    
    def area(self):
        import math
        return math.pi * self.radius ** 2
    
    def perimeter(self):
        import math
        return 2 * math.pi * self.radius

# 尝试实例化抽象类会引发错误
# shape = Shape()  # TypeError

# 实例化具体类
circle = Circle(5)
print(f"面积: {circle.area():.2f}")
print(f"周长: {circle.perimeter():.2f}")

7. 数据类

Python 3.7+引入了数据类,简化了创建主要用于存储数据的类:

from dataclasses import dataclass

@dataclass
class Point:
    x: float
    y: float
    
    def distance_from_origin(self):
        import math
        return math.sqrt(self.x ** 2 + self.y ** 2)

@dataclass
class Rectangle:
    width: float
    height: float
    position: Point = None  # 默认值
    
    def area(self):
        return self.width * self.height

# 使用
p = Point(3, 4)
print(p)  # 输出: Point(x=3, y=4)
print(p.distance_from_origin())  # 输出: 5.0

rect = Rectangle(10, 5, p)
print(rect)  # 输出: Rectangle(width=10, height=5, position=Point(x=3, y=4))
print(rect.area())  # 输出: 50

这类似于Java的记录类(Java 14+)或Lombok的@Data注解。

8. 上下文管理器

Python的上下文管理器(with语句)用于资源管理,类似于Java的try-with-resources:

class FileManager:
    def __init__(self, filename, mode):
        self.filename = filename
        self.mode = mode
        self.file = None
    
    def __enter__(self):
        self.file = open(self.filename, self.mode)
        return self.file
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        if self.file:
            self.file.close()

# 使用
with FileManager('test.txt', 'w') as f:
    f.write('Hello, World!')
# 文件自动关闭

9. 练习:Java到Python的OOP转换

将以下Java代码转换为Python:

public abstract class Employee {
    private String name;
    private int id;
    
    public Employee(String name, int id) {
        this.name = name;
        this.id = id;
    }
    
    public String getName() {
        return name;
    }
    
    public int getId() {
        return id;
    }
    
    public abstract double calculateSalary();
    
    @Override
    public String toString() {
        return "Employee[name=" + name + ", id=" + id + ", salary=" + calculateSalary() + "]";
    }
}

public class FullTimeEmployee extends Employee {
    private double monthlySalary;
    
    public FullTimeEmployee(String name, int id, double monthlySalary) {
        super(name, id);
        this.monthlySalary = monthlySalary;
    }
    
    @Override
    public double calculateSalary() {
        return monthlySalary;
    }
}

public class PartTimeEmployee extends Employee {
    private double hourlyRate;
    private int hoursWorked;
    
    public PartTimeEmployee(String name, int id, double hourlyRate, int hoursWorked) {
        super(name, id);
        this.hourlyRate = hourlyRate;
        this.hoursWorked = hoursWorked;
    }
    
    @Override
    public double calculateSalary() {
        return hourlyRate * hoursWorked;
    }
}

public class Main {
    public static void main(String[] args) {
        Employee[] employees = new Employee[2];
        employees[0] = new FullTimeEmployee("张三", 1001, 10000);
        employees[1] = new PartTimeEmployee("李四", 1002, 150, 80);
        
        for (Employee emp : employees) {
            System.out.println(emp);
        }
    }
}

Python解决方案:

from abc import ABC, abstractmethod

class Employee(ABC):
    def __init__(self, name, id):
        self.name = name
        self.id = id
    
    @property
    def name(self):
        return self._name
    
    @name.setter
    def name(self, value):
        self._name = value
    
    @property
    def id(self):
        return self._id
    
    @id.setter
    def id(self, value):
        self._id = value
    
    @abstractmethod
    def calculate_salary(self):
        pass
    
    def __str__(self):
        return f"Employee[name={self.name}, id={self.id}, salary={self.calculate_salary()}]"

class FullTimeEmployee(Employee):
    def __init__(self, name, id, monthly_salary):
        super().__init__(name, id)
        self.monthly_salary = monthly_salary
    
    def calculate_salary(self):
        return self.monthly_salary

class PartTimeEmployee(Employee):
    def __init__(self, name, id, hourly_rate, hours_worked):
        super().__init__(name, id)
        self.hourly_rate = hourly_rate
        self.hours_worked = hours_worked
    
    def calculate_salary(self):
        return self.hourly_rate * self.hours_worked

def main():
    employees = [
        FullTimeEmployee("张三", 1001, 10000),
        PartTimeEmployee("李四", 1002, 150, 80)
    ]
    
    for emp in employees:
        print(emp)

if __name__ == "__main__":
    main()

10. 今日总结

  • Python的面向对象编程与Java有许多相似之处,但也有一些重要差异
  • Python使用class关键字定义类,__init__方法作为构造函数
  • Python没有访问修饰符,而是使用命名约定(如___前缀)
  • Python支持多重继承,而Java只支持单继承和多接口实现
  • Python的特殊方法(魔术方法)允许自定义类的行为,如运算符重载
  • Python 3.7+提供了数据类,简化了创建主要用于存储数据的类

11. 明日预告

明天我们将学习Python的模块和包,包括如何组织代码、导入模块、创建包以及使用第三方库,这对于构建大型Python项目至关重要。