深入理解Python中的类和对象是掌握面向对象编程(OOP)的关键。在Python中,类和对象是一种组织和封装代码以及数据的方式,使得代码更易于理解、扩展和维护。下面我们将通过一系列示例来探索Python中类与对象的奥秘世界。
1. 面向对象
面向对象(Object-Oriented Programming,简称OOP)是一种程序设计范型,或者程序设计的方法。它利用“对象”来设计应用程序,对象的属性反映事物的状态,方法则用来实现对象的行为。面向对象的主要思想是将现实世界的事物抽象成对象,对象之间通过消息进行通信。OOP的三大特性是:封装、继承和多态。
1.1 面向对象的定义
百度百科说:面向对象(Object Oriented)是软件开发方法,一种编程范式。面向对象的概念和应用已超越了程序设计和软件开发,扩展到如数据库系统、交互式界面、应用结构、应用平台、分布式系统、网络管理结构、CAD技术、人工智能等领域。面向对象是一种对现实世界理解和抽象的方法,是计算机编程技术发展到一定阶段后的产物。
面向对象是相对于面向过程来讲的,面向对象方法,把相关的数据和方法组织为一个整体来看待,从更高的层次来进行系统建模,更贴近事物的自然运行模式。
1.2 面向对象的三大基本特征
面向对象的特征主要包括以下几个方面:
-
封装性(Encapsulation)
封装性是指将对象的属性和方法(或称为成员变量和成员函数)结合成一个独立的单元,并对它们加以保护,使得类的外部只能访问特定的属性和方法。在面向对象的程序设计中,信息隐蔽是一个重要的原则,可以通过类的访问修饰符(如public
、private
、protected
等)来实现封装性。封装性的好处是隐藏了类的内部实现细节,使得代码更加安全、可维护和可重用。 -
继承性(Inheritance)
继承性允许创建分等级层次的类。继承表示的是一个类(称为子类或派生类)可以继承另一个类(称为父类或基类)的成员(包括属性和方法)。子类可以继承父类的属性和方法,也可以添加新的属性和方法,或者重写父类的方法。继承性使得代码更加模块化,提高了代码的可重用性,同时也便于管理和扩展代码。 -
多态性(Polymorphism)
多态性是指不同的对象对同一消息做出不同的响应。在面向对象的程序设计中,多态性是通过继承和接口实现的。同一个类中的方法名可以在子类中重载,而同一个接口的方法可以在不同的类中实现。这样,在运行时就可以根据对象的实际类型来决定调用哪个版本的方法,从而实现了多态性。多态性的好处是提高了代码的灵活性和可扩展性。
这三大特性(封装性、继承性、多态性)共同构成了面向对象程序设计的基石,它们使得代码更加模块化、可重用、可维护和可扩展。
1.3 面向对象的设计原则
面向对象的七大设计原则包括:
- 开闭原则(Open Close Principle):系统应对扩展开放,对修改关闭,即在不修改现有代码的基础上,能够扩展新功能。
- 里氏替换原则(Liskov Substitution Principle):子类必须能够替换其基类而不会引起程序行为的改变。
- 依赖倒置原则(Dependency Inversion Principle):高层模块不应该依赖于低层模块,而应该依赖于抽象。抽象不应该依赖于细节,细节应该依赖于抽象。
- 单一职责原则(Single Responsibility Principle):一个类应该只有一个引起变化的原因,即一个类应该只有一个职责。
- 接口隔离原则(Interface Segregation Principle):客户端不应该依赖于它不需要的接口,接口应该尽可能小且专注于单一职责。
- 迪米特法则(Law of Demeter):一个对象应当尽可能少地了解其他对象,即对象之间的耦合度应尽可能低。
- 合成复用原则(Composite Reuse Principle):优先使用组合或聚合关系来复用已有的对象,而不是通过继承来实现代码复用。
这些原则是面向对象设计中的基本准则,旨在提高软件的可维护性、可扩展性和灵活性
2. 类与对象
2.1 什么是类?
类是面向对象程序设计(OOP)的核心概念之一,它是实现信息封装的基础。类是一种用户定义的引用数据类型,每个类包含数据说明和一组操作数据或传递消息的函数。
2.2 什么是对象?
对象(Object) 在面向对象的编程(Object-Oriented Programming,简称 OOP)中是一个核心概念。对象可以看作是现实世界中任何实体在软件中的抽象表示。它通常具有状态(即属性,或称为成员变量)和行为(即方法,或称为成员函数)。
类和对象是面向对象编程中的两个核心概念,类是对象的抽象,而对象是类的具体实例。类是抽象的,不占用内存,而对象是具体的,占用存储空间。类是用于创建对象的蓝图,它是一个定义包括在特定类型的对象中的方法和变量的软件模板。
2.3 类的声明
类的声明格式为:
class 类名:
//类的属性
//类的方法
-
类名:类名是一个标识符,用于定义和引用一个类。类名的命名应遵循Python的标识符命名规则,具体如下:
- 类名必须以字母或下划线(_)开头,后面可以跟任意数量的字母、数字或下划线。
- 类名不能与Python内置的关键字冲突,如class、def、if、for等。
- 通常,类名使用驼峰命名法(CamelCase),即每个单词的首字母大写,单词之间不使用下划线分隔。例如,MyClass、MySpecialClass。
-
属性:类的属性通常指的是类变量和实例变量。这两种类型的变量在定义和使用上有所不同。
- 类变量也称为静态变量,是定义在类中但在任何方法之外的变量。类变量是所有实例共享的,对类变量的修改会影响到所有的实例。类变量通常用于定义类的某些状态或属性,这些属性与类的所有实例都相关。
-
方法:可以定义类对象的动作。它们封装了与类相关的逻辑,并允许通过类的实例来调用这些逻辑。
Python中类的属性主要有三种类型:类属性、实例属性和私有属性。
2.4 类的属性
在Python中,类的属性主要分为两种:类属性(Class Attributes)和实例属性(Instance Attributes),尽管还可以包括一些特殊的属性(如方法)。但从常规意义上讲,当我们谈论类的“属性”时,我们主要指的是类属性和实例属性。
2.4.1 类属性(Class Attributes)
类属性是定义在类中但在任何方法之外的变量,它们与类本身相关联,而不是类的特定实例。类属性由所有类的实例共享,并且可以通过类名或类的实例来访问。
class MyClass:
class_attribute = "I am a class attribute"
# 通过类名访问类属性
print(MyClass.class_attribute) # 输出: I am a class attribute
# 创建一个类的实例
obj = MyClass()
# 通过实例访问类属性(不推荐,因为可能导致混淆)
print(obj.class_attribute) # 输出: I am a class attribute
2.4.2 实例属性(Instance Attributes)
实例属性是定义在类的方法中(通常是__init__
方法中)的变量,它们与类的特定实例相关联。实例属性仅存在于类的实例中,并通过实例来访问。
class MyClass:
def __init__(self, instance_value):
self.instance_attribute = instance_value
# 创建一个类的实例并设置实例属性
obj = MyClass("I am an instance attribute")
# 通过实例访问实例属性
print(obj.instance_attribute) # 输出: I am an instance attribute
2.4.3 私有属性(Special Attributes 或 Magic Attributes)
__private_attrs:两个下划线开头,声明该属性为私有,不能在类的外部被使用或直接访问。在类内部的方法中使用时 self.__private_attrs。
#!/usr/bin/python3
class JustCounter:
__secretCount = 0 # 私有变量
publicCount = 0 # 公开变量
def count(self):
self.__secretCount += 1
self.publicCount += 1
print (self.__secretCount)
counter = JustCounter()
counter.count()
counter.count()
print (counter.publicCount)
print (counter.__secretCount) # 报错,实例不能访问私有变量
2.5 类的方法
在Python中,类的方法是与类关联的函数,它们可以在类的实例上调用,或者作为类本身的方法调用(如果它们被定义为类方法或静态方法)。类的方法主要有三种类型:实例方法、类方法和静态方法。
2.5.1 实例方法(Instance Methods)
实例方法是与类实例(对象)关联的方法。它们必须至少有一个参数,通常命名为self
,该参数引用实例本身。
class MyClass:
def __init__(self, value):
self.value = value
def my_instance_method(self):
print(f"The value is: {self.value}")
# 创建对象并调用实例方法
obj = MyClass(10)
obj.my_instance_method() # 输出: The value is: 10
2.5.2 类方法(Class Methods)
类方法是与类关联的方法,可以通过类本身或类的实例调用。类方法使用@classmethod
装饰器定义,并且第一个参数是类本身,通常命名为cls
。
class MyClass:
def __init__(self, value):
self.value = value
@classmethod
def my_class_method(cls, arg):
print(f"Class method called with arg: {arg}")
# 通过类调用类方法
MyClass.my_class_method('hello') # 输出: Class method called with arg: hello
# 也可以通过实例调用类方法,但这样做并不常见
obj = MyClass(10)
obj.my_class_method('world') # 输出: Class method called with arg: world
2.5.3 静态方法(Static Methods)
静态方法与类关联,但它们不需要访问类的状态或实例状态。静态方法可以通过类本身或类的实例调用,但不像实例方法那样有self
参数,也不像类方法那样有cls
参数。静态方法使用@staticmethod
装饰器定义。
class MyClass:
def __init__(self, value):
self.value = value
@staticmethod
def my_static_method(arg):
print(f"Static method called with arg: {arg}")
# 通过类调用静态方法
MyClass.my_static_method('foo') # 输出: Static method called with arg: foo
# 也可以通过实例调用静态方法
obj = MyClass(10)
obj.my_static_method('bar') # 输出: Static method called with arg: bar
2.5.4 特殊方法(Special Methods 或 Magic Methods)
这些方法是由双下划线(__
)前缀和后缀包围的,它们是Python内置的,用于实现类的特殊功能或行为。虽然它们也是类的属性,但通常不直接作为类的常规属性来讨论。一些常见的特殊属性包括:
__init__
: 类的构造函数,用于初始化实例。__str__
: 当使用str()
函数或print()
函数时调用,返回对象的字符串表示。__repr__
: 返回一个对象的“官方”字符串表示,主要用于调试。__len__
: 当使用内置的len()
函数时调用,返回对象的长度。__call__
: 允许类的对象像函数一样被调用。__dict__
: 返回对象的属性字典。
当涉及到Python中的特殊属性(也称为魔法方法或双下划线方法)时,以下是一些常用的特殊属性及其使用示例:
- 示例 1. __init__
用于初始化实例。当你创建一个新的类实例时,会自动调用此方法。
class MyClass:
def __init__(self, value):
self.value = value
# 创建实例
obj = MyClass(10)
# 现在 obj 有一个属性 value,值为 10
print(obj.value) # 输出: 10
- 示例 2. __str__
定义对象的字符串表示形式。当你尝试将对象转换为字符串时(如使用print
函数或str()
函数时),会调用此方法。
class MyClass:
def __init__(self, value):
self.value = value
def __str__(self):
return f"MyClass({self.value})"
# 创建实例
obj = MyClass(10)
# 转换为字符串并打印
print(obj) # 输出: MyClass(10)
- 示例 3. __repr__
定义对象的官方字符串表示形式。如果未定义__str__
,__repr__
也会被用于print
函数。此外,当你在Python shell或交互式环境中输入对象名并回车时,也会调用此方法。
class MyClass:
def __init__(self, value):
self.value = value
def __repr__(self):
return f"MyClass(value={self.value})"
# 创建实例
obj = MyClass(10)
# 在Python shell中直接输入对象名并回车
# 将显示类似于 'MyClass(value=10)' 的输出
- 示例 4. __len__
定义对象长度的计算方式。当你对对象使用内置的len()
函数时,会调用此方法。
class MySequence:
def __init__(self, *args):
self.values = list(args)
def __len__(self):
return len(self.values)
# 创建实例
seq = MySequence(1, 2, 3, 4, 5)
# 计算长度
print(len(seq)) # 输出: 5
- 示例 5. __call__
定义对象的调用行为。当你像函数一样调用对象时(即对象后跟括号),会调用此方法。
class CallableObject:
def __call__(self, x, y):
return x + y
# 创建实例
callable_obj = CallableObject()
# 调用对象(就像调用函数一样)
result = callable_obj(3, 4)
print(result) # 输出: 7
- 示例 6. __getitem__
, __setitem__
, __delitem__
分别用于实现对象索引、设置索引值、删除索引值的行为。这使你能够像操作列表或字典一样操作自定义对象。
class MyCollection:
def __init__(self):
self.values = []
def __getitem__(self, index):
return self.values[index]
def __setitem__(self, index, value):
self.values[index] = value
def __delitem__(self, index):
del self.values[index]
# 创建实例
coll = MyCollection()
# 使用索引设置值
coll[0] = 10
# 使用索引获取值
print(coll[0]) # 输出: 10
# 使用索引删除值
del coll[0]
注意:虽然特殊属性在技术上也是类的属性,但它们通常被视为类定义和实现特定行为的一部分,而不是存储数据的普通属性。
这些特殊方法提供了很大的灵活性,使你可以根据需要定制Python类的行为。在创建自定义类时,合理使用这些特殊方法可以增强类的功能性和易用性。
2.6 类对象
在Python中,类(Class)是一个用户定义的蓝图或原型,用于创建对象(Object)。对象是类的实例,它们通过类的构造函数(在Python中通常是__init__
方法)来创建,并具有类的属性和方法。
以下是一个简单的例子,展示了如何在Python中定义一个类以及如何创建该类的对象:
# 定义一个类
class Dog:
# 类的属性(静态属性或类变量),但通常我们会直接在__init__中定义实例属性
species = "犬科"
# 构造函数(也称为初始化方法),当创建类的实例时自动调用
def __init__(self, name, age):
# 实例属性(每个对象独有的)
self.name = name
self.age = age
# 类的方法
def bark(self):
print(f"{self.name} says: Woof! I am {self.age} years old.")
# 类的另一个方法
def description(self):
return f"{self.name} is a {self.species} and is {self.age} years old."
# 创建类的实例(对象)
my_dog = Dog("Buddy", 3)
# 访问对象的属性
print(my_dog.name) # 输出: Buddy
print(my_dog.age) # 输出: 3
print(my_dog.species) # 输出: 犬科,但注意这是类属性,所有Dog对象共享
# 调用对象的方法
my_dog.bark() # 输出: Buddy says: Woof! I am 3 years old.
print(my_dog.description()) # 输出: Buddy is a 犬科 and is 3 years old.
# 创建一个新的Dog对象
another_dog = Dog("Max", 5)
print(another_dog.name) # 输出: Max
print(another_dog.species) # 输出: 犬科,和my_dog共享相同的类属性
在上面的例子中,Dog
是一个类,my_dog
和another_dog
是Dog
类的实例(对象)。我们通过调用Dog
类并提供适当的参数来创建这些对象。每个对象都有它自己的状态(由实例属性表示,如name
和age
),但也可能共享某些状态(由类属性表示,如species
)。此外,每个对象都可以执行类定义中的方法(如bark
和description
)。
注意:
self
是一个对实例本身的引用,用于访问实例的属性和方法。在类的方法定义中,第一个参数总是self
(虽然在调用该方法时不需要显式提供)。- 类属性(如
species
)是在类级别定义的,而不是在__init__
方法中。这意味着所有该类的实例都会共享这个属性。如果你修改了一个实例的类属性,它会影响所有的实例(除非你在某个实例上重新定义了该属性)。
2.7 金融示例
当我们在金融领域使用Python的类和对象时,可以创建许多有用的抽象和数据结构。
以下是一个使用类和对象在金融领域中的示例,假设我们正在开发一个简单的股票投资组合管理系统。
2.7.1 创建一个股票类(Stock)
首先,我们定义一个Stock
类,用于表示股票市场中的一只股票。这个类将包含股票的名称、当前价格、购买价格、购买数量等属性,以及计算盈亏等方法。
class Stock:
def __init__(self, name, current_price, purchase_price, quantity):
self.name = name
self.current_price = current_price
self.purchase_price = purchase_price
self.quantity = quantity
def calculate_profit(self):
"""计算该股票的盈亏"""
profit_per_share = self.current_price - self.purchase_price
total_profit = profit_per_share * self.quantity
return total_profit
def __str__(self):
"""返回股票信息的字符串表示"""
return f"{self.name} - 当前价格: {self.current_price}, 购买价格: {self.purchase_price}, 数量: {self.quantity}"
2.7.2 投资组合类(Portfolio)
接下来,我们定义一个Portfolio
类,用于表示一个股票投资组合。这个类将包含一个股票列表,以及计算总投资、总盈亏等方法。
class Portfolio:
def __init__(self):
self.stocks = []
def add_stock(self, stock):
"""向投资组合中添加一只股票"""
self.stocks.append(stock)
def total_investment(self):
"""计算总投资额"""
total = 0
for stock in self.stocks:
total += stock.quantity * stock.purchase_price
return total
def total_profit(self):
"""计算总盈亏"""
total = 0
for stock in self.stocks:
total += stock.calculate_profit()
return total
def __str__(self):
"""返回投资组合信息的字符串表示"""
portfolio_str = "投资组合:\n"
for stock in self.stocks:
portfolio_str += f"{stock}\n"
portfolio_str += f"总投资: {self.total_investment()}\n"
portfolio_str += f"总盈亏: {self.total_profit()}\n"
return portfolio_str
2.7.3 调用
现在我们可以使用这些类来创建一个简单的投资组合,并计算其盈亏情况。
# 创建股票对象
stock1 = Stock("Apple", 150.0, 100.0, 100)
stock2 = Stock("Google", 2000.0, 1800.0, 50)
# 创建投资组合对象并添加股票
portfolio = Portfolio()
portfolio.add_stock(stock1)
portfolio.add_stock(stock2)
# 打印投资组合信息
print(portfolio)
这个示例展示了如何使用Python的类和对象来模拟金融领域中的股票和投资组合。通过使用这些类,我们可以更容易地管理和操作这些金融实体,并计算它们的相关指标。这仅仅是OOP在金融领域应用的一个简单示例,实际上我们可以根据需要创建更复杂的类和对象来模拟金融市场的各个方面。