跳到主要内容 Python 面向对象编程:软件对象基础与封装 | 极客日志
Python 算法
Python 面向对象编程:软件对象基础与封装 介绍 Python 面向对象编程(OOP)核心概念。涵盖类与对象的定义、实例化过程、构造器__init__、字符串表示__str__、类属性与静态方法。重点讲解对象封装原则,包括私有特性与方法的使用,以及@property 装饰器控制属性访问。通过 Critter 虚拟宠物示例演示了如何设计类结构、管理状态及实现交互逻辑。
山野诗人 发布于 2026/3/28 更新于 2026/4/17 6 浏览Python 面向对象编程
Python 与 Java 一样都是面向对象编程(Object-oriented programming, OOP)。
单词 :
critter /ˈkrɪtə $ -ər/ noun
a creature, especially an animal 生物;〔尤指〕动物
最终会以 Critter Caretaker 程序来展示面向对象编程。Critter Caretaker 程序的功能是让用户去照顾自己的虚拟宠物。用户需要给小动物起名,还要通过给小动物喂好吃的、和它一起玩来让它保持好心情。需要倾听小动物的心声,来了解它现在是高兴还是生气。
面向对象基础知识
特性(attribute)与方法(method)
面向对象编程(OOP)是一种编程思考方式,OOP 中的基本构建单元是软件对象(software object),也称为对象(object)。OOP 允许用户将真实世界中的对象表示为软件对象,与真实世界中的对象一样,软件对象也有特征。比如真实世界中的小动物有名字,有颜色,有年龄,可以吃东西,可以跑,可以叫等等。这些特征表现在软件对象中,'名字','颜色','年龄'等这些名词就是软件对象的特性(attribute),'吃东西','跑','叫'这些行为就是方法(method)。
在程序中对象(object)是如何被表示出来的呢?
对象通过类(class)来创建(又称为实例化,instantiate)——用于定义对象属性和方法的代码都在类中编写。
类(class)好比是设计图,类不是对象,只是对象的设计图,可以根据同一个类实例化出各个对象(aka 实例,instance),这些实例拥有相同的结构。比如有一个 Critter 类,基于这个类我们就可以实例化出 cat, dog, panda 等等小动物。
面向对象编程
创建类、方法和对象
定义类 class Critter (object ):
pass
解释:class 是关键字,Critter 是类名,约定俗成类名以大写字母开头。object 是一个最基本的内建类型,类可以基于 object 或其他任何已经定义好的类。
定义方法 def talk (self ):
print ("Hi. I'm an instance of class Critter." )
解释:实例方法的定义方式与之前介绍的函数定义方式相同。在任何实例方法中都必须有一个特殊的第一参数 -- self,该参数使方法能够访问他所属的对象。如果实例方法没有任何参数的话,调用的时候会报错。
实例化对象
调用实例方法
init (self) 构造器方法(constructor method)又称为初始化方法(initialization method),构造器方法通常用于设置对象的初始值,在新对象被创建后,构造器方法会被自动调用。
创建构造器 def __init__ (self ):
print ("A new critter has been born!" )
解释:__init__ 是 Python 内建的'特殊方法',可以被 Python 识别,告诉 Python 这是一个构造器方法。每当创建新的 Critter 对象进入其生命周期后,__init__() 会被自动调用。
def __init__ (self, name ):
self .name = name
crit1 = Critter("Poochie" )
需要注意的是,这里的参数需要与 __init__ 中的一致,如果 __init__(self),没有后面的 name 参数,使用 Critter("Poochie") 会提示错误。
TypeError: Critter.__init__() takes 1 positional argument but 2 were given
self 参数 self 是所有方法的第一个参数,会自动接收调用该方法的对象的引用。也就是说,通过 self,方法可以获取调用它的那个对象,于是就可以访问该对象的特性和方法了,也可以为该对象创建新特性。
在上面的例子中,def __init__(self, name): 参数 self 自动接收新 Critter 对象的引用,参数 name 则接收'Poochie'。'self.name = name'会为该对象创建出特性 name,并将其设置为参数 name 的值。
Python 有很多内建的'特殊方法',都是以双下划线开始和结尾的。
str (self) 格式化输出格式为自己的对象创建其字符串表示方式。当对象被打印时会显示这个字符串。程序自动调用。
def __str__ (self ):
rep = "Critter object\n"
rep += "name: " + self .name + "\n"
return rep
如果定义了 __str__ 方法执行 print(crit1) 时,会打印如下:
Critter object
name: Poochie
如果没有定义 __str__ 方法执行 print(crit1) 时,打印如下:
<__main__.Critter object at 0x00000248B01D0BF0 >
class Critter (object ):
"""A virtual pet"""
def __init__ (self, name ):
print ("A new critter has been born!" )
self .name = name
def __str__ (self ):
rep = "Critter object\n"
rep += "name: " + self .name + "\n"
return rep
def talk (self ):
print ("Hi. I'm" , self .name, "\n" )
crit1 = Critter("Poochie" )
crit1.talk()
crit2 = Critter("Randolph" )
crit2.talk()
print ("Printing crit1: " )
print (crit1)
print ("Printing crit1.name: " )
print (crit1.name)
input ("\n\nPress the enter key to exit." )
类特性(class attribute) 上面有提到对象特性,相同类的不同对象可以拥有各自专属的值。比如十只小狗,拥有属于自己独特的名字。
而类特性,与对象无关,但与整个类有关。比如用户希望记录总共创建了多少动物,添加一个 total 特性,每实例化一个新对象,就更新 total 特性。
类特性是类本身的值。不管创建多少个对象类特性只有一份。
定义类特性 class Critter (object ):
total = 0
访问类特性 Critter.total
crit1.total
对类特性赋值 Critter.total += 1
crit1.total += 1
静态方法 @staticmethod 与类特性类似,属于类本身。通过类来调用,而非通过对象。
定义静态方法 class Critter (object ):
total = 0
@staticmethod
def status ():
print ("\nThe total number of critters is" , Critter.total)
解释:因为静态方法都是通过类来调用的,所以无需 self 参数。修饰符 @staticmethod 表示该方法为静态方法。
调用静态方法
class Critter (object ):
"""A virtual pet"""
total = 0
@staticmethod
def status ():
print ("\nThe total number of critters is" , Critter.total)
def __init__ (self, name ):
print ("A critter has been born!" )
self .name = name
Critter.total += 1
print ("Accessing the class attribute Critter.total:" )
print (Critter.total)
print ("\nCreating critters." )
crit1 = Critter("critter1" )
crit2 = Critter("critter2" )
crit3 = Critter("critter3" )
Critter.status(Critter)
print ("\nAccessing the class attribute through an object:" )
print (crit1.total)
input ("\n\nPress the enter key to exit." )
对象封装
函数是封装起来的,对程序主体部分中调用它的那些代码隐藏其内部工作细节。客户端与函数之间只会通过参数和返回值进行通信。
对象封装可以理解为客户端与对象之间之通过方法的参数和返回值进行通信。客户端代码应避免直接修改对象的特性值。
举个例子,假设有一个对象 Checking_Account 对象,它有一个 balance 特性。现在需要处理取款业务(在某个对象的 balance 特性上减去某个数值)。要实现取款,客户端可以直接从 balance 上减去一个数,这种直接访问的方式很简单,但会导致一些问题,比如客户端可以把 balance 改为负数。
最好的方式是,写一个 withdraw() 的方法,然后让客户端通过向该方法传递取款金额的方式来请求一次取款操作。具体的工作又对象自己去处理。如果取款数额太大,对象可以对其进行处理,比如直接拒绝此次交易。这种通过方法对特性进行非直接访问的方式能够使类保持足够的安全性。
私有特性 默认情况下,对象的所有特性和方法都是公共的(public),它们可以被客户端直接访问或调用。为了强调封装,可以将特性和方法定义为私有的(private),只有该对象中的其他方法才能轻松访问或调用。
创建私有特性 class Critter (object ):
def __init__ (self, name, mood ):
print ("A new critter has been born!" )
self .name = name
self .__mood = mood
解释:在特性名称前加两个下划线,即可创建出私有特性。
访问私有特性 在 Critter 对象内部访问私有特性,直接使用 self.__mood。
def talk (self ):
print ("\nI'm" , self .name)
print ("Right now I feel" , self .__mood, "\n" )
虽说外部不能直接访问私有特性,但并非绝对,可以使用 crit._Critter__mood 访问到私有特性。
crit = Critter(name="Poochie" , mood="happy" )
print (crit.mood)
print (crit.__mood)
print (crit._Critter__mood)
Python 的私有性只是一种用于说明'特性或方法只应在对象内部使用'的指示器而已,也有助于防止不经意间访问到这样的特性或方法。尽量避免在类定义的外部直接访问对象的私有特性或方法。
属性 (@property) 如何访问对象的私有特性呢?Python 提供了一些技术,比如属性(property),property 可以精确控制特性的访问和修改方式。
创建属性 创建属性就能控制对私有特性的读取访问,可以理解为 Java 中的 getter 方法。
class Critter (object ):
def __init__ (self, name, mood ):
print ("A new critter has been born!" )
self .name = name
self .__mood = mood
@property
def mood (self ):
return self .__mood
写入访问 对私有特性的写入访问,相当于 Java 的 setter 方法。
@mood.setter
def mood (self, new_mood ):
if new_mood == "" :
print ("A critter's mood can't be the empty string." )
else :
self .__mood = new_mood
print ("Mood changes successful" )
使用属性 设置完属性后,在 Critter 类内部访问私有特性:
print ("Right now call property mood, I feel " , self .mood)
设置完属性后,在 Critter 类外部访问和修改私有特性:
crit.mood = "grief"
print (crit.mood)
私有方法
创建私有方法 def __private_method (self ):
print ("This is a private method." )
访问私有方法 def public_method (self ):
print ("This is a public method" )
self .__private_method()
crit = Critter(name="Poochie" , mood="happy" )
print (crit._Critter__mood)
crit.private_method()
crit.__private_method()
crit._Critter__private_method()
尊重对象的隐私性,程序主体部分,要严格要求自己不去触碰对象的私有特性或方法。
要专门编写一些方法来避免出现'客户端需要直接访问对象特性'的情况;
对于那些只会在对象内部使用的特性和方法,应该将它们弄成私有的。
尽量不要直接读取对象的特性;
避免直接修改对象的特性;
永远不要直接访问对象的私有特性或方法。
class Critter (object ):
"""A virtual pet"""
def __init__ (self, name, mood ):
print ("A new critter has been born!" )
self .name = name
self .__mood = mood
@property
def mood (self ):
return self .__mood
@mood.setter
def mood (self, new_mood ):
if new_mood == "" :
print ("A critter's mood can't be the empty string." )
else :
self .__mood = new_mood
print ("Mood changes successful" )
def talk (self ):
print ("\nI'm" , self .name)
print ("Right now I feel" , self .__mood, "\n" )
print ("Right now call property mood, I feel " , self .mood)
def __private_method (self ):
print ("This is a private method." )
def public_method (self ):
print ("This is a public method" )
self .__private_method()
crit = Critter(name="Poochie" , mood="happy" )
crit.mood = "grief"
print (crit.mood)
综合示例:Critter Caretaker 程序
class Critter (object ):
"""A virtual pet"""
def __init__ (self, name, hunger=0 , boredom=0 ):
self .name = name
self .hunger = hunger
self .boredom = boredom
def __pass_time (self ):
self .hunger += 1
self .boredom += 1
@property
def mood (self ):
unhappiness = self .hunger + self .boredom
if unhappiness < 5 :
m = "happy"
elif 5 <= unhappiness <= 10 :
m = "okay"
elif 11 <= unhappiness <= 15 :
m = "frustrated"
else :
m = "mad"
return m
def talk (self ):
print ("I'm" , self .name, "and I feel" , self .mood, "now.\n" )
self .__pass_time()
def eat (self, food=4 ):
print ("Brruppp. Thank you." )
self .hunger -= food
if self .hunger < 0 :
self .hunger = 0
self .__pass_time()
def play (self, fun=4 ):
print ("Wheee!" )
self .boredom -= fun
if self .boredom < 0 :
self .boredom = 0
self .__pass_time()
def main ():
crit_name = input ("What do you want to name your critter?: " )
crit = Critter(crit_name)
choice = None
while choice != "0" :
print ("""
Critter Caretaker
0 - Quit
1 - Listen to your critter
2 - Feed your critter
3 - Play with your critter
""" )
choice = input ("Choice: " )
print ()
if choice == "0" :
print ("Good-bye." )
elif choice == "1" :
crit.talk()
elif choice == "2" :
crit.eat()
elif choice == "3" :
crit.play()
else :
print ("\nSorry, but" , choice, "isn't a valid choice." )
main()
input ("\n\nPress the enter key to exit." )
微信扫一扫,关注极客日志 微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
相关免费在线工具 加密/解密文本 使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
curl 转代码 解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
Markdown转HTML 将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
HTML转Markdown 将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online