Python 3中的封装

图片


定义


术语“封装”的含义含糊不清,并且因来源而异。 尽管一些科学文章完全从列表中省略了封装,但是普遍认为封装是OOP的基本原理之一。 例如,约翰·米切尔(John Mitchell)在“编程语言的概念”一书中列出了OOP中的主要概念时,只提到了抽象-这个术语被认为在意义上接近封装,但仍然更为广泛和更高层次。 另一方面,Robert Martin在他的《 Pure Architecture》一书中明确指出封装,继承和多态被认为是OOP的基础。


术语“封装”的各种定义很难带来共同的分母。 通常,可以区分两种解决该术语含义的方法。 封装可以认为是:


  • 使用控制该数据的方法进行数据通信;
  • 一组用于控制对数据的访问或控制此数据的方法的工具。

封装为连接


术语“封装”的这种解释非常容易解释。 在这种情况下,任何至少有一个变量和一个控制它的方法的类都清楚地证明了这一原理。


#!/usr/bin/python3 class Phone: number = "111-11-11" def print_number(self): print( "Phone number is: ", self.number ) my_phone = Phone() my_phone.print_number() input( "Press Enter to exit" ) 

Phone类将变量号中的数据与print_number()方法组合在一起


您可以创建一个仅包含方法(且不包含变量)的类,这在某些编程语言中可能会很方便。 也可以创建仅包含数据而没有方法的类,在许多情况下应避免使用该方法。 两种做法都应在必要时应用,并且它们与“统一”封装的关系尚有争议。


封装为访问控制


解释限制对数据或方法的访问的概念需要更多细节。 首先,在这种情况下,术语“访问”应理解为查看和/或修改类的内部内容的能力。 大多数OOP语言提供几种访问级别。 总而言之,我们可以说对象的数据可以是:


  • 公共( public )-每个人都可以使用数据;
  • 私有( private )-数据仅对它所属的对象/类可用。

大多数语言在这些边界之间具有其他访问权限。 例如,在C ++和Python3中,访问分为三个级别:公共,受保护和私有;访问权限分为以下三种: C#将关键字“内部”添加到列表中。


值得注意的是,在大多数编程语言中,默认情况下会设置对任何数据的访问级别。 例如,在C ++中,默认情况下,将对类中数据的访问级别设置为私有-只有该类的成员和朋友才能访问其数据。 C ++中对结构( struct )的标准访问级别有所不同-它是公共的,任何人都可以访问这种结构中的数据。 Python 3中类变量和方法的访问级别完全取决于语法。


例子


封装形式


Python 3提供3级数据访问:


  • public( public ,没有特殊语法, publicBanana );
  • protected( protected ,名称开头_protectedBanana );
  • private( private ,名称开头的两个下划线__privateBanana )。

为了简洁起见,示例中仅突出了两个基本级别(私有和公共)。


 #!/usr/bin/python3 class Phone: username = "Kate" # public variable __how_many_times_turned_on = 0 # private variable def call(self): # public method print( "Ring-ring!" ) def __turn_on(self): # private method self.__how_many_times_turned_on += 1 print( "Times was turned on: ", self.__how_many_times_turned_on ) my_phone = Phone() my_phone.call() print( "The username is ", my_phone.username ) # my_phone.turn_on() # my_phone.__turn_on() # print( “Turned on: “, my_phone.__how_many_times_turned_on) # print( “Turned on: “, my_phone.how_many_times_turned_on) # will produce an error input( "Press Enter to exit" ) 

可以从主程序访问公共变量和方法。 尝试检索私有数据或运行私有方法将导致错误。


违反封装


该语言本身为程序员提供了可以绕过封装的语法工具。 仍然可以读取和修改私有变量并调用私有函数。


 #!/usr/bin/python3 class Phone: username = "Kate" # public variable __serial_number = "11.22.33" # private variable __how_many_times_turned_on = 0 # private variable def call(self): # public method print( "Ring-ring!" ) def __turn_on(self): # private method self.__how_many_times_turned_on += 1 print( "Times was turned on: ", self.__how_many_times_turned_on ) my_phone = Phone() my_phone._Phone__turn_on() my_phone._Phone__serial_number = "44.55.66" print( "New serial number is ", my_phone._Phone__serial_number ) input( "Press Enter to exit" ) 

关于魔术的几句话


有一些方法,即所谓的“魔术方法”或“特殊方法”,它们使类可以确定其相对于标准语言运算符的行为。 以下表达式可以作为此类语言运算符的示例:


  • x > y
  • x[ i ]

Python 3支持许多这样的方法,完整列表可以在官方语言文档页面上找到。 __init__ (初始化程序)是其中最常用的方法,它在创建新的类对象时开始。 另一个__lt__ (高级比较)定义用于比较用户类的两个对象的规则。 这种方法不属于“私有”或“公共”类别,因为它们有其他用途,并且深深扎根于语言的内部结构中。


 #!/usr/bin/python3 class Phone: def __init__(self, number): # magic method / inititalizer print( "The Phone object was created" ) self.number = number def __lt__(self, other): # magic method / rich comparison return self.number < other.number my_phone = Phone(20) other_phone = Phone(30) if my_phone < other_phone: print( "Two instances of custom class were compared" ) print( "'__lt__' was called implicitly" ) if my_phone.__lt__(other_phone): print( "Now, '__lt__' was used explicitly" ) input( "Press Enter to exit" ) 

魔术方法可以由任何用户以与Python中的任何公共方法相同的方式调用,但是在特殊情况下,应隐式使用它们。 __init__方法的一种特殊情况是新类对象的初始化。 __lt__用于比较两个对象。


结论


Python3不提供对任何类变量或方法的有限访问。 实际上可以读取和修改必须隐藏的数据。 在Python3中,封装更像是一种约定,程序员必须照顾好自己保存它的情况。


资料来源


  1. John C. Mitchell,编程语言概念
  2. 罗伯特·C·马丁(Robert C. Martin),《清洁架构》,《软件结构和设计手工艺人指南》

Source: https://habr.com/ru/post/zh-CN444338/


All Articles