python鸭子类型_关于鸭子类型

其实对我来说鸭子类型一直是一个比较模糊的概念,因为平常不去关注,关注的时候一般是在面试或者被面试的时候,今天在看一篇博客的时候又有看到,所以就索性弄清楚

```

首先 与duck typing相对应的是normal typing(对象的类型决定对象的特性)

*既然是相对,可以简单理解为 duck typing 就是对象的特性决定了他是什么,说一个烂大街的句子:“当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。”,不是因为它是鸭子所以走路,游泳和叫像鸭子,而是走路,游泳和叫像鸭子所以被``认为``是鸭子

duck typing中对象的类型不重要,只要对象有类型A的方法和属性,那么它被当做类型A来使用。熟悉c的同学应该明白c就是normal typing,在编译阶段静态检查,函数定义和传参类型需要保持一致,不一致就编译报错。参数类型当然也包含了 ``对象`` 参数,后面我会举个Go的例子。

Python中的鸭子类型:

classDuck:deffly(self):print("Duck flying")classAirplane:deffly(self):print("Airplane flying")classWhale:defswim(self):print("Whale swimming")defruntest(obj):

obj.fly()

duck=Duck()

airplane=Airplane()

whale=Whale()

此时:

runtest(duck) √

runtest(airplane) √

runtest(whale) ×

前两个有fly方法,所以在下面的runtest中直接就可以调用,runtest不去理会你传进来的到底是谁的对象,只要你有这个方法,那么我就可以去调用运行。

其实就是多态的一种体现,多态是什么?“多态是指不同类的对象对同一消息作出响应,同一个接口,不同的对象会做出不同的反应;同一个行为可以通过多种表现形式展现出来就是多态”

例如上面同样的runtest这个接口,输入了不同的对象,打印了不同的结果。

在go语言中的  接口:

首先我们定义一个规范,也就是说定义一个接口:

type Duckinterface{

Quack()//鸭子叫

DuckGo() //鸭子走

}

这个接口是鸭子的行为,我们认为,作为一只鸭子,它需要会叫,会走。然后我们再定义一只鸡:

type Chickenstruct{

}

假设这只鸡特别厉害,它也会像鸭子那样叫,也会像鸭子那样走路,那么我们定义一下这只鸡的行为:

func (c Chicken) Quack() {

fmt.Println("嘎嘎")

}

func (c Chicken) DuckGo() {

fmt.Println("大摇大摆的走")

}。*注意,这里只是实现了 Duck 接口方法,并没有将鸡类型和鸭子接口显式绑定。这是一种非侵入式的设计。

然后我们让这只鸡,去叫,去像鸭子那样走路:

func main() {

c :=Chicken{}vard Duck

d=c

d.Quack()

d.DuckGo() # 这一点目前有点疑问,关于接口可以先参照下面的题外话代码

}

执行之后我们可以得到结果:

嘎嘎

大摇大摆的走

这里 go 的func (c Chicken) DuckGo()

func (c Chicken) Quack()

两个函数可以看成是Python中的方法,go利用接口 type Duck interface 实现了go中的多态,如果没有这个interface的存在,可以看出 一个函数的方法,必须要指定入参的类型,例如func (c Chicken) Quack(),指定了这个入参是Chicken类型的,

如果传入其它的,当然就会编译报错

例:

type Vertex struct {

X, Y float64

}

type Vertex2 struct {

X, Y float64

}

func (v *Vertex) test(){

v.X++;

v.Y++;

}

func main(){

v2 := Vertex2{2,3}

v2.test()

}

# awesomeProject

.\test.go:77:3: v.test2 undefined (type Vertex2 has no field or method test)

题外话插一嘴,关于go的接口的,这一部分参考go by exampel:

package main

import ("fmt"

"math")

type geometryinterface{

area() float64

perim() float64

}

type rectstruct{

width, height float64

}

type circlestruct{

radius float64

}

func (r rect) area() float64 {return r.width *r.height

}

func (r rect) perim() float64 {return 2*r.width + 2*r.height

}

func (c circle) area() float64 {return math.Pi * c.radius *c.radius

}

func (c circle) perim() float64 {return 2 * math.Pi *c.radius

}

func measure(g geometry) { # 这里才体现出了接口的作用,入参统一为geometry,所以下面↓

fmt.Println(g)

fmt.Println(g.area())

fmt.Println(g.perim())

}

func main() {

r := rect{width: 3, height: 4}

c := circle{radius: 5}

measure(r) # 这里这里,r和c不是同一个结构体对象,但是可以同时作为入参使用measure函数,并且满足在measure中的g.area()和g.perim()方法

measure(c)

}

```

知识储备有限,很可能会出现错误,欢迎指正,尤其是go语言部分刚刚接触,所以如果有错误请留言??

参考:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值