数据类型

单位换算

  • 最小的单位bit,表示一个二进制的0或1,一般使用小写的b表示
  • 存储的最小单位字节(Byte),1B = 8b
  • 1024B = 1KB
  • 1024KB = 1MB
  • 1024MB = 1GB
  • 1024GB = 1TB
  • 1024TB = 1PB
  • 2^32 B = 2^10 * 2^10 * 2^10 * 2^2 B = 4 GiB
  • 严格说 1024 进制应写作 KiB / MiB / GiB,厂商按 1000 进制时才叫 KB / MB,所以同一块硬盘两边算出来的容量对不上

进制转换

  • 十进制

    • 基数0-9,逢10进1
    • 示例:123 = 1 * 10^2 + 2 * 10^1 + 3 * 10^0 = 100 + 20 + 3 = 123
  • 二进制

    • 基数0和1,逢2进1,Python 中以 0b 开头(数字 0 + 字母 b,不是字母 o)
    • 示例:0b110100 = 2^5 + 2^4 + 2^2 = 52
    • 十进制转换二进制:除2取余,倒序书写
      • 22 = 0b10110
  • 八进制

    • 基数0-7,逢8进1,Python 中以 0o 开头(数字 0 + 字母 o)
    • 示例:0o123 = 1* 8^2 + 2 * 8^1+ 3 * 8^0 = 64 + 16 + 3 = 83
    • 八进制转换二进制:八进制1位表示3位二进制
      • 0o123 = 0b 001 010 011
  • 十六进制

    • 基数0-9、A-F,逢16进1,Python 中以 0x 开头
    • 示例:0xAB = 10 * 16^1 + 11 * 16^0 = 160 + 11 = 171
    • 十六进制转换二进制:十六进制1位表示4位二进制
      • 0xABC = 0b 1010 1011 1100
  • 计算机中的数据是以哪种进制存储的?为什么?

    • 二进制,因为计算机只识别二进制,具体原因如下:
      • 稳定性高(只有0和1)
      • 成本低(技术上容易实现)
      • 与生活中的真假逻辑相吻合
  • 计算机中的数据是如何存储的?

    • 如何存储负数?
      • 最高位为符号位,0表示正数,1表示负数
      • 这样表示负数很直观,但代价是最高位不能再参与数值,而且不能直接做加减:得先判断符号再决定是加是减,硬件反而更复杂
      • 示例:(1 + 1) (1 - 1)
        1
        2
        3
        0000 0001                  0000 0001
        0000 0001 1000 0001
        0000 0010 1000 0010 = -2
      • 上面的例子说明:把符号位当成普通数位一起算,1 - 1 会算成 -2,这正是需要反码、补码的原因
    • 原码、反码、补码?
      • 正数的三码一致,只有负数才有反码和补码
      • 反码:原码符号位不变,其余位取反
      • 补码:原码的反码加1
      • 整数在内存中一律以补码形式存储:浮点数不是补码,它按 IEEE 754 的「符号位 + 指数 + 尾数」存放;文本按字符编码(如 UTF-8)存放。所以别说成「所有数据都是补码」
    • 示例:
      1
      2
      3
      4
      5
      6
      7
      原码:1000 0001
      反码:1111 1110
      补码:1111 1111
      (1 - 1)
      0000 0001
      1111 1111
      0000 0000 = 0

数据类型

  • 简介

    • 数据类型是为了处理不同的运算而存在的
    • Python中的数据类型有:整数、浮点数、字符串、布尔值、列表、元组、集合、字典、空值
    • 另外还有 complex(复数)、bytes / bytearray(字节序列)、range、memoryview 等;需要十进制精确运算时用标准库的 decimal.Decimal、fractions.Fraction
  • 整数(int)

    • 在 Python 中,整数(int)是一种基本的数据类型,用于表示整数值(正整数和负整数)。整数在 Python 中没有固定的大小限制,可以表示任意大或小的整数。
    • 对于很大的数,例如 10000000000 ,很难数清楚 0 的个数。Python 允许在数字中间以 _ 分隔,因此,写成10_000_000_000 和 10000000000 是完全一样的。
    • 整数相关函数与方法:abs()(绝对值)、divmod()(同时取商和余数)、pow()(幂)是内置函数,不是 int 对象的方法(hasattr(3, 'abs') 为 False)。int 自己提供的是 bit_length()(二进制位数,(255).bit_length() 得 8)、to_bytes() 与 int.from_bytes()(与字节互转)、as_integer_ratio()。
    • 示例
      1
      2
      3
      4
      # 整数
      a = 10
      # 获取变量的类型
      print(type(a))
  • 浮点数(float)

    • 在Python中,浮点数(float)是一种数据类型,用于表示带有小数点的数值。它是二进制的近似值(IEEE 754 双精度,约 15~17 位有效数字),恰恰不适合精度要求高的计算——涉及金额、税率这类要用 decimal.Decimal。
    • 浮点数由整数部分与小数部分组成,之所以称为浮点数,是因为按照科学记数法表示时,一个浮点数的小数点位置是可变的,比如,1.23×10^9 和 12.3×10^8 是完全相等的。
    • 浮点数可以用数学写法,如1.23,3.14,-9.01,等等。但是对于很大或很小的浮点数,就必须用科学计数法表示,把10用e替代,1.23x10^9就是1.23e9,或者12.3e8,0.000012可以写成1.2e-5,等等。
    • 整数和浮点数在计算机内部存储的方式不同:整数的 +、-、*、//、% 永远是精确的(// 向负无穷取整,-7 // 2 得 -4),但 / 的结果是浮点数,1 / 3 得 0.3333333333333333,已经带上了舍入误差;浮点数运算普遍存在精度问题,0.1 + 0.2 的结果是 0.30000000000000004。
    • 浮点数方法:
      • float 真正的对象方法是 is_integer()(是否恰好是整数值)、hex() 与 float.fromhex()(十六进制精确表示)、as_integer_ratio()。
      • abs()、round() 是内置函数。
      • 注意 round() 用的是银行家舍入(四舍六入五成双):round(0.5) 得 0,round(1.5) 和 round(2.5) 都得 2。
      • 比较浮点数建议用 math.isclose() 而不是 ==。
    • 示例
      1
      2
      3
      4
      5
      6
      7
      # 小数(浮点数)
      b = 3.14
      print(type(b))

      # 科学计数法
      c = 3.14e-3
      print(c)
  • 布尔值(bool)

    • 在Python中,布尔值(bool)是一种数据类型,用于表示真(True)和假(False)两个逻辑值。布尔值通常用于控制程序的流程和执行条件判断。
    • 创建布尔值:可以直接使用关键字True和False来创建布尔值对象,例如:x = True、y = False。
    • 布尔运算:布尔值支持逻辑运算操作,包括逻辑与(and)、逻辑或(or)和逻辑非(not)等。例如:result = True and False、result = True or False。
    • 比较运算:布尔值可以通过比较运算符进行比较操作,例如相等比较(==)、不等比较(!=)、大于(>)、小于(<)、大于等于(>=)和小于等于(<=)等。比较运算的结果是布尔值。例如:result = 5 > 3、result = "hello" == "world"。
    • 布尔转换:可以使用bool()函数将其他类型的数据转换为布尔值。在布尔上下文中,一些值被视为假(False),如 0、0.0、空字符串、空列表、空字典、空元组、空集合、None、range(0),以及自定义类里 __bool__ / __len__ 返回 False / 0 的对象;其余被视为真(True)。另外 bool 是 int 的子类,False == 0、True == 1 都成立,True + 1 得 2
    • 布尔操作的短路求值:在逻辑运算中,如果根据前面的条件已经可以确定整个表达式的结果,Python会进行短路求值。例如,在逻辑与运算中,如果第一个条件为假(False),则整个表达式的结果必定为假(False),后续条件不会被计算。还有一点容易忽略:and / or 返回的是参与运算的那个值而不是布尔,True and 5 得 5、0 or 'x' 得 'x',所以 x = x or default 可以当默认值写法用。
    • 示例
      1
      2
      3
      # bool类型,只有两个值,True、False
      d = False
      print(type(d))
  • 空值(NoneType)

    • 在Python中,空值(None)是一种特殊的数据类型,用于表示空或缺失的值。空值通常用于表示变量尚未被赋予具体的值或函数没有返回任何有效结果的情况。
    • None不能理解为0,因为0是有意义的,而None是一个特殊的空值。
    • 创建空值:可以使用关键字None来创建空值对象。例如:x = None。
    • 空值的特性:空值是一个特殊的对象,它不代表任何具体的值。它不等于任何其他的对象,包括空字符串、零和空容器(如空列表、空字典等)。
    • 变量赋值:可以将空值赋给变量,表示该变量当前没有具体的值。例如:x = None。
    • 函数返回值:在函数中,可以使用return语句返回空值,表示函数没有返回任何有效结果。例如:
      1
      2
      def my_function():
      return None
    • 空值的判断:判断是否为空值要用身份运算符 is,写成 if x is None:。None 是全局唯一的那个对象,is 比较的是身份,而 == 允许对方自定义相等逻辑,所以官方风格一律用 is None / is not None。另外 None 和数字比较大小会抛 TypeError。
    • 条件判断:空值在条件判断中被视为假(False),因此可以在条件语句中使用空值来判断某个变量是否有值。例如:
      1
      2
      if x is None:
      print("x is None")
    • 示例
      1
      2
      3
      # 空值
      e = None
      print(type(e))
  • 字符串(str)

    • 在Python中,字符串(string)是一种表示文本数据的数据类型。字符串由一系列字符组成,可以包含字母、数字、符号和空格等。
    • 创建字符串:可以使用单引号(')或双引号(")将文本括起来创建字符串。例如:
      1
      2
      s1 = 'Hello, World!'
      s2 = "Python is awesome!"
    • 多行字符串:如果字符串需要跨越多行,可以使用三引号(‘’')或三双引号(“”")来创建多行字符串。例如:
      1
      2
      s3 = '''This is a multi-line
      string in Python.'''
    • 字符串操作:可以对字符串进行多种操作,包括拼接、切片、长度获取等。
      • 字符串拼接:可以使用加号(+)将两个字符串连接起来。例如:s4 = s1 + s2。
        1
        2
        3
        4
        5
        6
        7
        # 直接拼接(注意不会自动加空格)
        greeting = 'hello' + 'world'
        print(greeting) # helloworld

        # 指定的字符串重复若干次,然后拼在一起
        repeated = 'abc' * 3
        print(repeated) # abcabcabc
      • 切片操作:可以使用索引和切片操作符([])截取字符串的部分内容,遵循左闭右开原则。例如:s5 = s1[7:12]可以获取字符串中的子串。
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        s5 = 'abcdefg'
        # s[起始下标:结束下标],包括起始下标元素,不包括结束下标元素
        print(s5[0:3])
        # 从开头提取到指定位置
        print(s5[:4])
        # 从指定下标提取到结尾
        print(s5[3:])
        # 从指定位置提取到倒数第一个,不包括倒数第一个
        print(s5[3:-1])
        # 提取最后四个字符
        print(s5[-4:])
        # 提取全部元素
        print(s5[:])
        # 指定步进值,默认为一
        print(s5[::2])
        # 字符串逆序
        print(s5[::-1])

        # 提取单个字符
        s4 = '123456'
        # 从开头提取,下标从0开始
        print(s4[0])
        # 从末尾提取,下标从-1开始
        print(s4[-1])
      • 字符串长度:可以使用len()函数获取字符串的长度,按码点计数(码点就是字符在 Unicode 字符表里的编号,一个汉字、一个英文字母都各算 1 个码点)。例如:length = len(s1)。
        1
        2
        3
        # 按码点计数:中英文都各算 1;组合 emoji 会被算成多个(一家三口 = 3 个表情码点 + 2 个零宽连接符,len() 得 5)
        s = 'hello你好'
        print(len(s))
    • 字符串格式化:可以使用字符串的format()方法或者使用 f-string(格式化字符串字面值)来格式化字符串,还支持使用百分号(%)进行字符串格式化。例如:
      1
      2
      3
      4
      5
      6
      name = "Alice"
      age = 25

      s6 = "My name is {} and I'm {} years old.".format(name, age)
      s7 = f"My name is {name} and I'm {age} years old."
      s8 = "My name is %s and I'm %d years old." % (name, age)
      % 格式化符号(老式写法,Python 3.6 起优先用 f-string 或 format()):
      符 号 描述
      %c 格式化字符及其ASCII码
      %s 格式化字符串
      %d 格式化整数
      %u 与 %d 等价,Python 3 中无独立含义
      %o 格式化无符号八进制数
      %x 格式化无符号十六进制数
      %X 格式化无符号十六进制数(大写)
      %f 格式化浮点数字,可指定小数点后的精度
      %e 用科学计数法格式化浮点数
      %E 作用同%e,用科学计数法格式化浮点数
      %g 自动在 %f / %e 中选更短的,去掉多余0
      %G 同 %g,配合 %E 使用
      %p Python 不支持(那是 C 的 printf),实测抛 ValueError
    • 性能提示:字符串不可变,+= 循环拼接每次都生成新对象、整体是 O(n²),批量拼接应该用 ''.join(parts)。
    • 字符串方法:字符串对象有许多内置方法,可以对字符串进行各种操作,如查找子串、替换、大小写转换等。下表已按 Python 3 校对,标注「内置函数」的那几项不是方法。
      方法 描述
      capitalize() 将字符串的第一个字符转换为大写
      center(width, fillchar) 返回一个指定的宽度 width 居中的字符串,fillchar 为填充的字符,默认为空格。
      count(sub, start=0, end=len(string)) 返回 sub 出现的次数,可用 start / end 限定范围(参数名是 start,不是 beg)
      bytes.decode(encoding=“utf-8”, errors=“strict”) Python3 中没有 decode 方法,但我们可以使用 bytes 对象的 decode() 方法来解码给定的 bytes 对象,这个 bytes 对象可以由 str.encode() 来编码返回。
      encode(encoding=‘UTF-8’,errors=‘strict’) 以 encoding 指定的编码格式编码字符串,如果出错默认报一个ValueError 的异常,除非 errors 指定的是’ignore’或者’replace’
      endswith(suffix, beg=0, end=len(string)) 检查字符串是否以 suffix 结束,如果 beg 或者 end 指定则检查指定的范围内是否以 suffix 结束,如果是,返回 True,否则返回 False。
      expandtabs(tabsize=8) 把字符串 string 中的 tab 符号转为空格,tab 符号默认的空格数是 8 。
      find(str, beg=0, end=len(string)) 检测 str 是否包含在字符串中,如果指定范围 beg 和 end ,则检查是否包含在指定范围内,如果包含返回开始的索引值,否则返回-1
      index(str, beg=0, end=len(string)) 跟find()方法一样,只不过如果str不在字符串中会报一个异常。
      isalnum() 如果字符串至少有一个字符并且所有字符都是字母或数字则返 回 True,否则返回 False
      isalpha() 如果字符串至少有一个字符并且所有字符都是字母或中文字则返回 True, 否则返回 False
      isdigit() 如果字符串只包含数字则返回 True 否则返回 False…
      islower() 如果字符串中包含至少一个区分大小写的字符,并且所有这些(区分大小写的)字符都是小写,则返回 True,否则返回 False
      isnumeric() 如果字符串中只包含数字字符,则返回 True,否则返回 False
      isspace() 如果字符串中只包含空白,则返回 True,否则返回 False.
      istitle() 如果字符串是标题化的(见 title())则返回 True,否则返回 False
      isupper() 如果字符串中包含至少一个区分大小写的字符,并且所有这些(区分大小写的)字符都是大写,则返回 True,否则返回 False
      join(seq) 以指定字符串作为分隔符,将 seq 中所有的元素(的字符串表示)合并为一个新的字符串
      len(s)(内置函数) 返回字符串长度(按码点计数)
      ljust(width[, fillchar]) 返回一个原字符串左对齐,并使用 fillchar 填充至长度 width 的新字符串,fillchar 默认为空格。
      lower() 转换字符串中所有大写字符为小写.
      lstrip() 截掉字符串左边的空格或指定字符。
      maketrans() 创建字符映射的转换表,对于接受两个参数的最简单的调用方式,第一个参数是字符串,表示需要转换的字符,第二个参数也是字符串表示转换的目标。
      max(s)(内置函数) 返回字符串中码点最大的字符
      min(s)(内置函数) 返回字符串中码点最小的字符
      replace(old, new [, max]) 把 将字符串中的 old 替换成 new,如果 max 指定,则替换不超过 max 次。
      rfind(str, beg=0,end=len(string)) 类似于 find()函数,不过是从右边开始查找.
      rindex( str, beg=0, end=len(string)) 类似于 index(),不过是从右边开始.
      rjust(width[, fillchar]) 返回一个原字符串右对齐,并使用fillchar(默认空格)填充至长度 width 的新字符串
      rstrip() 删除字符串末尾的空格或指定字符。
      split(sep=None, maxsplit=-1) 按 sep 切分返回列表;sep 省略时按任意空白切分并忽略空串,maxsplit 限制切分次数(Python 3 没有 num 参数)
      splitlines([keepends]) 按照行(‘\r’, ‘\r\n’, \n’)分隔,返回一个包含各行作为元素的列表,如果参数 keepends 为 False,不包含换行符,如果为 True,则保留换行符。
      startswith(substr, beg=0,end=len(string)) 检查字符串是否是以指定子字符串 substr 开头,是则返回 True,否则返回 False。
      strip([chars]) 在字符串上执行 lstrip()和 rstrip()
      swapcase() 将字符串中大写转换为小写,小写转换为大写
      title() 返回"标题化"的字符串,就是说所有单词都是以大写开始,其余字母均为小写(见 istitle())
      translate(table) 按 maketrans() 生成的映射转换字符;Python 3 已删除 deletechars 参数,要删字符就把映射值设成 None
      upper() 转换字符串中的小写字母为大写
      zfill (width) 返回长度为 width 的字符串,原字符串右对齐,前面填充0
      isdecimal() 检查字符串是否只包含十进制字符,如果是返回 true,否则返回 false。
  • 列表(list)

    • 在Python中,列表(List)是一种有序、可变的数据类型,用于存储多个元素。列表可以包含不同类型的元素,如整数、浮点数、字符串等。
    • 创建列表:可以使用方括号 [] 来创建一个空列表,或者在方括号中用逗号分隔的元素来初始化列表。例如:
      1
      2
      3
      empty_list = []
      numbers = [1, 2, 3, 4, 5]
      fruits = ['apple', 'banana', 'orange']
    • 访问列表元素:可以使用索引来访问列表中的元素。列表的索引从0开始,可以使用正向索引和反向索引。当索引超出了范围时,Python会报一个IndexError错误。例如:
      1
      2
      3
      4
      5
      lt = ['小芳', '小乔', '小王', '小杜', '小韩']

      # 提取元素
      print(lt[0])
      print(lt[-1])
    • 修改列表元素:列表是可变的,可以通过索引来修改列表中的元素。
      1
      2
      # 将列表中索引为1的元素修改为'grape'
      fruits[1] = 'grape'
    • 列表操作:可以对列表进行多种操作,包括添加元素、删除元素、切片、长度获取等。
      • 添加元素:可以使用append()方法在列表末尾添加一个元素,或使用insert()方法在指定位置插入元素。例如:
        1
        2
        fruits.append('pear')
        fruits.insert(1, 'kiwi')
      • 删除元素:可以使用del语句或remove()方法删除列表中的元素。例如:
        1
        2
        del fruits[0]          # 去掉 'apple'
        fruits.remove('kiwi') # 按值删除第一个匹配项;值不存在会抛 ValueError
      • 切片操作:可以使用切片操作符([])截取列表的部分内容。例如:
        1
        2
        3
        4
        5
        6
        7
        8
        # 获取列表中索引从1到3的元素
        sliced_list = numbers[1:4]

        # 清空列表
        lt[:] = []

        # 删除前两个元素
        lt[:2] = []
      • 列表长度:可以使用len()函数获取列表的长度。例如:
        1
        length = len(numbers)
      • 列表拼接(+)和重复(*)
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        # 列表可以使用加号 + 进行拼接操作,将两个列表合并为一个新的列表
        list1 = [1, 2, 3]
        list2 = [4, 5, 6]
        result = list1 + list2
        print(result) # 输出 [1, 2, 3, 4, 5, 6]

        # 列表还可以使用乘号 * 进行重复操作,将列表中的元素重复多次
        list1 = [1, 2, 3]
        result = list1 * 3
        print(result) # 输出 [1, 2, 3, 1, 2, 3, 1, 2, 3]

        需要注意的是,拼接和重复操作都会生成一个新的列表,原始列表本身不会被修改。

      • 列表推导式:由可迭代对象(能被 for 一个个取出来的东西,如列表、元组、字符串、range、字典)一行生成列表,比 for + append 更简洁也更快。
        1
        2
        3
        squares = [x * x for x in range(5)]                   # [0, 1, 4, 9, 16]
        evens = [x for x in range(10) if x % 2 == 0] # [0, 2, 4, 6, 8]
        pairs = [(x, y) for x in range(2) for y in range(2)] # 多层 for,从左往右读,[(0, 0), (0, 1), (1, 0), (1, 1)]
      • 底层与性能:
        • 列表是动态数组(存的是元素引用的指针数组),append() 均摊 O(1),按下标访问 O(1)。
        • insert(0, x)、pop(0)、del lt[0] 要整体搬移是 O(n),两端频繁增删该用 collections.deque。
        • x in lt 是 O(n) 线性扫描,频繁查找请改用集合或字典。
    • 列表方法:列表对象有许多内置方法,可以对列表进行各种操作,如排序、反转、查找元素等。
      方法 描述
      list.append(obj) 在列表末尾添加新的对象
      list.count(obj) 统计某个元素在列表中出现的次数
      list.extend(seq) 在列表末尾一次性追加另一个序列中的多个值(用新列表扩展原来的列表)
      list.index(obj) 从列表中找出某个值第一个匹配项的索引位置
      list.insert(index, obj) 将对象插入列表
      list.pop([index=-1]) 移除列表中的一个元素(默认最后一个元素),并且返回该元素的值
      list.remove(obj) 移除列表中某个值的第一个匹配项
      list.reverse() 反向列表中元素
      list.sort( key=None, reverse=False) 对原列表进行排序
      list.clear() 清空列表
      list.copy() 复制列表
  • 元组(tuple)

    • 在Python中,元组(Tuple)是一种有序、不可变的数据类型。元组可以存储多个元素,可以是不同的数据类型,例如整数、浮点数、字符串等。元组的特点是一旦创建后,其元素和结构不能被修改,是不可变的。
    • 元组元素之间用逗号 , 分隔,逗号才是元组的语法标志,小括号只是可选装饰:t = 1, 2 与 t = (1, 2) 等价。只有一个元素时必须写逗号 t = (123,),否则 (123) 只是括号表达式、得到的是 int。示例:
      1
      2
      my_tuple = (1, 2, 3, 'apple', 'banana')
      t = (123,)
    • 可以通过索引来访问元组中的元素,索引从0开始。例如:
      1
      2
      # 表示访问元组中的第一个元素,结果为1
      my_tuple[0]
    • 元组支持切片操作,可以使用切片来获取元组的子集。例如:
      1
      2
      # 表示获取元组中索引为1和2的元素,结果为 (2, 3)。
      my_tuple[1:3]
    • 元组还可以进行拼接和重复操作。拼接可以使用加号 +。重复操作可以使用乘号 *,示例:
      1
      2
      3
      4
      5
      6
      7
      my_tuple = (1, 2, 3, 'apple', 'banana')

      # 拼接
      new_tuple = my_tuple + (4, 5)
      print(new_tuple) # (1, 2, 3, 'apple', 'banana', 4, 5)
      # 重复
      print(my_tuple * 2) # (1, 2, 3, 'apple', 'banana', 1, 2, 3, 'apple', 'banana')
    • 元组的优点是不可变性,因此可以作为字典的键或集合的元素——但真正的要求是可哈希,只有当元组内所有元素都可哈希时才行:hash((1, 2, [3])) 会抛 TypeError: unhashable type: 'list'。元组也常用于存放不希望被修改的数据,以及一行完成多值交换 a, b = b, a。
    • 需要注意的是,虽然元组本身是不可变的,但如果元组中包含可变对象(例如列表),那么这些可变对象可以被修改。因此,元组的不可变性是指元组本身的结构和元素,而不是元组中的可变对象。
  • 集合(set)

    • 在Python中,集合(Set)是一种无序且不重复的数据类型。集合中的元素是唯一的,不会重复出现。集合可以用于去除重复元素、判断元素的存在性以及进行集合运算,如交集、并集、差集等。
    • 集合使用大括号 {} 或者 set() 函数来创建,元素之间使用逗号 , 分隔。注意: 创建一个空集合必须用 set() 而不是 {},因为 {} 是用来创建一个空字典。
      1
      2
      3
      4
      # 创建非空集合
      my_set = {1, 2, 3, 4, 5}
      # 创建空集合
      empty_set = set()
    • 可以使用 set() 函数将其他可迭代对象(如列表、元组、字符串等)转换为集合。例如:
      1
      2
      my_list = [1, 2, 3, 3, 4, 4, 5]
      my_set = set(my_list)
    • 类似列表推导式,同样集合支持集合推导式(Set comprehension)
      1
      2
      3
      >>> a = {x for x in 'abracadabra' if x not in 'abc'}
      >>> a
      {'r', 'd'}
    • 集合操作:
      • 添加元素:使用 add() 方法向集合中添加单个元素,使用 update() 方法向集合中添加多个元素
        1
        2
        3
        4
        # 添加单个元素
        my_set.add(4)
        # 添加多个元素
        my_set.update([4, 5, 6])
      • 删除元素:使用 remove() 方法删除指定的元素,如果元素不存在会引发 KeyError 异常。使用 discard() 方法删除指定的元素,如果元素不存在不会引发异常。使用 pop() 取出并返回集合中的一个元素,取哪个由哈希表内部布局决定,不保证与插入顺序一致(不是真随机,同一个集合可复现),所以别依赖它。
        1
        2
        3
        4
        5
        6
        # 删除指定的元素,如果元素不存在会引发 KeyError 异常
        my_set.remove(4)
        # 删除指定的元素,如果元素不存在不会引发异常
        my_set.discard(4)
        # 随机删除并返回集合中的一个元素
        my_set.pop()
      • 清空集合:用 clear() 方法清空集合中的所有元素
        1
        2
        # 清空集合
        my_set.clear()
    • 集合运算:
      • 交集:使用 intersection() 方法或 & 运算符,例如:set1.intersection(set2) 或 set1 & set2。
      • 并集:使用 union() 方法或 | 运算符,例如:set1.union(set2) 或 set1 | set2。
      • 差集:使用 difference() 方法或 - 运算符,例如:set1.difference(set2) 或 set1 - set2。
      • 对称差集:使用 symmetric_difference() 方法或 ^ 运算符,例如:set1.symmetric_difference(set2) 或 set1 ^ set2。
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        set1 = {1, 2, 3}
        set2 = {2, 3, 4}

        # 交集:集合 set1 和 set2 中都包含了的元素
        intersection = set1 & set2
        # 并集:集合 set1 和 set2 中包含的所有元素
        union = set1 | set2
        # 差集:集合 set1 中包含而集合 set2 中不包含的元素
        difference = set1 - set2
        # 对称差集:两个集合中不重复的元素的集合
        symmetric_difference = set1 ^ set2

        print(intersection) # 输出 {2, 3}
        print(union) # 输出 {1, 2, 3, 4}
        print(difference) # 输出 {1}
        print(symmetric_difference) # 输出 {1, 4}
    • 底层与性能:集合是哈希表,in、add、remove 平均 O(1),所以「判断是否存在 / 去重」优先想到集合,而不是列表的 O(n);代价是元素必须可哈希(列表、字典不能进集合),且不保证顺序(去重后原顺序会丢)。不可变版本是 frozenset,它可以当字典的键、也能放进另一个集合。
    • 集合方法:
      方法 描述
      add() 为集合添加元素
      clear() 移除集合中的所有元素
      copy() 拷贝一个集合
      difference() 返回多个集合的差集
      difference_update() 移除集合中的元素,该元素在指定的集合也存在。
      discard() 删除集合中指定的元素
      intersection() 返回集合的交集
      intersection_update() 原地保留与其他集合的交集,修改原集合、返回 None,不是「返回交集」
      isdisjoint() 判断两个集合是否包含相同的元素,如果没有返回 True,否则返回 False。
      issubset() 判断指定集合是否为该方法参数集合的子集。
      issuperset() 判断该方法的参数集合是否为指定集合的子集
      pop() 随机移除元素
      remove() 移除指定元素
      symmetric_difference() 返回两个集合中不重复的元素集合。
      symmetric_difference_update() 移除当前集合中在另外一个指定集合相同的元素,并将另外一个指定集合中不同的元素插入到当前集合中。
      union() 返回两个集合的并集
      update() 给集合添加元素
      len(s)(内置函数) 计算集合元素个数
  • 字典(dict)

    • Python 字典(Dictionary)是一种可变、可迭代的数据结构,用于存储键值对,每个键值对由一个键(key)和一个对应的值(value)组成。
    • 注意: 从 Python 3.7 开始,字典按 插入顺序 迭代由语言规范保证(3.6 里也能看到有序,但那是 CPython 的实现细节;3.5 及以前确实是无序的)。
    • 在字典中,键和值之间用冒号 : 分隔,每个键值对之间用逗号 , 分隔。键必须是不可变的数据类型,如字符串、数字或元组,而值可以是任意类型的数据,包括字符串、数字、列表、字典等。
    • 创建字典:
      • 使用花括号 {} 和冒号 : 来定义键值对,多个键值对之间用逗号 , 分隔。例如:
        1
        my_dict = {'key1': 'value1', 'key2': 'value2', 'key3': 'value3'}
      • 使用 dict() 函数,将键值对作为参数传递给函数。例如:
        1
        my_dict = dict(key1='value1', key2='value2', key3='value3')
      • 通过将其他可迭代对象(如列表或元组)转换为字典。例如:
        1
        my_dict = dict([('key1', 'value1'), ('key2', 'value2'), ('key3', 'value3')])
      • 创建空字典
        1
        2
        # 使用大括号 {} 来创建空字典
        empty_dict = {}
    • 访问字典元素:
      • 使用索引操作符 [] 通过键访问对应的值,键不存在时会报错,例如:
        1
        print(my_dict['key1'])  # 输出:value1
      • 使用 dict.get(key, default) 方法获取指定键的值,如果键不存在,则返回默认值。例如:
        1
        print(my_dict.get('key4', 'default_value'))  # 输出:default_value
    • 添加或修改字典元素:
      • 使用索引操作符 [] 来添加或修改键值对。例如:
        1
        2
        3
        my_dict = {'key1': 'value1', 'key2': 'value2'}
        my_dict['key3'] = 'value3' # 添加键值对(没有则添加键值对)
        my_dict['key2'] = 'new_value' # 修改值(已存在则修改)
      • 使用 dict.update(other_dict) 方法将其他字典中的键值对更新到当前字典中。例如:
        1
        2
        3
        my_dict = {'key1': 'value1', 'key2': 'value2'}
        other_dict = {'key3': 'value3', 'key4': 'value4'}
        my_dict.update(other_dict) # 更新字典
    • 删除字典元素:
      • 使用 del 关键字删除指定键的键值对。例如:
        1
        2
        my_dict = {'key1': 'value1', 'key2': 'value2', 'key3': 'value3'}
        del my_dict['key2'] # 删除键值对
      • 使用 dict.pop(key) 方法删除并返回指定键的值。例如:
        1
        2
        my_dict = {'key1': 'value1', 'key2': 'value2', 'key3': 'value3'}
        value = my_dict.pop('key2') # 删除并返回值
    • 遍历字典:
      • 使用 for 循环遍历字典的键。例如:
        1
        2
        3
        my_dict = {'key1': 'value1', 'key2': 'value2', 'key3': 'value3'}
        for key in my_dict: # 或:for key in my_dict.keys():
        print(key) # 输出:key1, key2, key3
      • 使用 for 循环遍历字典的值。例如:
        1
        2
        3
        my_dict = {'key1': 'value1', 'key2': 'value2', 'key3': 'value3'}
        for value in my_dict.values():
        print(value) # 输出:value1, value2, value3
      • 使用 for 循环遍历字典的键值对。例如:
        1
        2
        3
        my_dict = {'key1': 'value1', 'key2': 'value2', 'key3': 'value3'}
        for key, value in my_dict.items():
        print(key, value) # 输出:key1 value1, key2 value2, key3 value3
    • 字典的特性:
      • 有序性:Python 3.7 起迭代顺序就是插入顺序;popitem() 也因此弹出最后插入的那一对。删除再插入同一个键,它会排到最后。
      • 可变性:字典中的元素可以被修改、添加和删除。
      • 键的唯一性:字典中的键是唯一的,不允许重复。
      • 可迭代性:可以通过循环遍历字典中的键或值。
      • 动态性:字典的大小和内容可以动态地改变。
    • 字典推导式:
      1
      2
      {k: len(k) for k in ['a', 'bb', 'ccc']}      # {'a': 1, 'bb': 2, 'ccc': 3}
      {v: k for k, v in {'a': 1, 'b': 2}.items()} # 键值互换:{1: 'a', 2: 'b'}
    • 底层与性能:字典是哈希表,d[k]、k in d、赋值平均 O(1);键必须可哈希(不可变只是它通常满足的条件),所以列表、字典、集合不能当键,而只含可哈希元素的元组可以。计数用 collections.Counter,分组/避免 KeyError 用 collections.defaultdict,合并字典在 3.9+ 可以直接 d1 | d2。
    • 字典方法
      方法 描述
      len(dict) 返回字典中键值对的数量
      dict.clear() 删除字典内所有元素
      dict.copy() 返回一个字典的浅复制
      dict.fromkeys() 创建一个新字典,以序列seq中元素做字典的键,val为字典所有键对应的初始值。坑:val 是可变对象(如 [])时所有键共享同一个对象,改一个全变
      dict.get(key, default=None) 返回指定键的值,如果键不在字典中返回 default 设置的默认值
      key in dict 如果键在字典dict里返回true,否则返回false
      dict.items() 返回一个包含字典所有键值对的视图对象(视图 = 跟着字典实时变化的只读投影,不是拷贝;它支持集合运算但不能用下标取) ,每个键值对以元组形式表示
      dict.keys() 返回一个包含字典所有键的视图对象
      dict.setdefault(key, default=None) 和get()类似, 但如果键不存在于字典中,将会添加键并将值设为default
      dict.update(dict2) 把字典dict2的键/值对更新到dict里
      dict.values() 返回一个包含字典所有值的视图对象
      pop(key[,default]) 删除字典 key(键)所对应的值,返回被删除的值
      popitem() 返回并删除字典中的最后一对键和值
  • 视图对象

    • 说明视图对象(View Object)是Python中一种特殊的对象类型,它提供了一种动态查看数据结构内容的方式。
    • 视图对象(View Object)的含义:
      1. 动态视图:视图对象不是静态的数据副本,而是对原始数据结构的动态引用。当原始数据发生变化时,视图对象会自动反映这些变化。
      2. 内存效率:视图对象不创建新的数据副本,而是提供对原始数据的直接访问,这样可以节省内存空间。
      3. 只读特性:大多数视图对象是只读的,你不能直接修改视图对象,但可以通过修改原始数据结构来影响视图。
      4. 可迭代:视图对象可以被迭代,例如用在for循环中。
    • 代码示例
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      # 创建一个字典
      d = {'a': 1, 'b': 2, 'c': 3}

      # 获取视图对象
      keys_view = d.keys() # 键的视图
      values_view = d.values() # 值的视图
      items_view = d.items() # 键值对的视图

      print("初始状态:")
      print(f"Keys: {list(keys_view)}")
      print(f"Values: {list(values_view)}")
      print(f"Items: {list(items_view)}")

      # 修改原始字典
      d['d'] = 4

      print("\n添加元素后:")
      print(f"Keys: {list(keys_view)}") # 视图自动更新
      print(f"Values: {list(values_view)}") # 视图自动更新
      print(f"Items: {list(items_view)}") # 视图自动更新


      """
      运行结果
      初始状态:
      Keys: ['a', 'b', 'c']
      Values: [1, 2, 3]
      Items: [('a', 1), ('b', 2), ('c', 3)]

      添加元素后:
      Keys: ['a', 'b', 'c', 'd']
      Values: [1, 2, 3, 4]
      Items: [('a', 1), ('b', 2), ('c', 3), ('d', 4)]
      """
  • 可变与不可变

    • 可变(创建后内容能就地改):list、dict、set、bytearray,以及大多数自定义类的实例。
    • 不可变(一改就是新对象):int、float、bool、complex、str、bytes、tuple、frozenset、None。
    • 为什么要分清楚:
      • 能不能当键:字典的键和集合的元素必须可哈希(hash() 有值且在其生命周期内不变)。可变对象默认不可哈希,所以列表、字典、集合不能当键;元组只有在元素全部可哈希时才行。
      • 函数传参的副作用:把可变对象传进函数,函数内部改了就真的改了(见下一节「获取变量的地址」的示例);不可变对象「修改」后是新对象,外面看不到。
      • 能不能共享:小整数、形状像标识符的字符串会被解释器缓存复用,前提就是它们不可变。
    • 清空列表的两种写法,差别在对象身份:
      1
      2
      3
      4
      5
      6
      lt = [1, 2, 3]
      print(id(lt))
      lt[:] = [] # 原地清空:id 不变,指向它的其他引用也看到空列表
      print(id(lt))

      lt = [] # 重新绑定:id 变了,原来的引用仍指向旧列表
    • 浅拷贝与深拷贝:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      import copy

      a = [[1, 2], 3]
      b = a.copy() # 浅拷贝:只复制最外层,b[0] 和 a[0] 还是同一个列表
      c = copy.deepcopy(a) # 深拷贝:逐层复制

      b[0].append(99)
      print(a) # [[1, 2, 99], 3] —— 浅拷贝被「穿透」了
      print(c) # [[1, 2], 3]
    • 用乘法造嵌套列表会让内层共享同一个对象:
      1
      2
      3
      grid = [[0] * 3] * 3
      grid[0][0] = 1
      print(grid) # [[1, 0, 0], [1, 0, 0], [1, 0, 0]],三行是同一个列表
      正确写法是每行独立生成:[[0] * 3 for _ in range(3)]。
  • 强制类型转换

    • 概述

      强制类型转换是将一个数据类型的值转换为另一个数据类型的值的过程。Python提供了内置函数来进行各种类型的转换。

    1. int() - 转换为整数类型

      1
      2
      3
      4
      5
      6
      7
      8
      # 将浮点数转换为整数(截断小数部分)
      a = int(3.14) # 结果为 3

      # 将字符串转换为整数
      b = int("123") # 结果为 123

      # 将其他进制数转换为十进制整数
      c = int("1010", 2) # 将二进制"1010"转换为十进制,结果为 10
    2. float() - 转换为浮点数类型

      1
      2
      3
      4
      5
      # 将整数转换为浮点数
      a = float(10) # 结果为 10.0

      # 将字符串转换为浮点数
      b = float("3.14") # 结果为 3.14
    3. str() - 转换为字符串类型

      1
      2
      3
      # 将数字转换为字符串
      a = str(123) # 结果为 "123"
      b = str(3.14) # 结果为 "3.14"
    4. list() - 转换为列表类型

      1
      2
      3
      4
      5
      6
      7
      8
      # 将元组转换为列表
      a = list((1, 2, 3)) # 结果为 [1, 2, 3]

      # 将字符串转换为列表(每个字符成为列表的一个元素)
      b = list("hello") # 结果为 ['h', 'e', 'l', 'l', 'o']

      # 将字典转换为列表(只包含键)
      c = list({'a': 1, 'b': 2}) # 结果为 ['a', 'b']
    5. tuple() - 转换为元组类型

      1
      2
      3
      4
      5
      # 将列表转换为元组
      a = tuple([1, 2, 3]) # 结果为 (1, 2, 3)

      # 将字符串转换为元组
      b = tuple("hello") # 结果为 ('h', 'e', 'l', 'l', 'o')
    6. set() - 转换为集合类型

      1
      2
      3
      4
      5
      # 将列表转换为集合(自动去重)
      a = set([1, 2, 2, 3, 3, 4]) # 结果为 {1, 2, 3, 4}

      # 将字符串转换为集合(每个字符成为集合的一个元素)
      b = set("hello") # 结果为 {'h', 'e', 'l', 'o'}
    7. dict() - 转换为字典类型

      1
      2
      3
      4
      5
      # 将键值对列表转换为字典
      a = dict([('name', 'Alice'), ('age', 25)]) # 结果为 {'name': 'Alice', 'age': 25}

      # 使用关键字参数创建字典
      b = dict(name='Bob', age=30) # 结果为 {'name': 'Bob', 'age': 30}
    • 注意事项

      • 类型兼容性:不是所有类型之间都可以相互转换。例如,字符串"abc"不能转换为整数,会抛出ValueError异常。
      • 数据丢失:某些转换可能会导致数据丢失,如将浮点数转换为整数时会截断小数部分。
      • 强类型:Python 不会在数字和字符串之间自动转换,1 + 'a' 直接抛 TypeError;所谓隐式转换只发生在很窄的场景——int 与 float 混合运算时结果提升为 float、bool 参与算术(它是 int 的子类)。
    • 实际应用

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      # 列表去重:列表 => 集合 => 列表
      original_list = [1, 2, 2, 3, 3, 4, 4, 5]
      unique_list = list(set(original_list))
      print(unique_list) # 输出:[1, 2, 3, 4, 5](顺序可能不同)

      # 数值计算前确保类型正确
      user_input = "123"
      number = int(user_input) # 将字符串转换为整数才能进行数学运算
      result = number + 10
      print(result) # 输出:133
  • 获取变量的地址

    • 说明

      Python中的"获取变量的地址"指的是获取变量在内存中的存储位置。在Python中,每个对象在内存中都有一个唯一的标识符,我们可以通过内置函数 id() 来获取这个标识符。

    • id() 函数

      id() 函数返回对象的"身份标识",在 CPython 解释器中,这个身份标识就是对象在内存中的地址。

    • 基本用法

      1
      2
      3
      4
      5
      6
      7
      8
      a = 10
      print(id(a)) # 输出类似: 140712816230432 (具体数值可能不同)

      b = "hello"
      print(id(b)) # 输出类似: 2220386890352

      my_list = [1, 2, 3]
      print(id(my_list)) # 输出类似: 2220386891456
    • 理解对象身份和可变性

      • 不可变对象(如数字、字符串、元组)

        对于不可变对象,当你"修改"它们时,实际上是创建了新的对象:

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        # 整数是不可变对象
        a = 10
        print(id(a)) # 输出地址1

        a = 20
        print(id(a)) # 输出地址2(与地址1不同)

        # 字符串是不可变对象
        s = "hello"
        print(id(s)) # 输出地址1

        s = s + " world"
        print(id(s)) # 输出地址2(与地址1不同)
      • 可变对象(如列表、字典、集合)

        对于可变对象,你可以修改它们的内容而不会改变对象的身份:

        1
        2
        3
        4
        5
        6
        7
        8
        9
        # 列表是可变对象
        my_list = [1, 2, 3]
        print(id(my_list)) # 输出地址1

        my_list.append(4)
        print(id(my_list)) # 输出地址1(与上面相同)

        my_list[0] = 10
        print(id(my_list)) # 输出地址1(仍然相同)
    • 对象引用和身份比较

      使用 id() 可以帮助我们理解对象引用的概念:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      # 两个变量指向同一个对象
      a = [1, 2, 3]
      b = a
      print(id(a)) # 输出地址
      print(id(b)) # 输出相同地址
      print(id(a) == id(b)) # True

      # 修改一个会影响另一个
      a.append(4)
      print(b) # 输出: [1, 2, 3, 4]

      # 创建两个相同内容的不同对象
      c = [1, 2, 3]
      d = [1, 2, 3]
      print(id(c)) # 输出地址1
      print(id(d)) # 输出地址2(与地址1不同)
      print(c == d) # True(内容相同)
      print(id(c) == id(d)) # False(不同的对象)
    • 小整数和字符串的缓存机制

      Python对小整数(-5到256)和某些字符串有缓存机制:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      # 小整数被缓存
      a = 100
      b = 100
      print(id(a) == id(b)) # True

      # 大整数不被缓存
      c = 1000
      d = 1000
      print(id(c) == id(d)) # 可能是False(取决于实现)

      # 短字符串可能被缓存
      s1 = "hello"
      s2 = "hello"
      print(id(s1) == id(s2)) # True
    • 实际应用

      1. 调试和理解程序行为

        1
        2
        3
        4
        5
        6
        7
        8
        9
        def modify_list(lst):
        print("函数内修改前的地址:", id(lst))
        lst.append(4)
        print("函数内修改后的地址:", id(lst))

        my_list = [1, 2, 3]
        print("函数外的地址:", id(my_list))
        modify_list(my_list)
        print("修改后的列表:", my_list)
      2. 检查两个变量是否指向同一个对象

        1
        2
        3
        4
        5
        6
        a = [1, 2, 3]
        b = a
        c = [1, 2, 3]

        print(a is b) # True (等同于 id(a) == id(b))
        print(a is c) # False (虽然内容相同,但不是同一个对象)
    • 注意事项

      1. 地址不等于值:值相同的对象可以有不同地址(c = [1, 2, 3] 与 d = [1, 2, 3]);两个对象同时存在时地址相同,才说明它们是同一个对象(值自然相同)。但 CPython 会复用已释放对象的地址,所以对临时对象比 id()(id(f()) == id(g()))可能得出假相等——判断同一性要在两个变量都存活时用 is。
      2. 实现相关:具体的内存地址值依赖于Python的实现和运行时环境,不应该在程序逻辑中依赖这些具体数值。
      3. 性能考虑:频繁调用 id() 函数通常不是性能瓶颈,但在性能敏感的代码中应避免不必要的调用。
本文结束 感谢您的阅读
正在加载今日诗词....