Python 是一种动态类型语言,而不是静态类型语言(如 Go、Rust)。Python 解释器(负责执行 Python 代码)在执行之前不一定知道变量的类型。
Python 的这种动态特性既是它的优点也是它的缺点。它的优势在于您不必担心类型系统,使您能够在更短的时间内完成很多工作(例如,一次性 POC 项目)。然而,它的弱点会影响软件的寿命(难以重构并且缺乏不言自明的结构)。类型注释(在 Python v3.5 中引入)试图弥合差距,这通常比没有类型要好。
内置数据类型
Python 具有以下内置数据类型:
- 数字 (int, float, complex)
- 字符串 (string)
- 序列 (list, tuple, range)
- 二进制 (bytes, bytes, bytearrays, memoryview)
- 映射 (dict)
- 布尔值 (bool)
- Set (set, frozenset)
Python 中的所有数据都由对象(或对象之间的关系)表示。每个对象都有一个标识、类型和一个值。is 运算符比较两个对象的标识;id() 函数返回一个表示其标识的整数。(在 CPython 的情况下,它是存储值的内存地址。type() 函数返回对象的类型 (即对象本身)。
在开始数据类型之前,让我们回顾一下没有讨论过的数据类型:None、NotImplemented 和 Ellipsis (...)。
没有
None 是一个特殊的常量,表示没有值或 null 值。这被认为是假的。(这意味着在布尔表达式中使用时,它会计算 False。此外,None 是一个单例对象,即内存中只有一个实例。
from typing import Optional
x: Optional[str] = None
y: Optional[str] = None
print(id(x) == id(y)) # True
print(x is None) # True, since None is a singleton, the `is` operator returns True
# ====================
# A function that doesn't return anything has a return type of None (as it implicitly returns None)
def do_nothing() -> None:
print("Does nothing")
print(do_nothing() is None) # True
Always use 是检查变量的值是否为 None,而不是使用相等 ==。
未实现
此 NotImplemented 是一个类型。有一个具有此值的对象,可以通过内置名称 NotImplemented 访问它。
它主要用于运算符重载和比较。当定义了 __eq__、__add__ 或任何其他特殊方法等方法但无法处理给定的作时,它应返回 NotImplemented。这向 Python 发出信号,尝试反向作,或者如果未定义合适的作,则引发 TypeError 。
请考虑以下示例:
class CustomNumber:
def __add__(self, other: object) -> int:
if isinstance(other, int):
return 42 + other
return NotImplemented
num = CustomNumber()
print(num + 3) # Output: 45
print(3 + num) # Output: TypeError, as reverse operation is not defined
省略
此类型具有单个值。有一个对象具有此值。此对象可通过文本 ... 或内置名称 Ellipsis 进行访问。它的 truth 值为 true。
它用于以下上下文:
- 指示未实现的代码段。
- 切片
- 键入注释以表示可变长度或未指定的元素。
# ======== Type Annotations ========
def unimplemented_function():
...
# Equivalent to `pass`, but more explicit about intent
# ======== Slicing ========
import numpy as np
array = np.array([[1, 2, 3], [4, 5, 6]])
print(array[..., 1]) # Output: [2, 5] - selects the second column
# ======== Type annotations ========
from typing import Callable
# A function taking any number of arguments and returning an int
FuncType = Callable[..., int]
def example_func(*args) -> int:
return len(args)
现在,这些不太常见的类型已经不碍事了,让我们继续讨论其他数据类型。
数值的
在 Python 中,您可以使用整数 (int)、浮点数 (float) 或复数 (complex) 来表示数值数据。
整数表示无限精度的整数(正数或负数)。在内部,整数是使用任意精度实现的,允许 Python 处理非常大的数字而不会溢出。
x = 42
print(type(x)) # Output:
浮点数表示带小数点的实数。Python 浮点数基于 IEEE 754 标准,提供大约 15-17 位的精度。
pi = 3.14159
print(type(pi)) # Output:
复数表示具有实部和虚部的数字。虚部用 j 表示,可以通过 .imag 和 .real 属性访问。
z = 3 + 4j
print(type(z)) # Output:
以下代码片段提供了几个示例:
num: int = 100
print(num) # 100
print(num + 100) # 200
print(num + 100.50) # 200.5
print(num - 100) # 0
print(num - 100.50) # -0.5
print(num * 100) # 10000
print(num * 100.50) # 10050.0
print(num / 100) # 1.0
print(num / 100.50) # 0.9950248756218906
print(num // 100) # 1
print(num // 100.50) # 0.0
print(num % 100) # 0
print(num % 100.50) # 100.0
print(num**2) # 10000
print(num**2.5) # 100000.0
以下代码片段显示了算术运算符和赋值运算符。
# Arithmetic Operators
# Addition: 1 + 2 = 3
# Subtraction: 2 - 1 = 1
# Multiplication: 2 * 3 = 6
# Division: 3 / 2 = 1.5
# Floor Division: 3 // 2 = 1 <-- Returns the integer quotient (rounded down to the nearest integer)
# Modulus: 3 % 2 = 1 <-- Returns the remainder of the division
# Exponentiation: 2 ** 3 = 8
# Assignment Operators
# Addition Assignment: a += 2 => a = a + 2
# Subtraction Assignment: a -= 2 => a = a - 2
# Multiplication Assignment: a *= 2 => a = a * 2
# Division Assignment: a /= 2 => a = a / 2
# Floor Division Assignment: a //= 2 => a = a // 2
# Modulus Assignment: a %= 2 => a = a % 2
# Exponentiation Assignment: a **= 2 => a = a ** 2
如果 str type 分别有效,我们也可以将 str type 转换为 int 和 float。
num1_str: str = "100"
try:
num1_int: int = int(num1_str)
print(num1_int)
except ValueError as e:
print(f"Error: {e}")
num2_str: str = "100.50"
try:
num2_float: float = float(num2_str)
print(num2_float)
except ValueError as e:
print(f"Error: {e}")
需要了解的一些有用信息:
print(3 == 3.0) # True
print(3 == 3.0000000001) # False
print(3 == "3") # False
字符串
字符串是字符序列。创建字符串的方法有很多种 — 单引号 (')、双引号 (“),对于多行字符串,我们可以使用三引号 (”“”)。
# Single quotes are used to create strings
email_subject: str = "Welcome to the Python Type System Course!"
# Double quotes are used to create strings
email_body: str = (
"Hi there, welcome to the Python Type System course. We hope you enjoy it!"
)
# Triple quotes are used to create multi-line strings
email_html: str = """
Welcome to the Python Type System Course!
Hi there, welcome to the Python Type System course. We hope you enjoy it!
"""
使用哪一个取决于您的偏好或代码库偏好,但请坚持使用一个 U 盘和一种样式。我们可以使用斜杠 \ 来转义引号。
error_msg: str = "'str' object does not support item assignment"
print(error_msg)
# 'str' object does not support item assignment
Python 没有单独的字符类型,就像在 C 中我们有 char 一样。
字符串是可迭代且不可变的数据类型。
msg: str = "Hello, World!"
# Immutable
msg[0] = "h" # Error: 'str' object does not support item assignment
# Iterable
for char in msg:
print(char)
以下代码段涵盖了 String 上派上用场的一些常见方法:
msg: str = "Hello world"
print(msg)
print(msg.upper()) # Convert the string to uppercase
print(msg.lower()) # Convert the string to lowercase
print(msg.capitalize()) # Capitalize the first letter of the string
print(msg.title()) # Capitalize the first letter of each word
print(msg.startswith("Hello")) # Check if the string starts with "Hello"
print(msg.endswith("world")) # Check if the string ends with "world"
print(msg.replace("world", "Python")) # Replace "world" with "Python"
print(msg.split(" ")) # Split the string into a list of words
print(msg.find("world")) # Find the index of the first occurrence of "world"
print(msg.index("world")) # Find the index of the first occurrence of "world"
print(msg.count("l")) # Count the number of occurrences of "l" in the string
print(len(msg)) # Get the length of the string
print(" ".join(["Hello", "world"])) # Join a list of strings into a single string
print(msg.strip()) # Remove leading and trailing whitespace
print(msg.lstrip()) # Remove leading whitespace
print(msg.rstrip()) # Remove trailing whitespace
print(msg.isalpha()) # Check if the string contains only alphabetic characters
print(msg.isnumeric()) # Check if the string contains only numeric characters
print(msg.isalnum()) # Check if the string contains only alphanumeric characters
print(msg.isdigit()) # Check if the string contains only digits
print(msg.islower()) # Check if the string is in lowercase
print(msg.isupper()) # Check if the string is in uppercase
print(msg.istitle()) # Check if the string is in title case
print(msg.isspace()) # Check if the string contains only whitespace characters
索引和切片
就像 list 和 tuple 一样,我们可以为字符串编制索引并对它们进行切片。
msg: str = "Hello world"
print(msg)
print(msg[0]) # H
print(msg[1]) # e
print(msg[len(msg) - 1]) # d
print(msg[-1]) # d
print(msg[-2]) # l
print(msg[0:5]) # Hello
print(msg[6:11]) # world
串联和插值
在 concatenation 中,我们组合两个字符串。+ add 运算符是重载的,这意味着,就像我们可以添加两个数字一样,我们也可以添加两个字符串。(我们也可以添加两个列表。
greeting: str = "Welcome"
username: str = "John"
# Concatenation
full_greeting = greeting + ", " + username
print(full_greeting) # Output: Welcome, John
字符串插值是将变量或表达式的值插入字符串的过程。有几种方法可以做到这一点 — 使用 % 运算符、str.format 和 f-strings 格式的字符串文字。
greeting: str = "Welcome"
username: str = "John"
using_percent: str = "%s, %s!" % (greeting, username)
format_string: str = "{}, {}!".format(greeting, username)
f_string: str = f"{greeting}, {username}!"
布尔
Boolean 有 2 个可能的值:True 和 False。在 Python 中,还有用于表达真值和假值的概念。
以下脚本是 check_truthiness 函数计算给定输入的布尔值的示例:
from typing import Any
is_married: bool = True
is_dead: bool = False
def check_truthiness(value: Any) -> bool:
if value:
return True
return False
print(check_truthiness(())) # False
print(check_truthiness([])) # False
print(check_truthiness({})) # False
print(check_truthiness(set())) # False
print(check_truthiness(0)) # False
print(check_truthiness(0.0)) # False
print(check_truthiness("")) # False
print(check_truthiness(" ")) # True
类型转换为布尔值很简单,因为所有 falsehood 值都转换为 False,而其他值则转换为 True。
from typing import Any
def convert_to_bool(value: Any) -> bool:
return bool(value)
print(convert_to_bool("True")) # True
print(convert_to_bool("False")) # True
print(convert_to_bool("true")) # True
print(convert_to_bool("false")) # True
print(convert_to_bool(1)) # True
print(convert_to_bool(0)) # False
print(convert_to_bool(100)) # True
print(convert_to_bool(-100)) # True
print(convert_to_bool(1.0)) # True
print(convert_to_bool(0.0)) # False
print(convert_to_bool(100.0)) # True
print(convert_to_bool([])) # False
print(convert_to_bool([1, 2, 3])) # True
print(convert_to_bool({})) # False
print(convert_to_bool({"key": "value"})) # True
print(convert_to_bool(())) # False
print(convert_to_bool((1, 2, 3))) # True
print(convert_to_bool(set())) # False
print(convert_to_bool({1, 2, 3})) # True
print(convert_to_bool(None)) # False
print(convert_to_bool("")) # False
print(convert_to_bool(" ")) # True
我们应该注意的一些布尔类型行为:
- 使用相等 (==) 进行比较,而不是使用恒等 (is)。
- 布尔运算符 (and、or、not) 表现出短路行为,这意味着它们并不总是计算所有作数。
- 在比较或运算中混合使用布尔和非布尔作数可能会因隐式类型转换而导致意外结果。
x: bool = True
y: bool = True
# Identity and equality
print(x is True) # Output: True
print(x == True) # Output: True. Though `==` should be avoid to compare value with True
print(x is y) # Output: True
print(x == y) # Output: True
# Short-circuiting behavior
# some_function() is not called if the first operand is True
result = True or some_function() # Output: True
# Mixing boolean and non-boolean operands
print(True + 1) # Output: 2 (True is treated as 1 in numeric context)
print(True > 0) # Output: True (True is greater than 0 in numeric context)
二元的
二进制数据类型专门用于处理原始二进制数据,这些数据经常在文件、网络通信或低级作中遇到。Python 提供了三种内置的二进制类型:bytes、bytearray 和 memoryview。
字节
不可变的字节序列(8 位值,范围从 0 到 255)。它用于存储和处理原始二进制数据,例如文件内容或编码字符串。
它表示为前缀为 b 或 B 的序列(例如,b“hello”)。每个字节都是一个整数,并且直接对这些整数执行作。
# Creating a bytes object
b = b"hello"
print(b) # Output: b'hello'
# Accessing individual bytes
print(b[0]) # Output: 104 (ASCII value of 'h')
# Slicing a bytes object
print(b[1:3]) # Output: b'el'
# Encoding a string into bytes
text = "Python"
encoded = text.encode("utf-8")
print(encoded) # Output: b'Python'
print(encoded.decode("utf-8")) # Output: "Python"
字节数组
可变的字节序列。与 bytes 不同,bytearray 可以在创建后进行修改。它适用于需要就地更新二进制数据的情况,例如修改文件缓冲区或网络数据包。
# Creating a bytearray
ba = bytearray(b"hello")
print(ba) # Output: bytearray(b'hello')
# Modifying the bytearray
ba[0] = 72 # ASCII for 'H'
print(ba) # Output: bytearray(b'Hello')
# Adding bytes to the bytearray
ba.append(33) # ASCII for '!'
print(ba) # Output: bytearray(b'Hello!')
在以下示例中,我们将读取一个二进制文件:
with open("example.bin", "rb") as f:
data = bytearray(f.read())
# Modify the data
data[0] = 255
with open("example_modified.bin", "wb") as f:
f.write(data)
Memory(内存)view
一个视图对象,它提供了一种无需复制即可访问和作对象的基础二进制数据的方法。它对于必须避免数据重复的性能关键型应用程序非常有用,例如使用大型数据集或流数据。
# Creating a memoryview from a bytes object
b = b"example"
mv = memoryview(b)
# Accessing data through the memoryview
print(mv[0]) # Output: 101 (ASCII for 'e')
# Slicing the memoryview
print(mv[1:4].tobytes()) # Output: b'xam'
# Casting the memoryview to a different format
mv_cast = mv.cast("B") # Cast to unsigned bytes
print(list(mv_cast)) # Output: [101, 120, 97, 109, 112, 108, 101]
高效读取或处理大型二进制数据,而无需创建中间副本。
data = bytearray(b"large binary data here")
mv = memoryview(data)
# Modify a portion of the data
mv[0:5] = b"small"
print(data) # Output: bytearray(b'small binary data here')