Python 编程/数据类型
数据类型决定了一个对象是否可以执行某些操作,或者它是否没有意义。其他编程语言通常通过确保对象永远不会存储在将对该对象执行操作的地方来确定操作对该对象是否有意义(这种类型系统称为静态类型)。Python 不会这样做。相反,它将对象的类型与对象一起存储,并在执行操作时检查该操作对该对象是否有意义(这称为动态类型)。
Python 的内置(或标准)数据类型可以分为几个类别。按照官方 Python 文档中使用的层次结构方案,它们是数字类型、序列、集合和映射(以及一些此处不再讨论的其他类型)。某些类型仅在语言的某些版本中可用,如下所示。
- 布尔型:内置值
True
和False
的类型。在条件表达式和需要表示某些条件真假性的任何地方都有用。大多可以与整数 1 和 0 交换使用。实际上,条件表达式将接受任何类型的数值,将布尔False
、整数 0 和空字符串""
等特殊值视为等效于False
,并将所有其他值视为等效于True
。
数字类型
- 整数型:整数;在 Python 2.x 中等效于 C 中的 longs,在 Python 3.x 中长度不受限制
- 长整数型:长度不受限制的长整数;仅存在于 Python 2.x 中
- 浮点型:浮点数,等效于 C 中的 doubles
- 复数型:复数
序列
- 字符串型:字符串;在 Python 2.x 中表示为 8 位字符序列,但在 Python 3.x 中表示为 Unicode 字符序列(范围为 U+0000 - U+10FFFF)
- 字节型:0-255 范围内的整数序列;仅在 Python 3.x 中可用
- 字节数组型:与字节型类似,但可变(见下文);仅在 Python 3.x 中可用
- 列表型
- 元组型
集合
- 集合型:无序的唯一对象集合;从 Python 2.6 开始作为标准类型可用
- 冻结集合型:与集合型类似,但不可变(见下文);从 Python 2.6 开始作为标准类型可用
映射
- 字典型:Python 字典,也称为哈希表或关联数组,这意味着列表中的元素与一个定义相关联,类似于Java中的 Map
其他一些,例如类型和可调用对象
通常,Python 中的数据类型可以根据该类型对象是可变还是不可变来区分。不可变类型对象的內容在创建后不能更改。
一些不可变类型 | 一些可变类型 |
---|---|
|
|
只有可变对象支持原地更改对象的方法,例如重新分配序列切片,这对列表有效,但对元组和字符串会引发错误。
重要的是要理解,Python 中的变量实际上只是内存中对象的引用。如果你将对象分配给变量,如下所示,
a = 1
s = 'abc'
l = ['a string', 456, ('a', 'tuple', 'inside', 'a', 'list')]
你实际上只是让这个变量(a, s,或l)指向对象(1, 'abc', ['a string', 456, ('a', 'tuple', 'inside', 'a', 'list')]),它保存在内存中的某个位置,作为一种访问它的便捷方式。如果你重新分配变量,如下所示
a = 7
s = 'xyz'
l = ['a simpler list', 99, 10]
你让变量指向一个不同的对象(在我们示例中是新创建的对象)。如上所述,只有可变对象才能在原地更改(l[0] = 1在我们的示例中是可以的,但s[0] = 'a'会引发错误)。当操作没有明确要求原地更改时,这会变得棘手,例如+=(增量)运算符。当它用于不可变对象(如a += 1或在s += 'qwertz'中)时,Python 会默默地创建一个新对象,并将变量指向它。但是,当它用于可变对象(如l += [1,2,3]中)时,变量指向的对象将被原地更改。虽然在大多数情况下,你不需要了解这种不同的行为,但当多个变量指向同一个对象时,它就很重要。在我们的示例中,假设你设置了p = s和m = l,然后s += 'etc'和l += [9,8,7]。这将更改s并将p保持不变,但将同时更改m和l,因为它们都指向同一个列表对象。Python 的内置id()函数,它为给定变量名返回唯一的对象标识符,可以用来跟踪幕后发生的事情。
通常,Python 的这种行为会导致函数中的混乱。作为说明,请考虑以下代码
def append_to_sequence (myseq):
myseq += (9,9,9)
return myseq
tuple1 = (1,2,3) # tuples are immutable
list1 = [1,2,3] # lists are mutable
tuple2 = append_to_sequence(tuple1)
list2 = append_to_sequence(list1)
print('tuple1 = ', tuple1) # outputs (1, 2, 3)
print('tuple2 = ', tuple2) # outputs (1, 2, 3, 9, 9, 9)
print('list1 = ', list1) # outputs [1, 2, 3, 9, 9, 9]
print('list2 = ', list2) # outputs [1, 2, 3, 9, 9, 9]
这将给出上面指示的,通常是意外的输出。myseq是append_to_sequence函数的局部变量,但当调用该函数时,myseq仍然会指向与我们传入的变量(t或l在我们示例中)相同的对象。如果该对象是不可变的(如元组),则没有问题。+= 运算符将导致创建一个新的元组,并且myseq将被设置为指向它。但是,如果我们传入可变对象的引用,该对象将在原地操作(因此myseq和l,在我们示例中,最终指向同一个列表对象)。
链接
- 3.1. 对象、值和类型,Python 语言参考,docs.python.org
- 5.6.4. 可变序列类型,Python 标准库,docs.python.org
字面量整数可以用三种方式输入
- 十进制数可以直接输入
- 十六进制数可以通过在前面加上 0x 或 0X 来输入(0xff 是十六进制 FF,或十进制 255)
- 八进制字面量的格式取决于 Python 的版本
- Python 2.x:八进制可以通过在前面加上零 ( 0 ) 来输入(0732 是八进制 732,或十进制 474)
- Python 3.x:八进制可以通过在前面加上零,后面跟着字母 O (0o 或 0O) 来输入(0o732 是八进制 732,或十进制 474)
浮点数可以直接输入。
长整数可以通过直接输入(1234567891011121314151617181920 是一个长整数)或在后面追加 L (0L 是一个长整数) 来输入。涉及短整数的溢出计算会自动转换为长整数。
复数可以通过添加一个实数和一个虚数来输入,虚数通过在后面追加 j 来输入(例如 10+5j 是一个复数。10j 也是一个复数)。请注意,j 本身不构成一个数字。如果需要,请使用 1j。
字符串可以是单引号或三引号字符串。区别在于开始和结束分隔符,以及单引号字符串不能跨越多行。单引号字符串通过输入一个单引号 (') 或一个双引号 ("),后面跟着它的匹配项来输入。因此
'foo' works, and "moo" works as well, but 'bar" does not work, and "baz' does not work either. "quux'' is right out.
三引号字符串类似于单引号字符串,但可以跨越多行。它们的开始和结束分隔符也必须匹配。它们通过三个连续的单引号或双引号来输入,因此
'''foo''' works, and """moo""" works as well, but '"'bar'"' does not work, and """baz''' does not work either. '"'quux"'" is right out.
元组通过在括号中输入,并在条目之间使用逗号来输入
(10, 'Mary had a little lamb')
此外,当不含糊时,可以省略括号
10, 'whose fleece was as white as snow'
请注意,单元素元组可以通过将条目用括号括起来并添加逗号来输入,如下所示
('this is a singleton tuple',)
列表类似,但使用方括号
['abc', 1,2,3]
字典通过用大括号括起来一组用冒号分隔的键/值对,并在其他条目之间用逗号分隔来创建
{ 'hello': 'world', 'weight': 'African or European?' }
这些复合类型中的任何一个都可以包含任何其他类型,深度不限
((((((((('bob',),['Mary', 'had', 'a', 'little', 'lamb']), { 'hello' : 'world' } ),),),),),),)
在其他编程语言中,Python 中的空指针类似于None。None 不是空指针或空引用,而是一个只有一个实例的实际对象。None 的一个用途是在函数的默认参数值中,有关详细信息,请参阅Python Programming/Functions#Default_Argument_Values。通常使用is 而不是 == 来比较None。
测试 None 和赋值
if item is None:
...
another = None
if not item is None:
...
if item is not None: # Also possible
...
在默认参数值中使用 None
def log(message, type = None):
...
PEP8 指出,“对像 None 这样的单例的比较应始终使用 is 或 is not,绝不使用相等运算符”。因此,“if item == None:” 是不可取的。类可以重新定义相等运算符 (==),以便它的实例将等于 None。
您可以通过 dir(None) 或 id(None) 来验证 None 是一个对象。
另请参阅Operators#Identity 章节。
链接
- 4. 内置常量,docs.python.org
- 3.11.7 空对象,docs.python.org
- Python None 比较:我应该使用“is”还是 ==?,stackoverflow.com
- PEP 0008 -- Python 代码风格指南,python.org
类型转换
[edit | edit source]Python 中的类型转换示例
v1 = int(2.7) # 2
v2 = int(-3.9) # -3
v3 = int("2") # 2
v4 = int("11", 16) # 17, base 16
v5 = long(2) # Python 2.x only, not Python 3.x
v6 = float(2) # 2.0
v7 = float("2.7") # 2.7
v8 = float("2.7E-2") # 0.027
v9 = float(False) # 0.0
vA = float(True) # 1.0
vB = str(4.5) # "4.5"
vC = str([1, 3, 5]) # "[1, 3, 5]"
vD = bool(0) # False; bool fn since Python 2.2.1
vE = bool(3) # True
vF = bool([]) # False - empty list
vG = bool([False]) # True - non-empty list
vH = bool({}) # False - empty dict; same for empty tuple
vI = bool("") # False - empty string
vJ = bool(" ") # True - non-empty string
vK = bool(None) # False
vL = bool(len) # True
vM = set([1, 2])
vN = set((1, 2)) # Converts any sequence, not just a list
vO = set("abc") # {'c', 'b', 'a'}
vP = set(b"abc") # {97, 98, 99}
vQ = list(vM)
vR = list({1: "a", 2: "b"}) # dict -> list of keys
vS = tuple(vQ)
vT = list("abc") # ['a', 'b', 'c']
print(v1, v2, v3, type(v1), type(v2), type(v3))
隐式类型转换
int1 = 4
float1 = int1 + 2.1 # 4 converted to float
# str1 = "My int:" + int1 # Error: no implicit type conversion from int to string
str1 = "My int:" + str(int1)
int2 = 4 + True # 5: bool is implicitly converted to int
float2 = 4.5 + True # 5.5: True is converted to 1, which is converted to 1.0
关键字:类型转换。
链接
- 2. 内置函数 # bool,docs.python.org
- 2. 内置函数 # list,docs.python.org
- 2. 内置函数 # float,docs.python.org
- 2. 内置函数 # int,docs.python.org
- 2. 内置函数 # set,docs.python.org
- 2. 内置函数 # str,docs.python.org
- 2. 内置函数 # type,docs.python.org
- 2. 内置函数 # tuple,docs.python.org
练习
[edit | edit source]- 编写一个程序,实例化一个单一对象,向该对象添加 [1,2],并返回结果。
- 找到一个返回相同长度输出的对象(如果存在的话?)。
- 找到一个返回比它开始长度大 2 的输出的对象。
- 找到一个导致错误的对象。
- 找到两个数据类型 X 和 Y,使 X = X + Y 会导致错误,但 X += Y 不会。