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的含义和使用相关推荐

  1. python yield理解_对Python中Yield的理解

    看到下面这段程序的时候,有点不明白这个yield到底是个啥东西,看了网上很多的博客,大致理解了yield的含义,所以记录下来. 要说yield首先要说python中的生成器,那么什么是生成器? 假设有 ...

  2. 五分钟学会python函数_五分钟带你搞懂python 迭代器与生成器

    前言 大家周末好,今天给大家带来的是Python当中生成器和迭代器的使用. 我当初第一次学到迭代器和生成器的时候,并没有太在意,只是觉得这是一种新的获取数据的方法.对于获取数据的方法而言,我们会一种就 ...

  3. Unity协程那些事儿

    Unity协程那些事儿 1.什么是协程? 2.协程的使用 3.关于yield 4.关于IEnumerator/IEnumerable 5.从IEnumerator/IEnumerable到yield ...

  4. Unity 协程(Coroutine)原理与用法详解

    前言: 协程在Unity中是一个很重要的概念,我们知道,在使用Unity进行游戏开发时,一般(注意是一般)不考虑多线程,那么如何处理一些在主任务之外的需求呢,Unity给我们提供了协程这种方式 为啥在 ...

  5. 你能说出多线程中 sleep、yield、join 的用法及 sleep与wait区别吗?

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试资料 作者:noteless cnblogs.com/noteless/ ...

  6. 【unity】简要分析yield及协同程序的用法

    在学习unity3d的时候很容易看到下面这个例子: 1 void Start () {2 StartCoroutine(Destroy());3 }4 5 IEnumerator Destroy(){ ...

  7. “ yield”关键字有什么作用?

    Python中yield关键字的用途是什么? 它有什么作用? 例如,我试图理解这段代码1 : def _get_child_candidates(self, distance, min_dist, m ...

  8. Thunk 函数的含义和用法

    一.参数的求值策略 Thunk函数早在上个世纪60年代就诞生了. 那时,编程语言刚刚起步,计算机学家还在研究,编译器怎么写比较好.一个争论的焦点是"求值策略",即函数的参数到底应该 ...

  9. python yield和yieldfrom,Python:对于yield与yield from 的理解

    yield是什么? yield单词的含义:屈服,投降,提供 对于一个函数而言,程序的执行,从上到下执行完一遍,这个函数也就完成了它的使命. def hello(): print('exe 1') pr ...

最新文章

  1. python conda虚拟环境
  2. ImportError: /opt/ros/kinetic/lib/python2.7/dist-packages/cv2.so: undefined symbol: PyCObject_Type
  3. python语言入门m-Python学习基础篇 -1
  4. 全球化的LoRaWAN协议会给我们带来什么?
  5. Web前端开发笔记——第二章 HTML语言 第九节 框架标签、脚本标签
  6. 【牛客NOIP模拟】路径难题【建图】【最短路证明】
  7. datastax.repo_使用Datastax Java驱动程序与Cassandra进行交互
  8. oracle rac fail,Oracle RAC Load Balance , Fail Over测试
  9. 本周Whale Alert监测到7.9万枚BTC在匿名地址间转账
  10. Java 对象不使用时,为什么要赋值为 null?
  11. 计算机保研-中科大计算机
  12. nginx 集群部署
  13. Boxplot箱线图
  14. 路由器温度测试软件,教你增强小米路由WEB管理(一)——添加CPU温度显示
  15. AD再见--AdGuardHome神器
  16. 关闭“Chromium 未正确关闭”提示
  17. Android动画之帧动画
  18. 线上教学软件哪个平台好?
  19. 课程设计-在校整理-10 基于知识图谱的医疗智能问答小程序实现示例
  20. 计算机基础学习记录2-1

热门文章

  1. TP5 实现多字段的关键词模糊查询
  2. C语言经典例5-输入三个数由小到大输出
  3. 【C 语言】字符串模型 ( 两头堵模型 | 将 两头堵模型 抽象成业务模块函数 | 形参返回值 | 函数返回值 | 形参指针判空 | 形参返回值操作 )
  4. 【音频处理】Adobe Audition 快捷键设置
  5. 【FluidSynth】FluidSynth 简介 ( 相关资源链接 | 简介 | 特征 )
  6. 【Java 网络编程】服务器端 ServerSocket 配置 ( 端口复用 | 缓冲区设置 | 超时时间 | 性能权重 | 端口绑定 )
  7. 去掉字符串里特殊字符的正则表达式方求
  8. GNOME Menu File Browser-快速导航用户目次
  9. C#学习笔记(C#与C++的差异)001
  10. 16位代码段与32位代码段的区别