zoukankan      html  css  js  c++  java
  • Python从菜鸟到高手(18):类与方法的私有化

    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)

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

    image.png

    从上面的代码我们可以了解到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会为我们列出该对象中所有可以调用的资源,包括方法和属性,如下图所示。

    image.png

    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。

    image.png

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

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

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

    image.png

    image

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

  • 相关阅读:
    2018-2019-2 20175202实验三《敏捷开发与XP实践》实验报告
    20175202 葛旭阳 MyCP
    20175202 《Java程序设计》第九周学习总结
    20175202 《Java程序设计》第八周学习总结
    2018-2019-2 20175202实验二《Java面向对象程序设计》实验报告
    20175202 结对编程练习—四则运算(第一周)
    20175203 2018-2019 实验三 《敏捷开发与XP实践》
    2018-2019-20175203 实验二 《Java面向对象程序设计》
    20175203 2018-2019-2 实验一《Java开发环境的熟悉》实验报告
    20175203 2018-2019-2《Java程序设计》第五周学习总结
  • 原文地址:https://www.cnblogs.com/nokiaguy/p/10247909.html
Copyright © 2011-2022 走看看