变量是保存一个值的已命名的容器。变量的类型包括strings, lists, dictionaries等。type函数返回数据类型:
print(type(name))
python 中的数据类型可分为不可变数据类型与可变数据类型。
不可变(immutable)数据类型
在大多数编程语言中,以下数据类型通常是不可变的:
1 整型(Integer):整数类型数据是不可变的,一旦创建就不能被修改。每次对整数进行操作时,实际上是创建了一个新的整数对象。
2 浮点型(Float):浮点数类型也是不可变的,无法修改已经创建的浮点数对象。
3 字符串(String):字符串通常是不可变的,意味着一旦创建就不能直接修改。对字符串的操作通常会创建一个新的字符串对象,而不是在原字符串上进行修改。
4 元组(Tuple):元组是不可变的有序序列,一旦创建就不能被修改。无法在元组中添加、删除或修改元素,只能访问其中的元素。但是,元组的元素可以是任何类型的对象,包括可变和不可变类型。这意味着元组可以包含不可变的对象,如整数、字符串、元组等,也可以包含可变的对象,如列表、字典等。
my_tuple = (1, [2, 3], 'abc')
my_tuple[1].append(4)
print(my_tuple) # 输出: (1, [2, 3, 4], 'abc')
在上述示例中,元组 my_tuple 包含了一个列表 [2, 3] 作为其第二个元素。尽管元组不可变,但我们可以通过引用该列表并修改其内容。结果是,列表被修改为 [2, 3, 4],但元组本身仍然保持不变。
不可变性具有一些优点,例如线程安全性和缓存机制的利用,因为不可变对象的值无法被修改,所以在多线程环境下不需要进行额外的同步操作。
以下数据类型的元素也必须是不可变的,因为它们的哈希值是固定的:
字典的键
集合的元素
有一个问题,假如设x= 1, 然后x = 1 + 1, 这时x不是变了吗?
在这个特定的情况下,我们需要理解变量和对象之间的关系。
当你执行语句 x = 1 时,它创建了一个整数对象1,并将变量x引用到这个对象。此时,x引用的是整数对象1。
接着,当你执行语句 x = 1 + 1 时,首先执行表达式 1 + 1 得到结果2,然后创建了一个新的整数对象2,并将变量x重新引用到这个新的对象。此时,x引用的是整数对象2。
尽管我们使用了相同的变量名x,但实际上是创建了一个新的对象,并将变量x重新指向该对象。在这个过程中,原来的对象1并没有被修改,而是创建了一个新的对象2,并将变量x指向了这个新对象。
因此,从整体上来看,x的值在这个过程中发生了改变,从1变为2。但这并不意味着整数对象1本身是可变的,而是指变量x的引用发生了变化。整数对象本身仍然是不可变的,无法在原地修改。
x = 1
print(id(x))
x = x + 1
print(id(x))
通过检查x的地址,会发现地址不同,证明了第2次赋值实际是指向了一个新的对象。
可变数据类型
可变数据类型是指在创建后可以修改其值的数据类型。以下是常见的可变数据类型:
-
列表(List):列表是一种有序、可变的数据类型,可以通过索引进行访问、修改和删除元素。
-
字典(Dictionary):字典是一种无序的键值对集合,可以通过键来访问、修改和删除对应的值。字典中的键是唯一的,但值可以重复。
-
集合(Set):集合是一种无序、不重复的数据集合,可以进行集合运算(如并集、交集、差集)和添加、删除元素。
这些都是常见的可变数据类型,它们在创建后可以通过不同的方法进行修改。
可迭代对象(iterable)
在Python中,有多种类型的对象被称为可迭代对象,可以在循环中进行迭代。以下是一些常见的可迭代对象:
- 列表(List):有序的可变集合,使用方括号 [ ] 表示。
- 元组(Tuple):有序的不可变集合,使用圆括号 ( ) 表示。
- 字符串(String):有序的不可变字符序列,使用引号(单引号或双引号)括起来。
- 字典(Dictionary):无序的键值对集合,使用大括号 { } 表示。
- 集合(Set):无序的唯一元素集合,使用大括号 { } 表示或使用 set() 函数创建。
- 范围(Range):表示连续整数序列的不可变对象,使用 range() 函数创建。
- 文件对象(File Object):表示打开的文件,可按行迭代(readline()方法)读取文件内容。
- 生成器(Generator):使用函数和 yield 语句生成元素的可迭代对象。
- 迭代器(Iterator):实现了 __iter__() 和 __next__() 方法的对象,可以逐个返回元素。
这些可迭代对象可以在循环结构(如 for 循环)中使用,通过迭代访问其中的元素。
此外,还可以通过实现自定义类并定义 __iter__() 和 __next__() 方法来创建自己的可迭代对象。
需要注意的是,虽然字符串是一个可迭代对象,但它也是一个序列,因此可以通过索引访问单个字符。
可迭代对象(iterable)是指实现了 __iter__() 方法的对象,它表示一组元素可以按顺序进行迭代(遍历)。
正常情况下,我们通常不会直接访问和调用 __iter__() 方法,而是使用可迭代对象在迭代上下文中自动调用它。迭代上下文是指可以进行迭代操作的环境,例如 for 循环、列表推导式、in 关键字等。当我们在迭代上下文中使用可迭代对象时,Python 在每次迭代会隐式地调用可迭代对象的 __iter__() 方法,获取一个可迭代对象的元素,并进行迭代操作。
可迭代对象可以通过调用 iter() 函数来获取一个迭代器对象:
stra='''abcdefghijklmnopqrstuvwxyz'''
iter_stra = iter(stra)
for x in iter_stra:
print(x, end=' ') # a b c d e f g h i j k l m n o p q r s t u v w x y z
这个例子只是个示例,但由于在定义字符串变量 stra 并将其赋值时,这个字符串就会被完整地存储在内存中, 后面使用迭代器对象并不能减少字符串的内存占用。虽然可以尝试使用 del 关键字删除变量引用,以便让不再需要的对象尽早成为不可达对象,但垃圾回收的具体时机是不确定的,你无法直接控制内存的释放时机,但可以通过适当管理变量的引用来帮助垃圾回收机制尽早回收不再需要的对象。
迭代器对象(iterator)
迭代器对象(iterator)是实现了迭代器协议的对象,它具有 __iter__() 方法和 __next__() 方法。迭代器对象用于逐个返回元素,每次调用 __next__() 方法会返回下一个元素。如果没有更多元素可迭代,则引发 StopIteration 异常。
因此,迭代器对象是一种特殊的可迭代对象。可迭代对象是整个可迭代集合,而迭代器对象则是按需迭代这个集合。
生成器对象是一种特殊的迭代器对象,通过生成器函数生成值。生成器对象也是迭代器对象。
联合类型
联合类型(Union types)是一种类型系统的概念,它表示一个变量、参数或返回值可以具有多种可能的类型之一。
例如,在静态类型语言中,可以定义一个联合类型 int | float 表示一个变量可以是整数或浮点数类型之一。这意味着该变量可以存储整数值或浮点数值,而不限制于任何一种特定的类型。
但是,Python 是一种动态类型的编程语言,不需要在变量声明时显式地指定数据类型。变量在 Python 中是动态的,其类型是根据赋给变量的值来推断的。Python 的动态类型系统允许变量在运行时接受不同类型的值,而无需提前定义其类型。
然而,从 Python 3.10 开始,引入了一种类型提示的语法,可以通过类型提示来指定变量可能的联合类型。类型提示只是一种辅助工具,它并不会改变 Python 的动态类型特性。类型提示仅用于静态分析工具和编辑器来提供类型检查和代码补全的功能,用于增加代码的可读性和可维护性。在实际运行时,Python 仍然是动态类型的,并不会进行类型强制或检查,它对运行时行为没有直接影响。
def some_funcion(flexible_parameter: int | str) -> int | str:
return flexible_parameter
上述示例表示 flexible_parameter 参数可以是整数或字符串类型之一。返回类型注解也使用了相同的联合类型。