How to assign cache to a method in an OOP fashion? [duplicate] - python

This question already has answers here:
What is memoization and how can I use it in Python?
(14 answers)
Closed 9 years ago.
Suppose that I have class A and this class has a method called function. Can I assign a cache as a property to this method? In the sense that I could call it like a property?
class A:
def __init__(self,value):
self.value=value
def function(self,a):
"""function returns a+1 and caches the value for future calls."""
cache=[]
cache.append([a,a+1])
return a+1;
a=A(12)
print a.function(12)
print a.function.cache
Which gives me the error:
AttributeError: 'function' object has no attribute 'cache'
I know it is possible to assign a cache to the main class but I am looking for a possible way of assigning it as a property to the method object.

class A:
def __init__(self,value):
self.value=value
self.cache = {}
def function(self,a):
"""function returns a+1 and caches the value for future calls."""
# Add a default value of empty string to avoid key errors,
# check if we already have the value cached
if self.cache.get(a,''):
return self.cache[a]
else:
result = a + 1
self.cache[a] = result
return result
As far as I know there is no way of having the cache as a property of the method. Python doesn't have such a feature. But I think perhaps this solution will satisfy your needs.
EDIT
Upon further research, there is indeed a way to do this in Python 3
class A:
def __init__(self,value):
self.value=value
def function(self,a):
"""function returns a+1 and caches the value for future calls."""
# Add a default value of empty string to avoid key errors,
# check if we already have the value cached
if self.function.cache.get(a,''):
return self.function.cache[a]
else:
result = a + 1
self.function.cache[a] = result
return result
function.cache = {}
a=A(12)
print(a.function(12))
print(a.function.cache)
This is because in Python 3 instance methods are just functions. BTW in Python 2 it is indeed possible to add attributes to functions, but not to instance methods. If you need to use Python 2 then there is a solution to your problem involving decorators that you should look into.

Related

Pythonic way to get the first passed kwarg without knowing its name? [duplicate]

This question already has answers here:
Access an arbitrary element in a dictionary in Python
(14 answers)
Closed 3 years ago.
I have a function, which has a signature like this:
def func(**kwargs):
The user of that function will call the function with zero or one keyword arguments. If he passes one argument, the name will be foo_id, bar_id, baz_id etc., but I don't know the exact name he will use. The value of the passed argument will be some interger. I still want to take that argument's value and use it.
Currently I'm doing it like this, but I was wondering would there be a cleaner way to achieve this:
def func(**kwargs):
if kwargs:
target_id = list(kwargs.values())[0]
else:
target_id = None
# use target_id here, no worries if it's None
I'm using Python 3.8, so backwards compatibility is not an issue.
Here we are
def func(**kwargs):
target_id = next(iter(kwargs.values()), None)
print(target_id)
func(name_id='name')
func(value_id='value')
func(test_id='test')
func()
Outputs
python test.py
name
value
test
None
Since the dictionary has only one item, and you don't need to keep it in the dictionary, the cleanest way is to use the dict.popitem method. This returns both the argument name and its value as a pair.
def func(**kwarg):
if kwarg:
name, value = kwarg.popitem()
# ...
else:
# ...
Since the caller should supply at most one argument, I recommend explicitly raising an error if it is called with more arguments:
def func(**kwarg):
if len(kwarg) > 1:
raise TypeError(f'Expected at most 1 keyword arg, got {len(kwarg)}.')
elif kwarg:
name, value = kwarg.popitem()
# ...
else:
# ...

call method without parenthesis in python [duplicate]

This question already has answers here:
What's the pythonic way to use getters and setters?
(8 answers)
Closed last month.
what modification i would need to do in the below function computeDifference to get result printed in the console, instead of object message.
i know i need to add parenthesis () to call function to get the result printed in the console, but is there any other way to print the result?
class Difference1:
def __init__(self, a):
self.__elements = a
def computeDifference(self):
self.difference = max(self.__elements)- min(self.__elements)
return self.difference
a = [5,8,9,22,2]
c = Difference1(a)
print(c.computeDifference)
Make it a property
class Difference1:
#property
def computeDifference(self):
...
print(c.computeDifference)
However, I would change the name to difference. The idea of a property is that you shouldn't know or care whether the value is computed at that time or is stored as an attribute of the object. See uniform access principle.
You could add a magic function:
class Difference1:
...
def __str__(self):
return str(self.computeDifference())
...
>>> a = [5,8,9,22,2]
>>> c = Difference1(a)
>>> print(c)
20

Defining equivalence between parent and child classes [duplicate]

This question already has answers here:
Compare object instances for equality by their attributes
(16 answers)
Closed 6 years ago.
What is the best practice for defining an equality operation to determine if a parent and child are effectively the same? Is there any good way to achieve this, or should I just avoid this desired behavior with a architecture change?
Parent Class
class Equal1(object):
def __init__(self, value):
self.value=value
def get_value(self):
return self.value
def __eq__(self, other):
if isinstance(other, self.__class__):
return self.__dict__==other.__dict__
return NotImplemented
Child Class
class Equal2(Equal1):
def __init__(self, value):
super().__init__(2 * value)
self.other_values = ''
I want the following code to evaluate to True:
a = Equal1(2)
b = Equal2(1)
a == b
## True
It currently will not evaluate to True because the dictionaries are not identical, even if the functionality is the same.
One potential technique is to iterate through the smaller dictionary to check all of the key/value pairs to make sure they are the same as well as checking the local attributes using dir().
So you want to ignore the keys that only one of the objects has?
I would suggest replacing:
return self.__dict__==other.__dict__
with:
return all(self[k] == other[k]
for k in self.__dict__.keys() & other.__dict__.keys())
This makes the objects equal if all the keys, they both have, have equal values.

Use __get__, __set__ with dictionary item?

Is there a way to make a dictionary of functions that use set and get statements and then use them as set and get functions?
class thing(object):
def __init__(self, thingy)
self.thingy = thingy
def __get__(self,instance,owner):
return thingy
def __set__(self,instance,value):
thingy += value
theDict = {"bob":thing(5), "suzy":thing(2)}
theDict["bob"] = 10
wanted result is that 10 goes into the set function and adds to the existing 5
print theDict["bob"]
>>> 15
actual result is that the dictionary replaces the entry with the numeric value
print theDict["bob"]
>>> 10
Why can't I just make a function like..
theDict["bob"].add(10)
is because it's building off an existing and already really well working function that uses the set and get. The case I'm working with is an edge case and wouldn't make sense to reprogram everything to make work for this one case.
I need some means to store instances of this set/get thingy that is accessible but doesn't create some layer of depth that might break existing references.
Please don't ask for actual code. It'd take pages of code to encapsulate the problem.
You could do it if you can (also) use a specialized version of the dictionary which is aware of your Thing class and handles it separately:
class Thing(object):
def __init__(self, thingy):
self._thingy = thingy
def _get_thingy(self):
return self._thingy
def _set_thingy(self, value):
self._thingy += value
thingy = property(_get_thingy, _set_thingy, None, "I'm a 'thingy' property.")
class ThingDict(dict):
def __getitem__(self, key):
if key in self and isinstance(dict.__getitem__(self, key), Thing):
return dict.__getitem__(self, key).thingy
else:
return dict.__getitem__(self, key)
def __setitem__(self, key, value):
if key in self and isinstance(dict.__getitem__(self, key), Thing):
dict.__getitem__(self, key).thingy = value
else:
dict.__setitem__(self, key, value)
theDict = ThingDict({"bob": Thing(5), "suzy": Thing(2), "don": 42})
print(theDict["bob"]) # --> 5
theDict["bob"] = 10
print(theDict["bob"]) # --> 15
# non-Thing value
print(theDict["don"]) # --> 42
theDict["don"] = 10
print(theDict["don"]) # --> 10
No, because to execute theDict["bob"] = 10, the Python runtime doesn't call any methods at all of the previous value of theDict["bob"]. It's not like when myObject.mydescriptor = 10 calls the descriptor setter.
Well, maybe it calls __del__ on the previous value if the refcount hits zero, but let's not go there!
If you want to do something like this then you need to change the way the dictionary works, not the contents. For example you could subclass dict (with the usual warnings that you're Evil, Bad and Wrong to write a non-Liskov-substituting derived class). Or you could from scratch implement an instance of collections.MutableMapping. But I don't think there's any way to hijack the normal operation of dict using a special value stored in it.
theDict["bob"] = 10 is just assign 10 to the key bob for theDict.
I think you should know about the magic methods __get__ and __set__ first. Go to: https://docs.python.org/2.7/howto/descriptor.html Using a class might be easier than dict.

Using None as parameter to keyword argument [duplicate]

This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
python - returning a default value
I have a function in a class:
def foo(self, value = None):
if value is None:
return self.value
self.value = value
return self
This is a getter and setter combined into one, with the advantage that I can chain functions like this:
three = anInstanceOfMyClass.foo(3).bar().foo()
The problem appears when I do like this:
shouldBeNoneButIsThree = anInstanceOfMyClass.foo(3).foo(None).foo()
Here foo thinks that I did not pass an argument.
I can avoid this by:
Setting value to some strange object, like a random string
Create an object instance in the constructor which value has as default value
Both seem a bit too much work, what is an easier way?
setting value to something
You need to use a sentinel to detect that a default value was not set:
sentinel = object()
def foo(self, value=sentinel):
if value is not sentinel:
print("You passed in something else!")
This works because an instance of object() will always have it's own memory id and thus is will only return True if the exact value was left in place. Any other value will not register as the same object, including None.
You'll see different variants of the above trick in various different python projects. Any of the following sentinels would also work:
sentinel = []
sentinel = {}
Using a sentinel object value is fairly common; this is what the library does in abcoll.py:
__marker = object()
def pop(self, key, default=__marker):
...
if default is self.__marker:
Note that the sentinel object should be defined directly in the class.

Categories