我想了解如何使用dis(Python字节码的伪装者),具体来说,应该如何解释dis.dis
(或dis.disassemble
)的输出?
.
下面是一个非常具体的例子(在Python 2.7.3中):
dis.dis("heapq.nsmallest(d,3)")
0 BUILD_SET 24933
3 JUMP_IF_TRUE_OR_POP 11889
6 JUMP_FORWARD 28019 (to 28028)
9 STORE_GLOBAL 27756 (27756)
12 LOAD_NAME 29811 (29811)
15 STORE_SLICE+0
16 LOAD_CONST 13100 (13100)
19 STORE_SLICE+1
我看到JUMP_IF_TRUE_OR_POP
等是字节码指令(尽管有趣的是,BUILD_SET
没有出现在这个列表中,尽管我希望它作为BUILD_TUPLE
工作)。我认为右手边的数字是内存分配,左边的数字是goto数字...我注意到它们每次几乎增加3(但不完全是)。
如果我将dis.dis("heapq.nsmallest(d,3)")
包装在函数中:
def f_heapq_nsmallest(d,n):
return heapq.nsmallest(d,n)
dis.dis("f_heapq(d,3)")
0 BUILD_TUPLE 26719
3 LOAD_NAME 28769 (28769)
6 JUMP_ABSOLUTE 25640
9 <44> # what is <44> ?
10 DELETE_SLICE+1
11 STORE_SLICE+1
我正在重新发布另一个问题的答案,以确保在搜索dis时找到答案。dis()
为了完成伟大的加雷斯·里斯的答案,这里只是一个小小的逐列摘要来解释分解字节码的输出。
例如,给定此函数:
def f(num):
if num == 42:
return True
return False
这可以分解为(Python 3.6):
erlang prettyprint-override">(1)|(2)|(3)|(4)| (5) |(6)| (7)
---|---|---|---|----------------------|---|-------
2| | | 0|LOAD_FAST | 0|(num)
|-->| | 2|LOAD_CONST | 1|(42)
| | | 4|COMPARE_OP | 2|(==)
| | | 6|POP_JUMP_IF_FALSE | 12|
| | | | | |
3| | | 8|LOAD_CONST | 2|(True)
| | | 10|RETURN_VALUE | |
| | | | | |
4| |>> | 12|LOAD_CONST | 3|(False)
| | | 14|RETURN_VALUE | |
每一栏都有一个特定的目的:
您正在尝试反汇编包含源代码的字符串,但Python中的dis.dis
不支持此操作
Python 3中的情况不同,dis.dis
在拆解字符串参数之前编译它:
Python 3.2.3 (default, Aug 13 2012, 22:28:10)
>>> import dis
>>> dis.dis('heapq.nlargest(d,3)')
1 0 LOAD_NAME 0 (heapq)
3 LOAD_ATTR 1 (nlargest)
6 LOAD_NAME 2 (d)
9 LOAD_CONST 0 (3)
12 CALL_FUNCTION 2
15 RETURN_VALUE
在Python 2中,您需要在将代码传递给dis.dis
之前自己编译代码:
Python 2.7.3 (default, Aug 13 2012, 18:25:43)
>>> import dis
>>> dis.dis(compile('heapq.nlargest(d,3)', '<none>', 'eval'))
1 0 LOAD_NAME 0 (heapq)
3 LOAD_ATTR 1 (nlargest)
6 LOAD_NAME 2 (d)
9 LOAD_CONST 0 (3)
12 CALL_FUNCTION 2
15 RETURN_VALUE
这些数字意味着什么?最左边的数字1
是编译此字节码的源代码中的行号。左侧列中的数字是字节码中指令的偏移量,右侧的数字是oparg。让我们看看实际的字节码:
>>> co = compile('heapq.nlargest(d,3)', '<none>', 'eval')
>>> co.co_code.encode('hex')
'6500006a010065020064000083020053'
在字节码的偏移量0处,我们找到65,操作码为LOAD_NAME,操作码为0000;然后(在偏移量3处)6a是操作码LOAD_ATTR,操作码为0100,以此类推。请注意,操作码的顺序是小端,因此,0100是数字1。未文档化的操作码模块包含表,为每个操作码提供名称,为每个操作码提供操作码:
>>> opcode.opname[0x65]
'LOAD_NAME'
oparg的含义取决于操作码,对于完整的故事,您需要阅读ceval中的CPython虚拟机的实现。c
。对于LOAD_NAME
和LOAD_ATTR
而言,oparg是代码对象的co_names
属性的索引:
>>> co.co_names
('heapq', 'nlargest', 'd')
对于LOAD_CONST
,它是代码对象的co_consts
属性的索引:
>>> co.co_consts
(3,)
对于CALL_FUNCTION
,它是传递给函数的参数数,用16位编码,低字节中的普通参数数,高字节中的关键字参数数。
问题内容: 我想了解如何使用dis(Python字节码的反汇编程序)。具体来说,应该如何解释(或)的输出? 。 这是一个非常具体的示例(在Python 2.7.3中): 我看到等是字节码指令 (尽管有趣的是,它没有出现在此列表中,尽管我希望它可以作为)。我认为右侧的数字是内存分配,而左侧的数字是goto数字…我注意到它们每次 几乎 增加3(但不是完全一样)。 如果我包装一个函数: 问题答案: 您正
问题内容: 我写了一个小小的go脚本,并使用strace跟踪了该脚本,我试图使用netlink协议从内核中获取审核消息,就像auditd一样。 以下是我的旅途中strace的输出脚本- http://paste.ubuntu.com/8272760/ 我试图找到auditd提供给sendto函数的参数。当我在auditd上运行strace时,我得到以下输出 当我追踪我的go文件时,我得到以下输出。
问题内容: 有人可以为我指出一份良好的初学者指南,以安全地运行部分由用户输入构成的SQL查询吗?我正在使用Java,但是语言无关的指南也很好。 期望的行为是,如果有人在GUI中键入类似 数据库应将其视为文字字符串,并安全地存储它而不会删除任何表。 问题答案: 您肯定要使用PreparedStatement。他们很方便。这是一个例子。
我试图理解输出,以便更好地调试。 我对这些看似随机生成的字母数字字符串的含义感到困惑。 例如: 我相信下面的字符串是图像ID。 剩下的是什么?什么是层次?每次我对Dockerfile稍作修改后构建时,它们似乎都会重新构建 从“装载”是什么意思?
问题内容: 我有一种算法,当前会分配很大的双精度数组,它会经常更新和搜索。数组的大小为N ^ 2/2,其中N是算法在其上进行操作的行数。为了与算法周围的应用程序相关联,我还必须保留整个内容的副本。 当然,这对我的算法可以处理的行数施加了限制,因为我要应对堆的限制。到现在为止,我还没有要求使用该算法的人员更新- Xmx设置以分配更多的空间,并且效果很好。但是,我现在遇到了一个真正的问题,我需要此数组
本文向大家介绍详解如何在Go项目中输出版本信息,包括了详解如何在Go项目中输出版本信息的使用技巧和注意事项,需要的朋友参考一下 我们经常在使用CLI工具的时候,都会有这样的参数输出: 可以打印出构建时对应的版本信息,比如 Version,Go Version,Git Commit等,这个是如何实现的呢? 实现 主要是通过ldflags参数来实现在构建的时候对变量进行赋值。 比如下面一段代码: 构建