Python脚本是否可以自行进行md5哈希?

Python脚本是否可以自行进行md5哈希?,python,hash,Python,Hash,我希望能够在每次运行时对其自身进行哈希。这是否可能,而不必给出脚本的路径?我有两种方法可以做到这一点。第一种方法是散列源Python文本文件。 第二种方法是散列编译的字节码 我认为自己选择了第二条,因此提出了几个其他问题: 脚本能否确定其编译的字节码在脚本中的位置 我会在另一个问题中问这个问题 python脚本可以通过以下方式找到自己的路径: import os path = os.path.abspath(__file__) 之后,您可以打开源文件并通过hashlib.md5运行它 脚本文

我希望能够在每次运行时对其自身进行哈希。这是否可能,而不必给出脚本的路径?我有两种方法可以做到这一点。第一种方法是散列源Python文本文件。 第二种方法是散列编译的字节码

我认为自己选择了第二条,因此提出了几个其他问题:

  • 脚本能否确定其编译的字节码在脚本中的位置
  • 我会在另一个问题中问这个问题

  • python脚本可以通过以下方式找到自己的路径:

    import os
    
    path = os.path.abspath(__file__)
    
    之后,您可以打开源文件并通过
    hashlib.md5
    运行它

    脚本文件没有编译的字节码文件;只有模块可以

    注意,在Python2中,
    \uuuu file\uuu
    路径使用实际加载的文件的扩展名;对于模块,只有当缓存的字节码文件准备好重用时,才使用
    .pyc
    .pyo
    。如果Python必须编译字节码,那就是
    .py
    ,要么因为没有字节码文件,要么因为字节码文件过时

    您必须考虑到您的代码是通过命令行开关调用的,这些开关改变了Python加载的字节码;如果给出了
    -O
    -OO
    开关,或者设置了
    PYTHONOPTIMIZE
    环境标志,Python将加载或编译为
    .pyo
    文件。

    一个可能的(未测试的)解决方案是使用反汇编程序模块
    dis.dis()
    转换Python类或模块(但不是实例)转换成汇编语言。两个具有不同类名的相同编写的类将显示为相同的,但这可以通过在通过md5运行组合字符串之前添加
    cls.\uu\u name\uu
    来解决

    注意
    dis.dis()

    _


    我必须等20分钟才能发布第二个问题。这是为了什么?我想知道Python脚本是否发生了变化。选项1是最保守的,因为缩进(空格到制表符)的更改不会影响脚本的语法结构,也不会改变脚本的行为。选项2正在对编译的字节码文件进行md5哈希。也许有一些我不知道的解决方案?另请参见:如果脚本没有编译过的字节码文件,那么就无法使用选项2。
    _ >>> 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'