本笔记为阿里云天池龙珠计划SQL训练营的学习内容,链接为:https://tianchi.aliyun.com/specials/promotion/aicampsql
魔法方法
__init__(self, x, y)
构造方法,在对象创建时运行,常用于初始化
__del__(self)
析构方法,对象被系统回收时调用的方法
Python 采用自动引用计数(ARC)方式来回收对象所占用的空间。
当程序中有一个变量引用该 Python 对象时,Python 会自动保证该对象引用计数为 1;
当程序中有两个变量引用该 Python 对象时,Python 会自动保证该对象引用计数为 2,
依此类推,如果一个对象的引用计数变成了 0,则说明程序中不再有变量引用该对象,表明程序不再需要该对象,因此 Python 就会回收该对象。
大部分时候,Python 的 ARC 都能准确、高效地回收系统中的每个对象。
但如果系统中出现循环引用的情况,比如对象 a 持有一个实例变量引用对象 b,而对象 b 又持有一个实例变量引用对象 a,此时两个对象的引用计数都是 1,而实际上 程序已经不再有变量引用它们,(ps:也就是说程序中不能访问到ab两个变量)系统应该回收它们,此时 Python 的垃圾回收器就可能没那么快,要等专门的循环垃圾 回收器(Cyclic Garbage Collector)来检测并回收这种引用循环。
[[Drawing 2023-07-31 15.35.53.excalidraw]]
__new__(cls[,···])
- new 是在一个对象实例化的时候所调用的第一个方法,在调用 init 初始化前,先调用 new 。
- new 至少要有一个参数 cls ,代表要实例化的类,此参数在实例化时由 Python 解释器自动提供,后面的参数直接传递给 init 。
- new 对当前类进行了实例化,并将实例返回,传给 init 的 self 。但是,执行了 new ,并不一定会 进入 init ,只有 new 返回了,当前类 cls 的实例,当前类的 init 才会进入。
定制序列
协议(Protocols)类似于接口
在 Python 中,“协议”(Protocol)是一种概念,指的是对象或类遵循的特定约定或接口,而不是像接口(Interface)一样具有明确的语法结构。或者说没有显示的定义接口
协议在 Python 中是通过一组方法、属性或特殊方法的约定来定义的。如果一个对象或类实现了这些方法和属性,那么它就被认为是符合该协议的。
鸭子类型(Duck Typing)是一种动态类型系统中的概念,它不关注对象的类型,而是关注对象是否具有特定的方法、属性或行为。这个概念得名于谚语 “如果它走起来像鸭子、叫起来像鸭子,那么它就是鸭子”。在鸭子类型中,一个对象的类型并不重要,重要的是它是否具有特定的行为。
迭代器
-
迭代是 Python 最强大的功能之一,是访问集合元素的一种方式。
-
迭代器是一个可以记住遍历的位置的对象。
-
迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。
-
迭代器只能往前不会后退。
-
字符串,列表或元组对象都可用于创建迭代器
-
iter(self) 定义当迭代容器中的元素的行为,返回一个特殊的迭代器对象, 这个迭代器对象实现了 next() 方法并通过 StopIteration 异常标识迭代的完成。
-
next() 返回下一个迭代器对象。
-
StopIteration 异常用于标识迭代的完成,防止出现无限循环的情况,在 next() 方法中我们可以设置在完 成指定循环次数后触发 StopIteration 异常来结束迭代
迭代器(Iterator)是一种设计模式和编程概念,它是用于遍历集合或序列中元素的一种抽象方式。迭代器提供了一种统一的访问方式,让我们可以按顺序访问集合中的每个元素,而不需要了解集合的内部结构。
迭代器模式包含两个主要组件:
- 迭代器(Iterator):它是一个对象,负责遍历集合并访问其中的元素。迭代器通常会跟踪当前访问的位置,并提供方法来获取下一个元素和判断是否还有更多的元素可以访问。
- 可迭代对象(Iterable):它是包含一组元素的集合,实现了迭代器模式。可迭代对象需要提供一个方法(通常是
__iter__()
方法),该方法返回一个迭代器对象,从而允许我们遍历集合中的元素。
迭代器模式的使用使得我们可以通过相同的方式来访问不同类型的集合,而不用关心它们内部的数据结构。这种设计模式在很多编程语言和框架中都得到了广泛应用,比如在 Python 中,可迭代对象常见于列表、元组、字典等,而迭代器则通过iter()
函数来获取。
以下是一个简单的 Python 示例,展示了如何使用迭代器遍历一个列表:
pythonCopy code# 创建一个列表
my_list = [1, 2, 3, 4, 5]
# 获取迭代器对象
my_iterator = iter(my_list)
# 使用迭代器遍历列表
while True:
try:
# 获取下一个元素
element = next(my_iterator)
print(element)
except StopIteration:
# 当没有更多元素时,迭代器会抛出StopIteration异常,终止循环
break
在上面的例子中,我们使用 iter()
函数获取了列表 my_list
的迭代器,并通过 next()
函数来依次获取列表中的元素,并输出它们。当迭代器遍历完所有元素后,会抛出 StopIteration
异常,我们通过捕获该异常来终止遍历循环。
需要注意的是,在实际编程中,我们很少直接使用迭代器的 next()
方法,通常使用 for
循环来遍历可迭代对象,因为 for
循环会自动处理迭代器的终止条件。例如:
pythonCopy codemy_list = [1, 2, 3, 4, 5]
for element in my_list:
print(element)
这样使用 for
循环,Python 会自动获取可迭代对象的迭代器,并在遍历完成后终止循环,简化了代码的编写。
生成器
生成器(Generator)是 Python 中用于创建迭代器的一种特殊函数。
它的工作原理类似于迭代器,但生成器的定义更为简单和高效。生成器函数允许我们在需要的时候逐步生成值,而不是一次性将所有值生成并存储在内存中。
生成器函数的定义和普通函数类似,但使用了 yield
关键字来替代 return
关键字。当生成器函数被调用时,它会返回一个生成器对象,而不会立即执行函数内部的所有代码。每次我们使用生成器对象获取下一个值时,生成器函数会在 yield
处暂停执行,并将该值返回给调用者。
练习题
__new__(cls, *args, **kwargs)
: 用于创建一个新的实例对象。通常情况下,很少直接重写这个方法,而是在子类中重写__init__
方法来进行对象初始化。__init__(self, *args, **kwargs)
: 初始化对象的方法。在对象创建后,这个方法会被自动调用,用于对对象进行初始化操作。它不返回任何值,仅用于设置对象的初始状态。__str__(self)
: 当使用str()
函数或print()
函数打印对象时,会调用这个方法返回对象的字符串表示。它应该返回一个可读性较好的字符串。__repr__(self)
: 当使用repr()
函数获取对象的字符串表示时,会调用这个方法返回对象的“开发者友好”字符串表示。通常这个字符串应该是一个能够用于重现对象的表示。__getitem__(self, key)
: 用于实现对象的索引访问,即使用obj[key]
的形式。它使得对象可以像列表或字典一样使用索引来访问元素。__setitem__(self, key, value)
: 用于实现对象的索引赋值,即使用obj[key] = value
的形式。它使得对象可以像列表或字典一样使用索引来设置元素的值。__len__(self)
: 返回对象的长度,通常用于让对象支持len()
函数。例如,让自定义类的实例可以像列表一样使用len()
函数获取其长度。__iter__(self)
: 返回一个迭代器对象,用于支持对象的迭代。当我们使用for
循环遍历对象时,实际上会调用这个方法来获取迭代器。__next__(self)
: 当使用迭代器对象的next()
方法获取下一个值时,会调用这个方法返回下一个值。它通常和__iter__
方法一起定义,用于实现自定义的迭代器。__call__(self, *args, **kwargs)
: 允许将对象像函数一样调用。当使用obj()
的形式调用对象时,会调用这个方法执行对象的操作。
利用python做一个简单的定时器类 要求:
a. 定制一个计时器的类。
b. start 和 stop 方法代表启动计时和停止计时。
c. 假设计时器对象 t1 , print(t1) 和直接调用 t1 均显示结果。
d. 当计时器未启动或已经停止计时时,调用 stop 方法会给予温馨的提示。
e. 两个计时器对象可以进行相加: t1+t2 。
f. 只能使用提供的有限资源完成。
import time
class Timer:
second = 0
switch = False
def __init__(self):
self.second = 0
self.switch = False
def __str__(self):
return str(self.second)
def __add__(self, other):
return self.second + other.second
def start(self):
if self.switch:
print('已经开始了')
self.switch = True
tip = 0
while self.switch and tip < 5:
time.sleep(1)
self.second += 1
tip += 1
def stop(self):
if not self.switch:
print('已经停止了')
self.switch = False
if __name__ == "__main__":
t1 = Timer()
t2 = Timer()
t1.stop()
t1.start()
# 模拟计时进行中...
t1.stop()
print(t1) # 输出已计时的结果
t2.start()
# 模拟计时进行中...
t2.stop()
print(t2)
t3 = t1 + t2
print(t3) # 输出两个计时器相加的结果
# 已经停止了
# 5
# 5
# 10
不完整,应该使用异步进行,为了表现功能,让start 只进行了5秒
模块
-
内置命名空间(Built-in Namespaces):Python 运行起来,它们就存在了。内置函数的命名空间都属于内置命名空间,所以,我们可以在任何程序中直接运行它们,比如 id() ,不需要做什么操作,拿过来就直接使用了。
-
全局命名空间(Module:Global Namespaces):每个模块创建它自己所拥有的全局命名空间,不同模块的全局命名空间彼此独立,不同模块中相同名称的命名空间,也会因为模块的不同而不相互干扰。(类似于路径依赖)
-
本地命名空间(Function & Class:Local Namespaces):模块中有函数或者类,每个函数或者类所定义的命名空间就 是本地命名空间。如果函数返回了结果或者抛出异常,则本地命名空间也结束了。
查询顺序:Local Namespaces --> Global Namesspaces --> Built-in Namesspaces。
所以,if __name__ == '__main__'
的意思是:当 .py 文件被直接运行时, if __name__ == '__main__'
之下的代 码块将被运行;当 .py 文件以模块形式被导入时,if __name__ == '__main__'
之下的代码块不被运行。