How to memoize at class level? - python-3.x

I have the following class, with a cached property as so:
class Object:
def __init__(self, var):
self._var = var
#property
#lru_cache()
def some_property(self):
print("i did some calculation")
return self._var + 3
>> obj = Object(3)
>> obj.some_property
i did some calculation
6
How can I make it so that whenever I make a new Object, with the same var, it will not recalculate, but rather memoize the result fat class level and not recalculate somme_property.
In other words I would need it to behave as so:
>> new_obj = Object(3)
>> new_obj.some_property
6

Maybe not the answer but a suggestion. You could just create a function inside Object which will hold the variable.
Something like this:
def memorize(x):
self.MemorizedValue = x
Then you can pass the value through Object.memorize(3).

Related

Check if method is from class without known string

Trying to check if a method is from a class. It's as simple as:
class Foo:
def bar(self):
return
f = Foo()
ismethod(f.bar, Foo) # Should evaluate to true
Syntax like hasattr(Foo(), 'bar') works if you know the method name, and the same with 'bar' in dir(Foo()); howeveer, I need to be able to pass the method object itself as the argument, not like a string as shown here. In my scenario, I need to tell if a method—passed as an argument—is of a specific class.
In other words: How do I tell if an object is a method of a class, without knowing the name of the object?
You need inspect.ismethod:
import inspect
def just_func(a, b):
return a + b
class SomeClass:
def just_method(self, a, b, c):
return a * b + c
obj = SomeClass()
print(inspect.ismethod(just_func)) # False
print(inspect.ismethod(obj.just_method)) # True
UPD:
Oh sorry, you need to check if it belongs to a particular class, then use:
print('SomeClass' in obj.just_method.__qualname__) # True
print('SomeClass' in just_func.__qualname__) # False
Here's what the function you want might look like:
def ismethod(func, cls):
return cls.__name__ in func.__qualname__ and '.' in func.__qualname__
It actually looks like a duplicate of this.

How can i avoid repetitive calling of instance variables in Subclasses?

i was wondering if there is a way in Python to get rid of repetitive calling of instance variables , when creating subclasses.
for example:
class Name:
def __init__(self,first,last):
self.first = first
self.last = last
def __str__(self):
return f"Users first name is : {self.first}, Users last name is: {self.last}"
def __repr__(self):
return f"first:{self.first}, last:{self.last}"
class Cash(Name):
def __init__(self,first,last,cash):
super().__init__(first,last)
self.cash = cash
def full(self):
return f"{self.first},{self.last},{self.cash}"
c1 = Cash("Exa","Cool",200)
print(c1.full())
Is it possible to call all instance variables (self.first,self.last...) from "Name", without having to mention them in the constructor of "Cash"
something like:
class Cash(Name):
def __init__("all from Name" + new one ("cash" in this example)):
super().__init__("all from Name")
self.cash = cash
In your case, you can change the Cash class to look like this:
class Cash(Name):
def __init__(self,*inputs):
super(Cash,self).__init__(*inputs[:-1])
self.cash = inputs[-1]
def full(self):
return f"{self.first},{self.last},{self.cash}"
but for a more general solution that covers all situations take a look at this similar question.

Python / Attributes between methods of a class

I'm new in Python and I'm trying to get my head around how are managed attributes between methods of a class.
In the following example, I'm trying to modify a list in the method "regex" and use it afterwards in another method "printsc".
The "regex" part works without issues, but the attribute "self.mylist" is not updated so when I call "printsc" the result is "None".
class MyClass():
def __init__(self):
self.mylist = None
def regex(self, items):
self.mylist = []
for item in items:
if re.match(r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$", item):
self.mylist.append("IP:" + item)
else:
self.mylist.append("DNS:" + item)
return self.mylist
def printsc(self):
print(self.mylist)
items = ['192.168.0.1', 'hostname1', '10.0.1.15', 'server.local.fr']
MyClass().regex(items)
MyClass().printsc()
What am I missing ? What is the best way to achieve this goal ?
Thank you for your answers!
When you do MyClass(), it returns you an object.. And you are calling your methods on the object. Since you are doing it twice, each time a new object is created and regex and printsc are called on different objects.
what you should do is
myObj = MyClass()
myObj.regex(items)
myObj.printsc()
The problem is that when you do:
MyClass().regex(items)
MyClass().printsc()
You are creating 2 separate instances of MyClass, each of which will have a different .mylist attribute.
Either mylist is an instance attribute, and then this will work:
instance = MyClass()
instance.regex(items)
instance.printsc()
Or, if you want to share .mylist across instances, it should be
a class attribute:
class MyClass():
class_list = None
def __init__(self):
pass
def regex(self, items):
cls = self.__class__
if cls.class_list is None:
cls.class_list = []
for item in items:
if re.match(r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$", item):
cls.class_list.append("IP:" + item)
else:
cls.class_list.append("DNS:" + item)
return cls.class_list
def printsc(self):
# Going throuhgh `.__class__.` is actually optional for
# reading an attribute - if it is not in the instance
# Python will fetch it from the class instead.
# i.e. , the line bellow would work with `self.class_list`
print(self.__class__.class_list)
This way, the list persists across different instances of the class, as you try to do in your example.
You should create an object of the class:
a = MyClass()
a.regex(items)
a.printsc()
>>> ['IP:192.168.0.1', 'DNS:hostname1', 'IP:10.0.1.15', 'DNS:server.local.fr']

Why does vars(type('', (object,), input_dict)()) not return its variables?

To convert dict to class, I wrote the code as follows, and it works well.
output_class = type('', (object,), input_dict)()
However, the created class does not return its attributes by the code below!
print(vars(output_class))
>> {}
I solved this problem by using the code below, but I am still confused.
class Struct(object):
def __init__(self, **entries):
self.__dict__.update(entries)
output_class = Struct(**input_dict)
print(vars(output_class))
>> {'key': 'value'}
I would appreciate it if you could explain why the former does not return its attributes.
It's because in first case (calling type) object of your class has an empty __dict__ and your input_dict content is stored in class variables.
third argument of type() defines class (not object) variables or methods (they are defined by __new__ call not __init__ ).
Simply put, the first and the second code snippets are not the same.
So
output_class = type('', (object,), input_dict)(),
Has equivalent something like this:
class Struct(object):
def __new__(cls, **entries):
cls = super().__new__()
for k,v in **entries:
setattr(cls, k, v)
return obj
output_class = Struct()
If you want something like:
class Struct(object):
def __init__(self, **entries):
self.__dict__.update(entries)
output_class = Struct(**input_dict)
You should define init(). It can look like:
output_class = type('', (object,),
{'__init__': lambda self, inp_d: self.__dict__.update(inp_d)})(input_dict)
If my explanation isn't enough clear I suppose example from here can help: https://docs.python.org/3/library/functions.html#type
Pay you attention: a is not inside __init__() method so it's shared between all objects of class X.

Trigger a function when any property of an object changes with RxPy

In RxPy, is there anything similar to INotifyPropertyChanged in .NET framework mentioned here? I'm trying to add an observer to an object, so that any property of the object changes, a function will be called.
Try something like this:
class A(object):
def __init__(self):
self._my_attr = None
self.property_changed = Subject()
...
#property
def my_attr(self):
return self._my_attr
#my_attr.setter
def my_attr(self, value):
if value != self._my_attr:
self._my_attr = value
self.property_changed.on_next(('my_attr', value))
a = A()
a.property_changed.subscribe(print)
a.my_attr = 1
a.my_attr = 3

Resources