Python3类型提示

简介: Python3类型提示 本文环境基于 Python3.6.4。 通过 EPE483和EPE484两个版本,从Python3.5 开始支持类型提示(Type Hint)。 简单的例子 代码1-1: Python3.

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 this

The Zen of Python, by Tim Peters

Beautiful 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 <T extand Animal>  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,"+name
say_greeting("jian")

2. 类型别名

from typing import List
Vector = 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, List

MyDict = 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 NewType

UserId = NewType("UserId", int)
user_a = UserId(121)
user_b = UserId(2112)
print(user_a + user_b)

5. Callable

from typing import Callable
import requests

def 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, List
T = TypeVar('T', int, float) # T 类型必须为int或者float

def 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,TypeVar
from requests import Session
from requests import models

T = 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 Union

assert Union[int,str] ==Union [int]#True

assert Union[Union[int, str], float] == Union[int, str, float] #True

assert Union[int] == int # True

assert Union[str, int] == Union[int, str] #True

11. Any,默认任意类型

from typing import Any

def show_any(param: Any) -> Any:
    return 1, param, True

a, b, c = show_any(param='any_param')
print(a, b, c)

12.Optional,可选择类型

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

....

参考:https://docs.python.org/3/library/typing.html

参考

  1. 26.1. typing — Support for type hints
  2. PEP 483 -- The Theory of Type Hints
  3. PEP 484 -- Type Hints
  4. 鸭子类型
  5. 类型推论
  6. 现代编程语言系列1:静态类型趋势
  7. Type Hinting in PyCharm
目录
相关文章
|
9月前
|
存储 JavaScript Java
(Python基础)新时代语言!一起学习Python吧!(四):dict字典和set类型;切片类型、列表生成式;map和reduce迭代器;filter过滤函数、sorted排序函数;lambda函数
dict字典 Python内置了字典:dict的支持,dict全称dictionary,在其他语言中也称为map,使用键-值(key-value)存储,具有极快的查找速度。 我们可以通过声明JS对象一样的方式声明dict
491 2
|
10月前
|
IDE 开发工具 开发者
Python类型注解:提升代码可读性与健壮性
Python类型注解:提升代码可读性与健壮性
451 102
|
索引 Python
Python的变量和简单类型
本文介绍了Python中变量命名规则、常用变量类型及字符串操作。变量命名需遵循字母、数字和下划线组合,不能以数字开头且不可与关键字冲突。字符串支持单引号、双引号或三引号定义,涵盖基本输出、转义字符、索引、拼接等操作。此外,还详细解析了字符串方法如`islower()`、`upper()`、`count()`等,帮助理解字符串处理技巧。
358 15
|
11月前
|
安全 JavaScript Java
Python中None与NoneType的真相:从单例对象到类型系统的深度解析
本文通过10个真实场景,深入解析Python中表示“空值”的None与NoneType。从单例模式、函数返回值,到类型注解、性能优化,全面揭示None在语言设计与实际编程中的核心作用,帮助开发者正确高效地处理“无值”状态,写出更健壮、清晰的Python代码。
1042 3
|
Python
Python技术解析:了解数字类型及数据类型转换的方法。
在Python的世界里,数字并不只是简单的数学符号,他们更多的是一种生动有趣的语言,用来表达我们的思维和创意。希望你从这个小小的讲解中学到了有趣的内容,用Python的魔法揭示数字的奥秘。
287 26
|
11月前
|
缓存 数据可视化 Linux
Python文件/目录比较实战:排除特定类型的实用技巧
本文通过四个实战案例,详解如何使用Python比较目录差异并灵活排除特定文件,涵盖基础比较、大文件处理、跨平台适配与可视化报告生成,助力开发者高效完成目录同步与数据校验任务。
329 0
|
11月前
|
IDE API 开发工具
Python类型注解:让代码“开口说话”的隐形助手
Python类型注解为动态语言增添类型信息,提升代码可读性与健壮性。通过变量、函数参数及返回值的类型标注,配合工具如mypy、IDE智能提示,可提前发现类型错误,降低调试与协作成本。本文详解类型注解的实战技巧、生态支持及最佳实践,助你写出更高质量的Python代码。
473 0
|
存储 索引 Python
Python散列类型(1)
【10月更文挑战第9天】
213 0
|
人工智能 安全 IDE
Python 的类型安全是如何实现的?
本文探讨了 Python 的类型安全实现方式。从 3.5 版本起,Python 引入类型提示(Type Hints),结合静态检查工具(如 mypy)和运行时验证库(如 pydantic),增强类型安全性。类型提示仅用于开发阶段的静态分析,不影响运行时行为,支持渐进式类型化,保留动态语言灵活性。泛型机制进一步提升通用代码的类型安全性。总结而言,Python 的类型系统是动态且可选的,兼顾灵活性与安全性,符合“显式优于隐式”的设计哲学。
313 2
|
Rust JavaScript 前端开发
[oeasy]python075_什么是_动态类型_静态类型_强类型_弱类型_编译_运行
本文探讨了编程语言中的动态类型与静态类型、强类型与弱类型的概念。通过实例分析,如Python允许变量类型动态变化(如`age`从整型变为字符串),而C语言一旦声明变量类型则不可更改,体现了动态与静态类型的差异。此外,文章还对比了强类型(如Python,不允许隐式类型转换)和弱类型(如JavaScript,支持自动类型转换)的特点。最后总结指出,Python属于动态类型、强类型语言,对初学者友好但需注意类型混淆,并预告下期内容及提供学习资源链接。
419 21

推荐镜像

更多