I want to do a monkey patch only partially safely in Python

What is monkey patch?

Monkey patches extend or modify dynamic language (eg Smalltalk, JavaScript, Objective-C, Ruby, Perl, Python, Groovy, etc.) code at runtime without modifying the original source code. How to do it.

[Wiki reference](https://ja.wikipedia.org/wiki/%E3%83%A2%E3%83%B3%E3%82%AD%E3%83%BC%E3%83%91%E3% 83% 83% E3% 83% 81)

Subject

Round is no longer rounded in Python 3

print round(2.5) # => 3.0
print(round(2.5)) # => 2

It seems that the round function is treated as a floating point number from python3. So that you can use this by rounding !!

Rounding code

def custom_round(x, d=0):
    import math
    p = 10 ** d
    return float(math.floor((x * p) + math.copysign(0.5, x)))/p
print(custom_round(2.5)) #=> 3.0

Reference URL

↓ ↓ I want to write like this ↓ ↓

sample.py


import setting
print(round(2.5)) #=> 3.0

Generate setting.py

1. For the time being, monkey patch

setting.py


import builtins #Built-in functions are in builtins
def custom_round(x, d=0):
    import math
    p = 10 ** d
    return float(math.floor((x * p) + math.copysign(0.5, x)))/p
builtins.round = custom_round # monkey patch

sample.py


import setting
print(round(2.5)) #=> 3.0
I thought it was a success because it was displayed

sample.py


import setting
print(round(2.5)) #=> 3.0
import sample2

sample2.py


print(round(2.5)) #=> 3.0
=> Not safe !!!!?

2. Hook the caller's namespace from the stack trace

python


import inspect, imp
import builtins
def custom_round(x, d=0):
    import math
    p = 10 ** d
    return float(math.floor((x * p) + math.copysign(0.5, x)))/p

frame = [frame for (frame, filename, _, _, _,_) in 
             inspect.getouterframes(inspect.currentframe())[1:] 
                 if not 'importlib' in filename and not __file__ in filename][0]
        #Because import lib may be used for fetching and importing the caller.
frame.f_locals['round'] = custom_round

sample.py


import setting
print(round(2.5)) #=> 3.0
import sample2

sample2.py


print(round(2.5)) #=> 2

Last line replacement.py


# ${module} :Target module, ${function} :Target function
replacing = imp.load_module('temp', *imp.find_module(${module}))
setattr(replacing, '${function}', ${custom function})
frame.f_locals[${module}] = replacing
I wonder if the File was separated ... The setting process is not performed in sample2 ...

sample.py


import setting
print(round(2.5)) #=> 3.0
import sample2

sample2.py


import setting
print(round(2.5)) #=> 2

=> The module imported once is retained in sys.modules, and in the second import, it is referenced from sys.module and the code is not called.

3. Replace builtins.import directly and call the monkey patch function at the time of import.

setting.py


import inspect, imp
import builtins
def custom_round(x, d=0):
    import math
    p = 10 ** d
    return float(math.floor((x * p) + math.copysign(0.5, x)))/p

def hooking():
    frame = [frame for (frame, filename, _, _, _,_) in 
             inspect.getouterframes(inspect.currentframe())[1:] 
                 if not 'importlib' in filename and not __file__ in filename][0]
        #Because import lib may be used for fetching and importing the caller.
    frame.f_locals['round'] = custom_round

class Importer(object):
    old_import = __import__
    def new_import(self, *args, **kwargs):
        if args[0] == __name__: hooking() 
        return self.old_import(*args, **kwargs)

hooking()
import builtins
builtins.__import__ = Importer().new_import

sample.py


import setting
print(round(2.5)) #=> 3.0
import sample2

sample2.py


import setting
print(round(2.5)) #=> 3.0

Summary

Finally, I was able to implement a monkey patch only with the module where the import setting is written.

Recommended Posts

I want to do a monkey patch only partially safely in Python
I want to do Dunnett's test in Python
I want to create a window in Python
I want to embed a variable in a Python string
I want to write in Python! (2) Let's write a test
I want to randomly sample a file in Python
I want to do something in Python when I finish
I want to do something like sort uniq in Python
I want to make input () a nice complement in python
I want to print in a comprehension
I want to build a Python environment
I want to solve APG4b with Python (only 4.01 and 4.04 in Chapter 4)
I want to do a full text search with elasticsearch + python
[Python / AWS Lambda layers] I want to reuse only module in AWS Lambda Layers
I want to make a game with Python
I want to convert a table converted to PDF in Python back to CSV
I want to merge nested dicts in Python
I want to color a part of an Excel string in Python
I want to write to a file with Python
I want to display the progress in Python!
I want to create a priority queue that can be updated in Python (2.7)
Python program is slow! I want to speed up! In such a case ...
I want to iterate a Python generator many times
I want to generate a UUID quickly (memorandum) ~ Python ~
I want to transition with a button in flask
Even in JavaScript, I want to see Python `range ()`!
I tried to implement a pseudo pachislot in Python
[Python] I want to make a nested list a tuple
I want to write in Python! (3) Utilize the mock
I want to use the R dataset in python
I want to run a quantum computer with Python
I want to manipulate strings in Kotlin like Python!
[Python] I want to use only index when looping a list with a for statement
I want to use a python data source in Re: Dash to get query results
I want to save a file with "Do not compress images in file" set in OpenPyXL
I want to write a triple loop and conditional branch in one line in python
[Python] I want to get a common set between numpy
I want to start a lot of processes from python
I tried "How to get a method decorated in Python"
I want to send a message from Python to LINE Bot
I tried to make a stopwatch using tkinter in python
I want to be able to run Python in VS Code
[Python] How to do PCA in Python
I want to debug with Python
Do you want to wait for general purpose in Python Selenium?
What to do if you get a minus zero in Python
MacBookPro Setup After all I want to do a clean installation
I wrote a function to load a Git extension script in Python
I tried to implement a misunderstood prisoner's dilemma game in Python
If you want to assign csv export to a variable in python
I wanted to do something like an Elixir pipe in Python
[Introduction] I want to make a Mastodon Bot with Python! 【Beginners】
I wrote a script to extract a web page link in Python
I want to create a pipfile and reflect it in docker
I tried to implement PLSA in Python
I tried to implement permutation in Python
Do a non-recursive Euler Tour in Python
I made a payroll program in Python!
How to do R chartr () in Python
I tried to implement PLSA in Python 2
I want to use jar from python