【导读】写Python前你应该知道的各种数据类型

1.首先

在 Python 中编码时你知道类型吗?Python 可以在某种程度上进行编码而无需意识到这些事情,因此许多初学者可能在编码时没有意识到类型和对象。本文的目的是让那些对数据类型感兴趣的人在日常编码中使用它们。

目标听众 开始使用 Python 编程的人 什么是数据类型?一个人 想在 Python 中使用类型推断的人 想要开始使用面向对象和打字的人 环境 蟒蛇:3.10.4 mypy:0.971 版权所有:1.1.268 2.什么是模具? 2.1. 简介

类型类似于int 或str,用一种简单的方式表达。当你像这样投射它时,你会看到这个词:

hoge = str(1)
print(hoge)
>>> "1"

此转换将 int 类型转换为 str 类型。int类型和str类型等分类统称为“类型(数据类型)”。

2.2. 究竟什么是数据类型?

首先这里所说的数据是内存中二进制数信息转换时的解释。

01000001(二进制)-> 65(十进制)

例如char是C语言的基本数据类型,可以存储1个字节(值从-128到127)。(可以存储一个单字节字符,例如字母数字字符。在上面的示例中,分配了A。)

当然,在 Python 中,原理相同。 (来自 Python3是标准的)

# Aのコードポイントを2進数で出力
bin(ord('A'))
>>> '0b1000001'

对这些解释进行分类,放“数据类型”是这样处理的。

3. 数据类型的种类

有许多类型的数据类型。具有相同的数据类型可替代性或者等价有。例如,下面的add 函数将添加任何值,只要它是 int 类型。

def add(x:int, y:int) -> int:
    return x + y

比如你把add("1",1)放在这里,就会报错。(Python 直到运行时才知道这是否是一个错误。稍后会在 Typing 中详细介绍。)

add("1",1)
>>> Traceback (most recent call last):
>>> File "<stdin>", line 1, in <module>
>>> TypeError: can only concatenate str (not "int") to str

这是因为 Python 不允许不同类型之间的连接。这些机制是类型安全这是一种叫做

此外,数据类型分为“内置类型(原始类型)”和“复合类型(复合类型)”。两者经常被对比,但它们不是对比的概念。如果有的话,它更接近于自定义包装器或此类内置类型的图像。

3.1. 内置类型

每种编程语言定义的基本数据类型。 (例如 char、int、float、bool 等)因此,在一种语言中归类为复合类型的数据类型在另一种语言中可能是内置类型。

3.2. 复杂类型

由原始类型和复合数据类型的结构或递归组合(组合)形成的数据类型

(参考)

结构、数组、列表等通常与它们相对应。

3.3. Python的内置类型和复合类型有哪些?

有内置类型和容器数据类型(复合类型)。

: 包含在标准库中collections

另外,Numpy、ndarray等外部库提供的数据结构和自己实现的数据结构也属于复杂类型的范畴。

所有这些数据类型都是目的它是由如果你感兴趣请阅读。

4. 打字

早些时候,我说过“Python 直到运行时才知道这是否是错误。”这是因为 Python 通过解释器解释数据类型。这些编程语言解释数据类型的方式称为“类型化”。

分类主要有两点。(名称和结构类型在多态性章节中介绍。)

动态/静态类型 强/弱类型

没有所谓的好,因为它是“动态的”或好的,因为它是“强大的”。这取决于个人或团队的文化和价值观。

4.1. 动态/静态类型

在这里,为了方便起见,我们区分了常用的动态和静态处理方法。

* 有些解释型语言像编译提供的那样支持静态分析,有些编译型语言像解释器那样支持顺序执行。我的印象是,这些天静态和动态之间的界限越来越薄。

静态类型

类型在编译时(执行前)确定(编译器语言)

Java、C、C#、Go、Rust 等。 编译器语言可以在执行前确定数据类型是否正确。 虽然从编译到执行的障碍很高,但它运行速度很快。 动态类型

类型在运行时确定(解释语言)

Python、Ruby、Perl、PHP 等。 解释器直到运行时才知道数据类型。 虽然执行起来很方便,但是速度很慢,因为要一一翻译成机器语言。

目前,一些语言已经引入了一个叫做 Gradual Typing 的特性,它利用了动态类型和静态类型的特性。(详情为“和“什么是渐进式打字”)

渐进式打字

执行前推断的类型(未确定)

Python、TypeScript 等。 目前,在许多情况下,类型推断被引入到动态类型语言中。 C 语言中的 Auto 是一种添加了动态特性的静态类型语言。 Python 通过使用类型注释和第三方类型分析工具(mypy 和 pyright)来做到这一点。 在 Python 中,类型注解没有强制力,而在 TypeScript 中,如果类型不表达,就变成任意类型,所以实现的范围因语言而异。

* 常说TypeScript是静态类型语言,但我个人在这里归类,因为any类型太强,转js的地方比较混乱。

综上所述,Python 是一种“动态类型”或“渐进类型”的语言。当被问到要写哪一个时,我们应该明智地使用类型注释作为渐进式类型语言。

例如,匈牙利符号您不再需要在变量名称中包含数据类型,例如(不包括无法使用编辑器工具提示的项目)

# NG
drink_str_list = []
# OK (Python3.8 は List[str])
drinks: list[str] = []

所以,如果右边的类型是明确的,就不需要写类型了。

# NG
id: int = 1
# OK
id = 1
# OK (明らかだが型そのものが大事な場合)
DEFAULT_ID: Final[int] = 1

顺便说一句,当使用 Final 等类型添加到类型注释时,使用“mypy”更安全。 “Pylance(Pyright)”可能不会产生 PEP 定义的错误或警告。(的内容是在mypy的前提下讨论的)

但是,Pylance(Pyright)在很多情况下都比mypy方便,所以我使用Pylance(Pyright)。Python 有一个子句只提供类型注释,其余的留给第三方,所以如果你想要严格的类型,你应该选择另一种语言。

4.2. 强/弱类型

强和弱的定义相当混杂()这次我提到“类型安全”是因为我想谈一谈。

强类型

类型安全由语言规范维护

Java、C#、Python、Ruby 等。 类型安全:可以按类型(静态或动态)检测错误 不一定是 null 安全的。 (允许使用 Java、Python 等)如果你没有定义类型,Python 不应该允许 null(None)。 (因为我不想混合意外的数据类型) 弱打字

不保证类型安全

C、C++、JavaScript 等 类型不安全

通过查看以下 JavaScript 示例,您可以轻松理解如果不维护类型安全会发生什么。

console.log(1 + "1");
>>> 11

如您所见,int 和 string 类型之间存在意外连接。至于 Python,正如我之前提到的,我收到以下错误。

print(1 + "1")
>>> 1 + "1"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'str'

顺便说一句,Python 在这方面是类型安全的,但有一些警告。例如,可以如下计算int 类型和bool 类型。

print(1 + True)
>>> 2

这意味着 bool 类型是 int子类这就是为什么。(True 计算为 1,False 计算为 0。)

print(issubclass(bool, int))
>>> True

这不仅限于int类型,还适用于str、list等。另外,Python 对象有一个特殊的方法叫做__bool__,如果你定义了这个,你可以给对象设置默认值bool。

如您所见,即使是被认为是类型安全的语言也存在缺陷和差异,具体取决于语言规范,因此要小心。

5. OOP中的数据类型

面向对象编程(OOP)是基于“对象”概念的编程范式之一。

(参考)

构成 OOP 的元素是:

类(继承、抽象) 封装 多态性

面向对象编程也与数据类型密切相关。(由类定义的对象基本上具有复合数据结构。)这次我将从数据类型的角度来解释 Python 中的 OOP 类和多态性。

5.1. 类

类是“隐藏数据和处理并创建很多”的功能。这里有两个要点要讨论。

结构和类之间的区别 抽象类和接口的区别

首先,关于类和结构,存在以下差异。 (根据语言规范略有不同。)

班级 引用类型:保存数据的引用信息。 继承和抽象是可能的。 结构 值类型:直接保存数据的值信息。 没有继承或抽象。

之后是我个人的印象而不是区别,但是由于结构是专注于数据结构的,所以我有一个图像,成员变量基本上是公开的,方法并没有过于复杂。

在 Python 中,类和结构之间的区别是空无一人.或者更确切地说,没有结构,类也是结构。所以在 Python 中你必须小心不要在相同的上下文中使用类和结构。(例如,不要过度处理或继承/抽象将数据结构定义为结构的类。)让我们在某种程度上由个人和团队来决定这些决定和规则。

* 顺便说一句,namedtuple 可以定义类似结构的行为。

from collections import namedtuple
from typing import NamedTuple

# おすすめのnamedtuple宣言
class LoginForm(NamedTuple):
    id: str
    password: str

# こちらだと型が書けないため、ただの名前付きtupleとして使う場合以外おすすめしない
LoginForm = namedtuple(
    "LoginForm",
    [
        "id",
        "password",
    ],
)

其次,关于抽象类和接口,类也可以按“抽象”或“继承”来分类。这一次,我将专注于抽象。作为一种抽象方式抽象类如果您定义 (abstract) 和界面(interface) 可以定义。区别如下。

抽象类

这就像定义“当被问及动物时,这就是图像”。

可以写入处理(因为假设它会被重写重写) 仅继承自一个抽象类 界面

感觉就像定义诸如“动物具有这样的特征”之类的规范。

无法写入进程 可以组合多个接口(混入) 允许多重继承(因为未绘制行为)

Python没有接口,全部抽象基类将表示为考虑到语言的最新趋势,我们建议将其用作界面。(因为我们现在经常看到流行语言中没有类/带接口的规范)编写接口时,请保持它们的简单抽象,避免混入和多重继承。复杂的实现和抽象类思维只是在制作完成后才足以作为一种手段。

5.2. 多态性

多态性在日语中称为“多态性”或“多态性”。简单地说,就是“把一个类的类似方法(函数)看作具有类似的行为”。

我们以常见的Animal 类为例。(这里我用Java写,后面用Python写一个例子。)

abstract class Animal {
    abstract String bark();
}

动物的抽象类。让我们创建一个继承自这些的类。

class Dog extends Animal {
  String bark(){
    return "ワン";
  }
}

class Cat extends Animal {
  String bark(){
    return "ニャー"
  }
}

这些类的bark 方法是动物(Animal)无论其类型如何始终具有的行为。因此,无论动物的种类如何,都可以使使用这些方法的一方哭泣。

在这里,所有者(PetOwner)吹哨(blowWhistle)并实现啁啾的过程。

class PetOwner {
  void blowWhistle(Animal animal){
    System.out.println(animal.bark());
  }
}

既然可以这样实现,就可以省去写“when Dog”、“when Cat”等流程的麻烦。

以上是多态常见的具体解释,但我会用一点类型来解释。

在静态类型语言和动态类型语言中,实现多态性的方式略有不同。在静态类型语言中,需要继承源的类或接口的引用信息,如下所示。

许多静态类型语言要求你显式地实现继承或接口。这称为名义子类型。在名义子类型的情况下,即使它具有预期的行为,如果之前没有声明,它也会导致编译时错误。

((见报告

另一方面,动态类型语言不需要引用它们继承自的类或接口,而只验证方法和函数。这被称为“鸭子打字”。

以下是这两个差异的摘要。

名义子类型:如果父类信息相同,则识别为相同方法。

由于多态性是强绑定的,所以可以严格执行。 很多静态类型语言(有时也可以用动态类型语言来实现)

鸭子打字: 任何类如果有特定的方法就被认为是相同的。

多态性限制少,可以灵活实现。 很多动态类型的语言(一些静态类型的语言也可以用库来实现)

还有像 Go 这样的语言是静态类型的语言,可以像鸭子类型一样进行数据分析。这个结构子类型叫。

在 Python 中,多态可以通过以下方式实现:

创建一个具有相同名称的方法。 (鸭打字)

class Cat:
   def bark(self):
       return "ニャー"

class Dog:
   def bark(self):
       return "ワン"

def blow_whistle(f) -> None:
   print(f.bark())

blow_whistle(Cat())
blow_whistle(Dog())
>>> ニャー
>>> ワン

使用abc.ABC 创建一个抽象类。 (名义子类型)

from abc import ABC, abstractmethod

class Animal(ABC):
    @abstractmethod
    def bark(self):
        ...

class Cat(Animal):
    def bark(self):
        return "ニャー"

class Dog(Animal):
    def bark(self):
        return "ワン"

def blow_whistle(f: Animal) -> None:
    print(f.bark())

blow_whistle(Cat())
blow_whistle(Dog())
>>> ニャー
>>> ワン

使用typing.Protocol 创建同名方法。 (结构子类型)

from typing import Protocol

class Animal(Protocol):
    # ここのreturnの型を外すとCat()、Dog()で型の警告が出ます。※1
    def bark(self) -> str:
        ...

class Cat:
    def bark(self) -> str:
        return "ニャー"

class Dog:
    def bark(self) -> str:
        return "ワン"

def blow_whistle(f: Animal) -> None:
    print(f.bark())

blow_whistle(Cat())
blow_whistle(Dog())
>>> ニャー
>>> ワン

*1 如果您删除类型警告,您将在 Pylance (pyright) 中收到类似这样的错误。

Argument of type "Cat" cannot be assigned to parameter "f" of type "Animal" in function "blow_whistle"
"Cat" is incompatible with protocol "Animal"
 "bark" is an incompatible type
   Type "() -> str" cannot be assigned to type "() -> None"
     Function return type "str" is incompatible with type "None"
       Type cannot be assigned to type "None"Pylance(reportGeneralTypeIssues)

至于这三个应该用哪一个,1不需要接口推荐你不能。因此,我会使用2或3,但我的印象是推荐2。原因是 3 中的typing.Protocol 依赖于类型检查器,并将预期的检查结果委托给第三方库的保证。如果您希望在实现中具有一定的灵活性,或者如果您的团队使用统一类型检查器,这似乎是一种选择。2 是一种不灵活的形式,但是由于 Python 是动态类型语言,所以我认为***在某种程度上定义可以定义的部分。

六,结论

我解释了您需要了解的有关数据类型的知识。最后一个更多的是关于写作风格而不是数据类型。最近有一种趋势是函数式编程而不是 OOP,我认为数据类型将成为一个更重要的元素,所以我希望 Python 工程师首先感兴趣。

参考 python.org: ***: Python 对象和类的可视化指南: 什么是渐进式打字: 什么是渐进式打字:https://qiita.com/t2y/items/0a604384e18db0944398 PEP-591: C# 是强类型语言吗?还是弱类型语言? : Yukihiro Matsumoto 先生,关于让编程变得有趣的 Ruby3 类型的提案:

原创声明:本文系作者授权爱码网发表,未经许可,不得转载;

原文地址:https://www.likecs.com/show-308624519.html

20人参与, 0条评论 登录后显示评论回复

你需要登录后才能评论 登录/ 注册