类的定义
在 Python 中,class
是用来定义类的关键字。通过 class
关键字可以创建一个新的类,该类可以包含属性和方法。类名通常使用大写字母开头的驼峰命名法。
-
定义类的基本语法:
class 类名: # 类名惯用驼峰式命名 # 类属性(所有实例共享) 类属性 = 值 # 构造方法(初始化对象) def __init__(self, 参数1, 参数2, ...): # 实例属性(每个实例独有) self.属性1 = 参数1 self.属性2 = 参数2 # 实例方法 def 方法名(self, 参数1, 参数2, ...): # 方法体 pass # 类方法(使用 @classmethod 装饰器) @classmethod def 类方法名(cls, 参数1, 参数2, ...): # 方法体 pass # 静态方法(使用 @staticmethod 装饰器) @staticmethod def 静态方法名(参数1, 参数2, ...): # 方法体 pass
-
初始化方法 (
__init__
)
当定义一个类时,通常会提供一个特殊的方法__init__()
来初始化新创建的对象的状态。这个方法会在每次实例化对象时自动调用。
示例代码如下:class Student: # 初始化方法(构造函数) def __init__(self, id, name, course): self.id = id # 实例属性 self.name = name # 实例属性 self.course = course # 实例属性 # 实例方法 def show_data(self): print(f"ID:\t{self.id}") print(f"Name:\t{self.name}") print(f"Course:\t{self.course}") # 实例化对象并调用方法 student_obj = Student(1, 'Alice', 'Mathematics') student_obj.show_data()
输出结果为:
ID: 1 Name: Alice Course: Mathematics
继承与多态
继承是面向对象编程的重要特性,它允许一个类继承另一个类的属性和方法。被继承的类称为基类(父类),继承的类称为派生类(子类)
子类可以通过 super()
函数来调用父类的构造函数或其他方法。
类的继承
下面是一个简单的继承例子:
class ParentClass:
def __init__(self, value):
self.value = value
def display_value(self):
print(f"Value in parent class: {self.value}")
class ChildClass(ParentClass):
def __init__(self, value, extra_value):
super().__init__(value)
self.extra_value = extra_value
def display_extra_value(self):
print(f"Extra Value in child class: {self.extra_value}")
child_instance = ChildClass(10, 20)
child_instance.display_value() # 调用了父类的方法
child_instance.display_extra_value() # 调用了子类自己的方法
运行以上代码的结果将是:
Value in parent class: 10
Extra Value in child class: 20
方法重写
子类可以重写父类的方法,以实现不同的行为。
# 父类
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
return f"{self.name} makes a sound."
# 子类 继承于父类animal
class Cat(Animal):
def speak(self):
return f"{self.name} says meow!"
# 子类 重写父类的speak方法
class Bird(Animal):
def speak(self):
return f"{self.name} says chirp!"
# 创建子类对象
my_cat = Cat("Whiskers")
print(my_cat.speak()) # 输出: Whiskers says meow!
my_bird = Bird("Tweety")
print(my_bird.speak()) # 输出: Tweety says chirp!
多继承
Python 支持多继承,即一个类可以继承多个父类。
class A:
def method(self):
return "A"
class B:
def method(self):
return "B"
class C(A, B):
pass
my_object = C()
print(my_object.method()) # 输出: A(遵循方法解析顺序 MRO)
静态方法和类方法
静态方法使用 @staticmethod 装饰器定义,类方法使用 @classmethod 装饰器定义。
class MyClass:
@staticmethod
def static_method():
print("This is a static method.")
@classmethod
def class_method(cls):
print("This is a class method.")
MyClass.static_method() # 输出: This is a static method.
MyClass.class_method() # 输出: This is a class method.
-
静态方法
装饰有@staticmethod
标志的方法被视作静态方法,既不需要传入self
也不需传递cls
作为默认参数。这类方法实际上更接近于普通的全局辅助工具型函数,在语法结构上只是挂载到了某特定类之下而已。 -
类方法
使用装饰器@classmethod
标记的方法被称为类方法,它的首个隐含参数通常是代表类本身的cls
而非具体实例。因此,此类方法适用于那些需要处理整个类范围内的事务场景下。class Example: count = 0 # 类属性 def __init__(self, value): self.value = value # 实例属性 @classmethod def increment_count(cls): cls.count += 1 # 修改类属性 @staticmethod def static_method(): print("This is a static method.") def instance_method(self): return f"Value: {self.value}" # 访问实例属性
类的特殊方法
Python 中还存在一系列内置的特殊命名方法(即魔术方法),允许开发者自定义某些标准运算符或者语句的表现形式。
它们以双下划线开头和结尾,例如 __str__()
, __repr__()
, 和容器相关的 __len__()
, __getitem__()
等等。合理运用这些魔法方法可以让我们的类更加 Pythonic 并且易于与其他组件集成工作。
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
# 重写字符串表示
def __str__(self):
return f"Point({self.x}, {self.y})"
# 重写加法操作
def __add__(self, other):
return Point(self.x + other.x, self.y + other.y)
# 使用
p1 = Point(1, 2)
p2 = Point(3, 4)
print(p1) # 输出: Point(1, 2)
print(p1 + p2) # 输出: Point(4, 6)
类的封装
- 封装的意义
封装是一种面向对象编程的核心特性之一,它允许将数据(属性)和操作这些数据的方法组合在一起,并对外部隐藏不必要的细节。通过封装,可以提高程序的安全性和可维护性。
在 Python 中,可以通过命名约定来定义不同级别的访问权限:
-
公有属性 (Public)
公有属性可以直接被外部访问和修改。
-
受保护属性 (Protected)
受保护属性以单下划线 _ 开头,表示该属性仅应在类内部或其子类中使用。虽然可以从外部访问,但这通常被视为一种惯例。
-
私有属性 (Private)
私有属性以双下划线 __ 开头,Python 会对这类属性进行名称改写(Name Mangling),从而防止从外部直接访问。
class BankAccount:
def __init__(self, owner, balance=0):
self.owner = owner # 公有属性
self._account_number = "A12345" # 受保护属性
self.__balance = balance # 私有属性
def deposit(self, amount):
"""存款"""
if amount > 0:
self.__balance += amount
return f"Deposited {amount}. New balance: {self.__balance}"
else:
return "Invalid deposit amount."
def withdraw(self, amount):
"""取款"""
if 0 < amount <= self.__balance:
self.__balance -= amount
return f"Withdrew {amount}. Remaining balance: {self.__balance}"
else:
return "Insufficient funds or invalid withdrawal amount."
def get_balance(self):
"""获取余额"""
return f"Current balance: {self.__balance}"
# 测试BankAccount类的功能
account = BankAccount("Alice", 100)
# 正常操作
print(account.deposit(50)) # 输出: Deposited 50. New balance: 150
print(account.withdraw(70)) # 输出: Withdrew 70. Remaining balance: 80
print(account.get_balance()) # 输出: Current balance: 80
# 尝试非法访问私有属性
try:
print(account.__balance) # 这里会抛出 AttributeError 错误
except AttributeError as e:
print(e) # 输出: 'BankAccount' object has no attribute '__balance'
# 使用名称改写的机制间接访问私有属性
print(account._BankAccount__balance) # 输出: 80 【不推荐】
单例模式下的封装应用
除了基本的数据封装外,在某些场景下可能还需要确保某个类只存在一个实例。这种需求可以通过重写 __new__
方法并结合静态变量实现单例模式。
以下是基于日志管理器的一个简单示例:
class Logger:
_instance = None # 静态变量用于存储唯一实例
def __new__(cls, *args, **kwargs):
if not cls._instance: # 如果尚未创建过实例,则初始化一个新的实例
cls._instance = super(Logger, cls).__new__(cls)
return cls._instance # 返回已存在的实例
def log(self, message):
print(f"[LOG]: {message}")
# 测试Logger类的行为
logger1 = Logger()
logger2 = Logger()
assert logger1 is logger2 # True,表明两个引用指向同一个对象
logger1.log("System started.") # 输出: [LOG]: System started.
logger2.log("User logged in.") # 输出: [LOG]: User logged in.
总结
以上两段代码分别演示了常规封装技术和单例设计模式中的封装实践。前者强调的是对敏感字段的有效隔离;后者则进一步扩展到整个类层面,保证资源使用的统一性。