【问题标题】:How can I see the bytecode of a decorated function?如何查看修饰函数的字节码?
【发布时间】:2016-03-06 15:55:47
【问题描述】:

我想查看带有装饰器的装饰函数的字节码。

例如在下面的例子中,斐波那契是由 memoized 修饰的。但是,当我在斐波那契上调用“dis.dis”时,这将显示实际函数的字节码。

我希望能够查看一个函数是否已被装饰,并查看包含装饰部分的字节码。

我是不是完全误解了一些概念?

import collections
import functools

class memoized(object):
   '''Decorator. Caches a function's return value each time it is called.
   If called later with the same arguments, the cached value is returned
   (not reevaluated).
   '''
   def __init__(self, func):
      self.func = func
      self.cache = {}

   def __call__(self, *args):
      if not isinstance(args, collections.Hashable):
         # uncacheable. a list, for instance.
         # better to not cache than blow up.
         return self.func(*args)
      if args in self.cache:
         print 'get cached version{}'.format(args)
         return self.cache[args]
      else:
         print 'compute {}'.format(args)
         value = self.func(*args)
         self.cache[args] = value
         return value

   def __repr__(self):
      '''Return the function's docstring.'''
      return self.func.__doc__

   def __get__(self, obj, objtype):
      '''Support instance methods.'''
      return functools.partial(self.__call__, obj)

@memoized
def fibonacci(n):
   "Return the nth fibonacci number."
   if n in (0, 1):
      return n
   return fibonacci(n-1) + fibonacci(n-2)

print fibonacci(12)

import dis
f = fibonacci
dis.dis(f)

【问题讨论】:

    标签: python bytecode disassembly


    【解决方案1】:

    您正在一个实例上调用dis.dis()memoized 装饰器是一个类,memoized(function) 返回该类的一个实例。

    例如,instance.__dict__ 对象的值中的所有代码或函数对象都被反汇编(因为dis() 函数假定它正在处理一个类)。由于原始函数是代码对象,因此将其反汇编。就好像你打电话给dis.dis(f.func);这就是为什么dis.dis() 输出以Disassembly of func 行开头的原因。

    如果您想显示memoized.__call__ 方法的字节码,您必须在memoized 类上调用dis.dis()(并查看__init____call__ 的反汇编),或者反汇编直接使用memoized.__call__ 方法,通过使用dis.dis(memoized.__call__)dis.dis(fibonacci.__call__) 为反汇编程序提供对未绑定或绑定方法的引用。

    由于装饰只是语法糖,用于调用传入函数的另一个对象,然后用结果替换该函数,因此不存在将装饰器与原始函数一起反汇编的事情.你能做的最好的就是分别反汇编可调用的装饰器和原始函数:

    >>> dis.dis(fibonacci.__call__)
     15           0 LOAD_GLOBAL              0 (isinstance)
                  3 LOAD_FAST                1 (args)
                  6 LOAD_GLOBAL              1 (collections)
                  9 LOAD_ATTR                2 (Hashable)
                 12 CALL_FUNCTION            2
                 15 POP_JUMP_IF_TRUE        31
    
     18          18 LOAD_FAST                0 (self)
                 21 LOAD_ATTR                3 (func)
                 24 LOAD_FAST                1 (args)
                 27 CALL_FUNCTION_VAR        0
                 30 RETURN_VALUE
    
     19     >>   31 LOAD_FAST                1 (args)
                 34 LOAD_FAST                0 (self)
                 37 LOAD_ATTR                4 (cache)
                 40 COMPARE_OP               6 (in)
                 43 POP_JUMP_IF_FALSE       71
    
     20          46 LOAD_CONST               1 ('get cached version{}')
                 49 LOAD_ATTR                5 (format)
                 52 LOAD_FAST                1 (args)
                 55 CALL_FUNCTION            1
                 58 PRINT_ITEM
                 59 PRINT_NEWLINE
    
     21          60 LOAD_FAST                0 (self)
                 63 LOAD_ATTR                4 (cache)
                 66 LOAD_FAST                1 (args)
                 69 BINARY_SUBSCR
                 70 RETURN_VALUE
    
     23     >>   71 LOAD_CONST               2 ('compute {}')
                 74 LOAD_ATTR                5 (format)
                 77 LOAD_FAST                1 (args)
                 80 CALL_FUNCTION            1
                 83 PRINT_ITEM
                 84 PRINT_NEWLINE
    
     24          85 LOAD_FAST                0 (self)
                 88 LOAD_ATTR                3 (func)
                 91 LOAD_FAST                1 (args)
                 94 CALL_FUNCTION_VAR        0
                 97 STORE_FAST               2 (value)
    
     25         100 LOAD_FAST                2 (value)
                103 LOAD_FAST                0 (self)
                106 LOAD_ATTR                4 (cache)
                109 LOAD_FAST                1 (args)
                112 STORE_SUBSCR
    
     26         113 LOAD_FAST                2 (value)
                116 RETURN_VALUE
                117 LOAD_CONST               0 (None)
                120 RETURN_VALUE
    >>> dis.dis(fibonacci.func)
     39           0 LOAD_FAST                0 (n)
                  3 LOAD_CONST               4 ((0, 1))
                  6 COMPARE_OP               6 (in)
                  9 POP_JUMP_IF_FALSE       16
    
     40          12 LOAD_FAST                0 (n)
                 15 RETURN_VALUE
    
     41     >>   16 LOAD_GLOBAL              0 (fibonacci)
                 19 LOAD_FAST                0 (n)
                 22 LOAD_CONST               2 (1)
                 25 BINARY_SUBTRACT
                 26 CALL_FUNCTION            1
                 29 LOAD_GLOBAL              0 (fibonacci)
                 32 LOAD_FAST                0 (n)
                 35 LOAD_CONST               3 (2)
                 38 BINARY_SUBTRACT
                 39 CALL_FUNCTION            1
                 42 BINARY_ADD
                 43 RETURN_VALUE
    

    您可以从 fibonacci.__call__ 反汇编中看到它会调用 self.func()(字节码 18 到 27),这就是为什么您会查看 fibonacci.func

    对于使用闭包的 function 装饰器,您必须通过查看 __closure__ 对象进入包装闭包以提取原始函数:

    >>> def memoized(func):
    ...    cache = {}
    ...    def wrapper(*args):
    ...       if not isinstance(args, collections.Hashable):
    ...          # uncacheable. a list, for instance.
    ...          # better to not cache than blow up.
    ...          return func(*args)
    ...       if args in cache:
    ...          print 'get cached version{}'.format(args)
    ...          return cache[args]
    ...       else:
    ...          print 'compute {}'.format(args)
    ...          value = func(*args)
    ...          cache[args] = value
    ...          return value
    ...    return wrapper
    ...
    >>> @memoized
    ... def fibonacci(n):
    ...    "Return the nth fibonacci number."
    ...    if n in (0, 1):
    ...       return n
    ...    return fibonacci(n-1) + fibonacci(n-2)
    ...
    >>> fibonacci.__closure__
    (<cell at 0x1035ed590: dict object at 0x103606d70>, <cell at 0x1036002f0: function object at 0x1035fe9b0>)
    >>> fibonacci.__closure__[1].cell_contents
    <function fibonacci at 0x1035fe9b0>
    

    【讨论】:

      猜你喜欢
      • 2019-07-29
      • 2013-06-22
      • 1970-01-01
      • 2011-04-18
      • 2011-11-03
      • 1970-01-01
      • 2022-01-10
      相关资源
      最近更新 更多