在面向对象编程(OOP)这种软件设计方法中,我们使用“对象”来建模现实世界的实体。对象是一种包含属性(数据)和作用于这些数据的方法(函数)的数据结构。使用对象可以让复杂系统更易于设计。
想系统学习 OOP 的基础与软件工程理念,欢迎从我们的 Python 面向对象编程课程 开始。
封装是 OOP 的一个基本概念。它意味着将对象的数据与方法组合在一起,并对外部隐藏实现细节。可以把封装理解为创建一个具有自身数据及其操作方式的“胶囊”(对象)的过程。
封装的主要目的在于:
阻止对数据的直接访问(数据完整性)。
仅暴露必要信息以简化系统(抽象)。
私有方法通过隐藏类的内部实现细节,是实现封装的关键。
将方法设为私有,表示该方法并不打算被直接访问。这样可以确保对象的内部状态只能以受控方式更改,从而避免错误与缺陷。
本文将介绍私有方法、其定义语法、在真实场景中的实现方式,以及使用私有方法的最佳实践。
什么是私有方法?
在面向对象编程(OOP)中,私有方法是类中仅供内部使用的函数。它们封装类的功能,确保内部运作不被外部直接干预。
这种封装提供了一层抽象,使类能够控制其内部状态与行为,并可在不影响外部依赖代码的前提下更改内部实现。
在 Python 中,约定通过在方法名前添加单下划线(_)或双下划线(__)来表示私有方法。这是一种向开发者提示方法预期作用域的惯例,仅为约定。
尽管该约定不像某些语言那样强制隐私,但在 Python 社区中被广泛遵循,用于表明方法的预期用法。稍后我们将更全面地探讨这些方面。
私有方法的语法
定义私有方法有两种方式,我们将通过示例来说明。
可以在函数名前加单下划线来定义私有方法:
class MyClass :
def _private_method ( self) :
print ( "This is a private method" ) 技术支持
这种定义仅是一种对程序员的约定,因为该函数在类外仍然可以访问,但并不推荐这样做。
如果这是您第一次接触 Python 中的类,建议先阅读我们的 初学者友好教程:类(Classes) 。
让我们创建一个对象并尝试访问刚创建的私有方法:
obj = MyClass( )
obj. _private_method( ) 技术支持
在 Python 中还可以使用双下划线来定义私有方法,语法如下:
class MyClass :
def __private_method ( self) :
print ( "This is a private method" )
obj = MyClass( )
技术支持
当我们尝试在类外访问该私有方法时,会抛出 AttributeError,表示不能直接通过函数名访问。
总结一下 Python 中私有方法的语法:
单下划线: 仅是程序员之间的约定,方法在类外仍可访问。
双下划线: 不能仅用函数名在类外直接访问。仍可通过“名称改写(Name Mangling)”访问,我们将在后文介绍。
在 Python 中实现私有方法
以真实场景为例,考虑一个安全且易用的 BankAccount 类,用于管理用户的金融交易。其需求包括:
该类必须封装账户持有人的余额,允许存取款,同时确保余额不能在类外被直接操作。
该类应支持账户间的安全转账,在不暴露内部余额修改机制的情况下更新收款账户的余额。
该方案必须遵循面向对象编程原则,尤其是封装与抽象,以维护账户数据的完整性,并提供清晰、简洁的交互接口。
当然,银行账户还需要更多功能,如余额查询、货币转换、利息处理等——但为简化起见,我们在实现中暂不考虑这些。
让我们动手实现并理解这段代码。
class BankAccount :
def __init__ ( self, account_holder, initial_balance= 0 ) :
self. account_holder = account_holder
self. __balance = initial_balance
def deposit ( self, amount) :
if amount > 0 :
self. __balance += amount
print ( f"Deposited $ { amount} . New balance: $ { self. __balance} " )
else :
print ( "Deposit amount must be positive." )
def withdraw ( self, amount) :
if 0 < amount <= self. __balance:
self. __balance -= amount
print ( f"Withdrew $ { amount} . New balance: $ { self. __balance} " )
else :
print ( "Insufficient funds or invalid amount." )
def __update_balance ( self, amount) :
self. __balance += amount
def transfer ( self, amount, other_account) :
if 0 < amount <= self. __balance:
self. withdraw( amount)
other_account. __update_balance( amount)
print ( f"Transferred $ { amount} to { other_account. account_holder} ." )
else :
print ( "Insufficient funds or invalid amount." ) 技术支持
我们首先创建了一个 BankAccountclass,它封装了 BankAccount 对象所需的所有预期行为与功能。
BankAccount 类包含一个私有属性 __balance 和一个私有方法 __update_balance:
私有变量 (__balance):这是 BankAccount 类的属性,用于存储当前账户余额。通过在名称前添加两个下划线(__)将其标记为私有,表示仅打算在类内部访问。例如,它会在 deposit、withdraw 和 __update_balance 方法中被修改。不建议从外部访问该属性。
私有方法 (__update_balance):用于更新账户余额。该方法由 transfer 在转账操作中调用,以更新收款账户的余额。使用私有方法有助于封装更新余额的逻辑,确保只能通过类中定义的受控方式完成。
您可以新建一个 Python 文件,将以上与下方代码复制粘贴并运行,亲自查看效果。
account1 = BankAccount( "John Doe" , 1000 )
account2 = BankAccount( "Jane Doe" , 500 )
account1. deposit( 200 )
account1. withdraw( 100 )
account1. transfer( 300 , account2) 技术支持
您将看到如下输出:
Deposited $200. New balance: $1200
Withdrew $100. New balance: $1100
Withdrew $300. New balance: $800
Transferred $300 to Jane Doe. 技术支持
恭喜!您已经使用私有方法实现了自己的 BankAccount 解决方案!
从输出可见,在执行存款、取款、转账等常规银行业务时,账户遵循了合理的业务逻辑。
__init__ 方法:它是私有方法吗?
您可能注意到示例中使用了 __init__ 方法。由于它也使用了双下划线,您或许会疑惑它是否也是私有方法。
__init__ 方法并不被视为为隐私目的而加双下划线的那类私有方法。
相反,它属于 Python 的特殊方法,通常称为 “dunder” 方法(“double underscore”的缩写),在语言中具有特定用途。其他此类特殊方法的示例包括 __str__、__repr__ 和 __del__。
让我们看看该特殊方法在示例中的用法:
class BankAccount :
def __init__ ( self, account_holder, initial_balance= 0 ) :
self. account_holder = account_holder
self. __balance = initial_balance技术支持
如上所示,__init__ 方法是类的构造函数。它会在创建类的新实例时自动调用,用于初始化对象的属性。对 BankAccount 类而言,__init__ 用于设置 account_holder 和 __balance 的初始值。
进阶概念:Python 中的名称改写(Name Mangling)
前文提到,Python 中的私有方法更多是一种约定,Python 语言不像其他编程语言那样严格强制隐私。
因此我们看到,使用单下划线时可以直接访问所谓的私有方法,而使用双下划线时访问会受限。
为什么会这样?这源于 Python 中的一个概念——“名称改写(name mangling) ”。
当您在属性名前加上双下划线时,Python 会自动修改该名称:在原属性名前加上单下划线和类名。
类在内部以这种修改后的名称存储该属性。这一修改名称的过程被称为名称改写。
名称改写有两个好处:
防止命名冲突: 在继承中,如果子类定义了与父类同名的属性,会产生冲突。名称改写通过确保名称对每个类唯一来避免此问题。
提供一定程度的私有性: 尽管 Python 不存在真正意义上的私有属性,名称改写可以让属性在类外部更难被访问,从而提供一定程度的私有性。
让我们通过示例来加深理解。
class MyClass :
def __init__ ( self) :
self. __private_attribute = "I am private"
def __private_method ( self) :
print ( "This is a private method" )
obj = MyClass( )
print ( obj. __private_attribute) 技术支持
在此示例中,__private_attribute 和 __private_method 都经过了名称改写。在内部,它们分别存储为 _MyClass__private_attribute 和 _MyClass__private_method。尝试在类外使用原名称访问它们将导致 AttributeError。
不过,您仍可通过改写后的名称来访问它们:
print ( obj. _MyClass__private_attribute)
obj. _MyClass__private_method( ) 技术支持
需要注意的是,名称改写只是让属性更难被访问,并非万无一失的隐私保证。它更多是一种约定,表明该属性仅用于类的内部实现。
使用私有方法与变量的最佳实践
要有效利用私有方法和私有变量,需要遵循一些最佳实践。这些做法有助于确保代码不仅可用,还清晰、可维护且更安全。
建议遵循以下实践:
对“受保护”的属性使用单下划线。 如果希望表示某个属性或方法仅供类及其子类内部使用,而不面向外部,请在其名前加单下划线(_)。这是 Python 中的一种约定,用于向其他开发者传达该成员是“受保护”的,不应直接访问。
对“私有”的属性使用双下划线。 如果希望让某个属性或方法在类外更难被访问,以避免意外修改或误用,请在其名前加双下划线(__)。这会触发名称改写,使得从类外部访问它更困难(但并非不可能)。
将私有方法用于内部逻辑。 带单或双下划线前缀的私有方法适合封装类的内部实现逻辑。将它们用于与类实现细节密切相关且不应作为公共接口暴露的任务。
最后,坚持一致的编码最佳实践非常重要。遵循命名约定并在整个代码库中保持一致,这将使您的代码更易于他人(以及未来的您)理解和维护。
结语
本教程介绍了私有方法背后的概念、其语法以及适用场景。我们还通过多个示例展示了您如何在下一个编码项目中使用它们。最后,我们总结了使用私有方法时需要牢记的一些最佳实践。
如需进一步学习,您可以查看 Python Programming 技能路径 以及 Python 面向对象编程课程 。
在面向对象编程(OOP)这种软件设计方法中,我们使用“对象”来建模现实世界的实体。对象是一种包含属性(数据)和作用于这些数据的方法(函数)的数据结构。使用对象可以让复杂系统更易于设计。
想系统学习 OOP 的基础与软件工程理念,欢迎从我们的 Python 面向对象编程课程开始。
封装是 OOP 的一个基本概念。它意味着将对象的数据与方法组合在一起,并对外部隐藏实现细节。可以把封装理解为创建一个具有自身数据及其操作方式的“胶囊”(对象)的过程。
封装的主要目的在于:
私有方法通过隐藏类的内部实现细节,是实现封装的关键。
将方法设为私有,表示该方法并不打算被直接访问。这样可以确保对象的内部状态只能以受控方式更改,从而避免错误与缺陷。
本文将介绍私有方法、其定义语法、在真实场景中的实现方式,以及使用私有方法的最佳实践。
什么是私有方法?
在面向对象编程(OOP)中,私有方法是类中仅供内部使用的函数。它们封装类的功能,确保内部运作不被外部直接干预。
这种封装提供了一层抽象,使类能够控制其内部状态与行为,并可在不影响外部依赖代码的前提下更改内部实现。
在 Python 中,约定通过在方法名前添加单下划线(_)或双下划线(__)来表示私有方法。这是一种向开发者提示方法预期作用域的惯例,仅为约定。
尽管该约定不像某些语言那样强制隐私,但在 Python 社区中被广泛遵循,用于表明方法的预期用法。稍后我们将更全面地探讨这些方面。
私有方法的语法
定义私有方法有两种方式,我们将通过示例来说明。
可以在函数名前加单下划线来定义私有方法:
这种定义仅是一种对程序员的约定,因为该函数在类外仍然可以访问,但并不推荐这样做。
如果这是您第一次接触 Python 中的类,建议先阅读我们的 初学者友好教程:类(Classes)。
让我们创建一个对象并尝试访问刚创建的私有方法:
在 Python 中还可以使用双下划线来定义私有方法,语法如下:
当我们尝试在类外访问该私有方法时,会抛出 AttributeError,表示不能直接通过函数名访问。
总结一下 Python 中私有方法的语法:
在 Python 中实现私有方法
以真实场景为例,考虑一个安全且易用的 BankAccount 类,用于管理用户的金融交易。其需求包括:
当然,银行账户还需要更多功能,如余额查询、货币转换、利息处理等——但为简化起见,我们在实现中暂不考虑这些。
让我们动手实现并理解这段代码。
我们首先创建了一个
BankAccountclass,它封装了 BankAccount 对象所需的所有预期行为与功能。BankAccount类包含一个私有属性__balance和一个私有方法__update_balance:__balance):这是BankAccount类的属性,用于存储当前账户余额。通过在名称前添加两个下划线(__)将其标记为私有,表示仅打算在类内部访问。例如,它会在deposit、withdraw和__update_balance方法中被修改。不建议从外部访问该属性。__update_balance):用于更新账户余额。该方法由transfer在转账操作中调用,以更新收款账户的余额。使用私有方法有助于封装更新余额的逻辑,确保只能通过类中定义的受控方式完成。您可以新建一个 Python 文件,将以上与下方代码复制粘贴并运行,亲自查看效果。
您将看到如下输出:
恭喜!您已经使用私有方法实现了自己的 BankAccount 解决方案!
从输出可见,在执行存款、取款、转账等常规银行业务时,账户遵循了合理的业务逻辑。
__init__ 方法:它是私有方法吗?
您可能注意到示例中使用了
__init__方法。由于它也使用了双下划线,您或许会疑惑它是否也是私有方法。__init__方法并不被视为为隐私目的而加双下划线的那类私有方法。相反,它属于 Python 的特殊方法,通常称为 “dunder” 方法(“double underscore”的缩写),在语言中具有特定用途。其他此类特殊方法的示例包括
__str__、__repr__和__del__。让我们看看该特殊方法在示例中的用法:
如上所示,
__init__方法是类的构造函数。它会在创建类的新实例时自动调用,用于初始化对象的属性。对BankAccount类而言,__init__用于设置account_holder和__balance的初始值。进阶概念:Python 中的名称改写(Name Mangling)
前文提到,Python 中的私有方法更多是一种约定,Python 语言不像其他编程语言那样严格强制隐私。
因此我们看到,使用单下划线时可以直接访问所谓的私有方法,而使用双下划线时访问会受限。
为什么会这样?这源于 Python 中的一个概念——“名称改写(name mangling)”。
当您在属性名前加上双下划线时,Python 会自动修改该名称:在原属性名前加上单下划线和类名。
类在内部以这种修改后的名称存储该属性。这一修改名称的过程被称为名称改写。
名称改写有两个好处:
让我们通过示例来加深理解。
在此示例中,
__private_attribute和__private_method都经过了名称改写。在内部,它们分别存储为_MyClass__private_attribute和_MyClass__private_method。尝试在类外使用原名称访问它们将导致AttributeError。不过,您仍可通过改写后的名称来访问它们:
需要注意的是,名称改写只是让属性更难被访问,并非万无一失的隐私保证。它更多是一种约定,表明该属性仅用于类的内部实现。
使用私有方法与变量的最佳实践
要有效利用私有方法和私有变量,需要遵循一些最佳实践。这些做法有助于确保代码不仅可用,还清晰、可维护且更安全。
建议遵循以下实践:
_)。这是 Python 中的一种约定,用于向其他开发者传达该成员是“受保护”的,不应直接访问。__)。这会触发名称改写,使得从类外部访问它更困难(但并非不可能)。最后,坚持一致的编码最佳实践非常重要。遵循命名约定并在整个代码库中保持一致,这将使您的代码更易于他人(以及未来的您)理解和维护。
结语
本教程介绍了私有方法背后的概念、其语法以及适用场景。我们还通过多个示例展示了您如何在下一个编码项目中使用它们。最后,我们总结了使用私有方法时需要牢记的一些最佳实践。
如需进一步学习,您可以查看 Python Programming 技能路径 以及 Python 面向对象编程课程。