LoginSignup
1
1

More than 3 years have passed since last update.

飛び越えモンキーパッチ

Last updated at Posted at 2021-04-13

はじめに

既存のパッケージを少しだけ変えて使いたい。そんなときに役に立つのがモンキーパッチです。今回はモンキーパッチをする際にハマってしまったことがあるので、その理由と解決策を記載しておこうと思います。

ハマったこと

モンキーパッチをしても、メソッドが上書きできない。それが今回のハマったことです。状況を簡潔に再現するためにA.py, B.pyを以下のようなファイルとします。

A.py
def func_a(i):
    return i
B.py
from A import func_a 

def func_b(i):
    return func_a(i)

要するにA.pyで作ったメソッドをB.pyにimportして使用しています。このとき、実行結果は以下のようになります。

main.py
import B 

print(B.func_b(1))
#実行結果:1

ここまでは特に問題なく動きます。さて、ここでfunc_aをモンキーパッチによって上書きします。

main2.py
import A
import B

#上書きするメソッド
def func_a_alt(i):
     return 10*i

#モンキーパッチ!
A.func_a = func_a_alt

print(func_c(1))
#A.func_aをfunc_a_altで上書きしたから10が表示されるはず!
#実行結果:1

func_aをfunc_a_altで上書きしようとしたのにうまくいきませんでした。なぜだ...?

原因

原因はB.pyで

from A import func_a

をしていたことでした。これをすると、元々A.pyで定義したfunc_aと別のメモリに新しくfunc_aが記録されるみたいです。したがって、main2.pyを実行すると以下のような現象が起きます。

main2(解説つき).py
import A
import B #B.pyのfunc_aがA.pyのfunc_aとは別のメモリにできる

#上書きするメソッド
def func_a_alt(i):
     return 10*i

#モンキーパッチ!
A.func_a = func_a_alt #A.pyのfunc_aだけ上書きされる

print(func_b(1)) #B.pyのfunc_aは上書きされていないから上書きされる前のメソッドが呼び出される
#実行結果:1

解決策

解決策は意外と簡単で、A.pyのfunc_aを上書きしたあとにB.pyを実行(import)するだけです。

main3.py
import A
#ここではBをimportしない

#上書きするメソッド
def func_a_alt(i):
     return 10*i

#モンキーパッチ!
A.func_a = func_a_alt #A.pyのfunc_aが上書きされる

import B #B.pyのfunc_aが上書きされた状態でimportされる

print(func_b(1)) 
#実行結果:10
#無事にモンキーパッチできました!

終わりに

モンキーパッチをする際には

  • おおもとのメソッドを上書きする
  • 他の.pyからメソッドを呼び出す前に上書きする

この2点を気を付ける必要があるようです。今回は簡単なスクリプトで再現しましたが、私は既存のパッケージに対してモンキーパッチしようとしてはまりました。私のハマり経験が何かのお役に立てれば嬉しいです!

1
1
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
1