当前位置: 首页 > news >正文

学习日志22 python

1 Python元组的定义方式

在 Python 中,元组(tuple)是一种不可变的序列类型,用于存储多个元素。元组的定义方式有以下几种:

1. 使用逗号分隔元素(最基本方式)

元组可以直接通过逗号分隔值来定义,括号不是必需的,但建议加上以提高可读性。

python

运行

# 定义元组(括号可选)
t1 = 1, 2, 3       # 无括号的元组
t2 = (1, 2, 3)     # 带括号的元组(推荐写法)# 单元素元组必须加逗号
t3 = (1,)          # 正确:单元素元组
t4 = 1,            # 等价写法(无括号)
t5 = (1)           # 错误:这是整数,不是元组!# 空元组
empty = ()

2. 使用内置函数 tuple()

  • tuple() 可以将其他可迭代对象(如列表、字符串、集合等)转换为元组。

python

运行

# 从列表转换
t_list = tuple([1, 2, 3])    # 结果:(1, 2, 3)# 从字符串转换
t_str = tuple("hello")       # 结果:('h', 'e', 'l', 'l', 'o')# 空元组
empty = tuple()              # 等价于 ()

3. 元组解包(Tuple Unpacking)

元组可以用于同时赋值多个变量,称为 “解包”。

python

运行

# 解包赋值
a, b, c = (1, 2, 3)          # a=1, b=2, c=3
x, y = (1, 2)                # x=1, y=2# 交换变量值(无需临时变量)
a, b = b, a                  # 交换 a 和 b 的值

4. 嵌套元组

元组的元素可以是其他元组,形成嵌套结构。

python

运行

nested = (1, (2, 3), (4, (5, 6)))
print(nested[1][0])          # 输出:2(访问嵌套元素)

5. 特殊语法:元组作为函数参数或返回值

函数可以返回多个值,本质上是返回一个元组。

python

运行

def get_name_and_age():return "Alice", 30       # 返回元组 ("Alice", 30)name, age = get_name_and_age()  # 解包返回值

注意事项

  • 单元素元组必须加逗号(1,) 是元组,(1) 是整数。
  • 元组不可变:定义后无法修改元素(但元素内部的可变对象可以修改,如列表)。
  • 括号的歧义(1 + 2) * 3 是表达式,(1, 2) * 3 是元组重复。

示例代码

python

运行

# 各种元组定义方式
t1 = 1, 2, 3                # 无括号元组
t2 = (4, 5, 6)              # 带括号元组
t3 = ("a",)                 # 单元素元组
t4 = tuple(range(3))        # 从 range 生成元组
t5 = 1, "hello", [3, 4]     # 混合类型元组# 访问元组元素
print(t5[1])                # 输出:hello# 元组不可变(修改会报错)
# t2[0] = 10  # 错误:TypeError

元组的不可变性使其适合存储不可变数据(如配置参数、坐标点等),或作为字典的键(列表等可变对象不可作为键)。

2 在Python中,(1)这种写法表示的是一个整数,而不是元组。

在Python中,(1)这种写法表示的是一个整数,而不是元组。

虽然使用了圆括号,但要定义一个只包含单个元素的元组,必须在元素后面加上逗号,即(1,)的形式。 

在 Python 里,圆括号既能够用来表示元组,也可以用于表达式分组。所以,当圆括号中只有一个元素时,Python 会把它解读成表达式分组,最终得到的结果就是这个元素本身。

下面通过代码来展示这一特性:

python

运行

a = (1)
b = (1,)
c = 1,  # 定义元组时,括号不是必需的print(type(a))  # 输出:<class 'int'>
print(type(b))  # 输出:<class 'tuple'>
print(type(c))  # 输出:<class 'tuple'>

由此可见:

  • 若想定义只含单个元素的元组,正确的写法是在元素后面加上逗号,像 (1,) 这样。
  • 其实,定义元组时括号并不是必不可少的,例如 1, 也能创建一个元组。不过,为了代码的可读性,通常还是会加上括号。 【元组可以直接通过逗号分隔值来定义,括号不是必需的,但建议加上以提高可读性。】

3 "IndexError" 错误

"IndexError" 错误是在尝试访问序列(如列表、元组、字符串)中不存在的索引位置时触发的,并非因为数据结构不支持索引。具体解释如下:

1. 什么情况下会触发 IndexError

当你使用超出序列有效范围的索引时,Python 会抛出 IndexError

python

运行

my_list = [10, 20, 30]  # 有效索引:0, 1, 2# 错误:索引 3 超出范围
print(my_list[3])  # 报错:IndexError: list index out of range# 错误:负索引超出范围
print(my_list[-4])  # 报错:IndexError

2. 哪些数据结构支持索引?哪些会报 IndexError

数据结构支持索引可能触发 IndexError 的场景
列表 (list)索引超出范围(如 my_list[100]
元组 (tuple)索引超出范围(如 my_tuple[5]
字符串 (str)索引超出范围(如 my_str[10]
字典 (dict)不支持索引,但可通过键访问(如 my_dict["key"]
集合 (set)完全不支持索引或键访问

3. 不支持索引的结构会报什么错?

如果尝试对不支持索引的数据结构使用索引语法,会触发 TypeError,而非 IndexError

python

运行

my_dict = {"name": "Alice"}
my_set = {1, 2, 3}# 错误:字典不支持索引
print(my_dict[0])  # 报错:TypeError: 'dict' object is not subscriptable# 错误:集合不支持索引
print(my_set[0])   # 报错:TypeError: 'set' object is not subscriptable

4. 如何避免 IndexError

  • 检查索引范围:确保索引在 0 到 len(seq)-1 之间,或使用负索引(如 -1 表示最后一个元素)。
  • 使用安全访问方法

    python

    运行

    my_list = [1, 2, 3]# 安全访问(避免 IndexError)
    if len(my_list) > 3:print(my_list[3])# 或使用 try-except 捕获错误
    try:print(my_list[3])
    except IndexError:print("索引超出范围")
    

总结

  • IndexError:在支持索引的数据结构(列表、元组、字符串)中使用无效索引时触发。
  • TypeError:对不支持索引的数据结构(字典、集合)使用索引语法时触发。

4字典(dict)和集合(set)不支持通过索引访问元素

这里是IndexError,不是TypeError的原因!

题目

下面代码执行后的结果是(      )
#!/usr/bin/python3
demo_list = ['hello']
print(demo_list[2])A 输出'hello'
B 输出'e'
C 输出'l'
D 报"IndexError"错误正确答案:D

你的代码中的错误确实会导致 IndexError,而不是 TypeError。让我解释一下原因:

关键点分析:

  1. 代码中的 demo_list 是一个列表(list),而不是字典(dict)。列表是支持索引访问的,但仅限于有效索引范围(本例中只有 0)。
  2. 索引超出范围demo_list[2] 试图访问第 3 个元素,但列表中只有 1 个元素(索引 0),因此触发 IndexError
  3. 字典和集合才会报 TypeError:如果 demo_list 是字典或集合,使用索引访问会直接报错 TypeError(如 my_dict[0] 或 my_set[0])。但你的代码是列表,因此不适用。

正确答案:

D. 报 "IndexError" 错误

代码解释:

python

运行

demo_list = ['hello']  # 创建包含1个元素的列表
print(demo_list[2])    # 访问索引2(超出范围,有效索引只有0)
# 报错:IndexError: list index out of range

对比示例:

python

运行

# 1. 列表(支持索引,但超出范围报 IndexError)
my_list = ['a']
print(my_list[1])  # IndexError# 2. 字典(不支持索引,报 TypeError)
my_dict = {'key': 'value'}
print(my_dict[0])  # TypeError: 'dict' object is not subscriptable# 3. 集合(不支持索引,报 TypeError)
my_set = {1, 2}
print(my_set[0])   # TypeError: 'set' object is not subscriptable

总结:

  • IndexError:索引超出有效范围(列表、元组、字符串等支持索引的结构)。
  • TypeError:使用索引访问不支持索引的数据结构(如字典、集合)。

你的代码属于前者,因此选 D

5 字典、集合、列表、元组有关“索引访问元素”

在 Python 中,字典(dict)和集合(set)不支持通过索引访问元素,因为它们是无序的数据结构(3.7+ 版本的字典会保持插入顺序,但仍不支持索引)。下面详细解释:

1. 字典(Dictionary)

字典使用 ** 键(key)** 而非索引来访问值。键必须是唯一的不可变类型(如字符串、数字、元组)。

python

运行

my_dict = {"name": "Alice", "age": 30}# 正确:通过键访问值
print(my_dict["name"])  # 输出:Alice# 错误:不能通过索引访问
# print(my_dict[0])     # 报错:KeyError

2. 集合(Set)

集合是无序且元素唯一的数据结构,不支持任何形式的索引或切片

python

运行

my_set = {1, 2, 3}# 错误:不能通过索引访问
# print(my_set[0])      # 报错:TypeError# 正确:遍历集合
for element in my_set:print(element)      # 输出:1 2 3(顺序不确定)

3. 为什么不支持索引?

  • 字典键值对的存储顺序不固定(Python 3.7+ 会保持插入顺序,但仍不支持索引)。
  • 集合元素无序且无重复,索引无意义。

4. 替代方案

  • 字典:通过键访问,或用 list(my_dict.keys())[0] 将键转为列表后索引(不推荐,效率低)。
  • 集合:转为列表后索引,但集合本身无序,结果可能不稳定。

python

运行

# 字典转列表后索引(不推荐)
keys = list(my_dict.keys())
print(keys[0])  # 输出第一个键:"name"(3.7+ 按插入顺序)# 集合转列表后索引(结果不确定)
elements = list(my_set)
print(elements[0])  # 可能输出 1、2 或 3

总结

数据结构是否支持索引访问方式
列表通过索引(如 list[0]
元组通过索引(如 tuple[0]
字典通过键(如 dict["key"]
集合无索引,只能遍历或判断存在

6 __len__方法的调用 

题目

根据以下程序,在对lis对象相关方法的调用中,调用方式错误的是()
class List:def __init__(self):self.list = [1,2,3]def __len__(self):return len(self.list)
lis = List() A lis.__len__()B __len__(lis)C len(lis)D lis.len()正确答案:BD你的答案:BCD

题目分析

题目给出了一个自定义类List,该类包含了__init____len__两个方法。需要判断对lis对象的四种方法调用方式中,哪些是错误的。

各选项正误判断

  1. 选项 A:lis.len()
    此调用方式是正确的。在 Python 里,特殊方法虽然一般是隐式调用,但也能够显式地直接调用。
  2. 选项 B:len(lis)
    这种调用方式是错误的。__len__作为一个特殊方法,是供 Python 解释器内部使用的,不能像普通函数那样直接调用。
  3. 选项 C:len (lis)
    该调用方式是正确的。当使用len()函数时,Python 解释器会去调用对象的__len__方法,所以这属于隐式调用特殊方法
  4. 选项 D:lis.len ()
    这种调用方式是错误的。在类的定义中,只定义了__len__方法,并没有定义len方法,所以这样的调用会引发AttributeError

错误原因剖析

  • 选项 B:由于__len__是特殊方法,必须通过len()函数或者对象实例来调用,直接调用__len__(lis)是不符合 Python 语法规则的。
  • 选项 D:因为类中没有定义len方法,所以调用lis.len()会出现属性错误。

总结

综上所述,选项 B 和选项 D 的调用方式是错误的,所以正确答案是 BD。

7 需要补充的知识

1. 特殊方法(Magic Methods)与运算符重载

特殊方法(以双下划线 __ 开头和结尾)是 Python 的核心特性,用于实现内置行为(如 len()+[] 等)。需要掌握:

  • 隐式调用len(obj) 会自动调用 obj.__len__()
  • 常见特殊方法__init____str____add____getitem__ 等。
  • 不要直接调用特殊方法:应使用对应的内置函数或运算符。

python

运行

class MyList:def __init__(self, data):self.data = datadef __len__(self):return len(self.data)my_list = MyList([1, 2, 3])
print(len(my_list))  # 正确:隐式调用 __len__
print(my_list.__len__())  # 不推荐:显式调用特殊方法

2. Python 内置函数与方法的区别

区分内置函数(如 len()str())和对象方法(如 list.append()):

  • 内置函数:通过对象作为参数调用(如 len(obj))。
  • 对象方法:通过对象直接调用(如 obj.method())。

python

运行

# 内置函数 vs 方法
my_list = [1, 2, 3]
print(len(my_list))     # 内置函数
print(my_list.append(4))  # 方法

3. 类的定义与实例化

理解类的属性和方法如何通过实例调用:

  • 实例方法:第一个参数是 self,只能通过实例调用。
  • 特殊方法:由 Python 解释器自动调用,无需手动调用。

python

运行

class MyClass:def normal_method(self):  # 实例方法return "Hello"obj = MyClass()
obj.normal_method()  # 正确
MyClass.normal_method()  # 错误(缺少实例)

4. 错误类型辨析

区分常见的错误类型:

  • TypeError:类型不支持操作(如 'abc' + 1)。
  • AttributeError:访问不存在的属性 / 方法(如 obj.unknown_method())。
  • IndexError:索引超出范围(如 my_list[100])。
  • SyntaxError:语法错误(如 if x = 1:)。

5. 鸭子类型(Duck Typing)

Python 中,只要对象实现了特定方法,就可以使用对应的操作(如实现 __len__ 即可用 len())。这是 Python 动态特性的核心。

python

运行

class Duck:def quack(self):print("Quack!")class Person:def quack(self):print("I'm mimicking a duck!")def make_quack(obj):obj.quack()  # 只要对象有 quack 方法即可调用make_quack(Duck())  # 输出:Quack!
make_quack(Person())  # 输出:I'm mimicking a duck!

学习建议

  1. 阅读官方文档

    • Python 数据模型(特殊方法)
    • 内置函数
  2. 练习代码

    • 自定义类并实现特殊方法(如 __add____eq__)。
    • 编写函数处理不同类型的对象(鸭子类型实践)。
  3. 调试错误

    • 故意触发不同类型的错误,观察错误信息。
    • 使用 try-except 捕获和处理错误。

通过这些知识的补充,你将能更清晰地理解 Python 的面向对象编程和错误处理机制。

http://www.lryc.cn/news/605119.html

相关文章:

  • CUDA编程9 - 卷积实践
  • Python - 元类
  • 离散扩散模型在数独问题上的复现与应用
  • RAG工作流程总览
  • 解析非法获取计算机信息系统数据罪中的其他技术手段
  • 《超级秘密文件夹》密码遗忘?试用版/正式版找回教程(附界面操作步骤)
  • IATF 16949详解(腾讯混元)
  • Oracle11g数据库迁移达梦8数据库方案
  • 论文阅读|CVPR 2025|Mamba进一步研究|GroupMamba
  • 领域驱动设计(DDD)在分布式系统中的架构实践
  • cpp实现音频重采样8k->16k及16k->8k
  • 不同环境安装配置redis
  • 网络端口号全景解析:从基础服务到特殊应用的完整指南
  • 代码随想录算法训练营第三十六天
  • 【git】GitHub 的专用代理地址
  • day21-Excel文件解析
  • uvm-tlm-port-export-imp
  • 在VS2022中调试ASP.NET项目时修改DLL或ASPX动态页面的原理及实现方法
  • STM32CubeIDE新建项目过程记录备忘(二) GPIO输出demo:LED闪烁
  • 2025 IT专业人才培养趋势与职业发展指南:技术+数据复合型能力的构建路径
  • 【Kubernetes 指南】基础入门——Kubernetes 201(一)
  • OpenEuler 安装 apache + php8 不解析php文件的处理
  • 微信小程序中实现页面跳转的方法
  • Python奇幻之旅:从零开始的编程冒险
  • cpp-httplib 线程安全
  • mybatis中的极易出现错误用法
  • Chroma安装教程
  • uni-app webview的message监听不生效(uni.postmessage is not a function)
  • 明智运用C++异常规范(Exception Specifications)
  • 监测预警系统:让园区更高效、更安全、更智能