博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Python3类型提示
阅读量:7239 次
发布时间:2019-06-29

本文共 6865 字,大约阅读时间需要 22 分钟。

Python3类型提示

本文环境基于 Python3.6.4。 通过 EPE483和EPE484两个版本,从Python3.5 开始支持类型提示(Type Hint)。

简单的例子

代码1-1: Python3.5之前方法定义

def say_hi(name):        return "Hi,"+name

代码1-2:Python3.5之后的方法定义

def say_hi(name:str)->str:        return "Hi,"+name

Python 与 动态语言

Python作为动态语言, 其设计本意体现了简洁的哲学,这一点从import this就可以看出。

代码2-1 Python之禅

> import thisThe Zen of Python, by Tim PetersBeautiful is better than ugly.Explicit is better than implicit.Simple is better than complex.Complex is better than complicated.Flat is better than nested.Sparse is better than dense.Readability counts.Special cases aren't special enough to break the rules.Although practicality beats purity.Errors should never pass silently.Unless explicitly silenced.In the face of ambiguity, refuse the temptation to guess.There should be one-- and preferably only one --obvious way to do it.Although that way may not be obvious at first unless you're Dutch.Now is better than never.Although never is often better than *right* now.If the implementation is hard to explain, it's a bad idea.If the implementation is easy to explain, it may be a good idea.Namespaces are one honking great idea -- let's do more of those!

所谓动态语言,从维基百科上来看,

一类在运行时可以改变其结构的语言:例如新的函数、对象、甚至代码可以被引进,已有的函数可以被删除或是其他结构上的变化。比如众所周知的ECMAScript(JavaScript)便是一个动态语言。除此之外如Ruby、Python等也都属于动态语言,而C、C++等语言则不属于动态语言。

而动态类型语言的最大特点也就是只会在运行期间检查数据类型,不用给变量特定的类型,最具代表性的也就是Javascript,Ruby,Python了。

代码2-2

def quack(param):    return param+' is quacking'

上述代码只会在运行期间,Cython解释器做类型检查。

静态类型语言会在运行前(比如:编译期间)判断数据类型,例如Java,C#。

代码2-3

private String quack(String param){    return param+' is quacking';}

同样上述Java代码会在编译时就会对参数和返回值做检查,如果不一致,则会导致编译错误。

由以上综述可见,我们解释为什么Python设计原则Simple is better than complex.。动态类型语言没有强制类型检查保证了Python语法的简洁,与此同时动态语言在运行时的类型检查也是影响Python运行效率的一个因素,也给IDE做类型检查时产生了挑战。

而动态语言典型的风格便是鸭子类型。

鸭子类型(duck typing)

鸭子类型(Duck Typing),是动态类型语言的一种风格。“当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。”在这种风格中,对象不取决于继承的类或是实现的接口,而是关注对象可以调用的方法或是属性。

代码3-1 鸭子类型

# 鸭子类型class Animal(object):    def run(self):        print("Animal is running")class Dog(object):    def run(self):        print("Dog is running")class Cat(object):    def run(self):        print("Cat is running")def in_the_forest(param):    param.run()def duck_type():    animal = Animal()    dog = Dog()    cat = Cat()    in_the_forest(animal)    in_the_forest(dog)    in_the_forest(cat)if __name__ == '__main__':    duck_type()

代码3-1所示,对象animaldogcat没有实现或者继承关系,都拥有run方法,在in_the_forest方法中分别传入animaldogcat对象,调用run方法,各个对象分别表现出不同的状态。

代码3-2 鸭子类型实现多态

# 动态语言鸭子类型来实现多态class Animal(object):    def run(self):        print("Animal is running")class Dog(Animal):    # 重写run 方法    def run(self):        print("Dog is running")class Cat(Animal):    # 重写run 方法    def run(self):        print("Cat is running")def in_the_forest(animal):    animal.run()def duck_type():    """鸭子类型"""    animal = Animal()    dog = Dog()    cat = Cat()    in_the_forest(animal)    in_the_forest(dog)    in_the_forest(cat)duck_type()

与代码3-1 对比,我们抽象出Animal类,Dog类和Cat类继承Animal,分别重写run方法,在in_the_forest方法中通过传入父类Animal来调用run方法。熟悉Java的同学一定可以看出这是Java中多态,其满足三个必要条件,继承,重写,父类引用指向子类,所以代码3-2 用鸭子类型来实现多态。代码3-3 所示,用Java代码实现上述功能。

代码3-3 Java模拟鸭子类型

// Java通过接口实现来模拟鸭子类型interface Animal{    default  void run(){        System.out.println("Animal is running");    }}public class DuckTyping {    static class Dog implements Animal{        @Override        public void run() {            System.out.println("Dog is runnning");        }    }    static class Cat implements Animal{        @Override        public void run() {            System.out.println("Cat is running");        }    }    private  static 
void inTheForest(T animal){ animal.run(); } public static void main(String[] args) { Animal dog = new Dog(); Animal cat = new Cat(); inTheForest(dog); inTheForest(cat); }}

Animal dog = new Dog();这段代码中dog对象,在编译期表现的是Animal类型,在运行期表现的是Dog类型,而Python在运行期之前并不会表现出任何类型,所以代码3-2使用鸭子类型来实现多态显得鸡肋,还不如直接使用鸭子类型(代码3-1)来得简洁明了。

代码3-3,我们可以做以下修改,通过反射推断入参对象是否存在可调用的方法,使得更加符合鸭子类型,

代码3-4

private static void inTheForest(Object object)        throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {        object.getClass().getMethod("run",new Class
[]{}).invoke(object); }

但是我们再也无法判断inTheForest中参数object类型,也很难对入参作出约束。所以说鸭子类型放弃类型检查,完全依赖程序员通过文档,注释来弹性约束。

使用

通过 EPE483和EPE484两个版本建议,从Python3.5 开始支持类型提示(Type Hint)。我们可以在typing包中找到所需的类型。

1. 基本用法

def say_greeting(name:str)->str:    return "Hi,"+namesay_greeting("jian")

2. 类型别名

from typing import ListVector = List[float] # 定义List别名def scale(scalar: float, vector: Vector) -> Vector:    return [scalar * num for num in vector]print(scale(0.5, [1.3, 1.2, 1.2, 1.0]))

3.List,Dict,Tuple

from typing import Dict, Any, Tuple, ListMyDict = Dict[str, Any]MyTuple = Tuple[str, int]MyList = List[str]def show_dict(my_tuple: MyTuple, my_dict: MyDict, my_list: MyList) -> None:    assert (isinstance(my_dict, dict))    assert (isinstance(my_tuple, tuple))    print(my_dict)    print(my_tuple)show_dict(my_tuple=("1", 1), my_dict={'1': 1}, my_list=["1", "2"])

4. NewType

from typing import NewTypeUserId = NewType("UserId", int)user_a = UserId(121)user_b = UserId(2112)print(user_a + user_b)

5. Callable

from typing import Callableimport requestsdef async_request(url: str, on_success: Callable[[str], None]) -> None:    request = requests.get(url=url, verify=False)    if request.status_code == 200:        on_success(request.text)async_request(url='https://www.baidu.com', on_success=lambda result: print("request_call:%s", result))

6. Generics(泛型),运行期间使用isinstance(t,T)来判断类型,会抛出TypeError错误。同样issubclass()也不用。

from typing import TypeVar, ListT = TypeVar('T', int, float) # T 类型必须为int或者floatdef sum_from_list(li: List[T]) -> T:    return sum([x for x in li])print(sum_from_list([1.1, 2, 3, 43, 43, 4]))

7. 泛型约束

from typing import Callable,TypeVarfrom requests import Sessionfrom requests import modelsT = TypeVar('T',bound=models.Response)def async_request(url: str, on_success: Callable[[T], None]) -> None:    response = Session().get(url=url, verify=False)    if response.status_code == 200:        on_success(response)async_request(url='https://www.baidu.com', on_success=lambda response: print("request_call:%s", response.text))

8. typing.TypeVar

T = TypeVar('T')  # 任意类型A = TypeVar('A', str, bytes)  # 必须为str,bytes

9. AnyStr ,等价于AnyStr = TypeVar('AnyStr',str,bytes)

10. Union,Union[X, Y] 代表要不是X,要不是Y。

from typing import Unionassert Union[int,str] ==Union [int]#Trueassert Union[Union[int, str], float] == Union[int, str, float] #Trueassert Union[int] == int # Trueassert Union[str, int] == Union[int, str] #True

11. Any,默认任意类型

from typing import Anydef show_any(param: Any) -> Any:    return 1, param, Truea, b, c = show_any(param='any_param')print(a, b, c)

12.Optional,可选择类型

from typing import Optional,Listxs: List[Optional[str]] = []#等价于 xs = []

....

参考:

参考

转载地址:http://kafbm.baihongyu.com/

你可能感兴趣的文章
1134. Vertex Cover (25)
查看>>
神经网络的激活函数总结
查看>>
[Guava源码日报](10)Iterables
查看>>
Google Jib 即将迎来正式版
查看>>
python高级特性-迭代
查看>>
Android属性设置android:noHistory="true"
查看>>
Jackson对泛型的序列化和反序列化方法汇总
查看>>
玩完自动驾驶,现代又钻研起了机器骨骼和智能房间
查看>>
如何自学人工智能?
查看>>
Linux系统使用普通命令删除不掉的文件处理方法
查看>>
canon iPF 系列保养墨盒清零方法
查看>>
Emulating Neural Synapses through AI
查看>>
Oracle in与exists语句
查看>>
字体大宝库:20款免费的情人节字体
查看>>
让共享单车变得更加智能 看高通在物联网领域的“全覆盖”策略
查看>>
数论 + 公式 - HDU 4335 What is N?
查看>>
Android 蓝牙通信——AndroidBluetoothManager
查看>>
No curses/termcap library found
查看>>
iOS:点击button卡死
查看>>
WebForm-带接口工厂模式的三层架构
查看>>