迭代器和生成器
生成器(Generators)和迭代器(Iterators)在Python中都是用来遍历数据集合的工具:
迭代器(Iterators)
迭代器是一个实现了迭代器协议的对象,该协议包括两个方法:
__iter__()
方法,它返回迭代器自身。__next__()
方法,它返回序列中的下一个值。当没有更多的值可以返回时,会抛出一个StopIteration
异常。
用于遍历数据,但不是一次性加载所有数据到内存中,通过调用内置函数iter()
来获取一个列表的迭代器,然后使用next()
函数逐个访问元素直到抛出StopIteration
。
my_list = [1, 2, 3]
my_iterator = iter(my_list)
print(next(my_iterator)) # 输出: 1
print(next(my_iterator)) # 输出: 2
print(next(my_iterator)) # 输出: 3
# print(next(my_iterator)) # 这里会抛出 StopIteration 异常
生成器(Generators)
生成器是特殊的迭代器,它们使用关键字yield
来产生一系列的值。生成器看起来像一个函数,但是当你调用它时,它不会执行并返回结果,而是返回一个生成器对象。当你迭代这个对象时,生成器函数内的代码会被执行,直到遇到yield
语句,此时它会产生一个值并记住当前位置。当你再次迭代时,它会从上次停止的地方继续执行,直到再次遇到yield
或函数结束。
生成器的主要优点是它们延迟计算和节省内存。它们只在需要的时候计算下一个值,并且不保存之前的值,除非明确地在生成器函数中保存状态。
下面是一个简单的生成器示例:
def simple_generator():
yield 1
yield 2
yield 3
gen = simple_generator()
print(next(gen)) # 输出: 1
print(next(gen)) # 输出: 2
print(next(gen)) # 输出: 3
# print(next(gen)) # 这里会抛出 StopIteration 异常
生成器是一种特殊的迭代器,它们通过yield
语句来实现延迟计算和内存效率。迭代器则是一个遵循迭代器协议的对象,用于顺序访问集合中的元素。生成器可以被看作是创建迭代器的一种简便方式,特别是当数据集非常大或者数据是在运行时动态生成的时候。这里举个例子,在流加密算法中伪随机字节流部分:
def PRGA(S):
i = 0
j = 0
# 生成器不断生成密钥流
while True:
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i], S[j] = S[j], S[i] # 交换i,j的两个位置
K = S[(S[i] + S[j]) % 256] # 取S中的S[i]与S[j]相加%256结果的位置作为密钥流的值
yield K
1.lambda函数
首先从函数类型和默认表示来看区别
add = lambda x, y: x + y
print(type(add)) # <class 'function'>
print(add) # <function <lambda> at 0x000001E025739080>
def add1(x, y):
return x + y
print(type(add1)) # <class 'function'>
print(add1) # <function add1 at 0x000001E025A3C2C0>
def是绑定到相对于的名称上。lambda函数是打上lambda标签。可以定义一个变量指向lambda函数对其调用(不推荐)。
lambda函数适合小型,一次性使用的函数,不能包含控制结构。
简单使用
res = (lambda x, y: x + y)(1, 2)
与内置函数结合使用
squares = list(map(lambda x: x ** 2, number))
squared = [x**2 for x in number]
与max结合
对于此类函数,key=
接受一个函数,会在函数内部先运行这个函数,然后获取函数返回值,在进行排序或取最大值,然后将结果返回或覆盖
ctf = {
"pwn": 30,
"web": 23,
"misc": 17,
"crypto": 12,
"reverse": 18
}
print(max(ctf)) # 默认比较的是key
print(max(ctf, key=lambda k: ctf[k])) # pwn
print(max(ctf.values())) # 30
如果想要返回最大值的键,需要lambda
如果仅需要最大的值,则直接使用自带value()
方法即可。
结合filter函数
filte返回的是迭代器并非生成器
from collections.abc import Generator
from collections.abc import Iterable
ctf_week_rank = [50, 36, 35, 21, 67, 68, 34]
flt_res = filter(lambda rank: rank > 35, ctf_week_rank)
print(flt_res)
print(isinstance(flt_res, Generator)) # False
print(isinstance(flt_res, Iterable)) # True
print(list(flt_res)) # 将迭代器转为list, 底层迭代在append
结合sorted函数对字典操作
ctf = {
"pwn": 30,
"web": 23,
"misc": 17,
"crypto": 12,
"reverse": 18
}
sorted_ctf = sorted(ctf, key=lambda k: ctf[k]) # 按照值排序返回键
# ['crypto', 'misc', 'reverse', 'web', 'pwn']
sorted_ctf1 = sorted(ctf)
# ['crypto', 'misc', 'pwn', 'reverse', 'web']
结合sort方法与sorted函数对列表操作
ctf = [
{"ctf1": 30, "pwn": 10},
{"ctf2": 23, "pwn": 20},
{"ctf3": 17, "pwn": 14},
]
ctf1 = sorted(ctf, key=lambda k: k['pwn'])
print(ctf)
# [{'ctf1': 30, 'pwn': 10}, {'ctf2': 23, 'pwn': 20}, {'ctf3': 17, 'pwn': 14}]
print(ctf1)
# [{'ctf1': 30, 'pwn': 10}, {'ctf3': 17, 'pwn': 14}, {'ctf2': 23, 'pwn': 20}]
ctf.sort(key=lambda k: k['pwn'])
print(ctf)
# [{'ctf1': 30, 'pwn': 10}, {'ctf3': 17, 'pwn': 14}, {'ctf2': 23, 'pwn': 20}]
注意sort
方法会直接修改列表本身,如果不希望修改列表本身可以用sorted
结合lambda进行操作
作为参数传递
def apply(func, arg):
return func(arg)
print(apply(lambda x: x + 1, 5)) # 5
用于列表推导式或生成器表达式中的条件表达式
num = [1, 2, 3, 4]
print([(lambda x: x if x > 2 else -x)(x) for x in num ])
# [-1, -2, 3, 4]
2.面向对象基础
实例属性在创建时每个实例对象都有存在,所以不适合作为计数器,类属性只占一份,所以适合作为计数器。
通过类本身调用实例方法
class CTFerClass:
def __init__(self,rank):
self.rank = rank
def print_rank(self):
print(self.rank)
CTFer1 = CTFerClass(50)
CTFer1.print_rank() # 50 底层是直接调用__class__方法传入self
CTFerClass.print_rank(CTFer1) # 50
CTFer1.__class__.print_rank(CTFer1) # 50
print(CTFer1.__class__) # <class '__main__.CTFerClass'>
类保存在内存,实例只需要存自身属性,不必再存方法,直接调用类方法即可。
类定义实例属性,则self必须是对象
class CTFerClass:
def __init__(self,rank):
self.rank = rank
def print_rank(self):
print(self)
print(type(self))
CTFerClass.print_rank("123")
# 123
# <class 'str'>
类未定义实例属性,slef可以是任意参数
下面是屎山代码
class CTFerClass:
def print_rank(self):
print(type(self))
for i in self:
print(i, end=" ")
CTFerClass.print_rank([1, 2, 3, 4])
# 1 2 3 4
python模拟私有属性但是并不是不可访问
单下划线(非公开成员)
意在告诉其他开发者这是一个内部实现细节,不应该在类的外部直接访问。但这并不阻止外部代码访问这些成员,只是起到一种约定上的暗示。
class CTFer:
def __init__(self, rank):
self._self_attr = "_self_attr"
self.rank = rank
def _self_method(self):
print(self.rank)
CTFer1 = CTFer(50)
CTFer1._self_method() # 50
print(CTFer1._self_attr) # _slef_attr
双下划线
当一个属性或方法名称前加上两个下划线,Python会触发名称改编(name mangling)。这意味着原始名称会被修改为 _classname__attributename
的形式,这使得从类的外部直接访问这些成员变得困难,但不是完全不可能。名称改编的主要目的是避免子类中不小心覆盖基类的私有属性或方法。
class CTFer:
def __init__(self, rank):
self.__private_attr = "_self_attr"
self.rank = rank
def __private_method(self):
print(self.rank)
CTFer1 = CTFer(50)
print(CTFer1._CTFer__private_attr)
CTFer1._CTFer__private_method()
依然可以通过改名后的形式进行访问。
名称改编的主要目的是避免子类中不小心覆盖基类的私有属性或方法。
class CTFer:
def __init__(self):
self.public_attribute = "capture the flag"
self.__private_attribute = "CTFer"
class PWNer(CTFer):
def __init__(self):
super().__init__()
self.public_attribute = "pwn!pwn!pwn!"
self.__private_attribute = "pwn your linux"
PWNer_1 = PWNer()
print(PWNer_1.public_attribute) # pwn!pwn!pwn!
print(PWNer_1._CTFer__private_attribute) # CTFer
不理解super()
,参考下面代码
class Parent:
def __init__(self, name):
self.name = name
print(f"Parent {self.name} created.")
class Child(Parent):
def __init__(self, name, age):
super().__init__(name) # 调用父类构造函数,需要补齐父类参数,去掉补齐的前提是不能运行父类方法
self.age = age
print(f"Child {self.name} created, age: {self.age}.")
child_instance = Child("Alice", 10)
类的实例属性的动态创建及对象关联
class CTFTeam:
def __init__(self, t_name):
self.name = t_name
class PWNer:
def __init__(self, pwn_name):
self.pwn_name = pwn_name
team1 = CTFTeam('team1')
pwn1 = PWNer('pwn1')
pwn2 = PWNer('pwn2')
team1.member_info = pwn1
team1.member_info = pwn2
print(team1.member_info.pwn_name) # pwn2
team1.member_info = list()
# team1.member_info.append(pwn1)
# team1.member_info.append(pwn2)
team1.member_info.extend([pwn1, pwn2]) # pwn2
CTFTeam类动态创建实例属性并使其指向PWNer类的实例对象内存地址,新属性指向PWNer实例对象本身,所以可以直接用PWNer类的实例对象访问PWNer实例属性
反向迭代
team_list = ['pwn1', 'web1', "crypt1", 'pwn1']
for tem_power in team_list:
if tem_power == 'pwn1':
team_list.remove(tem_power)
print(team_list) # ['web1', 'crypt1', 'pwn1']
最后一个pwn1
没有被删除,因为列表动态变化了
team_list = ['pwn1', 'web1', "crypt1", 'pwn1', 'pwn1']
for tem_power in reversed(team_list):
if tem_power == 'pwn1':
team_list.remove(tem_power)
print(team_list)
reversed()
会创建新列表。
如果希望保留原有列表的话,还有其他很多方法
new_lst = list(filter(lambda x: x != 'pwn1', team_list))
new_lst = [x for x in lst if x != 'pwn1']
或者
for idx in range(len(team_lst)-1, -1, -1):
if idx == 'pwn1':
del lst[idx]
使用类属性完成数据库连接功能
class ConnectionMysql:
db = pymysql.connect(host='localhost', port=3306, user='root', passwd='123456', db='test', charset='utf8')
cursor = db.cursor()
类方法角度看self
如果类访问的属性只有类属性则可以考虑将实例方法修改成类方法
class CTFTeam:
total_team = 0
def __init__(self):
CTFTeam.total_team += 1
@classmethod
def get_total_team(cls):
print(cls)
# <class '__main__.CTFTeam'>
print(f'total team: {cls.total_team}')
team1 = CTFTeam()
team1.get_total_team() # total team: 1