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

浏览: 1204

在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)
<ipython-input-15-e95fb07fc2fd> in <module>
1 if __name__ == '__main__':
----> 2 result = length(6)

<ipython-input-14-163c4fcaa1fa> 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)
<ipython-input-30-6cb94e6fe732> in <module>
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)
<ipython-input-35-530c2f325779> in <module>
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属性
推荐 0
本文由 皮大大 创作,采用 知识共享署名-相同方式共享 3.0 中国大陆许可协议 进行许可。
转载、引用前需联系作者,并署名作者且注明文章出处。
本站文章版权归原作者及原出处所有 。内容为作者个人观点, 并不代表本站赞同其观点和对其真实性负责。本站是一个个人学习交流的平台,并不用于任何商业目的,如果有任何问题,请及时联系我们,我们将根据著作权人的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。

0 个评论

要回复文章请先登录注册