Trigger a function when any property of an object changes with RxPy - python-3.x

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

Related

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']

Execute python method from a string

I have a string that has the method name and value in it. Currently, I'm using the following implementation which works but doesn't seem elegant. Is there a better way to implement this?
class ObjectResolver:
def methodResolver(self, value):
"""Some logic here"""
print(value)
objectResolver = ObjectResolver()
channel = 'methodResolver(helloWorld)'
findValue = channel.strip().find('(')
objectMethod = channel.strip()[:findValue]
attribute = channel.strip()[findValue:][1:-1]
channelResolver = getattr(objectResolver, objectMethod)(attribute)
Output:
helloWorld
You can use eval() or exec()
class ObjectResolver:
def methodResolver(self, value):
"""Some logic here"""
print(value)
objectResolver = ObjectResolver()
// Something like this...
channel = eval('methodResolver')(helloWorld)
// OR
exec('channel = "methodResolver(helloWorld)"')
findValue = channel.strip().find('(')
objectMethod = channel.strip()[:findValue]
attribute = channel.strip()[findValue:][1:-1]
channelResolver = getattr(objectResolver, objectMethod)(attribute)
Learn more about eval and exec
The best method I found is to use eval here and specifically to my question above, the implementation is as follows:
class ObjectResolver:
def methodResolver(self, value):
"""Some logic here"""
print(value)
objectResolver = ObjectResolver()
channel = "methodResolver('helloWorld')"
handlers = dict(methodResolver=objectResolver.methodResolver)
eval(channel, handlers)

How to memoize at class level?

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).

How to return a list as a string when calling a getter in a class instance

I have a class variable, a list, that can contain more than one value at a time (a MAC address). I would like to be able to return the value(s) as a comma-delimited string rather than a list. I know that I can do something like this:
class test(object):
def __init__(self, mac):
self.mac = mac
#property
def mac(self):
return self.mac
# return ','.join(map(str, self.mac))
#mac.setter
def mac(self, mac):
self.mac = mac
#self.mac = ','.join(map(str, mac))
def macs_as_a_list(self):
return ','.join(map(str, self.mac))
m1 = test(mac=['aa:bb:cc:dd:ee:ff', '11:22:33:44:55:66'])
m1.mac
Out: ['aa:bb:cc:dd:ee:ff', '11:22:33:44:55:66']
Desired: 'aa:bb:cc:dd:ee:ff,11:22:33:44:55:66'
This works, of course:
m1.macs_as_a_list()
But, isn't there a way to make this conversion in the setter (or in the getter as demonstrated in the commented lines above)?
The common approach is to use a private variable to store the raw value behind your property and to user your getter to format it accordingly.
class test(object):
def __init__(self, mac):
self.mac = mac
#property
def mac(self):
return ','.join(self._mac)
#mac.setter
def mac(self, mac):
self._mac = mac
m1 = test(['aa:bb:cc:dd:ee:ff', '11:22:33:44:55:66'])
print(m1.mac) # 'aa:bb:cc:dd:ee:ff,11:22:33:44:55:66'

Find owner class of a method in Python

I'm writing decorators, and part of what I need to do is discern whether a function is a function or a method. Is there a way I can find what class a given method is a part of?
e.g. If I was to run this code, what could I write in getOwner to make exampleFunc print something like <class '__main__'.Example>?
class Example:
def method(self):
print("I'm a method")
def exampleFunc(func):
owner = getOwner(func)
print(owner)
test = Example()
exampleFunc(test.method)
If all you need to do is figure out of the thing behaving like a function is a method or a function, that is one purpose of the types module.
import types
def is_method(f):
return type(f) == types.MethodType
In the event that the function-like object is a method, you can find its parent class as follows.
Update Patched for Python3 compatibility.
def method_parent(f):
return f.__self__
If you have a reference to the classes defined in your scope, you'd need to check for each one:
def exampleFunc(f):
class_list = [...]
return any(f in vars(c).values() for c in class_List)
This will return True if function f is an instance method. However, if you wish to return the actual class name:
def exampleFunc(f):
class_list = [...]
for c in class_list:
if f in vars(c).values():
return c.__name__
return 'global function' if 'lambda' not in f.__name__ else 'lambda'
Note that this does not work for __dunder__ methods, and methods that your class inherits. For example,
class A:
def f1(self): pass
class B(A):
def f2(self): pass
print(vars(B))
mappingproxy({'__doc__': None,
'__module__': '__main__',
'f2': <function __main__.B.f2>})
Note that f1 is not a part of B's mappingproxy.

Resources