override a method of a class with an method from another class - python

I have following code:
class SomeClass:
def __init__(self) -> None:
pass
def some_class_function(self, par):
print(par)
class SomeOtherClass:
def __init__(self) -> None:
pass
def some_other_class_function(self, par):
print(par+1)
if __name__ == "__main__":
sc = SomeClass()
sc.some_class_function = SomeOtherClass.some_other_class_function
sc.some_class_function(1)
When I execute the code I get
TypeError: some_other_class_function() missing 1 required positional argument: 'par'
How can I override the method of the first class with the method of the second class properly?

As you have noted in the comments, you are interested in adding method that will use sc as the "self" instance.
To that end, see this post. To summarize, you can either add a function to the class definition (affecting future instances of the same class), or bind the function to the particular instance.
As an example, consider the following class and function.
class Test():
def __init__(self):
self.phrase = "hello world"
def func(self):
print("this is the old method")
def test_func(self):
print(self.phrase)
For the first approach, we could do the following
test = Test()
Test.func = test_func
test.func()
Note that future instances of Test will have this function as an attribute. For example, running Test().func() will still result in the same output, even though the method is being used on a new class instance.
For the second, we could do the following.
import types
test = Test()
test.func = types.MethodType(test_func, test)
test.func()
In this case, running the line Test().func() will result in the output "this is the old method" because func has not been overwritten for new instances.

You need to initialize the class to call its method.
sc = SomeClass()
sco = SomeOtherClass() # initialize the second call to call it's method
sc.some_class_function = sco.some_other_class_function
sc.some_class_function(1)

Related

How to call functions in class from another file in python [duplicate]

I have some code like:
class Pump:
def __init__(self):
print("init")
def getPumps(self):
pass
p = Pump.getPumps()
print(p)
But I get an error like:
Traceback (most recent call last):
File "C:\Users\Dom\Desktop\test\test.py", line 7, in <module>
p = Pump.getPumps()
TypeError: getPumps() missing 1 required positional argument: 'self'
Why doesn't __init__ seem to be called, and what does this exception mean? My understanding is that self is passed to the constructor and methods automatically. What am I doing wrong here?
To use the class, first create an instance, like so:
p = Pump()
p.getPumps()
A full example:
>>> class TestClass:
... def __init__(self):
... print("in init")
... def testFunc(self):
... print("in Test Func")
...
>>> testInstance = TestClass()
in init
>>> testInstance.testFunc()
in Test Func
You need to initialize it first:
p = Pump().getPumps()
Works and is simpler than every other solution I see here :
Pump().getPumps()
This is great if you don't need to reuse a class instance. Tested on Python 3.7.3.
The self keyword in Python is analogous to this keyword in C++ / Java / C#.
In Python 2 it is done implicitly by the compiler (yes Python does compilation internally).
It's just that in Python 3 you need to mention it explicitly in the constructor and member functions. example:
class Pump():
# member variable
# account_holder
# balance_amount
# constructor
def __init__(self,ah,bal):
self.account_holder = ah
self.balance_amount = bal
def getPumps(self):
print("The details of your account are:"+self.account_number + self.balance_amount)
# object = class(*passing values to constructor*)
p = Pump("Tahir",12000)
p.getPumps()
Adding a #classmethod decorator to the method allows for calling it like Pump.getPumps().
A class method receives the class as the implicit first argument, just like an instance method receives the instance.
class Pump:
def __init__(self):
print("init")
#classmethod
def getPumps(cls):
pass
You can also get this error by prematurely taking PyCharm's advice to annotate a method #staticmethod. Remove the annotation.
If skipping parentheses for the object declaration (typo), then exactly this error occurs.
# WRONG! will result in TypeError: getPumps() missing 1 required positional argument: 'self'
p = Pump
p.getPumps()
Do not forget the parentheses for the Pump object
# CORRECT!
p = Pump()
p.getPumps()
I got the same error below:
TypeError: test() missing 1 required positional argument: 'self'
When an instance method had self, then I called it directly by class name as shown below:
class Person:
def test(self): # <- With "self"
print("Test")
Person.test() # Here
And, when a static method had self, then I called it by object or directly by class name as shown below:
class Person:
#staticmethod
def test(self): # <- With "self"
print("Test")
obj = Person()
obj.test() # Here
# Or
Person.test() # Here
So, I called the instance method with object as shown below:
class Person:
def test(self): # <- With "self"
print("Test")
obj = Person()
obj.test() # Here
And, I removed self from the static method as shown below:
class Person:
#staticmethod
def test(): # <- "self" removed
print("Test")
obj = Person()
obj.test() # Here
# Or
Person.test() # Here
Then, the error was solved:
Test
In detail, I explain about instance method in my answer for What is an "instance method" in Python? and also explain about #staticmethod and #classmethod in my answer for #classmethod vs #staticmethod in Python.

How to create own class App without intersecion with Kivy App? [duplicate]

I have some code like:
class Pump:
def __init__(self):
print("init")
def getPumps(self):
pass
p = Pump.getPumps()
print(p)
But I get an error like:
Traceback (most recent call last):
File "C:\Users\Dom\Desktop\test\test.py", line 7, in <module>
p = Pump.getPumps()
TypeError: getPumps() missing 1 required positional argument: 'self'
Why doesn't __init__ seem to be called, and what does this exception mean? My understanding is that self is passed to the constructor and methods automatically. What am I doing wrong here?
To use the class, first create an instance, like so:
p = Pump()
p.getPumps()
A full example:
>>> class TestClass:
... def __init__(self):
... print("in init")
... def testFunc(self):
... print("in Test Func")
...
>>> testInstance = TestClass()
in init
>>> testInstance.testFunc()
in Test Func
You need to initialize it first:
p = Pump().getPumps()
Works and is simpler than every other solution I see here :
Pump().getPumps()
This is great if you don't need to reuse a class instance. Tested on Python 3.7.3.
The self keyword in Python is analogous to this keyword in C++ / Java / C#.
In Python 2 it is done implicitly by the compiler (yes Python does compilation internally).
It's just that in Python 3 you need to mention it explicitly in the constructor and member functions. example:
class Pump():
# member variable
# account_holder
# balance_amount
# constructor
def __init__(self,ah,bal):
self.account_holder = ah
self.balance_amount = bal
def getPumps(self):
print("The details of your account are:"+self.account_number + self.balance_amount)
# object = class(*passing values to constructor*)
p = Pump("Tahir",12000)
p.getPumps()
Adding a #classmethod decorator to the method allows for calling it like Pump.getPumps().
A class method receives the class as the implicit first argument, just like an instance method receives the instance.
class Pump:
def __init__(self):
print("init")
#classmethod
def getPumps(cls):
pass
You can also get this error by prematurely taking PyCharm's advice to annotate a method #staticmethod. Remove the annotation.
If skipping parentheses for the object declaration (typo), then exactly this error occurs.
# WRONG! will result in TypeError: getPumps() missing 1 required positional argument: 'self'
p = Pump
p.getPumps()
Do not forget the parentheses for the Pump object
# CORRECT!
p = Pump()
p.getPumps()
I got the same error below:
TypeError: test() missing 1 required positional argument: 'self'
When an instance method had self, then I called it directly by class name as shown below:
class Person:
def test(self): # <- With "self"
print("Test")
Person.test() # Here
And, when a static method had self, then I called it by object or directly by class name as shown below:
class Person:
#staticmethod
def test(self): # <- With "self"
print("Test")
obj = Person()
obj.test() # Here
# Or
Person.test() # Here
So, I called the instance method with object as shown below:
class Person:
def test(self): # <- With "self"
print("Test")
obj = Person()
obj.test() # Here
And, I removed self from the static method as shown below:
class Person:
#staticmethod
def test(): # <- "self" removed
print("Test")
obj = Person()
obj.test() # Here
# Or
Person.test() # Here
Then, the error was solved:
Test
In detail, I explain about instance method in my answer for What is an "instance method" in Python? and also explain about #staticmethod and #classmethod in my answer for #classmethod vs #staticmethod in Python.

define a decorator as method inside class

I'm trying to create a method inside my class that counts the complete run of a specific function. I want to use a simple decorator. I found this reference and rewrite this simple script:
class myclass:
def __init__(self):
self.cnt = 0
def counter(function):
"""
this method counts the runtime of a function
"""
def wrapper(self, **args):
function(**args)
self.counter += 1
return wrapper
#myclass.counter
def somefunc():
print("hello from somefunc")
if __name__ == "__main__":
obj = myclass()
# or if comment #myclass.counter
# somefunc = myclass.counter(somefunc)
somefunc()
And of course, I get:
TypeError: wrapper() missing 1 required positional argument: 'self'
I tried to rewrite the counter as a class method:
class myclass:
def __init__(self):
self.cnt = 0
def counter(self, function):
"""
this method counts the runtime of a function
"""
def wrapper(**args):
function(**args)
self.cnt += 1
return wrapper
def somefunc():
print("hello from somefunc")
if __name__ == "__main__":
obj = myclass()
somefunc = obj.counter(somefunc)
for i in range(10):
somefunc()
print(obj.cnt)
Which works fine but I think it is not a valid decorator definition. Is there any way to define the decorator inside the class method and pass the self-argument to its function? or defining a decorator inside a class is useless?
EDIT:------
First I can't define the decoration outside of the class method. Second I'm trying to make a scheduled class that runs a specific function (as input) for a fixed interval and a specific amount of time so I need to count it.
So I was able to draft up something for you, below is the code:
def count(func):
def wrapper(self):
TestClass.call_count += 1
func(self)
return wrapper
class TestClass(object):
call_count = 0
#count
def hello(self):
return 'hello'
if __name__ == '__main__':
x = TestClass()
for i in range(10):
x.hello()
print(TestClass.call_count)
Why would it cause problems to have the decorator in a class:
It's not straight forward to have a decorator function inside the class. The reasons are below:
Reason 1
Every class method must take an argument self which is the instance of the class through which the function is being called. Now if you make the decorator function take a self argument, the decorator call #count would fail as it get converted to count() which doesn't pass the self argument and hence the error:
TypeError: wrapper() missing 1 required positional argument: 'self'
Reason 2
Now to avoid that you can make your decorator as static by changing the declaration like below:
#staticmethod
def count(func):
pass
But then you have another error:
TypeError: 'staticmethod' object is not callable
Which means you can't have a static method as well. If you can't have a static method in a class, you have to pass the self instance to the method but if you pass the self instance to it, the #count decorator call wouldn't pass the self instance and hence it won't work.
So here is a blog that explains it quite well, the issues associated with it and what are the alternatives.
I personally prefer the option to have a helper class to hold all my decorators that can be used instead of the only class in which it's defined. This would give you the flexibility to reuse the decorators instead of redefining them which would follow the ideology
code once, reuse over and over again.
Your second code example is functionally equivalent to a standard decorator. The standard decorator syntax is just a shorthand for the same thing, namely, reassigning a function value equal to a closure (a function pointer with arguments predefined), where the closure is your decorator wrapper holding the original as its predefined argument.
Here's an equivalent with standard syntax. Notice you need to create the counter class instance in advance. The decorator syntax refers to that instance, because it must indicate the specific object which holds your counter, rather than just the class of the object:
class myclass:
def __init__(self):
self.cnt = 0
def counter(self,function):
"""
this method counts the number of runtime of a function
"""
def wrapper(**args):
function(self,**args)
self.cnt += 1
return wrapper
global counter_object
counter_object = myclass()
#counter_object.counter
def somefunc(self):
print("hello from somefunc")
if __name__ == "__main__":
for i in range(10):
somefunc()
print(counter_object.cnt)

How to unit test a method called within __init__() function?

I am trying to test a class method which is called within an__init__ function.
class abc:
def __init__(path):
list = []
foo(path)
bar('hello') # test function bar
def foo(self, path):
# does a bunch of stuff and creates internal list
list =
def bar(self):
# does a bunch of stuff and uses list
I would like to write a test for method bar here which I guess must be called through an instance of class abc. I can mock list array for this test, but cannot understand how to avoid the call to foo().
Just mock foo method for the time of testing bar. You can use patch.object.
A full example below:
import unittest
from unittest.mock import patch
class MyClass:
def __init__(self, path):
self.list = []
self.foo(path)
self.bar('/init')
def foo(self, path):
self.list.append(path)
def bar(self, path):
self.list.insert(0, path)
class MyTestClass(unittest.TestCase):
#patch.object(MyClass, 'foo')
def test_bar_decorated(self, mock):
a = MyClass('/foo')
a.bar('/bar')
self.assertEqual(a.list, ['/bar', '/init']) # .foo() wasn't invoked
if __name__ == '__main__':
unittest.main()
Notice that, a mock is created for you and passed in as an extra argument to the decorated function (we don't use it in this test). To avoid that you can use context manager version of patch.object:
def test_bar_context_manager(self):
with patch.object(MyClass, 'foo'):
a = MyClass('/foo')
a.bar('/bar')
self.assertEqual(a.list, ['/bar', '/init']) # same behaviour

How do you mock patch a python class and get a new Mock object for each instantiation?

OK,
I know this is mentioned in the manual, and probably has to do with side_effect and/or return_value, but a simple, direct example will help me immensely.
I have:
class ClassToPatch():
def __init__(self, *args):
_do_some_init_stuff()
def some_func():
_do_stuff()
class UUT():
def __init__(self, *args)
resource_1 = ClassToPatch()
resource_2 = ClassToPatch()
Now, I want to unit test the UUT class, and mock the ClassToPatch. Knowing the UUT class will instantiate exactly two ClassToPatch objects, I want the Mock framework to return a new Mock object for each instantiation, so I can later assert calls on each separately.
How do I achieve this using the #patch decorator in a test case? Namely, how to fix the following code sample?
class TestCase1(unittest.TestCase):
#patch('classToPatch.ClassToPatch',autospec=True)
def test_1(self,mock1,mock2):
_assert_stuff()
Here's a quick'n'dirty example to get you going:
import mock
import unittest
class ClassToPatch():
def __init__(self, *args):
pass
def some_func(self):
return id(self)
class UUT():
def __init__(self, *args):
resource_1 = ClassToPatch()
resource_2 = ClassToPatch()
self.test_property = (resource_1.some_func(), resource_2.some_func())
class TestCase1(unittest.TestCase):
#mock.patch('__main__.ClassToPatch', autospec = True)
def test_1(self, mock1):
ctpMocks = [mock.Mock(), mock.Mock()]
ctpMocks[0].some_func.return_value = "funky"
ctpMocks[1].some_func.return_value = "monkey"
mock1.side_effect = ctpMocks
u = UUT()
self.assertEqual(u.test_property, ("funky", "monkey"))
if __name__ == '__main__':
unittest.main()
I've added test_property to UUT so that the unit test does something useful. Now, without the mock test_property should be a tuple containing the ids of the two ClassToPatch instances. But with the mock it should be the tuple: ("funky", "monkey").
I've used the side_effect property of the mock object so that a different instance of ClassToPatch is returned on each call in the UUT initialiser.
Hope this helps.
Edit: Oh, by the way, when I run the unit test I get:
.
----------------------------------------------------------------------
Ran 1 test in 0.004s
OK
Here is another version which is more generic to handle any number of instances created:
class TestUUT:
def test_init(self, mocker):
class MockedClassToPatchMeta(type):
static_instance = mocker.MagicMock(spec=ClassToPatch)
def __getattr__(cls, key):
return MockedClassToPatchMeta.static_instance.__getattr__(key)
class MockedClassToPatch(metaclass=MockedClassToPatchMeta):
original_cls = ClassToPatch
instances = []
def __new__(cls, *args, **kwargs):
MockedClassToPatch.instances.append(
mocker.MagicMock(spec=MockedClassToPatch.original_cls))
MockedClassToPatch.instances[-1].__class__ = MockedClassToPatch
return MockedClassToPatch.instances[-1]
mocker.patch(__name__ + '.ClassToPatch', new=MockedClassToPatch)
UUT()
# since your original code created two instances
assert 2 == len(MockedClassToPatch.instances)
If you need more thorough validation for each instance you can access MockedClassToPatch.instances[0] or MockedClassToPatch.instances[1].
I've also created a helper library to generate the meta class boilerplate for me. To generate the needed code for your example I wrote:
print(PytestMocker(mocked=ClassToPatch, name=__name__).mock_classes().mock_classes_static().generate())

Categories