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

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

Related

Return class object after changing object variables

Im new to OOP in Python (and in general) and wondering about the correct way to change object variables. Since Python cant return void i need to return something when an object variable has changed.
class classA:
var_a = 1
var_b = 1
def changeSomething(classAObj):
classAObj.var_a = 2
return classAobj
def main()
classAObj = classA()
changeSomething(classAObj)
.....use object with new changes here....
Is it correct to return the entire classAObj in the changeSomething function? Or should i only return the variable i.e
...
return classAobj.var_a
I get the same result in either way, classAObj.var_a has changed in both cases, but what is the correct way to do it?
changeSomething should not return anything; when it modifies the argument in place, it should return nothing (implicitly None). Only functions that make new modified copies should return them (and leave the argument unmodified).
So your code should just be:
class classA:
def __init__(self):
self.var_a = 1 # You forget self here
self.var_b = 1 # You forget self here
def changeSomething(classAObj):
classAObj.var_a = 2 # Fix name, self wouldn't exist, you received it by a different name
def main():
classAObj = classA()
changeSomething(classAObj) # classAObj is modified in place, so changes seen in caller
# .....use object with new changes here....
Or, given this is a class, it makes sense to have changeSomething be an instance method, e.g.:
class classA:
def __init__(self):
self.var_a = 1 # You forget self here
self.var_b = 1 # You forget self here
# Indented to make it a method of the class
def changeSomething(self): # Argument renamed to follow standard naming for instance methods
self.var_a = 2
def main():
classAObj = classA()
classAObj.changeSomething() # Use method call syntax, classAObj still modified in place
# .....use object with new changes here....

Make class method able to check if it has been called

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

in python how to check object type inside a class for class comparison

I create a class in python and I would like to create a comparison method to compare instances of the same class.
As such:
class A():
def __init__(self,a):
self.var = a
def comparison(self,other):
if not isinstance(other,self): # <<--- ERROR HERE
raise Exception("You are not comparing apples to apples")
else:
if self.var==other.var:
print('we are equal')
else:
print('we are different')
This foes not fly.
The intended used would be like:
first = A(8)
second = A(9)
third = A(8)
fourth = ['whatever']
first.comparison(second) # should give "different"
first.comparison(third) # should give "equal"
first.comparison(fourth) # should raise error
the method comparison should raise an exception if the user passes something different than another instance of the same class, and make the comparison if they both are instances of the same class.
How to proceed?
Thx.
your instance is not self, but it is A.
If you change this line:
if not isinstance(other,self):
to this:
if not isinstance(other,A):
Or to this:
if not isinstance(other,type(self)):
it works fine.

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

Getting an instance name inside class __init__() [duplicate]

This question already has answers here:
Getting the name of a variable as a string
(32 answers)
Closed 3 years ago.
While building a new class object in python, I want to be able to create a default value based on the instance name of the class without passing in an extra argument. How can I accomplish this? Here's the basic pseudo-code I'm trying for:
class SomeObject():
defined_name = u""
def __init__(self, def_name=None):
if def_name == None:
def_name = u"%s" % (<INSTANCE NAME>)
self.defined_name = def_name
ThisObject = SomeObject()
print ThisObject.defined_name # Should print "ThisObject"
Well, there is almost a way to do it:
#!/usr/bin/env python
import traceback
class SomeObject():
def __init__(self, def_name=None):
if def_name == None:
(filename,line_number,function_name,text)=traceback.extract_stack()[-2]
def_name = text[:text.find('=')].strip()
self.defined_name = def_name
ThisObject = SomeObject()
print ThisObject.defined_name
# ThisObject
The traceback module allows you to peek at the code used to call SomeObject().
With a little string wrangling, text[:text.find('=')].strip() you can
guess what the def_name should be.
However, this hack is brittle. For example, this doesn't work so well:
ThisObject,ThatObject = SomeObject(),SomeObject()
print ThisObject.defined_name
# ThisObject,ThatObject
print ThatObject.defined_name
# ThisObject,ThatObject
So if you were to use this hack, you have to bear in mind that you must call SomeObject()
using simple python statement:
ThisObject = SomeObject()
By the way, as a further example of using traceback, if you define
def pv(var):
# stack is a list of 4-tuples: (filename, line number, function name, text)
# see http://docs.python.org/library/traceback.html#module-traceback
#
(filename,line_number,function_name,text)=traceback.extract_stack()[-2]
# ('x_traceback.py', 18, 'f', 'print_var(y)')
print('%s: %s'%(text[text.find('(')+1:-1],var))
then you can call
x=3.14
pv(x)
# x: 3.14
to print both the variable name and its value.
Instances don't have names. By the time the global name ThisObject gets bound to the instance created by evaluating the SomeObject constructor, the constructor has finished running.
If you want an object to have a name, just pass the name along in the constructor.
def __init__(self, name):
self.name = name
You can create a method inside your class that check all variables in the current frame and use hash() to look for the self variable.
The solution proposed here will return all the variables pointing to the instance object.
In the class below, isinstance() is used to avoid problems when applying hash(), since some objects like a numpy.array or a list, for example, are unhashable.
import inspect
class A(object):
def get_my_name(self):
ans = []
frame = inspect.currentframe().f_back
tmp = dict(frame.f_globals.items() + frame.f_locals.items())
for k, var in tmp.items():
if isinstance(var, self.__class__):
if hash(self) == hash(var):
ans.append(k)
return ans
The following test has been done:
def test():
a = A()
b = a
c = b
print c.get_my_name()
The result is:
test()
#['a', 'c', 'b']
This cannot work, just imagine this: a = b = TheMagicObjet(). Names have no effect on Values, they just point to them.
One horrible, horrible way to accomplish this is to reverse the responsibilities:
class SomeObject():
def __init__(self, def_name):
self.defined_name = def_name
globals()[def_name] = self
SomeObject("ThisObject")
print ThisObject.defined_name
If you wanted to support something other than global scope, you'd have to do something even more awful.
In Python, all data is stored in objects. Additionally, a name can be bound with an object, after which that name can be used to look up that object.
It makes no difference to the object what names, if any, it might be bound to. It might be bound to dozens of different names, or none. Also, Python does not have any "back links" that point from an object to a name.
Consider this example:
foo = 1
bar = foo
baz = foo
Now, suppose you have the integer object with value 1, and you want to work backwards and find its name. What would you print? Three different names have that object bound to them, and all are equally valid.
print(bar is foo) # prints True
print(baz is foo) # prints True
In Python, a name is a way to access an object, so there is no way to work with names directly. You could search through various name spaces until you find a name that is bound with the object of interest, but I don't recommend this.
How do I get the string representation of a variable in python?
There is a famous presentation called "Code Like a Pythonista" that summarizes this situation as "Other languages have 'variables'" and "Python has 'names'"
http://python.net/~goodger/projects/pycon/2007/idiomatic/handout.html#other-languages-have-variables
If you want an unique instance name for a class, try __repr__() or id(self)
class Some:
def __init__(self):
print(self.__repr__()) # = hex(id(self))
print(id(self))
It will print the memory address of the instance, which is unique.
Inspired by the answers of unutbu and Saullo Castro, I have created a more sophisticated class that can even be subclassed. It solves what was asked for in the question.
"create a default value based on the instance name of the class
without passing in an extra argument."
Here's what it does, when an instance of this class or a subclass is created:
Go up in the frame stack until the first frame which does not belong to a method of the current instance.
Inspect this frame to get the attributes self.creation_(name/file/module/function/line/text).
Perform an an additional check whether an object with name self.creation_name was actually defined in the frame's locals() namespace to make 100% sure the found creation_name is correct or raise an error otherwise.
The Code:
import traceback, threading, time
class InstanceCreationError(Exception):
pass
class RememberInstanceCreationInfo:
def __init__(self):
for frame, line in traceback.walk_stack(None):
varnames = frame.f_code.co_varnames
if varnames is ():
break
if frame.f_locals[varnames[0]] not in (self, self.__class__):
break
# if the frame is inside a method of this instance,
# the first argument usually contains either the instance or
# its class
# we want to find the first frame, where this is not the case
else:
raise InstanceCreationError("No suitable outer frame found.")
self._outer_frame = frame
self.creation_module = frame.f_globals["__name__"]
self.creation_file, self.creation_line, self.creation_function, \
self.creation_text = \
traceback.extract_stack(frame, 1)[0]
self.creation_name = self.creation_text.split("=")[0].strip()
super().__init__()
threading.Thread(target=self._check_existence_after_creation).start()
def _check_existence_after_creation(self):
while self._outer_frame.f_lineno == self.creation_line:
time.sleep(0.01)
# this is executed as soon as the line number changes
# now we can be sure the instance was actually created
error = InstanceCreationError(
"\nCreation name not found in creation frame.\ncreation_file: "
"%s \ncreation_line: %s \ncreation_text: %s\ncreation_name ("
"might be wrong): %s" % (
self.creation_file, self.creation_line, self.creation_text,
self.creation_name))
nameparts = self.creation_name.split(".")
try:
var = self._outer_frame.f_locals[nameparts[0]]
except KeyError:
raise error
finally:
del self._outer_frame
# make sure we have no permament inter frame reference
# which could hinder garbage collection
try:
for name in nameparts[1:]: var = getattr(var, name)
except AttributeError:
raise error
if var is not self: raise error
def __repr__(self):
return super().__repr__()[
:-1] + " with creation_name '%s'>" % self.creation_name
A simple example:
class MySubclass(RememberInstanceCreationInfo):
def __init__(self):
super().__init__()
def print_creation_info(self):
print(self.creation_name, self.creation_module, self.creation_function,
self.creation_line, self.creation_text, sep=", ")
instance = MySubclass()
instance.print_creation_info()
#out: instance, __main__, <module>, 68, instance = MySubclass()
If the creation name cannot be determined properly an error is raised:
variable, another_instance = 2, MySubclass()
# InstanceCreationError:
# Creation name not found in creation frame.
# creation_file: /.../myfile.py
# creation_line: 71
# creation_text: variable, another_instance = 2, MySubclass()
# creation_name (might be wrong): variable, another_instance
I think that names matters if they are the pointers to any object..
no matters if:
foo = 1
bar = foo
I know that foo points to 1 and bar points to the same value 1 into the same memory space.
but supose that I want to create a class with a function that adds a object to it.
Class Bag(object):
def __init__(self):
some code here...
def addItem(self,item):
self.__dict__[somewaytogetItemName] = item
So, when I instantiate the class bag like below:
newObj1 = Bag()
newObj2 = Bag()
newObj1.addItem(newObj2)I can do this to get an attribute of newObj1:
newObj1.newObj2
The best way is really to pass the name to the constructor as in the chosen answer. However, if you REALLY want to avoid asking the user to pass the name to the constructor, you can do the following hack:
If you are creating the instance with 'ThisObject = SomeObject()' from the command line, you can get the object name from the command string in command history:
import readline
import re
class SomeObject():
def __init__(self):
cmd = readline.get_history_item(readline.get_current_history_length())
self.name = re.split('=| ',cmd)[0]
If you are creating the instance using 'exec' command, you can handle this with:
if cmd[0:4] == 'exec': self.name = re.split('\'|=| ',cmd)[1] # if command performed using 'exec'
else: self.name = re.split('=| ',cmd)[0]

Categories