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)
<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属性
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,128评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,316评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,737评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,283评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,384评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,458评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,467评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,251评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,688评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,980评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,155评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,818评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,492评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,142评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,382评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,020评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,044评论 2 352