がべーじこれくしょん

技術系とかいろいろ

Pythonで関数名から実装内容を出力する

執筆・創作活動への支援をぜひお願いします🙏
Buy Me A Coffee

TL;DR

  • inspectを使う
  • Jupyter Notebookでは、??func_name or func_name??で同様の結果を得られる。【情報提供元: @na90ya 様】

目的

「サンプルコードでしれっと使われてる関数の実装を知りたい」「でも元ソースを追うのはつらい」といったときがありました。

どうせなら、REPL上で簡単に確認できないものかと常々思ってました。

例えば、こんなソース

...
import tensorflow as tf

from nets.mobilenet import conv_blocks as ops
from nets.mobilenet import mobilenet as lib

slim = tf.contrib.slim
op = lib.op

expand_input = ops.expand_input_by_factor

# pyformat: disable
# Architecture: https://arxiv.org/abs/1801.04381
V2_DEF = dict(
    defaults={
        # Note: these parameters of batch norm affect the architecture
        # that's why they are here and not in training_scope.
        (slim.batch_norm,): {'center': True, 'scale': True},
        (slim.conv2d, slim.fully_connected, slim.separable_conv2d): {
            'normalizer_fn': slim.batch_norm, 'activation_fn': tf.nn.relu6
...

ここのtf.nn.relu6というメソッドが一体何をしているのか知りたい。大方予想はつくが、予想と違うと後々困る。

やり方

調べたら普通にありました。

ソース:https://stackoverflow.com/questions/427453/how-can-i-get-the-source-code-of-a-python-function

ここによると、inspectモジュールに、今回の用途を満たしてくれる機能が詰まってるようです。

今回は、単純に実装だけわかればいいので、inspectモジュールの中の、getsourceという関数を使用します。 これは、関数名を引数として与えることにより、実装内容を返してくれる関数のようです。

以下のような感じで使用することができます。

[musaprg@sylveon ~]$ python 
Python 3.6.8 |Anaconda custom (64-bit)| (default, Dec 30 2018, 01:22:34)
[GCC 7.3.0] on linux
Type "help", "copyright", "credits" o
>>> import tensorflow as tf
>>> lines = inspect.getsource(tf.nn.relu6)
>>> print(lines)
@tf_export("nn.relu6")
def relu6(features, name=None):
  """Computes Rectified Linear 6: `min(max(features, 0), 6)`.

  Source: [Convolutional Deep Belief Networks on CIFAR-10. A.
  Krizhevsky](http://www.cs.utoronto.ca/~kriz/conv-cifar10-aug2010.pdf)

  Args:
    features: A `Tensor` with type `float`, `double`, `int32`, `int64`, `uint8`,
      `int16`, or `int8`.
    name: A name for the operation (optional).

  Returns:
    A `Tensor` with the same type as `features`.
  """
  with ops.name_scope(name, "Relu6", [features]) as name:
    features = ops.convert_to_tensor(features, name="features")
    return gen_nn_ops.relu6(

もっと色々できるみたいですね。詳しくは公式docへ。

https://docs.python.jp/3/library/inspect.html

Jupyter Notebookの場合

Jupyter Notebookを使っている場合は、IPython自体にinspectモジュールと同様の出力を得られる構文が存在しました。

情報提供してくださった @na90ya 様、ありがとうございます!

やり方

調べたい関数名をfunc_nameとすると、以下のように記述することで、inspect.getsourceと同様の出力を得ることができます。

??func_name
func_name??

??は、目的の関数の前後どちらにつけても動作するみたいです。