[PythonAdvanced] 学习笔记 - Day 2
Overview
Date: 2024-11-27 Time Spent: 6 hours
Topics: Decorators Difficulty: ⭐⭐⭐ (1-5 ⭐)
What I Learned Today
-
[Generator & Iterator 迭代器和生成器]
-
Main points:
當我們使用循環來循環某些內容時,稱為迭代。它是進程本身的名稱。迭代器是一個對象,它使程式設計師能夠遍歷容器,特別是列表。迭代器用于遍历集合中的元素,但它本身并不存储元素,而是提供了一种按顺序访问集合元素的方式。因此,说迭代器更像是一个访问元素的接口。
生成器(generator)是一种特殊的迭代器,它使用函数来产生序列中的元素。生成器函数使用
yield
关键字来暂停函数执行并产生一个值,然后在下一次迭代时从上次暂停的位置继续执行。生成器的一个关键特性是它们可以“惰性求值”(lazy evaluation),即只在需要时才生成值。 -
Generator Example code
# Generators are best for calculating large sets of results (particularly calculations involving loops themselves) where you don’t want to allocate the memory for all results at the same time. # generator version def fibon(n):a = b = 1for i in range(n):yield aa, b = b, a + b for x in fibon(1000000):print(x)
-
Iterator Example code
int_var = 1779 iter(int_var) # Output: Traceback (most recent call last): # File "<stdin>", line 1, in <module> # TypeError: 'int' object is not iterable # This is because int is not iterablemy_string = "Yasoob" my_iter = iter(my_string) print(next(my_iter)) # Output: 'Y'
-
-
[Classes 类]
-
Main points: 类变量用于在类的不同实例之间共享的数据。
-
Classes Example code
class Cal(object): #不可变函数使用过程中不会出现污染# pi is a class variablepi = 3.142def __init__(self, radius):# self.radius is an instance variableself.radius = radiusdef area(self):return self.pi * (self.radius ** 2)a = Cal(32) a.area() # Output: 3217.408 a.pi # Output: 3.142 a.pi = 43 a.pi # Output: 43
-
__init__
是类初始值设定项。每当创建类的实例时,都会调用其__init__
方法。class GetTest(object):def __init__(self, name):print('Greetings!! {0}'.format(name))def another_method(self):print('I am another method which is not'' automatically called')a = GetTest('yasoob') # Output: Greetings!! yasoob# Try creating an instance without the name arguments b = GetTest() Traceback (most recent call last):File "<stdin>", line 1, in <module> TypeError: __init__() takes exactly 2 arguments (1 given)
-
__getitem__
在类中实现 get item 允许其实例使用 [](索引器)运算符。class GetTest(object):def __init__(self):self.info = {'name':'Yasoob','country':'Pakistan','number':12345812}def __getitem__(self,i):return self.info[i]foo = GetTest()foo['name'] # Output: 'Yasoob'foo['number'] # Output: 12345812
-
-
[Meta classes 元类]
-
Main points: 类定义了对象的行为,而元类则定义了类的行为。通过元类,我们可以改变类的创建方式,自动添加属性或方法,实现类的注册,强制API一致性等。
-
Meta classes Example code
class MyMeta(type):def __new__(cls, name, bases, dct):x = super().__new__(cls, name, bases, dct)x.attr = 100return xclass MyClass(metaclass=MyMeta):passprint(MyClass.attr) # 输出: 100
-
-
[Descriptor 属性描述符]
-
Main points:
描述符是一个类,只要内部定义了
__get__
、__set__
、__delete__
中的一个或多个方法,就可以被视为描述符。如果描述符同时定义了__set__
和__get__
方法(或只定义了__set__
方法),则被称为数据描述符。数据描述符的优先级高于实例属性。如果描述符只定义了__get__
方法(或未定义__set__
方法),则被称为非数据描述符。 -
Descriptor Example code
class Descriptor:def __set_name__(self, owner, name):self.name = f"__{name}__"def __get__(self, instance, owner):return getattr(instance, self.name, None)def __set__(self, instance, value):setattr(instance, self.name, value)def __delete__(self, instance):raise AttributeError("delete is disabled")class X:data = Descriptor()x = X() x.data = 100 print(x.data) # 输出: 100 print(x.__dict__) # {'__data__': 100}
-
Example code
def do_twice(func):def wrapper_do_twice(*args, **kwargs):func(*args, **kwargs)func(*args, **kwargs)return wrapper_do_twice@do_twice # greet = do_twice(greet) def greet(name):print(f"Hello {name}") >>> greet(name = "Mia")
-
Example code
-
-
[Context Managers 上下文管理器]
-
Main points: 上下文管理器可讓您在需要時精確地指派和釋放資源。上下文管理器最廣泛使用的範例是
with
語句。举例:打開文件,向其中寫入一些數據,然後關閉它
with open('some_file', 'w') as opened_file:opened_file.write('Hola!')Silimar as following code:file = open('some_file', 'w') try:file.write('Hola!') finally:file.close()
-
File Example code
#by defining __enter__ and __exit__ methods we can use our new class in a with statement. class File(object):def __init__(self, file_name, method):self.file_obj = open(file_name, method)def __enter__(self):return self.file_objdef __exit__(self, type, value, traceback):self.file_obj.close()with File('demo.txt', 'w') as opened_file:opened_file.write('Hola!')
-
以生成器的形式调用上下文管理器
Example code
from contextlib import contextmanager@contextmanager def open_file(name):f = open(name, 'w')try:yield ffinally:f.close() with open_file("test.txt") as f:f.write("Hi")
-
Code Practice
from torch.utils.hipify.hipify_python import valuetemp_str = "YouAreNumerousStars"
my_iter = iter(temp_str) # 转换为迭代器# for i in my_iter: #输出字符
# print(i)def fibo(n):a = b = 1for i in range(n):yield a # 将a的值返回给调用者fibo,然后暂停观察是否还需要进行下一次迭代# 如果需要下一次迭代,就继续运行a, b = b, a + ba, b = b, a + b # a=b,b=a+b# for i in fibo(5): # 调用斐波那契数列需要使用迭代才能调用
# print(i)class cal_area(object):pi = 3.142def __init__(self, r):self.r = rdef area(self):return self.pi * self.r * self.r # 需要给变量前面加上self# a = cal_area(5)
# print(a.area())class test_info(object):def __init__(self, **kwargs):self.info = {**kwargs}def __getitem__(self, item):return self.info[item]myinfo = {"name": "Arden", "position": 'student'}
a = test_info(**myinfo)
# print(a.__getitem__("name"))"""
元类是创建类的类。比如元类为Mymeta,其中的x为新建的类。
"""
class Mymeta(type): # type是内建的元类,用于创建类对象def __new__(cls, name, bases, dct): # 允许我们自定义类的创建过程"""注:以下内容为局部变量,非属性cls:指的是当前正在创建的类(即MyMeta自身)。name:是类的名称。bases:是类的基类元组(由于在Python 3中,所有类默认继承自object,所以这里可能不显式包含object)。dct:是一个字典,包含了类定义中所有的属性和方法。"""x = super().__new__(cls, name, bases, dct)# 新建类x,super()返回了母函数(Mymeta的上一级type)x.attrs = 100 #给x类添加属性attrs,赋值100return x
class MyClass(metaclass=Mymeta): #pass # 占位符语句
#print(MyClass.name) 局部变量无法运行
#print(MyClass.__name__) #__name__是Python自动为每个类设置的,用于存储类的名称#描述符只要定义了__set__,被称为数据描述符;没有定义__set__为实例描述符
#数据优先级>实例优先级
class Descriptor: #定义描述符def __set_name__(self, owner, name):#描述符被分配给了哪个类(owner)以及它在该类中的名称(name)self.name = f"__{name}__" #加下划线是为了符合描述符在类中被赋予的名称def __get__(self, instance, owner):#获取描述符的值。instance 是尝试访问描述符的实例(如果有的话)。return getattr(instance, self.name) #从实例的 __dict__ 中获取以 self.name的值,并返回它def __set__(self, instance, value):#设置描述符的值setattr(instance, self.name, value)#在实例的 __dict__ 中设置以 self.name命名的属性的值为 valuedef __delete__(self, instance):delattr(instance, self.name)#从实例的 __dict__ 中删除以self.name命名的属性。class X:"""data的类属性是 Descriptor 类的一个实例。它会自动为 X的实例提供 __get__, __set__, 和 __delete__ 方法所定义的行为。"""data=Descriptor()name=Descriptor()
x=X()
x.data=100
x.name="Arden"
#print(x.data, x.name)
#print(x.__dict__)"""
使用上下文管理器的好处带来了更好的异常处理、更简洁的代码和更高的可维护性。
"""
class File(): #可以省略括号中的object,因为在Python3中是默认的def __init__(self, file_name):#初始化File,每次使用都会实现以下代码self.file_name = file_nameself.file_obj = open(self.file_name, "w") #按file_name以写入模式打开文件def __enter__(self):return self.file_obj#在 with 语句中,这个返回的对象会被赋值给 as 关键字后面的变量def __exit__(self, exc_type, exc_val, exc_tb):#当 with 语句块执行完毕或发生异常时,会自动调用这个方法#异常类型 exc_type,异常值 exc_val,和异常跟踪信息 exc_tbprint(exc_type, exc_val, exc_tb)self.file_obj.close()
#with File("test.txt") as opened_file:#File中的self.file_obj返回给opened_file#opened_file.write("Hiiii")#opened_file.read() #只写文件,读会报错#with open("test2.txt", "w") as write_file: #直接实现对文件的修改#write_file.write("hello world")from contextlib import contextmanager
@contextmanager
def open_file(name):f = open(name, "w")try:yield f #这行代码是 contextmanager 装饰器使用的关键。# 它暂停了生成器的执行,并将 f 返回给上下文管理器的调用者。# 调用者可以使用这个文件对象进行读写操作。# 当调用者完成操作并退出 with 语句块时,生成器的执行将继续进行。finally:f.close()
"""
change_file打开了test3文件,文件对象返回给变量f
然后执行try命令,遇见yield f,暂停并返回给with语句调用者。
执行with语句中的操作,执行完毕后,生成器将继续执行。
"""
#with open_file("test3.txt") as f:#f.write("Context\n")#实现一个简单的性能监控装饰器
import functools
import time
import tracemallocdef performance(func):@functools.wraps(func)def wrapper_time_memory(*args, **kwargs):start_time = time.time()tracemalloc.start()value = func(*args,**kwargs)snapshot = tracemalloc.get_traced_memory()tracemalloc.stop()# 分别获取当前内存和峰值内存current_memory = snapshot[0]peak_memory = snapshot[1]end_time = time.time()time_taken = end_time - start_timeprint(f"Time: {time_taken:.4f} seconds") #格式化输出时间print(f"Memory taken: {current_memory/1024:.2f} KB")print(f"Peak Memory taken: {peak_memory/1024:.2f} KB")return valuereturn wrapper_time_memory@performance
def fibon(n):a=b=1for i in range(n):yield aa,b = b,a+bfibon(100) #运行时打印时间和内存占用情况
for i in fibon(100): #生成器会再次运行,再打印一次print(i)
遇见的挑战难及解决方法和笔记点见注释。
The challenges encountered, solutions, and key points for note-taking are indicated in the comments.
Resources Used
- [Python Tips]: A book of many contents like generators, decorators, mutation and so on.
- [Real Python]: Primer on Python Decorators.
Tomorrow's Plan
Today's Plan
Personal Thoughts
Today, my learning progress was faster than yesterday. Interestingly, I found that the knowledge is crossed because yesterday I used the classes although I don't have an insight of it. This made me think the tools are just tools, you may not need to know how it was invented before you used them. Of course, it would be better if you got a clear understanding of the tools. I am glad I am on my way.