如何查看修饰函数的字节码?

2024-06-16 08:48:06 发布

您现在位置:Python中文网/ 问答频道 /正文

我想看看一个带修饰符的修饰函数的字节码。你知道吗

例如,在下面的示例中,fibonacci由memoized修饰。但是当我打电话给dis.dis公司在fibonacci上,这将显示实际函数的字节码。你知道吗

我想能够看到,如果一个函数已经装饰,并看到字节码包括装饰部分。你知道吗

我完全误解了什么概念吗?你知道吗

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)

Tags: the函数importselfcachereturn字节value
1条回答
网友
1楼 · 发布于 2024-06-16 08:48:06

实例上调用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__)为反汇编程序提供对未绑定或绑定方法的引用。你知道吗

由于decorating是语法糖,用于用传入的函数调用另一个对象,然后用结果替换该函数,因此不存在decoratior与原始函数一起反汇编的情况。最好的方法是分别分解decorator可调用函数和原始函数:

>>> 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。你知道吗

对于使用闭包的函数装饰器,您必须通过查看__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>

相关问题 更多 >