面向对象编程(Object-Oriented Programming,简称OOP)是一种以对象为核心的编程范式。Python是一种支持多种编程范式的语言,其中对OOP的支持尤为强大和灵活。本文将通过以下几个方面介绍Python中的OOP:
目录
面向对象编程(OOP)在Python中的应用
1. 基本概念
2. 类和对象
3. 继承
4. 多态
5. 封装
6. 面向对象设计的实践准则
7. 面向对象的理解
Object类
1. 基本方法
__init__(self, ...)
__new__(cls, ...)
2. 字符串和表示方法
__str__(self)
__repr__(self)
3. 比较与哈希
__eq__(self, other)
__hash__(self)
4. 内存管理
__del__(self)
__sizeof__(self)
5. 其他通用方法
__getattribute__(self, name)
__setattr__(self, name, value)
__delattr__(self, name)
6. 动态方法
__dir__(self)
系统函数及其对应的类方法(表格)
在OOP中,以下几个核心概念需要理解:
类(Class):描述对象的抽象蓝图,包括属性和方法。
对象(Object):类的实例,是类的具体表现形式。
属性(Attribute):类中描述对象特征的变量。
方法(Method):类中定义的函数,表示对象的行为。
在Python中,定义类使用class
关键字,创建对象通过调用类。
# 定义一个简单的类
class Animal:
def __init__(self, name, sound):
self.name = name # 属性
self.sound = sound # 属性
def make_sound(self):
# 方法
return f"{self.name} says {self.sound}"
# 创建对象
cat = Animal("Cat", "Meow")
dog = Animal("Dog", "Woof")
print(cat.make_sound()) # 输出: Cat says Meow
print(dog.make_sound()) # 输出: Dog says Woof
__init__
是类的构造方法,用于初始化对象。
self
表示当前实例对象,必须作为方法的第一个参数。
继承允许我们基于现有类创建新类,新的类(子类)可以重用、扩展或修改父类的功能。
# 定义父类
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
return "Unknown sound"
# 定义子类
class Dog(Animal):
def speak(self):
return f"{self.name} says Woof!"
class Cat(Animal):
def speak(self):
return f"{self.name} says Meow!"
# 创建子类实例
dog = Dog("Buddy")
cat = Cat("Kitty")
print(dog.speak()) # 输出: Buddy says Woof!
print(cat.speak()) # 输出: Kitty says Meow!
子类通过继承获得父类的属性和方法,并可以根据需要重写方法。
参考链接:Python 继承详解
优点:
代码复用:子类继承了父类的属性和方法,减少了代码冗余。
扩展性强:可以在子类中添加新的属性或重写父类方法,实现功能扩展。
层次结构清晰:通过继承可以建立类与类之间的层次关系,有助于代码的组织和维护。
多态是指同一接口,表现出不同的行为。我们可以在不关心对象具体类型的情况下调用方法。
def animal_sound(animal):
print(animal.speak())
# 多态示例
animals = [Dog("Buddy"), Cat("Kitty")]
for animal in animals:
animal_sound(animal)
在上述代码中,无论传入的是Dog
还是Cat
,animal_sound
函数都能正确调用speak
方法。
优点:
接口统一:不同子类可以实现同一个方法,调用时无需关心具体对象的类型,代码更灵活。
扩展性强:可以轻松添加新的子类,而不影响现有代码。
降低耦合:调用者只需关注接口而无需了解具体实现细节,提高代码的可维护性。
封装通过控制属性的访问级别来实现数据保护。Python中通过以下方式实现:
单下划线_
:提示属性是保护的,不建议直接访问。
双下划线__
:实现属性的私有化。
class BankAccount:
def __init__(self, balance):
self.__balance = balance # 私有属性
def deposit(self, amount):
if amount > 0:
self.__balance += amount
def withdraw(self, amount):
if 0 < amount <= self.__balance:
self.__balance -= amount
def get_balance(self):
return self.__balance
account = BankAccount(1000)
account.deposit(500)
account.withdraw(200)
print(account.get_balance()) # 输出: 1300
直接访问__balance
会报错,必须通过类提供的方法访问。
优点:
数据安全性:通过限制直接访问属性,避免外部代码对属性的不当修改。
操作简化:提供统一的访问方法(getter和setter),方便操作数据。
灵活性高:可以对数据的访问进行更多的控制,比如添加验证逻辑。
单一职责原则:一个类只负责一个职责。
开闭原则:类应该对扩展开放,对修改关闭。
组合优于继承:优先考虑通过组合对象实现功能,而不是通过继承。
避免过度设计:保持代码简单,避免为未来的需求设计过多抽象。
面向对象的核心思想是将现实世界中的事物抽象为对象,并通过对象的属性和方法对其进行操作。简而言之,面向对象就是[对象].[属性/方法]。
如果你不理解,那么请看下列代码
# 1
"hello".split() # "hello"是字符串对象,split()是字符串对象的类方法,他们维护着一个字符串
# 2
s = "hello"
len(s) # s是一个字符串对象,len()实际上是调用的字符串对象的__len__()方法,如果没有这个方法,那么len(s)会报错:TypeError: object of type 'xx' has no len()
上述代码实际上都是在维护类中的某个属性,为了操纵某个属性而写了众多的类方法,又叫接口,供使用者调用。
实际上,这种设计理念的目标是维护某类属性,使代码更贴近现实逻辑、更易于理解和维护。例如:
car = Car("Toyota", "Corolla")
print(car.brand) # 属性: 输出品牌
print(car.drive()) # 方法: 调用驾驶行为
从深入的层面理解,面向对象是一种通过分解问题并将解决方案模块化的思考方式。现实世界中的事物通常是复杂的,OOP通过将功能组织到类和对象中,将这些复杂性分解为更小、更可管理的部分。
抽象世界:面向对象通过类将事物的共性抽象出来,用对象表达具体实例。类是模板,实例是现实。
比如,汽车可以抽象为类,而某辆具体的汽车是该类的一个实例。
强调状态和行为的结合:
状态:对象的属性(比如汽车的品牌、颜色)。
行为:对象的方法(比如启动、驾驶)。
重视逻辑封装:通过隐藏实现细节并只暴露必要的接口,面向对象确保了代码模块的独立性和安全性。
自然的模拟:面向对象和人类理解事物的方式一致,易于建模现实世界的问题。
以下是 object
类主要方法和属性的汇总表:
方法/属性 | 描述 | 示例 |
---|---|---|
__init__(self, …) |
构造方法,初始化对象。 | def __init__(self, name): self.name = name |
__new__(cls, …) |
创建对象实例,在 __init__ 之前调用。 |
def __new__(cls, *args): return super().__new__(cls) |
__str__(self) |
返回对象的“可读”字符串表示,供用户查看。 | def __str__(self): return f"MyClass(name={self.name})" |
__repr__(self) |
返回对象的“官方”字符串表示,供开发者查看。 | def __repr__(self): return f"MyClass(name={self.name!r})" |
__eq__(self, …) |
定义对象的相等性比较 (== )。 |
def __eq__(self, other): return self.value == other.value |
__hash__(self) |
返回对象的哈希值,用于字典键或集合元素。 | def __hash__(self): return hash(self.value) |
__del__(self) |
对象被销毁时调用,用于清理资源。 | def __del__(self): print("Object deleted") |
__sizeof__(self) |
返回对象的内存大小(字节)。 | def __sizeof__(self): return super().__sizeof__() |
__getattribute__() |
在访问属性时调用,用于拦截属性访问。 | def __getattribute__(self, name): return super().__getattribute__(name) |
__setattr__(self) |
在设置属性时调用,用于拦截属性赋值。 | def __setattr__(self, name, value): super().__setattr__(name, value) |
__delattr__(self) |
在删除属性时调用,用于拦截属性删除。 | def __delattr__(self, name): super().__delattr__(name) |
__dir__(self) |
自定义 dir() 方法返回的属性列表。 |
def __dir__(self): return ['custom_attribute'] |
__format__(self) |
定义对象的格式化字符串表示(支持 format() 函数)。 |
def __format__(self, format_spec): return f"Formatted {self.value}" |
__reduce__(self) |
提供对象序列化支持(如用于 pickle )。 |
def __reduce__(self): return (MyClass, (self.value,)) |
__reduce_ex__() |
类似于 __reduce__ ,但支持扩展协议。 |
- |
__subclasshook__() |
用于动态判断类是否是某个抽象基类的子类。 | @classmethod def __subclasshook__(cls, subclass): return True if 'method' in dir(subclass) else NotImplemented |
__class__ |
表示对象所属的类。 | obj.__class__ |
__doc__ |
类或方法的文档字符串。 | MyClass.__doc__ |
__init__(self, ...)
class MyClass:
def __init__(self, name):
self.name = name
obj = MyClass("Alice")
__new__(cls, ...)
__init__
配合使用,但很少直接重写。class MyClass:
def __new__(cls, *args, **kwargs):
print("Creating instance")
return super().__new__(cls)
def __init__(self, name):
self.name = name
obj = MyClass("Alice")
__str__(self)
print()
或 str()
时被调用。class MyClass:
def __str__(self):
return f"MyClass with name {self.name}"
def __init__(self, name):
self.name = name
obj = MyClass("Alice")
print(obj) # 输出:MyClass with name Alice
__repr__(self)
__repr__
主要是为开发者设计的,__str__
面向用户。class MyClass:
def __repr__(self):
return f"MyClass(name={self.name!r})"
def __init__(self, name):
self.name = name
obj = MyClass("Alice")
print(repr(obj)) # 输出:MyClass(name='Alice')
__eq__(self, other)
==
)。class MyClass:
def __init__(self, value):
self.value = value
def __eq__(self, other):
return self.value == other.value
obj1 = MyClass(10)
obj2 = MyClass(10)
print(obj1 == obj2) # 输出:True
__hash__(self)
__eq__
,通常也需要重写 __hash__
,以确保一致性。class MyClass:
def __init__(self, value):
self.value = value
def __eq__(self, other):
return self.value == other.value
def __hash__(self):
return hash(self.value)
obj1 = MyClass(10)
obj2 = MyClass(10)
print(hash(obj1) == hash(obj2)) # 输出:True
__del__(self)
try...finally
或上下文管理器 (with
)。class MyClass:
def __del__(self):
print("Object is being deleted")
obj = MyClass()
del obj # 输出:Object is being deleted
__sizeof__(self)
class MyClass:
pass
obj = MyClass()
print(obj.__sizeof__()) # 输出:默认对象的内存大小
__getattribute__(self, name)
class MyClass:
def __getattribute__(self, name):
print(f"Accessing {name}")
return super().__getattribute__(name)
def __init__(self, value):
self.value = value
obj = MyClass(10)
print(obj.value) # 输出:Accessing value
__setattr__(self, name, value)
class MyClass:
def __setattr__(self, name, value):
print(f"Setting {name} to {value}")
super().__setattr__(name, value)
obj = MyClass()
obj.value = 10 # 输出:Setting value to 10
__delattr__(self, name)
class MyClass:
def __delattr__(self, name):
print(f"Deleting {name}")
super().__delattr__(name)
obj = MyClass()
obj.value = 10
del obj.value # 输出:Deleting value
__dir__(self)
dir()
函数的返回值。class MyClass:
def __dir__(self):
return ['custom_attribute']
obj = MyClass()
print(dir(obj)) # 输出:['custom_attribute']
总结:python的Object类是所有类的父类,其方法和属性有很多,在此不一一列举了,感兴趣可以查看object的源码注释
以下是Python中常见系统函数及其对应的类方法的对比表格:
系统函数 | 对应类方法 | 描述 |
---|---|---|
len(obj) |
obj.__len__() |
返回对象的长度。 |
str(obj) |
obj.__str__() |
返回对象的可读字符串表示。 |
repr(obj) |
obj.__repr__() |
返回对象的“官方”字符串表示,用于调试或记录。 |
abs(obj) |
obj.__abs__() |
返回对象的绝对值。 |
round(obj, ndigits) |
obj.__round__(ndigits) |
返回对象四舍五入的值。 |
hash(obj) |
obj.__hash__() |
返回对象的哈希值。 |
bool(obj) |
obj.__bool__() |
返回对象的布尔值。 |
int(obj) |
obj.__int__() |
将对象转换为整数。 |
float(obj) |
obj.__float__() |
将对象转换为浮点数。 |
complex(obj) |
obj.__complex__() |
将对象转换为复数。 |
bytes(obj) |
obj.__bytes__() |
将对象转换为字节序列。 |
format(obj, spec) |
obj.__format__(spec) |
返回对象的格式化字符串。 |
dir(obj) |
obj.__dir__() |
返回对象的属性列表。 |
getattr(obj, name) |
obj.__getattribute__(name) |
获取对象的属性值。 |
setattr(obj, name, value) |
obj.__setattr__(name, value) |
设置对象的属性值。 |
delattr(obj, name) |
obj.__delattr__(name) |
删除对象的属性。 |
callable(obj) |
obj.__call__() |
检查对象是否可调用,若可调用则调用。 |
iter(obj) |
obj.__iter__() |
返回对象的迭代器。 |
next(obj) |
obj.__next__() |
返回迭代器的下一个值。 |
reversed(obj) |
obj.__reversed__() |
返回对象的反向迭代器。 |
contains(obj, item) |
obj.__contains__(item) |
检查对象是否包含某个项 (in 运算符)。 |
eq(a, b) |
a.__eq__(b) |
检查两个对象是否相等 (== ) 。 |
ne(a, b) |
a.__ne__(b) |
检查两个对象是否不等 (!= ) 。 |
lt(a, b) |
a.__lt__(b) |
检查 a 是否小于 b (< ) 。 |
le(a, b) |
a.__le__(b) |
检查 a 是否小于等于 b (<= ) 。 |
gt(a, b) |
a.__gt__(b) |
检查 a 是否大于 b (> ) 。 |
ge(a, b) |
a.__ge__(b) |
检查 a 是否大于等于 b (>= ) 。 |
add(a, b) |
a.__add__(b) |
返回两个对象的加法结果 (+ ) 。 |
sub(a, b) |
a.__sub__(b) |
返回两个对象的减法结果 (- ) 。 |
mul(a, b) |
a.__mul__(b) |
返回两个对象的乘法结果 (* ) 。 |
truediv(a, b) |
a.__truediv__(b) |
返回两个对象的浮点除法结果 (/ ) 。 |
floordiv(a, b) |
a.__floordiv__(b) |
返回两个对象的整除结果 (// ) 。 |
mod(a, b) |
a.__mod__(b) |
返回两个对象的取模结果 (% ) 。 |
pow(a, b) |
a.__pow__(b) |
返回 a 的 b 次幂 (** ) 。 |
and_(a, b) |
a.__and__(b) |
返回两个对象的按位与结果 (& ) 。 |
or_(a, b) |
a.__or__(b) |
返回两个对象的按位或结果 (` |
xor(a, b) |
a.__xor__(b) |
返回两个对象的按位异或结果 (^ ) 。 |
lshift(a, b) |
a.__lshift__(b) |
返回对象的左移位结果 (<< ) 。 |
rshift(a, b) |
a.__rshift__(b) |
返回对象的右移位结果 (>> ) 。 |
neg(obj) |
obj.__neg__() |
返回对象的负数 (-obj ) 。 |
pos(obj) |
obj.__pos__() |
返回对象的正数 (+obj ) 。 |
invert(obj) |
obj.__invert__() |
返回对象的按位取反结果 (~obj ) 。 |
这个表格列出了Python的系统函数与类方法之间的映射关系,方便查阅和理解两者的对应规则。