我希望每次运行时都能自己哈希。这是否可以在不必提供脚本路径的情况下实现?我可以看到两种方法来做到这一点。第一种方法是对源Python文本文件进行哈希处理。 第二种方法是对已编译的字节码进行哈希处理。
我认为自己会选择2,所以提出了其他几个问题:
答案 0 :(得分:6)
python脚本可以通过以下方式找出自己的路径:
import os
path = os.path.abspath(__file__)
之后您可以打开源文件并通过hashlib.md5
运行它。
脚本文件没有编译的字节码文件;只有模块才能。
请注意,在Python 2中,__file__
路径使用实际加载的文件的扩展名;对于模块,只有在准备好重用的缓存字节码文件时才会.pyc
或.pyo
。如果Python必须编译字节码,那么.py
要么是因为没有字节码文件,要么是因为字节码文件是陈旧的。
您必须考虑使用命令行开关调用您的代码,这些开关会改变Python加载的字节码;如果给出-O
或-OO
开关,或者设置了PYTHONOPTIMIZE
环境标志,则Python将加载或编译为.pyo
文件。
答案 1 :(得分:1)
一种可能的(未经测试的)解决方案是使用反汇编程序模块dis.dis()
将python类或模块(但不是实例)转换为汇编语言。具有不同的两个相同编写的类将显示相同,但可以通过在通过md5运行组合字符串之前添加cls.__name__
来修复此问题
注意dis.dis()
打印到stdout而不是返回一个字符串,因此还添加了使用StringIO捕获打印输出的步骤
_
_ >>> import dis, md5
_ >>> class A(object):
_ ... def __init__(self, item): print "A(%s)" % item
_ ...
_ >>> dis.dis(A)
_ Disassembly of __init__:
_ 2 0 LOAD_CONST 1 ('A(%s)')
_ 3 LOAD_FAST 1 (item)
_ 6 BINARY_MODULO
_ 7 PRINT_ITEM
_ 8 PRINT_NEWLINE
_ 9 LOAD_CONST 0 (None)
_ 12 RETURN_VALUE
_
_ >>> class B(A):
_ ... def __init__(self, item): super(A, cls).__init__(item); print "B(%s)" % item
_ ...
_ >>> dis.dis(B)
_ Disassembly of __init__:
_ 2 0 LOAD_GLOBAL 0 (super)
_ 3 LOAD_GLOBAL 1 (A)
_ 6 LOAD_GLOBAL 2 (cls)
_ 9 CALL_FUNCTION 2
_ 12 LOAD_ATTR 3 (__init__)
_ 15 LOAD_FAST 1 (item)
_ 18 CALL_FUNCTION 1
_ 21 POP_TOP
_ 22 LOAD_CONST 1 ('B(%s)')
_ 25 LOAD_FAST 1 (item)
_ 28 BINARY_MODULO
_ 29 PRINT_ITEM
_ 30 PRINT_NEWLINE
_ 31 LOAD_CONST 0 (None)
_ 34 RETURN_VALUE
_
_ >>> class Capturing(list):
_ ... def __enter__(self):
_ ... self._stdout = sys.stdout
_ ... sys.stdout = self._stringio = StringIO()
_ ... return self
_ ... def __exit__(self, *args):
_ ... self.extend(self._stringio.getvalue().splitlines())
_ ... del self._stringio # free up some memory
_ ... sys.stdout = self._stdout
_ ...
_ >>> with Capturing() as dis_output: dis.dis(A)
_ >>> A_md5 = md5.new(A.__name__ + "\n".join(dis_output)).hexdigest()
_ '7818f1864b9cdf106b509906813e4ff8'