from fastcore.basics import patch, patch_to
from dataclasses import dataclass
@dataclass
class TestOne:
a:int
#----------------------
def f1_test(x):
print(x)
#----------------------
f1_test("before patch") # returns before patch
#----------------------
@patch
def f1_test(self: TestOne, x ):
x="88"
f1_test(x)
x = "99"
f1_test(x)
#----------------------
f1_test("after patch") # fails with TypeError: 'NoneType' object is not callable
#----------------------
t1=TestOne(123)
#----------------------
t1.f1_test("abc")
I get
before patch
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[657], line 24
22 f1_test(x)
23 #----------------------
---> 24 f1_test("after patch")
25 #----------------------
26 t1=TestOne(123)
TypeError: 'NoneType' object is not callable
The same happens if I use
@patch
def f1_test(self:TestOne, x):
or
@patch_to(TestOne)
def f1_test(self, x):
Can someone explain why the original function gets deleted? (is the explanation below true?)
The original function f1_test gets deleted because the @patch decorator from fastcore dynamically injects the function into the class (TestOne) as a method and returns None. This overrides the global f1_test reference, effectively replacing it with None, which makes the original function no longer callable.
Why the Original Function Gets Deleted
The @patch decorator dynamically injects f1_test into the TestOne class as a method. During this process, @patch overrides the global f1_test name by reassigning it internally. Even though it may not explicitly return None, it effectively removes the original standalone function from the global namespace by binding f1_test exclusively to the class. Thus, the global f1_test becomes unusable.
The explanation you’ve provided is largely correct. When you use the @patch decorator from fastcore, it modifies the function in such a way that it becomes a method of the class TestOne. Here’s a detailed breakdown of what’s happening: wellnow com
Decorator Usage: The @patch decorator is intended to add methods to classes. When you use @patch on f1_test, it converts f1_test into a method of TestOne.
Global Function Replacement: During this process, the global reference to f1_test is replaced by the modified function intended for the class. As a result, the original standalone function f1_test is effectively removed from the global namespace.
Resulting inNoneTypeError: Since the global f1_test reference now points to None (due to the internal workings of the @patch decorator), attempting to call f1_test("after patch") results in a TypeError: 'NoneType' object is not callable.
Here’s how you might correct your approach to avoid this issue:
Rename the Method: To avoid confusion, you can rename the patched method so it doesn’t conflict with the global function name.
Explicit Method Call: Ensure you are calling the correct method associated with the class instance.
Here’s an example:
from fastcore.basics import patch
from dataclasses import dataclass
@dataclass
class TestOne:
a: int
# Original standalone function
def f1_test(x):
print(x)
# Test the standalone function
f1_test("before patch") # prints "before patch"
# Patch method with a different name to avoid conflict
@patch
def patched_f1_test(self: TestOne, x):
x = "88"
f1_test(x)
x = "99"
f1_test(x)
# Test the standalone function again
f1_test("after patch") # prints "after patch"
# Create an instance of TestOne and call the patched method
t1 = TestOne(123)
t1.patched_f1_test("abc")
This way, you maintain the original standalone function f1_test while also adding a method patched_f1_test to the TestOne class without causing name conflicts.