在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属性