• 鸭子类型 多态


    1

    继承和多态 - 廖雪峰的官方网站 https://www.liaoxuefeng.com/wiki/1016959663602400/1017497232674368

    python与鸭子类型

    部分参考来源:作者:JasonDing  https://www.jianshu.com/p/650485b78d11##s1

    首先介绍下面向对象(OOP)的三大特征:

    (1)面向对象程序设计有三大特征:封装(Encapsulation)、继承(Inheritance)、多态(Polymorphism)。这三个单词很常见,大家还是记住为好!

    (2)封装(Encapsulation):类包含了数据和方法,将数据和方法放在一个类中就构成了封装。

    (3)继承(Inheritance):Java是单继承的(这点和C++有区别),意味着一个类只能继承于一个类,被继承的类叫父类(或者叫基类,base class),继承的类叫子类。Java中的继承使用关键字extends。但是,一个类可以实现多个接口,多个接口之间用逗号进行分割。实现接口使用关键字implements。

    (4)多态(Polymorphism):多态最核心的思想就是,父类的引用可以指向子类的对象,或者接口类型的引用可以指向实现该接口的类的实例。多态之所以是这样的是因为基于一个事实:子类就是父类!

    (5)关于多态的一些重要说明:

    • 当使用多态方式调用方法时,首先检查父类中是否有此方法,如果没有则编译错误,如果有则再去调用子类重写(Override)【如果重写的话】的此方法,没有重写的话,还是调用从父类继承过来的方法。
    • 两种类型的强制类型转换:
      1. 向上类型转换(upcast):将子类型引用转换成父类型引用。对于向上类型转换不需要显示指定。
      2. 向下类型转换(downcast):将父类型引用转换成子类型引用。对于向下类型转换,必须要显示指定。向下类型转换的原则:父类型引用指向谁才能转换成谁。
    • 多态是一种运行期的行为,不是编译期行为!在编译期间它只知道是一个引用,只有到了执行期,引用才知道指向的是谁。这就是所谓的“软绑定”。
    • 多态是一项让程序员“将改变的事物和未改变的事物分离开来”重要技术。

    鸭子类型:

    调用不同的子类将会产生不同的行为,而无须明确知道这个子类实际上是什么,这是多态的重要应用场景。而在python中,因为鸭子类型(duck typing)使得其多态不是那么酷。
    鸭子类型是动态类型的一种风格。在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由"当前方法和属性的集合"决定。这个概念的名字来源于由James Whitcomb Riley提出的鸭子测试,“鸭子测试”可以这样表述:“当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。”
    在鸭子类型中,关注的不是对象的类型本身,而是它是如何使用的。例如,在不使用鸭子类型的语言中,我们可以编写一个函数,它接受一个类型为"鸭子"的对象,并调用它的"走"和"叫"方法。在使用鸭子类型的语言中,这样的一个函数可以接受一个任意类型的对象,并调用它的"走"和"叫"方法。如果这些需要被调用的方法不存在,那么将引发一个运行时错误。任何拥有这样的正确的"走"和"叫"方法的对象都可被函数接受的这种行为引出了以上表述,这种决定类型的方式因此得名。
    鸭子类型通常得益于不测试方法和函数中参数的类型,而是依赖文档、清晰的代码和测试来确保正确使用。

    Duck typing 这个概念来源于美国印第安纳州的诗人詹姆斯·惠特科姆·莱利(James Whitcomb Riley,1849- 
    1916)的诗句:”When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck.” 
    先上代码,也是来源于网上很经典的案例:

    复制代码
     1 class Duck():
     2     def walk(self):
     3         print('I walk like a duck')
     4     def swim(self):
     5         print('i swim like a duck')
     6 
     7 class Person():
     8     def walk(self):
     9       print('this one walk like a duck') 
    10     def swim(self):
    11       print('this man swim like a duck')
    复制代码

    可以很明显的看出,Person类拥有跟Duck类一样的方法,当有一个函数调用Duck类,并利用到了两个方法walk()swim()。我们传入Person类也一样可以运行,函数并不会检查对象的类型是不是Duck,只要他拥有walk()swim()方法,就可以正确的被调用。 
    再举例,如果一个对象实现了__getitem__方法,那python的解释器就会把它当做一个collection,就可以在这个对象上使用切片,获取子项等方法;如果一个对象实现了__iter__next方法,python就会认为它是一个iterator,就可以在这个对象上通过循环来获取各个子项。

     

    python与鸭子类型 - Guo磊 - 博客园 https://www.cnblogs.com/guolei2570/p/8830934.html

    package main

    import "fmt"

    // declare interface
    type Dog interface {
    Bark()
    }

    // declare struct
    type Dalmatian struct {
    DogType string
    }

    // implement the interface
    func (d Dalmatian) Bark() {
    fmt.Println("Dalmatian barking!!")
    }

    func MakeDogBark(d Dog) {
    d.Bark()
    }

    func main() {
    d := Dalmatian{"Jack"}
    MakeDogBark(d) // Dalmatian barking!!
    }

    Polymorphism in GoLang - GoLang Docs https://golangdocs.com/polymorphism-in-golang

    Polymorphism in GoLang

     

    In Object-Oriented Programming, an object can behave like another object. This property is called polymorphism. This post will cover how we achieve polymorphism in GoLang.

    What is polymorphism?

    Polymorphism is a property that is available to many OO-languages. Go despite not being an OO-language achieves polymorphism through interfaces.

    Polymorphism using interfaces

    In GoLang, polymorphism is achieved mainly using interfaces. A type implementing a function defined in interface becomes the type defined as an interface. This is the property that makes polymorphism achievable in Go.


     
     
     
     
     
    1.1M
     
    Square To Make a Hardware Wallet for Bitcoin
     
     

    Here is an example of polymorphism in action.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    package main
     
    import "fmt"
     
    // declare interface
    type Dog interface {
        Bark()
    }
     
    // declare struct
    type Dalmatian struct {
        DogType string
    }
     
    // implement the interface
    func (d Dalmatian) Bark() {
        fmt.Println("Dalmatian barking!!")
    }
     
    func MakeDogBark(d Dog) {
        d.Bark()
    }
     
    func main() {
        d := Dalmatian{"Jack"}
        MakeDogBark(d)                    // Dalmatian barking!!
    }

    In the code above, the struct Dalmatian implements the Dog interface. Thus the struct becomes the type Dog and so that it can be passed in that function.

    Now, we can simply add any type and implement that interface and the type will behave as that interface. That is polymorphism. An object taking many different forms.

     

    Uses of polymorphism

    Polymorphism is used to reduce code in general. There will be less coupling if polymorphism is used. A single function can be used to do the same thing on multiple different objects. This is where polymorphism is heavily used. It is one of the most important concepts in OO-Programming. Go not being a strict OO-language achieves polymorphism in an elegant way.

    Polymorphism in Golang using Interfaces | OOP in Go | golangbot.com https://golangbot.com/polymorphism/

    Polymorphism - OOP in Go

    29 MARCH 2021

    Welcome to tutorial no. 28 in Golang tutorial series.

    Polymorphism in Go is achieved with the help of interfaces. As we have already discussed, interfaces are implicitly implemented in Go. A type implements an interface if it provides definitions for all the methods declared in the interface. Let's see how polymorphism is achieved in Go with the help of interfaces.

    Polymorphism using an interface

    Any type which provides definition for all the methods of an interface is said to implicitly implement that interface. This will be more clear as we discuss an example of polymorphism shortly.

    A variable of type interface can hold any value which implements the interface. This property of interfaces is used to achieve polymorphism in Go.

    Let's understand polymorphism in Go with the help of a program that calculates the net income of an organization. For simplicity, let's assume that this imaginary organization has income from two kinds of projects viz. fixed billing and time and material. The net income of the organization is calculated by the sum of the incomes from these projects. To keep this tutorial simple, we will assume that the currency is dollars and we will not deal with cents. It will be represented using int. (I recommend reading https://forum.golangbridge.org/t/what-is-the-proper-golang-equivalent-to-decimal-when-dealing-with-money/413 to learn how to represent cents. Thanks to Andreas Matuschek in the comments section for pointing this out.)

    Let's first define an interface Income.

    type Income interface {  
        calculate() int
        source() string
    }
    

    The Income interface defined above contains two methods calculate() which calculates and returns the income from the source and source() which returns the name of the source.

    Next, let's define a struct for FixedBilling project type.

    type FixedBilling struct {  
        projectName string
        biddedAmount int
    }
    

    The FixedBilling project has two fields projectName which represents the name of the project and biddedAmount which is the amount that the organization has bid for the project.

    The TimeAndMaterial struct will represent projects of Time and Material type.

    type TimeAndMaterial struct {  
        projectName string
        noOfHours  int
        hourlyRate int
    }
    

    The TimeAndMaterial struct has three fields names projectNamenoOfHours and hourlyRate.

    The next step would be to define methods on these struct types which calculate and return the actual income and source of income.

    func (fb FixedBilling) calculate() int {  
        return fb.biddedAmount
    }
    
    func (fb FixedBilling) source() string {  
        return fb.projectName
    }
    
    func (tm TimeAndMaterial) calculate() int {  
        return tm.noOfHours * tm.hourlyRate
    }
    
    func (tm TimeAndMaterial) source() string {  
        return tm.projectName
    }
    

    In the case of FixedBilling projects, the income is just the amount bid for the project. Hence we return this from the calculate() method of FixedBilling type.

    In the case of TimeAndMaterial projects, the income is the product of the noOfHours and hourlyRate. This value is returned from the calculate() method with receiver type TimeAndMaterial.

    We return the name of the project as the source of income from the source() method.

    Since both FixedBilling and TimeAndMaterial structs provide definitions for the calculate() and source() methods of the Income interface, both structs implement the Income interface.

    Let's declare the calculateNetIncome function which will calculate and print the total income.

    func calculateNetIncome(ic []Income) {  
        var netincome int = 0
        for _, income := range ic {
            fmt.Printf("Income From %s = $%d
    ", income.source(), income.calculate())
            netincome += income.calculate()
        }
        fmt.Printf("Net income of organization = $%d", netincome)
    }
    

    The calculateNetIncome function above accepts a slice of Income interfaces as argument. It calculates the total income by iterating over the slice and calling calculate() method on each of its items. It also displays the income source by calling source() method. Depending on the concrete type of the Income interface, different calculate() and source() methods will be called. Thus we have achieved polymorphism in the calculateNetIncome function.

    In the future, if a new kind of income source is added by the organization, this function will still calculate the total income correctly without a single line of code change :).


    The only part remaining in the program is the main function.

    func main() {  
        project1 := FixedBilling{projectName: "Project 1", biddedAmount: 5000}
        project2 := FixedBilling{projectName: "Project 2", biddedAmount: 10000}
        project3 := TimeAndMaterial{projectName: "Project 3", noOfHours: 160, hourlyRate: 25}
        incomeStreams := []Income{project1, project2, project3}
        calculateNetIncome(incomeStreams)
    }
    

    In the main function above we have created three projects, two of type FixedBilling and one of type TimeAndMaterial. Next, we create a slice of type Income with these 3 projects. Since each of these projects has implemented the Income interface, it is possible to add all three projects to a slice of type Income. Finally, we call calculateNetIncome function and pass this slice as a parameter. It will display the various income sources and the income from them.

    Here is the full program for your reference.

    package main
    
    import (  
        "fmt"
    )
    
    type Income interface {  
        calculate() int
        source() string
    }
    
    type FixedBilling struct {  
        projectName string
        biddedAmount int
    }
    
    type TimeAndMaterial struct {  
        projectName string
        noOfHours  int
        hourlyRate int
    }
    
    func (fb FixedBilling) calculate() int {  
        return fb.biddedAmount
    }
    
    func (fb FixedBilling) source() string {  
        return fb.projectName
    }
    
    func (tm TimeAndMaterial) calculate() int {  
        return tm.noOfHours * tm.hourlyRate
    }
    
    func (tm TimeAndMaterial) source() string {  
        return tm.projectName
    }
    
    func calculateNetIncome(ic []Income) {  
        var netincome int = 0
        for _, income := range ic {
            fmt.Printf("Income From %s = $%d
    ", income.source(), income.calculate())
            netincome += income.calculate()
        }
        fmt.Printf("Net income of organization = $%d", netincome)
    }
    
    func main() {  
        project1 := FixedBilling{projectName: "Project 1", biddedAmount: 5000}
        project2 := FixedBilling{projectName: "Project 2", biddedAmount: 10000}
        project3 := TimeAndMaterial{projectName: "Project 3", noOfHours: 160, hourlyRate: 25}
        incomeStreams := []Income{project1, project2, project3}
        calculateNetIncome(incomeStreams)
    }
    

    Run in playground

    This program will output

    Income From Project 1 = $5000  
    Income From Project 2 = $10000  
    Income From Project 3 = $4000  
    Net income of organization = $19000  
    

    Adding a new income stream to the above program

    Let's say the organization has found a new income stream through advertisements. Let's see how simple it is to add this new income stream and calculate the total income without making any changes to the calculateNetIncome function. This becomes possible because of polymorphism.

    Lets first define the Advertisement type and the calculate() and source() methods on the Advertisement type.

    type Advertisement struct {  
        adName     string
        CPC        int
        noOfClicks int
    }
    
    func (a Advertisement) calculate() int {  
        return a.CPC * a.noOfClicks
    }
    
    func (a Advertisement) source() string {  
        return a.adName
    }
    

    The Advertisement type has three fields adNameCPC (cost per click) and noOfClicks (number of clicks). The total income from ads is the product of CPC and noOfClicks.

    Let's modify the main function a little to include this new income stream.

    func main() {  
        project1 := FixedBilling{projectName: "Project 1", biddedAmount: 5000}
        project2 := FixedBilling{projectName: "Project 2", biddedAmount: 10000}
        project3 := TimeAndMaterial{projectName: "Project 3", noOfHours: 160, hourlyRate: 25}
        bannerAd := Advertisement{adName: "Banner Ad", CPC: 2, noOfClicks: 500}
        popupAd := Advertisement{adName: "Popup Ad", CPC: 5, noOfClicks: 750}
        incomeStreams := []Income{project1, project2, project3, bannerAd, popupAd}
        calculateNetIncome(incomeStreams)
    }
    

    We have created two ads namely bannerAd and popupAd. The incomeStreams slice includes the two ads we just created.

    Here is the full program after adding Advertisement.

    package main
    
    import (  
        "fmt"
    )
    
    type Income interface {  
        calculate() int
        source() string
    }
    
    type FixedBilling struct {  
        projectName  string
        biddedAmount int
    }
    
    type TimeAndMaterial struct {  
        projectName string
        noOfHours   int
        hourlyRate  int
    }
    
    type Advertisement struct {  
        adName     string
        CPC        int
        noOfClicks int
    }
    
    func (fb FixedBilling) calculate() int {  
        return fb.biddedAmount
    }
    
    func (fb FixedBilling) source() string {  
        return fb.projectName
    }
    
    func (tm TimeAndMaterial) calculate() int {  
        return tm.noOfHours * tm.hourlyRate
    }
    
    func (tm TimeAndMaterial) source() string {  
        return tm.projectName
    }
    
    func (a Advertisement) calculate() int {  
        return a.CPC * a.noOfClicks
    }
    
    func (a Advertisement) source() string {  
        return a.adName
    }
    func calculateNetIncome(ic []Income) {  
        var netincome int = 0
        for _, income := range ic {
            fmt.Printf("Income From %s = $%d
    ", income.source(), income.calculate())
            netincome += income.calculate()
        }
        fmt.Printf("Net income of organization = $%d", netincome)
    }
    
    func main() {  
        project1 := FixedBilling{projectName: "Project 1", biddedAmount: 5000}
        project2 := FixedBilling{projectName: "Project 2", biddedAmount: 10000}
        project3 := TimeAndMaterial{projectName: "Project 3", noOfHours: 160, hourlyRate: 25}
        bannerAd := Advertisement{adName: "Banner Ad", CPC: 2, noOfClicks: 500}
        popupAd := Advertisement{adName: "Popup Ad", CPC: 5, noOfClicks: 750}
        incomeStreams := []Income{project1, project2, project3, bannerAd, popupAd}
        calculateNetIncome(incomeStreams)
    }
    

    Run in playground

    The above program will output,

    Income From Project 1 = $5000  
    Income From Project 2 = $10000  
    Income From Project 3 = $4000  
    Income From Banner Ad = $1000  
    Income From Popup Ad = $3750  
    Net income of organization = $23750  
    

    You would have noticed that we did not make any changes to the calculateNetIncome function though we added a new income stream. It just worked because of polymorphism. Since the new Advertisement type also implemented the Income interface, we were able to add it to the incomeStreams slice. The calculateNetIncome function also worked without any changes as it was able to call the calculate() and source() methods of the Advertisement type.

    This brings us to the end of this tutorial. Have a good day.

  • 相关阅读:
    ubuntu18 faster-rcnn
    osgViewer应用基础
    error C2086: “int WINGDIAPI”: 重定义
    test5
    test3
    test2
    Kinect关节数据
    MySQL乱码问题以及utf8mb4字符集
    mysql5.7执行sql语句报错:In aggregated query without GROUP BY, expression #1 of SELECT list contains nonagg
    yum安装软件报错:curl#6
  • 原文地址:https://www.cnblogs.com/rsapaper/p/12440997.html
Copyright © 2020-2023  润新知