好的今天我们来学习python的标准数据类型、索引与切片;Python 之所以好用,很大程度上归功于它内置了丰富且强大的数据结构。这就像做菜——锅碗瓢盆(语法)就那些,但食材(数据类型)的多样性和新鲜程度,直接决定了你能做出什么级别的菜。

一、数据类型总览:

Python 3 有六个标准数据类型:

 

  • 数字(Number) —— 不可变,非序列  
  • 字符串(String) —— 不可变,序列  
  • 列表(List) —— 可变,序列  
  • 元组(Tuple) —— 不可变,序列  
  • 字典(Dictionary) —— 可变,非序列(映射)  
  • 集合(Set) —— 可变(或不可变的 frozenset),非序列

 

这里面有两条主线:可变性 和 序列性。  

  • 可变(Mutable)意味着你可以原地增删改,而不改变内存地址;不可变(Immutable)则每次“修改”其实是新建对象。  
  • 序列(Sequence)意味着元素有顺序,可以通过整数下标(索引)访问;非序列则靠键(字典)或哈希(集合)来定位。

理解了这两条线,后面的方法记忆就会轻松很多。

 

 

二、数字(Number)

数字是一切计算的起点,它不可变,也不是序列。Python 里的数字分为四类:

 

1. 整数(int)

  • 理论上可以无限大(只受内存限制),所以你可以放心地算天文数字。  
  • 例子:999999...-999901234

 

2. 浮点数(float)

  • 带小数点,也可以用科学计数法 e 或 E。  
  • 例:1.231.3.14e-104E210(表示 )。

 

提醒:浮点数在计算机里是二进制近似存储,所以 0.1 + 0.2 并不精确等于 0.3。如果做金融计算,记得用 decimal.Decimal

 

3. 布尔型(bool)

  • Python 2 里没有专门的布尔型,用 0 和 1 代替;Python 3 把 True 和 False 变成了关键字,但它们本质上还是 1 和 0,所以 True + 3 的结果是 4,这个特性有时能派上用场(比如 sum([True, False, True]) 统计真值的个数)。

 

4. 复数(complex)

  • 形如 a + bj,虚部用 j 或 J,系数不能省略(比如 1j 是合法的,但 j 单独写会报错)。  
  • 例:2+1j1j

 

类型转换

Python 不会偷偷帮你转类型,需要你主动调用工厂函数:

函数

说明

type(obj)

查看对象类型

int([x], base=10)

转整数,可指定进制(x 需为字符串)

float([x])

转浮点数,字符串两头的空格不影响

bool([x])

转布尔,空、None0、空容器等都是 False

complex([real, imag])

转复数

 

大家可以试一试随手敲敲这些转换:

         
    # int() 各种姿势    
    print(int())                 # 0(不传参)    
    print(int("12"))             # 12    
    # print(int("12.1"))         # 报错!浮点型字符串不行    
    print(int("101010", base=2)) # 42(二进制转十进制)    
    print(int("0b101010", base=2)) # 42(带前缀也行)    
    print(int("11", base=8))     # 9(八进制)    
    print(int("0o11", base=8))   # 9    
    print(int("17", base=16))    # 23(十六进制)    
    print(int("0x17", base=16))  # 23    
         
    # float()    
    print(float())               # 0.0    
    print(float(123))            # 123.0    
    print(float("  1.23  "))     # 1.23(忽略空格)    
         
    # bool()    
    print(bool())                # False    
    print(bool(0))               # False    
    print(bool(None))            # False    
    print(bool([]))              # False    
    print(bool(1))               # True    
    print(bool("0"))             # True(非空字符串!)    
         
    # complex()    
    print(complex())             # 0j    
    print(complex(3.2, 1))       # (3.2+1j)    
    print(complex("3.2+1j"))     # (3.2+1j) 注意加号两边不能有空格    
         

p.s. :bool 是 int 的子类,所以 isinstance(True, int) 返回 True,这个细节在类型检查时可能让你意外,记住就好。

 

 

三、字符串(String)

字符串是 不可变的序列,意味着你无法修改某个位置的字符,只能通过生成新字符串来“变相修改”。它用单引号、双引号或三引号定义。

 

1. 引号嵌套与转义

当你想在字符串里输出引号时,有三种常用方式:

        
    # 方式一:转义字符    
    print("\"")          # 输出一个双引号 "    
         
    # 方式二:外层单引号,内层双引号    
    print('我说:"你好"')  # 我说:"你好"    
         
    # 方式三:三引号(多行字符串天然支持内部引号)    
    print("""这里可以随便写" ' 引号""")    
         

 

2. 转义字符与原始字符串(Raw String)

反斜杠 \ 会引发转义,比如 \n 换行,\t 制表符。但有时候我们不希望它转义(比如 Windows 路径或正则表达式),这时可以在字符串前面加 r 或 R,让它变成 原始字符串

         
    print("123\n456")      # 换行输出    
    print(r"123\n456")     # 原样输出 123\n456    
    print(R"www.baidu.com\n")  # 也是原样    
         

 

3. 字符串格式化

① % 格式化(传统,但偶尔会碰到)

常用符号:%s(字符串,调用 str())、%r(字符串,调用 repr(),会带引号)、%d(整数)、%f(浮点数)等。还可以加辅助指令,比如 - 左对齐,+ 显示正号,# 显示进制前缀,m.n 控制宽度和小数位。

    PI = 3.141592653    
    print("pi1 = %10.3f" % PI)      # 总宽10,保留3位小数    
    print("pi2 = %.5f" % PI)        # 保留5位    
    print("pi3 = %012.3f" % PI)     # 用0填充空位    
    print("pi4 = %-10.3f" % PI)     # 左对齐    
    print("pi5 = %+f" % PI)         # 显示正号    
    print("%o" % 12)                # 14(八进制)    
    print("%#o" % 12)               # 0o14(显示前缀)    
    print("%x" % 24)                # 18(十六进制)    
    print("%#x" % 24)               # 0x18    
         

 

② format() 方法(Python 2.6+,功能强大)

使用 {} 占位符,可以按顺序、按索引、按关键字传值,还支持对齐、填充、进制、千分位等。

         
    # 顺序    
    a = "它说它叫{},今年{}岁。".format("旺财", 2)    
    # 索引    
    b = "它说它叫{1},今年{0}岁。".format(2, "旺财")    
    # 关键字    
    c = "它说它叫{name},今年{age}岁。".format(name="旺财", age=2)    
    # 复用    
    d = "它说它叫{name},今年{age}岁,宝宝也是{age}个月。".format(name="旺财", age=2)    
         
    # 对齐与填充    
    print('{:>8}'.format('1'))      # 右对齐,总宽8    
    print('{:0>8}'.format('1'))     # 右对齐,0填充    
    print('{:a<8}'.format('1'))     # 左对齐,a填充    
    print('{:.2f}'.format(3.14159)) # 保留两位小数    
    print('{:8.2f}'.format(3.14159)) # 总宽8,保留两位    
    print('{:,}'.format(1234567890)) # 千分位分隔符    
    print('{:b}'.format(100))       # 二进制 1100100    
    print('{:o}'.format(100))       # 八进制 144    
    print('{:x}'.format(100))       # 十六进制 64    
         

 

③ f-string(Python 3.6+,墙裂推荐)

在字符串前加 f,大括号里可以直接写变量或表达式,甚至调用函数。它是目前最直观、性能最好的方式。

         
    name = "wangCai"    
    age = 2    
    print(f"它说它叫{name},它{age}岁,宝宝{age}月了!")    
    print(f"它说它叫{name.upper()},它{4//2}岁,宝宝{age}月了!")  # 表达式和函数    
         
    # 同样支持格式化    
    num = 1    
    PI = 3.141592653    
    print(f'{num:>8}')          # 右对齐    
    print(f'{num:0>8}')         # 0填充    
    print(f'{PI:.2f}')          # 保留两位小数    
    print(f'{PI:8.2f}')         # 总宽8    
    print(f'{1234567890:,}')    # 千分位    
         

个人建议:新代码统一用 f-string,老项目用 % 或 format 也不奇怪,至少你得能看懂。

 

4. 字符串的常用方法(别死记,多用就熟了)

我把最常用的整理成表格,再附上几个容易混淆的示例:

方法

作用

replace(old, new[, count])

替换子串,返回新字符串

strip([chars]) / lstrip / rstrip

移除两端(左/右)指定字符,默认空白

center(width[, fill]) / ljust / rjust

居中/左/右对齐,填充字符

partition(sep) / rpartition

按分隔符拆分,返回三元组(包含分隔符本身)

startswith(prefix[, start[, end]]) / endswith

检查前缀/后缀

isalnum() / isalpha() / isdigit() / isspace()

判断字符类别

split(sep=None, maxsplit=-1) / rsplit

分割成列表,默认按空白,丢弃空串

count(sub[, start[, end]])

统计子串出现次数(非重叠)

find(sub[, start[, end]]) / rfind

查找索引,找不到返回 -1

index(sub[, start[, end]]) / rindex

同 find,但找不到会抛异常

 

演示几个容易踩坑的点:

         
    s = "Line1-Li ne2-Line4"    
    # replace    
    print(s.replace("Li", "b"))          # 全部替换    
    print(s.replace("Li", "b", 2))       # 只替换前2个    
         
    # strip 是移除字符集合中的任意组合,不是移除整个子串    
    str3 = 'www.example.com'    
    print(str3.strip("mecow."))          # 'xampl'(移除两端的任意 m/e/c/o/w/.)    
         
    # partition 一定返回三个元素,很适合拆固定格式    
    print("hello world".partition("l"))  # ('he', 'l', 'lo world')    
    print("hello world".rpartition("l")) # ('hello wor', 'l', 'd')    
         
    # split 默认按空白,忽略空串    
    s = "Line1- abcdef \nLine2- abc \nLine4- abcd"    
    print(s.split())   # ['Line1-', 'abcdef', 'Line2-', 'abc', 'Line4-', 'abcd']    
    print(s.split(" "))  # 按单个空格分割,可能包含空串    
         

 

 

四、列表(List)

列表是可变序列,你可以随时增删改,它基于动态数组实现,自动管理容量。用方括号 [] 定义。

 

1. 列表的构造与修改

         
    # 构造    
    list0 = []    
    list1 = ['china', 1997, 2000]    
    list2 = list("hello")          # ['h','e','l','l','o']    
    list3 = list({1:2, 3:4})       # [1, 3](取字典的键)    
         
    # 修改(索引和切片赋值)    
    li = ["h", "e", "l", "l", "o", "l", "l", "牛", "3"]    
    li[4] = "-"                    # 改单个元素    
    li[0:4] = ["H", "E", "L", "L"] # 切片替换,长度可以不同    
    print(li)                      # ['H','E','L','L','-','l','l','牛','3']    
         

 

注意:列表的切片赋值是“变长”的,你甚至可以用空列表 [] 来删除一段切片,或者用更长的列表来插入。

 

2. 列表的常用方法(增删改查排)

 

方法

说明

append(x)

末尾添加一个元素

extend(iterable)

末尾添加可迭代对象中的每个元素

insert(i, x)

在索引 i 处插入

pop([i])

删除并返回索引 i 处的元素,默认最后一个

remove(x)

删除第一个匹配项,无返回值

index(x[, start[, end]])

返回第一个匹配的索引,找不到抛异常

count(x)

统计 x 出现次数

sort(key=None, reverse=False)

原地排序

reverse()

原地反转

copy()

浅拷贝

clear()

清空

 

演示一下容易混淆的 `append` 和 `extend`:

         
    li = [1, 2]    
    li.append([3, 4])   # [1, 2, [3, 4]](把列表当整体添加)    
    li.extend([5, 6])   # [1, 2, [3, 4], 5, 6](展开添加)    
         

 

排序和反转的example:

         
    num_list = [1, -2, 5, -3]    
    num_list.sort()                 # 升序 [-3,-2,1,5]    
    num_list.sort(reverse=True)     # 降序 [5,1,-2,-3]    
    num_list.sort(key=abs)          # 按绝对值排序 [1,-2,-3,5](注意原数据顺序)    
         
    # reverse 和 reversed 的区别    
    li = [1, 3, 5, 2]    
    li.reverse()           # 原地反转,无返回值    
    print(li)              # [2,5,3,1]    
         
    # reversed 返回反向迭代器,不改变原数据    
    seq = "helloworld"    
    it = reversed(seq)    
    print(list(it))        # ['d','l','r','o','w','o','l','l','e','h']    
         

 

3. sort 与 sorted 的区别

  • list.sort() 是列表的方法,原地修改,返回 None。  
  • sorted(iterable, key=None, reverse=False) 是内置函数,返回新列表,不修改原数据,适用于任何可迭代对象。
         
    tup = (1, -2, 5, -3)    
    new_list = sorted(tup, key=abs)  # [1, -2, -3, 5] 原元组不变    
         

 

4. 浅拷贝(copy)的陷阱

list.copy() 和 list[:] 都是浅拷贝——只复制外层引用,内部嵌套的可变对象仍然共享。

         
    original = [[1, 2], 3]    
    copied = original.copy()    
    copied[0].append(99)   # 修改内部列表,original 也会变    
    copied[1] = 4          # 重新赋值,不影响 original    
    print(original)        # [[1, 2, 99], 3]    
         

如果完全独立,需要使用 copy.deepcopy()(从 copy 模块导入)。

 

 

五、元组(Tuple)

元组是不可变序列,用圆括号 () 定义,但逗号是核心

         
    t1 = ()          # 空元组    
    t2 = (1,)        # 单元素元组,逗号不能少    
    t3 = (1)         # 这是整数!    
    t4 = 1, 2, 3     # 不加括号也是元组(俗称“元组打包”)    
         

因为不可变,元组的方法很少(只有 count() 和 index()),但它占用内存小、创建快,还能作为字典的键(因为可哈希)。不过要记住:如果元组内部包含可变元素,那个元素本身还是可变的,只是元组的引用不变。

 

 

六、字典(Dictionary)

字典是基于哈希表实现的,查找速度 O(1)。它是可变映射,键必须是不可变类型(可哈希)。

 

1. 创建字典的六种姿势

         
    # ① 直接 {}    
    a = {'姓名': '张三', '年龄': 28}    
         
    # ② 空字典,然后赋值    
    a = {}    
    a['姓名'] = '张三'    
         
    # ③ 关键字参数(键名必须符合标识符规则)    
    a = dict(姓名="张三", 年龄=28)    
         
    # ④ 可迭代对象(列表/元组/集合)包含键值对    
    a = dict([("姓名", "张三"), ("年龄", 28)])    
         
    # ⑤ zip 打包    
    a = dict(zip(["姓名", "年龄"], ["张三", 28]))    
         
    # ⑥ fromkeys 类方法(批量初始化,值默认 None)    
    dic1 = dict.fromkeys(("name", "age", "sex"))    
    dic2 = dict.fromkeys(("name", "age", "sex"), "I don't know!")    
         

 

2. 访问与修改

         
    d1 = {"身高": 175, "体重": 65}    
    print(d1["身高"])          # 175,键不存在会抛 KeyError    
    d1["身高"] = "1米75"       # 修改    
    d1["名字"] = "张三"        # 新增    
         

 

安全取值用 `get()`,还可以设置默认值:

         
    print(d1.get("体重"))       # 65    
    print(d1.get("体", "不存在")) # "不存在"    
         

 

3. 视图对象(动态变化)

keys()values()items() 返回视图,会实时反映字典的修改。

         
    d = {'a': 1, 'b': 2}    
    view = d.keys()    
    print(list(view))      # ['a', 'b']    
    d['c'] = 3    
    print(list(view))      # ['a', 'b', 'c'](动态更新)    
         

 

4. 常用字典方法

 

方法

说明

get(key[, default])

安全取值

update([other])

合并更新,覆盖相同的键

pop(key[, default])

删除并返回,不存在可返回默认或抛异常

popitem()

删除并返回最后一个键值对(Python 3.7+ 有序)

setdefault(key[, default])

若存在返回其值,否则插入 key:default

copy()

浅拷贝

clear()

清空

 

`setdefault` 的妙用(常用于计数):

         
    counts = {}    
    for char in "abracadabra":    
        counts[char] = counts.setdefault(char, 0) + 1    
    print(counts)  # {'a':5, 'b':2, 'r':2, 'c':1, 'd':1}    
         

 不过更推荐 collections.Counter

 

 

七、集合(Set)—— 去重与关系运算的利器

集合是可变、无序、不重复的容器,用花括号 {} 或 set() 定义(空集合必须用 set(),因为 {} 是空字典)。元素必须是不可变类型。

 

1. 基本操作

         
    # 去重    
    li = [1, 2, 4, 5, 7, 7, 4, 5]    
    s = set(li)        # {1,2,4,5,7}    
         
    # 集合运算    
    a = set("abdefga")    
    b = set("abc")    
    c = set("aef")    
    print(c <= a)      # True(判断子集)    
    print(a | b)       # 并集    
    print(a & b)       # 交集    
    print(a - b)       # 差集    
    print(a ^ b)       # 对称差    
         

 

2. 方法一览(分两大类)

① 所有 set 和 frozenset 都支持的方法(返回新集合)

 

方法

运算符版本

说明

union(*others)

|

并集

intersection(*others)

&

交集

difference(*others)

-

差集

symmetric_difference(other)

^

对称差

issubset(other)

<=

子集判断

issuperset(other)

>=

超集判断

isdisjoint(other)

无交集则 True

 

② 仅 set 对象可用的原地修改方法

 

方法

说明

update(*others)

添加所有元素

intersection_update(*others)

只保留交集

difference_update(*others)

移除所有 others 中的元素

symmetric_difference_update(other)

更新为对称差

add(elem)

添加元素

remove(elem)

删除,不存在抛 KeyError

discard(elem)

删除,不存在也不报错

pop()

弹出任意一个元素

clear()

清空

 

注意 `frozenset`:它是不可变的集合,可以作为普通集合的元素或字典的键。

 

         
    fset = frozenset([1,2,3])    
    set1 = {"four"}    
    set1.add(fset)  # 合法,因为 fset 可哈希    
    print(set1)     # {'four', frozenset({1,2,3})}    
         

 

 

八、序列的索引与切片

字符串、列表、元组都是序列,它们共享一套强大的索引和切片语法。

 

1. 索引(Indexing):正着数、倒着数

  • 正向索引从 0 到 len-1  
  • 负向索引从 -1 到 -len-1 永远指向最后一个元素)
         
    s = "Hello 1牛3 Python"    
    print(s[0])        # 'H'    
    print(s[-1])       # 'n'    
    print(s[6])        # '1'(空格也算一个字符)    
    print(s[-11])      # ' '(注意空格)    
         

 

2. 切片(Slicing):[start:stop:step]

  • 包含 start,不包含 stop(左闭右开)  
  • 默认 start=0stop=lenstep=1  
  • 步长为负时从右往左取
         
    s = "Hello 1牛3 Python"    
    print(s[0:2])          # 'He'    
    print(s[:2])           # 'He'    
    print(s[1:])           # 从索引1到末尾    
    print(s[:])            # 完整复制    
    print(s[-11:-9])       # ' 1'    
    print(s[2:6])          # 'llo '    
    print(s[1:10:2])       # 'el 牛'(步长2)    
    print(s[::-1])         # 反转字符串    
         

 

3. 一个重要区别:索引会降维,切片不降维

对列表而言,索引得到的是该位置的元素本身(可能是个整数、字符串甚至另一个列表),而切片得到的是新的列表(即使只取一个元素,它也是列表)。

 

         
    li = [123, "e", "l", "l", "o"]    
    print(li[0])        # 123(int)    
    print(li[:1])       # [123](list)    
         

这个特性在嵌套数据结构中尤其需要注意。

 

 

九、补充神器:len() 与 del

  • len(obj) 返回长度,O(1) 时间(容器内部维护了大小)。  
  • del 删除变量或序列中的元素,本质是解除引用,当引用计数归零时,内存会被回收。
         
    a = [1, 2, 3]    
    del a[0]        # 删除第一个元素    
    del a[1:3]      # 删除切片    
    del a[:]        # 清空列表    
    del a           # 删除变量本身    
         

 

 

收尾

到这里,我们已经把 Python 的六大标准数据类型以及索引切片的边边角角都梳理了一遍。从数字到集合,从不可变到可变,从索引到切片——这些内容会在你日后的每一行代码里反复出现。初学阶段不要怕记不住,多用、多查、多调试,自然就刻在脑子里了。如果非要给个建议:字符串、列表、字典 是日常使用频率最高的三巨头,把它们的方法玩熟,你就已经能解决80% 的问题了。

 

下图为本文知识点的思维导图(示意):

 

感谢阅读,祝你编码愉快!有任何疑问,随时欢迎来聊。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐