Make class method able to check if it has been called - python

Here is a nice way to make a function object self-aware and able to check if it has been called (per this answer):
def example():
example.has_been_called = True
pass
example.has_been_called = False
example()
#Actual Code!:
if example.has_been_called:
print("foo bar")
How can I translate this solution to a class instance method?
I have tried this:
class Example:
def method_one(self):
self.method_one.has_been_called = True
pass
def method_two(self):
self.method_two.has_been_called = True
pass
example = Example()
example.method_one()
#Actual Code!:
if example.method_one.has_been_called:
print("foo bar")
but I keep getting:
> Traceback (most recent call last): File "c:\python
> projects\dog\tests.py", line 8, in <module>
> example.run() File "c:\python projects\dog\tests.py", line 4, in run
> self.run.has_been_called = True AttributeError: 'method' object has no attribute 'has_been_called'

Instance methods are in fact members of the class. If you want to know whether an method has been called on a specific object, you should make the indicator a boolean member of the instance:
class Example:
has_been_called = False
def run(self):
self.has_been_called = True
After example = Example(), example.has_been_called will be true if and only if example.run() has been called
If you want to know whether the method has been called on any object, you should make the indicator a member of the class:
class Example:
has_been_called = False
def run(self):
Example.has_been_called = True # global
# self.__class__.has_been_called = True # per sub_class
Here Example.has_been_called (also accessible for any instance from Example) would be true if and only if it has been called on one instance. The difference between the global and per sub-class way only matters if you have subclasses.
For a class method, the method already receives a class object and not an instance, so it would be:
class Example:
has_been_called = False
#classmethod
def run(cls):
Example.has_been_called = True # global
# cls.has_been_called = True # per sub_class
Beware in the per sub-class way, the attribute is set on the subclass, so you should examine it only from an instance.
Even if it is possible, you would have no reason to set an attribute on the method itself. The code should be:
class Example:
has_been_called = False
def run(self):
Example.run.has_been_called = True
but it would be non Pythonic.

Create a dict to store the functions that have been run.
class Example:
def __init__(self):
self.has_been_called = {}
def run(self):
self.has_been_called["run"] = True
example = Example()
example.run()
#Actual Code!:
try:
if example.has_been_called["run"]:
print("foo bar")
except KeyError:
pass
If you comment example.run(), no error is raised.
Using a dictionary also allows you to apply the same process to other methods without creating a ton of variables.

Every use of self.run produces a new instance of method, not the actual function bound to Example.run. You need a reference to the actual function, which you can get through the special name __class__, which here will refer to the static class Example. You also need to ensure the attribute is initialized (though you don't need any special magic here; the name run is bound to an ordinary function at this point and doesn't need to be used as an attribute).
class Example:
def run(self):
__class__.run.has_been_called = True
run.has_been_called = False
If instead you want to update an override in a subclass, use type(self) instead of __class__.

As you want each instance to have its own has_been_called flag, then you shouldn't attempt to define has_been_called on the method, as the method exists on the class object, not on the instance (self).
Instead, define it as an attribute on the instance object (self). So just skip the .run part:
class Example:
def run(self):
self.has_been_called = True
example = Example()
example.run()
#Actual Code!:
if example.has_been_called:
print("foo bar")
If you want to have a separate flag for each method, then use a dictionary:
from collections import defaultdict
class Example:
def __init__(self):
self.has_been_called = defaultdict(bool)
def run(self):
self.has_been_called["run"] = True
example = Example()
example.run()
if example.has_been_called["run"]:
print("foo bar")

Don't use .'s in variable names:
class Example:
def method_one(self):
self.method_one_has_been_called = True
def method_two(self):
self.method_two_has_been_called = True
example = Example()
example.method_one()
#Actual Code!:
if example.method_one_has_been_called:
print("foo bar")
Output:
foo bar

Related

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

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)

How to define a callable that can only be called once?

To demonstrate what I want to do, here's a piece of code:
class CallOnce(object):
called=False
def web_service(cls,macid):
if cls.called:
print ("already called")
return
else:
# do stuff
print ("called once")
cls.called = True
return macid
To test our class, I proceed as follows:
for i in range(2):
macid = "123"
call_once_object = CallOnce()
call = call_once_object.web_service(macid)
print(call)
The expected result should be like this:
called once
123
already called
Except I got this as a result:
called once
123
called once
123
The idea is to store the value 123 only once in the call variable without using global variable.
cls.called is an attribute of the instance, not the class. Each time you create a new object, it gets its own attribute, which defaults to False.
If you want to share this among all the instances, you should use CallOnce.called, not cls.called.
BTW, the conventional name for the first argument of instance methods is self. cls is used for class methods.
So you're trying to save some state. What you could do is use an object instead.
class Test():
def __init__(self):
self.called = False
def call_me_maybe(self):
if (not self.called):
print('Hey, you called?')
self.called = True
else:
print("Stop calling me it's getting weird")
test = Test()
test.call_me_maybe() #-> Hey, you called?
test.call_me_maybe() #-> Stop calling me it's getting weird
You don't need a class for this. Functions can have their own attributes.
def web_service(macid):
if hasattr(web_service, 'called'):
print ("already called")
return
else:
# do stuff
print ("called once")
web_service.called = True
return macid
web_service(5)
web_service(6)
Output:
called once
already called

Self Attributes Live in Function Pointer?

Suppose I have a simple python3 class like so:
class Test():
def __init__(self):
self.a = 'a'
def checkIsA(self, checkA):
return self.a == checkA
And some further code such as:
def tester(func, item):
return func(item)
testObject = Test()
print(tester(testObject.checkIsA, 'a')) # prints True
How is the function pointer(?) checkIsA still aware of its class member variables (defined by self) when used independently by another function?
I want to use this functionality in a program I'm writing but I'm worried I'm not understanding these semantics correctly.
testObject.checkIsA is what's called a bound method - it remembers the instance it was taken from so that its self attribute gets automatically populated by that instance.
You can easily check a difference between a class function (unbound method) and an instance method (bound method), Python will quite happily tell you all the details:
testObject = Test()
print(Test.checkIsA) # <function Test.checkIsA at 0x00000000041236A8>
print(testObject.checkIsA) # <bound method Test.checkIsA of
# <__main__.Test object at 0x0000000004109390>>
You can simulate a call to testObject.checkIsA() directly through the unbound Test.checkIsA function by passing your instance, too, e.g.:
def tester(func, instance, item):
return func(instance, item)
testObject = Test()
print(tester(Test.checkIsA, testObject, 'a')) # prints True
Or, with functools.partial:
import functools
def tester(func, item):
return func(item)
testObject = Test()
print(tester(functools.partial(Test.checkIsA, testObject), 'a')) # prints True
And that's exactly what a bound instance method does for you in the back by supplementing the first self attribute with its stored __self__ value. You can check that, too:
testObject = Test()
print(testObject.checkIsA.__self__ is testObject) # True

Why don't a singleton-shaped Thread-subclass instance's attributes of type Event return the same value?

I have this part of code:
from threading import Thread, Event
class mySubThread(Thread):
instance = []
def __new__(cls):
if not cls.instance:
cls.instance.append(object.__new__(cls))
return cls.instance[0]
def __init__(self):
self.enabled = Event()
self.exit = Event()
Thread.__init__(self)
def run(self):
while self.enabled.wait():
if self.exit.is_set():
break
# ... boring useful stuff ...
enable = lambda self: self.enabled.set()
disable = lambda self: self.enabled.clear()
def quit(self):
self.enabled.set()
self.exit.set()
When I set attributes which are instances of class Event, I get different values from their method .is_set() whether I take the attribute from mySubThread() or a name which is initialised as equal to it. And if I get the method from mySubThread(), then, from the named one, I see the value obtained is then equal to mySubThread.attr.is_set(). To make it more clear (even to me, what I wrote seems a bit confused), I have:
>>> named = mySubThread()
>>> named.enabled.is_set()
False
>>> named.enable()
>>> named.enabled.is_set()
True
>>> named is mySubThread()
True
>>> mySubThread().enabled.is_set()
False
>>> named.enabled.is_set()
False
While mySubThread().enable() sets x.enabled.is_set() to True, mySubThread().enabled.is_set() is always False.
Does anyone know if I did anything wrong, or is it a bug in Python?
I work on OS X.9.1 with Python 3.3.3 and GCC 4.2.1.
__init__ is called on the object returned from __new__. When you call mySubThread() the second time, your __new__ returns a reference to the named object, and your __init__ overwrites its attributes.

Python : Assert that variable is instance method?

How can one check if a variable is an instance method or not? I'm using python 2.5.
Something like this:
class Test:
def method(self):
pass
assert is_instance_method(Test().method)
inspect.ismethod is what you want to find out if you definitely have a method, rather than just something you can call.
import inspect
def foo(): pass
class Test(object):
def method(self): pass
print inspect.ismethod(foo) # False
print inspect.ismethod(Test) # False
print inspect.ismethod(Test.method) # True
print inspect.ismethod(Test().method) # True
print callable(foo) # True
print callable(Test) # True
print callable(Test.method) # True
print callable(Test().method) # True
callable is true if the argument if the argument is a method, a function (including lambdas), an instance with __call__ or a class.
Methods have different properties than functions (like im_class and im_self). So you want
assert inspect.ismethod(Test().method)
If you want to know if it is precisely an instance method use the following function. (It considers methods that are defined on a metaclass and accessed on a class class methods, although they could also be considered instance methods)
import types
def is_instance_method(obj):
"""Checks if an object is a bound method on an instance."""
if not isinstance(obj, types.MethodType):
return False # Not a method
if obj.im_self is None:
return False # Method is not bound
if issubclass(obj.im_class, type) or obj.im_class is types.ClassType:
return False # Method is a classmethod
return True
Usually checking for that is a bad idea. It is more flexible to be able to use any callable() interchangeably with methods.

Categories