LoginSignup
1
0

More than 5 years have passed since last update.

自由変数の値を変更する

Posted at

関数の自由変数(Free variable)とそれを調べる方法は、以前こちらの記事で紹介しましたが、自由変数の値を無理やり置換した関数を作るということをやってみました。
通常、そのようなことは出来ませんが、ctypesという標準モジュールを用いると、
CPythonのAPIにアクセス出来ます。
これを用いて自由変数の新しい値をラップするcellオブジェクトを作成し、自由変数の定義順にcellを並べたtupleが新しいclosureです。
types標準モジュールの中にFunctionType型が定義されており、最初の引数に元々の関数のコードオブジェクトと、closure引数に先ほど作成した新しいclosureを渡せば、元々の関数の自由変数の値は新しい値に置き換わっています。

もちろんCPythonだけに適用できる方法です。

import ctypes
from types import FunctionType

def outer():
    x, y = 1, 'y'     # 外側のスコープで定義
    def temp_func():
        return x, y   # 内側の関数では自由変数となる
    return temp_func


def _create_cell(value):   # valueの値を持つ新しいcellオブジェクトを作成

    PyCell_New = ctypes.pythonapi.PyCell_New
    PyCell_New.argtypes = (ctypes.py_object,)
    PyCell_New.restype = ctypes.py_object

    return PyCell_New(value)


def _create_closure(*values):   # 複数の値からcellのtupleを作る
    return tuple(_create_cell(val) for val in values)

closure = _create_closure(2, 'z')

func = outer() # 置換前の関数
altfunc = FunctionType(func.__code__, globals(), closure=closure) # 置換した関数を作成
実行結果

In[2]: func()
Out[2]: (1, 'y')

In[3]: altfunc()
Out[3]: (2, 'z')
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0