Python札记37_多态和封装(私有化)

在Python中前面几篇札记中的继承,和本文中即将讲解的多态封装是面向对象编程 OOP的三个重要特征。

  • Python不在乎引用对象的类型,多态是对象多种表现形式的体现。
  • 私有化属性加上双下划线:self.__name,在类的外面不能够直接调用
  • 私有化属性通过加上接口,能够执行调用
  • 通过@property装饰器来调用私有化属性

多态

概念

多态:Polymorphism,同一种行为具有不同的表现形式和形态的能力,对象多种表现形式的体现。相同的信息给与不同的对象就会引发不同的动作。

"this is a book".count("s")   # 2
[1,2,3,4,2,1,2,3,2].count(2)  # 4

f = lambda x, y: x + y
f(2, 3)  # 5
f("python", "Peter")   # 'pythonPeter'
f(["python", "java"], ["shenzhen", "changsha"])  # ['python', 'java', 'shenzhen', 'changsha']

repr函数

repr()函数是将输入的任何对象返回一个字符串,多态的代表之一。

repr([1,2,3])  # '[1,2,3]'
repr(1)   # '1'

使用repr函数写个小函数:输出某个字符串的长度

def length(x):
    print("the length of", repr(x), "is", len(x))

if __name__ == '__main__':
    result = length("python")

结果:

the length of 'python' is 6

多态不是万能的,比如上面的函数中如果传入的是int型,则会报错,因为int是没有len的:

if __name__ == '__main__':
    result = length(6)

运行报错:
TypeError                                 Traceback (most recent call last)
 in 
      1 if __name__ == '__main__':
----> 2     result = length(6)

 in length(x)
      1 def length(x):
----> 2     print("the length of", repr(x), "is", len(x))
      3 
      4 if __name__ == '__main__':
      5     result = length("python")

TypeError: object of type 'int' has no len()   # int型没有len方法

特点

  • Python是一种不需要预编译的语言,只有在运行的时候才确定状态,但是最终还是编译啦,只是结果报错。
  • Python天生就是一种多态的语言。
  • 多态就是同一种行为具有不同的表现形式和形态的能力

多态特征

看一段多态特征的经典代码

class Pet:
    def speak(self):
        pass

class Cat(Pet):
    def speak(self):
        print("this is a cat")
        
class Dog(Pet):
    def speak(self):
        print("this is a dog")
        
def command(pet):   # 不要求传入的参数必须是Pet类
    pet.speak()  # Python不关心引用的对象是什么类型,只要参数有speak()方法即可;
    
pets = [Cat(), Dog()]   # 列表中的两个对象都有speak()方法

for pet in pets:
    command(pet)  # 将两个列表对象分别传进来

结果

this is a cat
this is a dog

上面代码中Pet类是多余的,将上述代码进行修改

class Cat:   # 继承自object
    def speak(self):
        print("this is a cat")
        
class Dog:
    def speak(self):
        print("this is a dog")
        
class Duck:  # 增加一个Duck类,继承自object父类;同时有3个方法,包含speak()
    def bow(self):
        print("hello python")
        
    def speak(self):
        print("this is a duck")
        
    def drive(self):
        print("this is a car")
        
def command(pet):
    pet.speak()   # 同上:传入的参数有speak()方法即可
    
pets = [Cat(), Dog(), Duck()]

for pet in pets:
    command(pet)

结果:

this is a cat
this is a dog
this is a duck

总结:

  • Python不检查传入对象的类型
  • 上述方式称之为隐式类型Laten Typing,或者结构式类型Structural Typing,或者鸭子类型Duck Typing
  • 鸭子类型是动态类型的一种风格,在这种方式中一个对象是由当前方法和属性的集合决定
  • 鸭子类型可以向任何对象发送消息。

封装和私有化

私有化

在Python中私有化很简单,就是在准备私有化的属性(方法、函数或者数据)前面加上双下划线__。通过例子来理解私有化:

class Protect:
    def __init__(self):
        self.me = "Peter"
        self.__name = "xiaoming"
        
    def __python(self):
        print("I love python")
        
    def code(self):
        print("which language do you like best")
        self.__python()
        
if __name__ == "__main__":
    p = Protect()
    print(p.me)
    print(p.__name)

# 结果
Peter
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
 in 
     14     p = Protect()
     15     print(p.me)
---> 16     print(p.__name)

AttributeError: 'Protect' object has no attribute '__name'   # Protect类没有__name属性

报错原因:属性被隐藏,在类的外面无法调用

class Protect:
    def __init__(self):
        self.me = "Peter"
        self.__name = "xiaoming"
        
    def __python(self):
        print("I love python")
        
    def code(self):
        print("which language do you like best")
        self.__python()
        
if __name__ == "__main__":
    p = Protect()
    print(p.code())      # 通过code()这个接口执行__python()方法
    print(p.__python)    # 直接调用会报错

结果

which language do you like best
I love python
------------------------------------------------------
AttributeError                            Traceback (most recent call last)
 in 
     14     p = Protect()
     15     print(p.code())   # 通过code函数调用成功
---> 16     print(p.__python)    # 直接调用被隐藏

AttributeError: 'Protect' object has no attribute '__python'

如何调用私有属性

上述的代码实现了封装,如果想调用私有属性,通过装饰器@property

class Protect:  # 创建类
    def __init__(self):  # 初始化函数
        self.me = "Peter"
        self.__name = "xiaoming"   # 私有属性加上双下划线
    
    @property  # 通过装饰器调用私有属性
    def name(self):
        return self.__name  # 调用私有属性
    
if __name__ == "__main__":
    p = Protect()    # 调用类,创建实例 
    print(p.name)    # 调用name属性

你可能感兴趣的:(Python札记37_多态和封装(私有化))