百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术资源 > 正文

Python | 理解多态(python多态的理解例子)

off999 2024-10-25 13:43 39 浏览 0 评论

多态(polymorphism),是OOP的一个重要概念。不少学习或使用 Python 的人,特别他们曾经了解过 Java 之后,对 Python 中的多态往往有不同的解读。为了避免因人微言轻,在本节将更多地引述一名权威对 Python 语言的多态的阐述,这位大神就是《Thinking in Java》的作者 Bruce Eckel ——将 Java 奉为圭皋的特别注意,这位可真是大神,如果学习 Java 而没有阅读他的书,借用 Java 界的朋友所说,“那就不算学过 Java”。

Bruce Eckel 在2003年5月2日发表了一篇题为《Strong Typing vs. Strong Testing》(https://docs.google.com/document/d/1aXs1tpwzPjW9MdsG5dI7clNFyYayFBkcXwRDo- qvbIk/preview)的博客,将 Java 和 Python 的多态特征进行了比较。

先来欣赏 Bruce Eckel 在文章中所撰写的一段说明多态的 Java 代码:

// Speaking pets in Java:
interface Pet {
    void speak();
 }
 
class Cat implements Pet {
    public void speak() { System.out.println("meow!"); }
 }
 
class Dog implements Pet {
    public void speak() { System.out.println("woof!"); }
 }
 
public class PetSpeak {
    static void command(Pet p) { p.speak(); }

    public static void main(String[] args) {
        Pet[] pets = { new Cat(), new Dog() };
        for(int i = 0; i < pets.length; i++)
            command(pets[i]);
    }
}

如果读者没有学习过 Java ,那么对上述代码理解可能不是很顺畅,不过这不重要,主要观察command(Pet p) ,这种写法意味着 command() 所能接受的参数类型必须是 Pet 类型,其他类型不行。所以,必须创建 interface Pet 这个接口并且让类 Cat 和 Dog 继承它,然后才能用于 command() 方法(原文:I must create a hierarchy of Pet, and inherit Dog and Cat so that I can upcast them to the generic command() method)。

然后,Bruce Eckel 又写了一段实现上述功能的 Python 代码:

# Speaking pets in Python:
class Pet:
    def speak(self): pass
 
class Cat(Pet):
    def speak(self):
        print "meow!"
 
class Dog(Pet):
    def speak(self):
        print "woof!"
 
def command(pet):
    pet.speak()
 
pets = [ Cat(), Dog() ]
 
for pet in pets:
    command(pet)

在这段 Python 代码中的 command() 函数,其参数 pet 并没有要求必须是前面定义的 Pet类型(注意区分大小写),仅仅是一个名字为 pet 的形参,用其他名称亦可。Python 不关心引用的对象是什么类型,只要该对象有 speak() 方法即可。提醒读者注意的是,因为历史原因(2003年),Bruce Eckel 当时写的是针对 Python 2 的旧式类,不过适当修改之后在 Python 3 下也能“跑”,例如将 print "meow!" 修改为 print("meow!") 。

根据已经学习过的知识,不难发现,上面代码中的类 Pet 其实是多余的。是的,Bruce Eckel 也这么认为,只是因为此代码是完全模仿 Java 程序而写的。随后,Bruce Eckel 就根据 Python 语言的特性对代码进行了优化。

# Speaking pets in Python, but without base classes:
class Cat:
    def speak(self):
        print "meow!"
 
class Dog:
    def speak(self):
        print "woof!"
 
class Bob:
    def bow(self):
        print "thank you, thank you!"
    def speak(self):
        print "hello, welcome to the neighborhood!"
    def drive(self):
        print "beep, beep!"
 
def command(pet):
    pet.speak()
 
pets = [ Cat(), Dog(), Bob() ]
 
for pet in pets:
    command(pet)

去掉了多余的类 Pet ,增加了一个新的对象类 Bob ——人类,这个类根本不是 Cat 和 Dog 那样的类型,只是它碰巧也有一个名字为 speak() 的方法罢了。但是,也依然能够在 command() 函数中被调用。

这就是Python中的多态特点,大师 Brue Eckel 通过非常有说服力的代码阐述了 Java 和 Python 的区别,并充分展示了 Python 中的多态特征。

诚如前面所述,Python 不检查传入对象的类型,这种方式被称为“隐式类型”(Laten Typing)或者“结构式类型”(Structural Typing),也被通俗地称为“鸭子类型”(Duck Typeing)。其含义在《维基百科》中被表述为:

在程序设计中,鸭子类型(Duck Typing)是动态类型的一种风格。在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口决定,而是由当前方法和属性的集合决定。这个概念的名字来源于由 James Whitcomb Riley 提出的鸭子测试。“鸭子测试”可以这样表述:“当看到一只鸟走起来像鸭子,游泳起来像鸭子,叫起来也像鸭子时,那么这只鸟就可以被称为鸭子。”

鸭子类型就意味着可以向任何对象发送任何消息,只关心该对象能否接收该消息,不强求该对象是否为某一种特定的类型。这种特征其实在前面函数部分就已经有所体现了。

>>> lam = lambda x, y: x + y
>>> lam(2, 3)
5
>>> lam('python', 'book')
'pythonbook'

对于 Python 的这种特征,有一批程序员不接受,他们认为在程序被执行的时候,可能收到错误的对象,而且这种错误还可能潜伏在程序的某个角落。

对于此类争论,大师 Brue Eckel 在上面所提到的博客中,给出了非常明确的回答。下面将原文恭录于此(注:读者如果阅读有困难,可以借用有关工具。之所以不翻译,是避免因个人才疏学浅而导致误传。):

Strong testing, not strong typing.

So this, I assert, is an aspect of why Python works. C++ tests happen at compile time (with a few minor special cases). Some Java tests happen at compile time (syntax checking), and some happen at run time (array-bounds checking, for example). Most Python tests happen at runtime rather than at compile time, but they do happen, and that's the important thing (not when). And because I can get a Python program up and running in far less time than it takes you to write the equivalent C++/Java/C# program, I can start running the real tests sooner: unit tests, tests of my hypothesis, tests of alternate approaches, etc. And if a Python program has adequate unit tests, it can be as robust as a C++, Java or C# program with adequate unit tests (although the tests in Python will be faster to write).

读完大师的话,犹如醍醐灌顶,豁然开朗,再也不去参与那些浪费口舌的争论了。

对于多态问题,最后还要告诫读者,类型检查是毁掉多态的利器,如 type() 、isinstance() 及isubclass() 这些检查类型的函数,一定要慎用。

相关推荐

十大免费cad网站(十大免费cad网站免费观看有风险)

1、CAD看图王这是一款非常专业的手机看图、DWG画图、CAD测量制图为一体的手机综合性绘图看图神器,全球累计用户超过3500多万,值得推荐下载!2、迅捷CAD看图迅捷CAD看图支持天正全系列的手机C...

老式联想台式电脑型号大全(老联想台式机主板型号有哪些)

有以下几款型号1、昭阳笔记本电脑针对行业客户设计的高品质笔记本电脑。高端、高性能的同时具备多重可信赖的安全保护方案。昭阳系列针对行业客户提供按需定制服务。2、旭日笔记本电脑联想旭日系列笔记本电脑是满足...

联想电脑官方售后维修服务网点

您可以通过联想官方网站的售后服务页面或者拨打联想客服热线进行售后维修网点查询。在官网上输入您所在的城市或地区,即可获得最近的维修网点信息。如果您有任何疑问,也可以直接致电联想客服热线,他们会为您提供详...

电脑启动蓝屏0x0007b修复(电脑开机蓝屏报错0x0000007b)
电脑启动蓝屏0x0007b修复(电脑开机蓝屏报错0x0000007b)

Power电脑蓝屏0x0000007b解决方法。1、首先点击开机键将电脑关闭,然后重启电脑开机按下F10进入bios。2、选择“storage”菜单用键盘选择“storageoptions”按下“enter”进行修改。3、此时的硬盘模式为...

2025-11-15 11:51 off999

如何安装网络打印机到电脑(网络打印机怎么安装使用)
  • 如何安装网络打印机到电脑(网络打印机怎么安装使用)
  • 如何安装网络打印机到电脑(网络打印机怎么安装使用)
  • 如何安装网络打印机到电脑(网络打印机怎么安装使用)
  • 如何安装网络打印机到电脑(网络打印机怎么安装使用)
随身wifi怎么设置网速快(随身wifi限速解除最简单三个步骤)

1、重新连接WiFi首先长按连接的WiF网络,然后选择“不保存网络”,完成后再重新选择该热点进行连接,看看网速是否有所改善。如果还是卡成狗,那么继续看下一条。2、优化网络同样长按连接的WiFi网络,然...

雨林木风绝版系统(雨林木风的系统好用吗)

XP精简版的速度无疑是最快的,因为占用内存是最小的,但是因为删除了很多文件所以肯定不如完整版的稳定。雨林木风的精简版不多,安装版的我推荐雨林木风WindowsXPSP3精简版Y1.1,因为是...

解压文件密码怎么解除(解压文件带密码怎么办)
  • 解压文件密码怎么解除(解压文件带密码怎么办)
  • 解压文件密码怎么解除(解压文件带密码怎么办)
  • 解压文件密码怎么解除(解压文件带密码怎么办)
  • 解压文件密码怎么解除(解压文件带密码怎么办)
win11家庭版和专业版哪个好(win11家庭版和专业版哪个好用)

win11用专业版本最好,玩游戏最稳定。相对于前代的操作系统来讲,windowS11系统无论哪个版本都非常稳定,但是在门斗41所有版本当中,最稳定的是专业版,但是这个版本占用的空间很大,对硬件的要求...

win7连不上win10打印机拒绝访问

原因及解决方法:1.在Win10Cortana搜索框中,搜索控制面板将打开;2.转到控制面板,选择查看方法作为一个小图标,然后单击程序和功能;3.单击以启用或禁用Windows功能选项;4....

电脑主机不启动但通电(电脑主机开机不通电没反应)

第1步:首先检查电脑的外部接线是否接好,把各个连线重新插一遍,看故障是否排除。第2步:如果故障依旧,接着打开主机箱查看机箱内有无多余金属物,或主板变形造成的短路,闻一下机箱内有无烧焦的糊味,主板上有无...

苹果一体机怎么重装系统(苹果一体机重装系统win10)

苹果更换硬盘后,如果您没有创建一个启动磁盘或者使用TimeMachine备份系统,您可以按照以下步骤重新安装操作系统:1.准备一个可用于安装系统的启动磁盘。您可以使用官方提供的macOS安装介质(...

装系统的u盘怎么制作(装系统怎么制作u盘启动盘)
装系统的u盘怎么制作(装系统怎么制作u盘启动盘)

1、下载安装u当家u盘启动盘制作工具,完成之后打开该软件2、将之前准备好的U盘插入电脑,U当家会自动识别并选为默认,如果有多个U盘可以在“选择U盘”的下拉框中选择要制作成U盘启动盘的U盘。3、点击下面的“一键制作”按钮。(如果是电脑主板是U...

2025-11-15 07:03 off999

台电u盘怎么样

感觉台电U盘还是可以的,我知道台电是国内最成功的数码产品制造商之一,是一个致力于IT及消费数码类产品研发、生产、销售及服务的一体化品牌,U盘很好用,用的人很多。威刚是480Mbit/S只是USB2...

u盘重装系统蓝屏进不去(u盘装系统重启蓝屏)

尊敬的用户您好:可按下面的步骤进行系统盘装系统:1.买一张win7光盘,将系统光盘放入光驱里。2.打开电源,然后观察屏幕的提示,在启动系统之前有按“f2进行bios设置。3.设置启动方式。找到boot...

取消回复欢迎 发表评论: