scapy-yield的含义和使用
scapy的实现中,yield的用法很好,它使得loop成为一个生成器,从而使得__iter__返回一个迭代器,那么yield的本质是什么呢?
保有yield的函数返回的是一个迭代器,而返回迭代器的也就是生成器了,用yield构造迭代器将会非常方便,总的来说,设yield函数返回一个迭代器iter1,只有在你显式的调用其next函数或者隐式作for-in操作时,yield函数中的yield值才会依次按照其yield的顺序返回出来,yield函数如果你使用yield N,那么这和return N是区别市很大的,如果仅仅return N的话,这个N就直接被返回了,它仅仅是一个值,而如果是yield N的话,虽然最终还是可以得到的还是N,但是你得到N的方式却变了,你只能通过iter的接口来得到N。yield只是在“塞”住了很多数据,只有iter的接口才能将其一个一个“拔”出来,在一个函数中,只要你yield了一个数据,那么就等于塞住了一个数据,将来需要用iter接口拔出它,比如以下的例子:
def test():
print "333"
yield 3
print "444"
yield 4
print "555"
yield 5
使用命令行运行之:
>>> def test():
... print "333"
... yield 3
... print "444"
... yield 4
... print "555"
... yield 5
...
>>> it=test() #没有任何输出
>>> a=it.next() #a的值是3,并且将输出333,后面的444,555依旧不输出,必须等待下次调用next以及下下次调用
333
>>> print a
3
隐式调用也一样:
>>> it=test()
>>> for k in it:
... print k
... break
...
333
3
>>> it=test()
>>> for r in it:
... print r
...
444
4
555
5
就是这样!有了yield的理论知识,接下来再看scapy的Packet类的__iter__这个函数:
00def __iter__(self):
01 def loop(todo, done, self=self):
02 if todo:
03 eltname = todo.pop()
04 elt = self.__getattr__(eltname)
05 if not isinstance(elt, Gen):
06 if self.fieldtype[eltname].islist:
07 elt = SetGen([elt])
08 else:
09 elt = SetGen(elt)
10 for e in elt:
11 done[eltname] = e
12 for x in loop(todo[:], done):
13 yield x
14 else:
15 if isinstance(self.payload,NoPayload):
16 payloads = [None]
17 else:
18 payloads = self.payload
19 for payl in payloads:
20 done2 = done.copy()
21 for k in done2:
22 if isinstance(done2[k], RandNum):
23 done2[k] = int(done2[k])
24 pkt = self.__class__(**done2)
25 pkt.underlayer = self.underlayer
26 pkt.overload_fields = self.overload_fields.copy()
27 if payl is None:
28 yield pkt
29 else:
30 yield pkt/payl
31 return loop(map(lambda x:str(x), self.fields.keys()), {})
在__str__中调用__iter__().next()返回的Packet实际上只有一个,那就是在13行返回的这个x,这是为何呢?在__iter__中总共有三个地方“塞”住了Packet(事实上可以归为两个,因为28行和30行可以视为一个),分别在13行,28行和30行,在__iter__的执行过程中,首先进入的是前半部分,只有在todo没有的时候才会进入后半部分else,可见if todo段是解决本层Packet对象的,如果todo没有了,在12行调用loop时才会进入到else段,因此else段是递归解决本层Packet对象的payload的,然后在28行或者30行“塞”一个Packet,可是如果执行到了28行或者30行,也塞住了Packet,那么接下来返回到哪里呢?想象一下当初是怎么进来的,是从12行进来的,于是返回12行,返回之后,直接就被“拔”出了,这是因为12行有一个for-in,拔出28行或者 30行塞入的Packet后紧接着又塞入一个,然后如果该层Packet对象的属性(也即todo链表)不止一个,还会进一步的返回上一个todo属性调用的loop,在for-in中又把刚刚在13行塞入的Packet给拔出了,最终__iter__返回的时候,其实只有最后一个Packet对象在13行被塞入。
对于直接调用__str__进而调用__iter__的Packet对象而言,进入else之后28行或者30行的yield被12行的for-in所抵消,最终在13行yield一个Packet对象,也是唯一的一个,对于进入19行的for-in而间接递归调用__iter__的所取得的payl这个Packet对象而言,其在13行最终yield的那个唯一的Packet对象被19行本身的for-in所抵消,这样最后就剩下了直接调用__str__函数的那个Packet对象本身。str函数的不断调用使得包的构建从下往上进行,每次上升一层,因为每次都会以已经处理完的Packet对象的payload再次调用str,从L3PacketSocket的send函数的outs.send中的str开始这一过程,随后在do_build中的p+str(self.payload)中继续这一过程,完成包的构建。
13行的yield x返回两个地方,一个是直接的__iter__().next()的调用,比如__str__中,另一个是隐式的for-in调用,其中也类似一个next的调用,比如19行的for-in,完全和13行的yield x“塞”“拔”抵消,另外12行的for-in,也是完全抵消,然而紧接着在13行又“塞”了一个,这就构成了一个循环,一个递归的循环。12-13行的“塞拔”是塞拔的同一个Packet对象,先拔再塞,拔的是28/29行塞入的对象或者13行塞入的对象,19行拔的是当前Packet对象的payload,而这个payload是在递归到上一层时在13行最后塞入的。懵了吗?递归加迭代就是这么...
转载于:https://blog.51cto.com/dog250/1271133
scapy-yield的含义和使用相关推荐
- python yield理解_对Python中Yield的理解
看到下面这段程序的时候,有点不明白这个yield到底是个啥东西,看了网上很多的博客,大致理解了yield的含义,所以记录下来. 要说yield首先要说python中的生成器,那么什么是生成器? 假设有 ...
- 五分钟学会python函数_五分钟带你搞懂python 迭代器与生成器
前言 大家周末好,今天给大家带来的是Python当中生成器和迭代器的使用. 我当初第一次学到迭代器和生成器的时候,并没有太在意,只是觉得这是一种新的获取数据的方法.对于获取数据的方法而言,我们会一种就 ...
- Unity协程那些事儿
Unity协程那些事儿 1.什么是协程? 2.协程的使用 3.关于yield 4.关于IEnumerator/IEnumerable 5.从IEnumerator/IEnumerable到yield ...
- Unity 协程(Coroutine)原理与用法详解
前言: 协程在Unity中是一个很重要的概念,我们知道,在使用Unity进行游戏开发时,一般(注意是一般)不考虑多线程,那么如何处理一些在主任务之外的需求呢,Unity给我们提供了协程这种方式 为啥在 ...
- 你能说出多线程中 sleep、yield、join 的用法及 sleep与wait区别吗?
点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试资料 作者:noteless cnblogs.com/noteless/ ...
- 【unity】简要分析yield及协同程序的用法
在学习unity3d的时候很容易看到下面这个例子: 1 void Start () {2 StartCoroutine(Destroy());3 }4 5 IEnumerator Destroy(){ ...
- “ yield”关键字有什么作用?
Python中yield关键字的用途是什么? 它有什么作用? 例如,我试图理解这段代码1 : def _get_child_candidates(self, distance, min_dist, m ...
- Thunk 函数的含义和用法
一.参数的求值策略 Thunk函数早在上个世纪60年代就诞生了. 那时,编程语言刚刚起步,计算机学家还在研究,编译器怎么写比较好.一个争论的焦点是"求值策略",即函数的参数到底应该 ...
- python yield和yieldfrom,Python:对于yield与yield from 的理解
yield是什么? yield单词的含义:屈服,投降,提供 对于一个函数而言,程序的执行,从上到下执行完一遍,这个函数也就完成了它的使命. def hello(): print('exe 1') pr ...
最新文章
- python conda虚拟环境
- ImportError: /opt/ros/kinetic/lib/python2.7/dist-packages/cv2.so: undefined symbol: PyCObject_Type
- python语言入门m-Python学习基础篇 -1
- 全球化的LoRaWAN协议会给我们带来什么?
- Web前端开发笔记——第二章 HTML语言 第九节 框架标签、脚本标签
- 【牛客NOIP模拟】路径难题【建图】【最短路证明】
- datastax.repo_使用Datastax Java驱动程序与Cassandra进行交互
- oracle rac fail,Oracle RAC Load Balance , Fail Over测试
- 本周Whale Alert监测到7.9万枚BTC在匿名地址间转账
- Java 对象不使用时,为什么要赋值为 null?
- 计算机保研-中科大计算机
- nginx 集群部署
- Boxplot箱线图
- 路由器温度测试软件,教你增强小米路由WEB管理(一)——添加CPU温度显示
- AD再见--AdGuardHome神器
- 关闭“Chromium 未正确关闭”提示
- Android动画之帧动画
- 线上教学软件哪个平台好?
- 课程设计-在校整理-10 基于知识图谱的医疗智能问答小程序实现示例
- 计算机基础学习记录2-1
热门文章
- TP5 实现多字段的关键词模糊查询
- C语言经典例5-输入三个数由小到大输出
- 【C 语言】字符串模型 ( 两头堵模型 | 将 两头堵模型 抽象成业务模块函数 | 形参返回值 | 函数返回值 | 形参指针判空 | 形参返回值操作 )
- 【音频处理】Adobe Audition 快捷键设置
- 【FluidSynth】FluidSynth 简介 ( 相关资源链接 | 简介 | 特征 )
- 【Java 网络编程】服务器端 ServerSocket 配置 ( 端口复用 | 缓冲区设置 | 超时时间 | 性能权重 | 端口绑定 )
- 去掉字符串里特殊字符的正则表达式方求
- GNOME Menu File Browser-快速导航用户目次
- C#学习笔记(C#与C++的差异)001
- 16位代码段与32位代码段的区别