Python从菜鸟到高手(18):类与方法的私有化

栏目: Python · 发布时间: 5年前

内容简介:学习面向对象的第一步,就是创建一个类。因为类是面向对象的基石。Python类和其他编程语言(Java、C#等)的类差不多,也需要使用class关键字。下面通过一个实际的例子来看一下Python类是如何创建的。本例会创建一个类,以及利用这个类创建两个对象,并调用其中的方法。程序运行结果如下图所示。

1. 创建自己的类

学习面向对象的第一步,就是创建一个类。因为类是面向对象的基石。Python类和其他编程语言(Java、C#等)的类差不多,也需要使用class关键字。下面通过一个实际的例子来看一下 Python 类是如何创建的。

本例会创建一个类,以及利用这个类创建两个对象,并调用其中的方法。

 1 # 创建一个Person类
 2 class Person:
 3     # 定义setName方法
 4     def setName(self, name):
 5         self.name = name
 6     # 定义getName方法
 7     def getName(self):
 8         return self.name
 9     # 定义greet方法
10     def greet(self):
11         print("Hello, I'm {name}.".format(name = self.name))
12 
13 # 创建Person对象
14 person1 = Person()
15 # 创建Person对象
16 person2 = Person()
17 # 调用person1对象的setName方法
18 person1.setName("Bill Gates")
19 # 调用person2对象的name属性
20 person2.name = "Bill Clinton"
21 # 调用person1对象的getName方法
22 print(person1.getName())
23 # 调用person1对象的greet方法
24 person1.greet()
25 # 调用person2对象的属性
26 print(person2.name)
27 # 调用person2对象的greet方法,另外一种调用方法的方式
28 Person.greet(person2)

程序运行结果如下图所示。

Python从菜鸟到高手(18):类与方法的私有化

从上面的代码我们可以了解到Python类的如下知识点。

  • Python类使用class关键字定义,类名直接跟在class关键字的后面。
  • 类也是一个代码块,所以类名后面要跟着一个冒号(:)。
  • 类中的方法其实就是函数,定义的方法也完全一样,只是由于函数定义在类的内部,所以为了区分,将定义在类内部的函数称为方法。
  • 我们可以看到,每一个方法的第1个参数都是self,其实这是必须的。这个参数名不一定叫self(可以叫abc或任何其他名字),但任意一个方法必须至少指定一个self参数,如果方法中包含多个参数,第1个参数将作为self参数使用。在调用方法时,这个参数的值不需要自己传递,系统会将方法所属的对象传入这个参数。在方法内部可以利用这个参数调用对象本身的资源,如属性、方法等。
  • 通过self参数添加的name变量是Person类的属性,可以在外部访问。本例设置了person2对象的name属性的值,与调用person2.setName方法的效果完全相同。
  • 使用类创建对象的方式与调用函数的方式相同。在Python语言中,不需要像 Java 一样使用new关键字创建对象,只需要用类名加上构造方法(在后面的章节会详细介绍)参数值即可。
  • 调用对象的方法有两种方式,一种是直接通过对象变量调用方法,另一种是通过类调用方法,并且将相应的对象传入方法的第1个参数。在本例中使用了Person.greet(person2)的方式调用了person2对象中的greet方法。

如果使用集成开发环境,如PyDev、PyCharm,那么代码编辑器也会对面向对象有很好的支持,例如,当在对象变量后输入一个点(.)后,IDE会为我们列出该对象中所有可以调用的资源,包括方法和属性,如下图所示。

Python从菜鸟到高手(18):类与方法的私有化

2.方法和私有化

Python类默认情况下,所有的方法都可以被外部访问。不过像很多其他编程语言,如Java、C#等,都提供了private关键字将方法私有化,也就是说只有类的内部方法才能访问私有化的方法,通过正常的方式是无法访问对象的私有化方法的(除非使用反射技术,这就另当别论了)。不过在Python类中并没有提供private或类似的关键字将方法私有化,但可以曲线救国。

在Python类的方法名前面加双下划线(__)可以让该方法在外部不可访问。

 1 class Person:
 2     # method1方法在类的外部可以访问
 3     def method1(self):
 4         print("method1")
 5     # __method2方法在类的外部不可访问
 6     def __method2(self):
 7         print("method2")
 8 
 9 p = Person()
10 p.method1()
11 p.__method2()       # 抛出异常

如果执行上面的代码,会抛出如下图所示的异常信息,原因是调用了私有化方法method2。

Python从菜鸟到高手(18):类与方法的私有化

其实“ method2”方法也不是绝对不可访问。Python编译器在编译Python源代码时并没有将“ method2”方法真正私有化,而是一旦遇到方法名以双下划线(__)开头的方法,就会将方法名改成“ ClassName methodName”的形式。其中ClassName表示该方法所在的类名,“ methodName”表示方法名。ClassName前面要加上但单下划线( )前缀。

对于上面的代码,Python编译器会将“ method2”方法更名为“_Person method2”,所以在类的外部调用“ method2”方法会抛出异常。抛出异常的原因并不是“ method2”方法被私有化了,而是Python编译器把“ method2”的名称改为“_Person method2”了。当我们了解了这些背后的原理,就可以通过调用“_Person method2”方法来执行“ method2”方法。

1 p = Person()
2 p._Person__method2()        # 正常调用“__method2”方法

本例会创建一个MyClass类,并定义两个公共的方法(getName和setName)和一个私有的方法( outName)。然后创建了MyClass类的实例,并调用了这些方法。为了证明Python编译器在编译MyClass类时做了手脚,本例还使用了inspect模块中的getmembers函数获取MyClass类中所有的成员方法,并输出方法名。很显然,“ outName”被改成了“_MyClass__outName”。

 1 class MyClass:
 2     # 公共方法
 3     def getName(self):
 4         return self.name
 5     # 公共方法
 6     def setName(self, name):
 7         self.name = name
 8         # 在类的内部可以直接调用私有方法
 9         self.__outName()
10     # 私有方法    
11     def __outName(self):
12         print("Name = {}".format(self.name))        
13 
14 myClass = MyClass()
15 # 导入inspect模块
16 import inspect
17 # 获取MyClass类中所有的方法
18 methods = inspect.getmembers(myClass, predicate=inspect.ismethod)
19 print(methods)
20 # 输出类方法的名称
21 for method in methods:
22     print(method[0])
23 print("------------")
24 # 调用setName方法
25 myClass.setName("Bill")
26 # 调用getName方法
27 print(myClass.getName())
28 # 调用“__outName”方法,这里调用了改完名后的方法,所以可以正常执行
29 myClass._MyClass__outName()
30 # 抛出异常,因为“__outName”方法在MyClass类中并不存在
31 print(myClass.__outName())

程序运行结果如下图所示。

Python从菜鸟到高手(18):类与方法的私有化

Python从菜鸟到高手(18):类与方法的私有化

从getmembers函数列出的MyClass类方法的名字可以看出,“_MyClass outName”被绑定到了“ outName”方法上,我们可以将“_MyClass outName”看做是“ outName”的一个别名,一旦为某个方法起了别名,那么原来的名字在类外部就不可用了。MyClass类中的getName方法和setName方法的别名和原始方法名相同,所以在外部可以直接调用getName和setName方法。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

How to Design Programs, 2nd Edition

How to Design Programs, 2nd Edition

Matthias Felleisen、Robert Bruce Findler、Matthew Flatt、Shriram Krishnamurthi / MIT Press / 2018-5-4 / USD 57.00

A completely revised edition, offering new design recipes for interactive programs and support for images as plain values, testing, event-driven programming, and even distributed programming. This ......一起来看看 《How to Design Programs, 2nd Edition》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具