学习日志41 python
1 __getitem__
方法
def __getitem__(self,pos):return range(0,30,10)[pos]
#这一段是什么意思?
这段代码定义了一个类的__getitem__
方法,这是 Python 中的一个特殊方法,用于支持类的实例像列表、元组等可迭代对象一样通过索引(或切片)来访问元素。
具体来说:
range(0, 30, 10)
创建了一个范围对象,包含的值是0, 10, 20
(从 0 开始,到 30 为止但不包含 30,步长为 10)[pos]
表示使用传入的pos
作为索引(或切片)来获取这个范围对象中的元素- 整个表达式的结果会作为
__getitem__
方法的返回值
例如,如果这个类的实例是obj
:
obj[0]
会返回0
(获取 range 的第 0 个元素)obj[1]
会返回10
(获取 range 的第 1 个元素)obj[2]
会返回20
(获取 range 的第 2 个元素)obj[0:2]
会返回range(0, 20, 10)
(获取切片)
这个方法使得该类的实例可以像列表一样通过索引来访问预定义的这三个值(0、10、20)。
打印实际递增的索引
class FOO():def __init__(self):passdef __getitem__(self, pos):return range(0,30,10)[pos]
foo = FOO()for i in foo :print(i)#我能不能把pos打印出来啊
可以的,你可以在__getitem__
方法中打印pos
的值,这样就能看到迭代过程中实际使用的索引了。当你用for
循环迭代对象时,Python 会自动调用__getitem__
方法并传入从 0 开始的递增索引,直到触发IndexError
为止。
修改后的代码如下:
python
运行
class FOO():def __init__(self):passdef __getitem__(self, pos):# 打印当前的pos值print(f"当前的pos是: {pos}")try:return range(0,30,10)[pos]except IndexError:# 当索引超出范围时,抛出IndexError终止迭代raisefoo = FOO()for i in foo:print(f"获取到的值: {i}\n")
运行这段代码会输出:
plaintext
当前的pos是: 0
获取到的值: 0当前的pos是: 1
获取到的值: 10当前的pos是: 2
获取到的值: 20当前的pos是: 3
可以看到,for
循环迭代时会依次传入pos=0,1,2,3
,当pos=3
时,range(0,30,10)[3]
会触发IndexError
,循环循环就会终止。
2 enumerate()函数的输出格式
代码
data = ['周一', '周二', '周三', '周四']
for i,j in enumerate(data):print(i,j)
输出
0 周一
1 周二
2 周三
3 周四
enumerate()
函数用于将一个可迭代对象(如列表、元组、字符串等)组合为一个索引序列,同时返回索引和对应的元素。
它的输出格式是包含元组的可迭代对象,每个元组由两个元素组成:
- 第一个元素:从指定起始值开始的整数索引(默认从 0 开始)
- 第二个元素:可迭代对象中对应的元素
示例代码:
python
运行
# 基本用法(默认索引从0开始)
fruits = ['apple', 'banana', 'cherry']
for item in enumerate(fruits):print(item)# 输出:
# (0, 'apple')
# (1, 'banana')
# (2, 'cherry')# 指定起始索引(从1开始)
for item in enumerate(fruits, start=1):print(item)# 输出:
# (1, 'apple')
# (2, 'banana')
# (3, 'cherry')# 通常会解构元组直接获取索引和值
for index, value in enumerate(fruits):print(f"索引: {index}, 值: {value}")
简单来说,enumerate()
相当于为可迭代对象的每个元素添加了一个编号,方便在循环中同时获取位置和内容。
3 解释 Python 类方法和静态方法(@classmethod和@staticmethod)
代码
class Person:@classmethoddef eat(self): print("吃饭")@staticmethoddef speak():print("说话")def run(self):print("走路")
测试
class Person:@classmethoddef eat(cls):print("吃饭")@staticmethoddef speak():print("说话")def run(self):print("走路")Person.speak()
Person.eat()
Person.run(Person())
Person.eat(Person())
输出
说话
吃饭
走路
Traceback (most recent call last):File "我的文件路径哈哈哈", line 16, in <module>Person.eat(Person())~~~~~~~~~~^^^^^^^^^^
TypeError: Person.eat() takes 1 positional argument but 2 were given
在 Python 中,@classmethod
和 @staticmethod
都是用于定义类方法的装饰器,但它们的作用和使用场景有所不同:
@classmethod(类方法)
- 第一个参数必须是类本身(通常命名为
cls
,而不是self
) - 可以访问和修改类的状态,能调用其他类方法
- 可以通过类名直接调用,也可以通过实例调用
- 常用于定义工厂方法,或者需要访问类属性的方法
你代码中的
@classmethod
使用有个小问题,通常第一个参数应该用cls
而不是self
,更规范的写法是:python
运行
@classmethod def eat(cls): # 这里用cls更合适print("吃饭")
- 第一个参数必须是类本身(通常命名为
@staticmethod(静态方法)
- 不需要接收
self
或cls
参数 - 不能访问类状态或实例状态
- 相当于一个普通函数,只是定义在类的命名空间里
- 可以通过类名或实例调用
- 常用于定义与类相关但不需要访问类状态的工具函数
- 不需要接收
普通实例方法(如你的
run
方法)- 第一个参数是实例本身(通常命名为
self
) - 可以访问和修改实例状态,也能访问类状态
- 只能通过实例调用
- 第一个参数是实例本身(通常命名为
简单来说:
- 如果你需要操作类属性或调用其他类方法,用
@classmethod
- 如果你需要一个与类相关但不依赖类或实例状态的函数,用
@staticmethod
- 如果你需要操作实例属性,用普通实例方法(带
self
参数)
针对测试产生的问题
遇到的错误是因为类方法的调用方式不正确导致的。
当你调用 Person.eat(Person())
时出现了错误,这是因为:
@classmethod
装饰的方法已经默认接收一个类参数cls
- 当你通过
Person.eat()
调用时,Python 会自动将类本身(Person)作为参数传给cls
- 但你额外传入了
Person()
(一个实例),导致参数数量变成了 2 个,从而引发TypeError
正确的调用方式应该是:
python
运行
# 正确调用方式
Person.speak() # 静态方法,无需参数
Person.eat() # 类方法,自动传入类本身作为参数
Person().run() # 实例方法,需通过实例调用
Person.eat() # 类方法正确调用方式,无需额外传参
类方法有两种调用方式:
- 通过类名调用:
Person.eat()
(推荐) - 通过实例调用:
Person().eat()
这两种方式都会正确传递类参数 cls
,而不需要你手动传递任何参数。
4 这个@是不能省略的吗(@classmethod
和 @staticmethod
这两个装饰器的 @
符号不能省略)
@classmethod
和 @staticmethod
这两个装饰器的 @
符号不能省略。
在 Python 中,以 @
开头的是装饰器语法,它的作用是修改被装饰函数的行为。如果省略 @
,就不再是装饰器调用,而只是普通的函数定义,会导致:
函数性质改变:
- 没有
@classmethod
,def eat(cls):
会被当作普通实例方法(但参数用了cls
会造成混淆) - 没有
@staticmethod
,def speak():
会被当作需要self
参数的实例方法,调用时会报错
- 没有
调用方式出错:
python
运行
class Person:# 省略 @classmethod 后,eat 变成普通实例方法def eat(cls):print("吃饭")# 省略 @staticmethod 后,speak 变成需要 self 的实例方法def speak():print("说话")Person.eat() # 报错:缺少 self 参数 Person.speak() # 报错:缺少 self 参数
简单说,@
是装饰器语法的标志,省略后就无法实现「类方法」和「静态方法」的特殊功能了,必须严格按照 @装饰器名
的格式使用。
5 装饰器语法
装饰器(Decorator)是 Python 中一种特殊的语法,用于在不修改原函数代码的前提下,为函数或类添加额外功能。
它的本质是一个接受函数作为参数,并返回新函数的高阶函数。
装饰器使用 @装饰器名
的形式放在函数或类的定义上方,这就是装饰器语法的标志。
举个简单例子理解:
比如我们想给一个函数添加「执行前打印日志」的功能,可以用装饰器实现:
python
运行
# 定义一个装饰器(本质是函数)
def log_decorator(func):def wrapper():print("函数开始执行...") # 额外功能func() # 执行原函数print("函数执行结束...") # 额外功能return wrapper# 使用装饰器(@语法)
@log_decorator
def say_hello():print("Hello, 装饰器!")# 调用函数
say_hello()
运行结果:
plaintext
函数开始执行...
Hello, 装饰器!
函数执行结束...
装饰器的作用:
- 代码复用:将通用功能(如日志、权限验证、计时等)抽离成装饰器,多个函数可以共享。
- 不修改原函数:符合「开放 - 封闭原则」,在扩展功能时不改变原有代码。
- 简化代码:用
@装饰器名
一行代码即可为函数添加功能,清晰直观。
常见应用场景:
- 日志记录(如函数调用时间、参数等)
- 权限验证(如判断用户是否登录)
- 性能测试(如计算函数执行时间)
- 缓存处理(如缓存函数返回结果)
像之前学的 @classmethod
和 @staticmethod
就是 Python 内置的装饰器,它们的作用是把普通函数「装饰」成类方法或静态方法。