Is it the best way to compare python objects - python

Considering these classes
class Foo(object):
def __init__(self, owner):
self.owner = owner
self.a = None
self.b = []
object = Foo(mike)
each hour, i need to check if Foo is updated (object.a or object.b has changed)
How can i do ?
Do i need to create a new object object2=Foo(mike) and parse attribute to compare with object, put the difference into a list or is there a pythonic way to do it ?
If a create two objects, parse them to build 2 lists and compare them is a good idea ?

If you have this problem, do not allow anything to change attributes directly.
Use methods instead (e.g. add_b(self, value), set_a(self, value)) in which you can keep control on what's happening.
Try using properties.
E.g.
class Foo(object):
__owner = None
__changed = False
def __init__(self, owner):
self.__owner = owner
def get_owner(self):
return self.__owner
def set_owner(self, owner):
old_owner = self.__owner
if owner != old_owner:
self.__changed = True
self.__owner = owner
owner = property(get_owner, set_owner)
#property
def changed(self):
return self.__changed
f = Foo('bar')
print f.owner # bar
f.owner = 'bar2'
print f.owner # bar2
print f.changed # True

Related

How to have the same updated value of a Parent class be passed down to a inner class?

I need to access the value of an attribute defined at the parent class inside an inner class, here's the code:
class main(object):
def __init__(self):
self.session_id = None
self.devices = self.Devices(self.session_id)
class Devices(object):
def __init__(self, session_id):
self.session_id = session_id
And here's how I would like to use it:
>>> m = main()
>>> m.session_id = 1
>>> m.session_id
1
>>> m.devices.session_id
>>>
My expectation is that m.devices.session_id will always have the exact same value as m.session_id. I understand that at this point when I instantiate the inner class the session_id value is passed down as None because that's how it was initiated but I'm not sure how I can keep both values the same without doing something very ugly like:
m.devices.session_id = m.session_id
outside the class code.
How can I accomplish that inside the class itself ?
The other answer works, but I think this is a better design: lose the nested class, and add a getter on the device object to lookup a backref:
class Main(object):
def __init__(self):
self.session_id = None
self.devices = Devices(main_obj=self)
class Devices(object):
def __init__(self, main_obj):
self.main_obj = main_obj
...
#property
def session_id(self):
return self.main_obj.session_id
The difference here is that you're not storing the same data twice, so they can not get out of sync - there is only one "source of truth" for the session_id (on main object).
In the earlier answer, the data is actually stored in two different namespaces and will get out of sync as easily as m.devices.session_id = 123.
You can do it like this:
class main(object):
def __init__(self):
self._session_id = None
self.devices = self.Devices(self._session_id)
#property
def session_id(self):
return self._session_id
#session_id.setter
def session_id(self, value):
self._session_id = self.devices.session_id = value
class Devices(object):
def __init__(self, session_id):
self.session_id = session_id

Why #property broke synchronizing with source object on proxy class

I want to create a proxy in Python because of function and attributes access (something like private). I create the proxy with references to functions in the source object. But I have a problem, that functions have no problem with changing attributes but property yes. Here is an example:
A working example
class A:
def __init__(self):
self.value = 1
def get_value(self):
return self.value
class Proxy:
def __init__(self, cls):
self.get_value = cls.get_value
# del cls
a = A()
p = Proxy(a)
print(a.get_value(), p.get_value())
a.value = 2
print(a.get_value(), p.get_value())
Output:
1 1
2 2
Not working:
class A:
def __init__(self):
self.value = 1
#property
def get_value(self):
return self.value
class Proxy:
def __init__(self, cls):
self.get_value = cls.get_value
# del cls
a = A()
p = Proxy(a)
print(a.get_value, p.get_value)
a.value = 2
print(a.get_value, p.get_value)
Output:
1 1
2 1
Can someone explain me where the problem is and if there is any solution for this? I could use functions, but I think #property is more Python solution. And I really want to know what is the difference. Thank you
In Proxy.__init__, you end up executing:
self.get_value = a.get_value
and very different things happen in your two examples.
In the first case, a.get_value is a method of a. So, calling p.get_value() is the same as calling a.get_value(). You get identical results.
In the second case, you have already defined a.get_value as a property, so self.get_value = a.get_value is basically self.get_value = 2, it is just an int attribute of p.

Python: manage multiple classes (from serialization) with common properties

I am new to structure Python projects, so please forgive any wrong approaches that could be written down here.
Two JSON schemes represent two objects. These are serialised into classes and have properties in common.
Example:
class TwoWheelVeicle(object):
def __init__(self,v_family, v_subfamily):
self.Family = v_family
self.SubFamily = v_subfamily
self.OtherProp = "other"
class FourWheelVeicle(object):
def __init__(self,v_family):
self.Family = v_family
self.AnotherProp = "another"
def run_an_highway(vehicle):
if isinstance(vehicle,FourWheelVeicle):
return "Wrooom"
if isinstance(vehicle,TwoWheelVeicle):
if veichle.SubFamily in SubFams.NotAllowed:
return "ALT!"
else:
return "Brooom" #forgive me for the sound
class SubFams(object):
NotAllowed = ["Bicycle","50cc"]
Known = ["200cc","Motorbike"]
I am quite unsure of the procedure overall:
- Shall I create an abstract parent class?
- Is NotAllowed stored correctly? This is due to the need of changing its content (that is serialized from some global parameter JSON, it's a #TODO)
..or simply I should not want to do any of these?
Lastly, the code does not allow for any checks if the properties that I serialize are correct (what if SubFamily is unknown? Should it be checked in the decoder?).
A big thank you.
Looks like you should abstract vehicle with a Vehicle class and then subclass it for your different vehicle types.
Your if chain isn't needed if your different subclasses have their own version for that same method.
Something in the line with these:
class Vehicle(object):
def __init__(self, name, cc):
self.name = name
self.cc = cc
self.wheels = None
def runs_on_highway(self):
return self.cc > 50
def sound(self):
pass
class TwoWheels(Vehicle):
def __init__(self, name, cc):
Vehicle.__init__(self, name, cc)
self.wheels = 2
def sound(self):
return 'Brooom.'
class FourWheels(Vehicle):
def __init__(self, name, cc):
Vehicle.__init__(self, name, cc)
self.wheels = 4
def sound(self):
return 'Vruuum'
class ElectricWheels(Vehicle):
def __init__(self, name, cc):
Vehicle.__init__(self, name, 0)
self.wheels = 4
def runs_on_highway(self):
return True
def sound(self):
return 'zzzzz.'
v1 = TwoWheels('Bicycle', 50)
v2 = FourWheels('Motorbike', 200)
v3 = ElectricWheels('ElectricBike', 0)
print(v1.runs_on_highway())
print(v2.runs_on_highway())
print(v3.runs_on_highway())
print(v1.name, v1.cc, v1.wheels, v1.sound())
print(v2.name, v2.cc, v2.wheels, v2.sound())
print(v3.name, v3.cc, v3.wheels, v3.sound())

how can i reference to an object variable without passing it as parameter in python classes

I am try to reference an object variable inside the class without passing it in parameters but it is throwing error
class Sample:
def __init__(self):
v = []
v.append(name)
v.append(email)
s = Sample()
s.name = "xxxx"
s.email = "ss#ss.com"
print s.v
error:
NameError: global name 'name' is not defined
I am assigning the variable name in the object now how can i call it inside the class without adding parameters to function
if you absolutely must avoid attributes:
class Sample:
def __init__(self):
self.v = []
def addName(self, name):
self.v.append(name)
def addEmail(self, email):
self.v.append(email)
s = Sample()
s.addName("xxxx")
s.addEmail("abc#def.com")
print(s.v)
Yet another way to do this is to use decorators and #property:
class Sample(object):
def __init__(self):
self.v = [None, None]
#property
def name(self):
return self.v[0]
#property
def email(self):
return self.v[1]
#name.setter
def name(self, value):
self.v[0] = value
#email.setter
def email(self, value):
self.v[1] = value
s = Sample()
s.name = "xxxx"
s.email = "ss#ss.com"
print s.v
Notes:
Your class must be extending object explicitly in python 2 for this to work
#property decorated methods are working as "getters" and return a value
#<name>.setter is a setter method responsible for setting <name> member, so #email.setter sets the email and is being invoked when x.email = ... is called
The above may be a bit long-winded but allows for a clean API which hides the details from the user... Some people do prefer to add get/set_name methods to be more explicit but the above is more pythonic
If your requirements are dynamic, you can create attributes at run time like,
class Sample:
pass
s = Sample()
setattr(s,"name","chanda")
setattr(s,"email","xyz#gmail.com")
setattr(s,"v",[s.name,s.email])
print(s.name) #chanda
print(s.email) #xyz#gmail.com
print(s.v) #['chanda', 'xyz#gmail.com']
print(s.__dict__) #{'email': 'xyz#gmail.com', 'v': ['chanda', 'xyz#gmail.com'], 'name': 'chanda'}

How to create and store instances of a class at initialization?

Using Python 3.3, I want to bind a class Test to another class called TestManager so that the manager creates instances of Test and stores them to give an access to them afterwards.
In a nutshell (I mean, Python shell...), I want to be able to do this (assuming name is an attribute of Test):
> t = Test.objects.get(id=3)
> t.name
# Returns 'Name 3'
The trick is that my collection of objects is a "static" collection, in a sense that it is created at first (not by any user) and then never modified or deleted, nor its records removed or edited. It's fixed.
So here is the code I tried:
class TestManager:
def __init__(self, *args, **kwargs):
self._tests = [Test(name='Name {}'.format(i)) for i in range(100)]
def get(self, id):
return self._tests[id]
class Test:
objects = TestManager()
def __init__(self, name=''):
self.name = name
Aaaand, as expected, NameError: global name 'Test' is not defined due to the circular initialization. Ideally, I should have a create() method in the manager which would take care of adding elements in the list (instead of the __init__()), but that would mean that the creation is not done in the manager but elsewhere.
The "best" solution I came up with, so far, is to check first in the get() method if the list is empty, and thus call a fill_the_damn_list() method, but it seems very hackish to me. Another way to do that would be to use a dict instead of a list and to create the instances on the fly at first get(). The advantage of the latter one is that it does not create useless/never get()-ed instances, but with only an hundred of them in total, I am not sure it really matters, and the hackish-ness of this solution looks quite the same to me...
As I am quite new to Python (if it isn't clear enough...), I wonder if there is a better way to do that and to keep it simple. I am also OK to refactor if needed, but I didn't find any better solution yet...
Your design seems a little odd -- it's unclear why the Test class needs a reference to a TestManger instance. Regardless, I think the following will make that happen. It uses a metaclass to create the objects attribute of the Test class and adds the _tests attribute you want to the TestManger instance it created -- which all go into making this a rather peculiar answer...fitting, I suppose. ;-)
class TestManager:
def __init__(self, *args, **kwargs):
print('creating TestManager')
def get(self, id):
return self._tests[id]
class TestMetaClass(type):
def __new__(mcl, name, bases, classdict):
# add an "objects" attribute to the class being created
classdict['objects'] = tm = TestManager()
cls = type.__new__(mcl, name, bases, classdict)
# add a "_tests" attribute to the TestManager instance just created
# (can't use class's name, since it hasn't been returned yet)
tm._tests = [cls(name='Name {}'.format(i)) for i in range(100)]
return cls
class Test(metaclass=TestMetaClass):
def __init__(self, name=''):
self.name = name
t = Test.objects.get(3)
print(t.name)
I completely agree with sean's comment: your design is strange and, I think, quite useless, and this is causing problems even before starting using it. Anyway, if you want to do that you can use a lot of different methods.
The simple way:
class TestManager:
def __init__(self, *args, **kwargs):
self._tests = [Test(name='Name {}'.format(i)) for i in range(100)]
def get(self, id):
return self._tests[id]
class Test:
objects = None
def __init__(self, name=''):
self.name = name
Test.objects = TestManager()
An other approach can be using a decorator:
>>> class TestManager(object):
... def __init__(self, *args, **kwargs):
... self._tests = []
... def init_class(self, cls):
... self._tests = [cls(name='Name {}'.format(i)) for i in range(100)]
... cls.objects = self
... return cls
... def get(self, id):
... return self._tests[id]
...
>>> manager = TestManager()
>>> #manager.init_class
... class Test(object):
... def __init__(self, name=''):
... self.name = name
...
>>> manager.get(5)
<__main__.Test object at 0x7f4319db8110>
The above recipe works if TestManager is a Singleton, but if it is not a singleton you simply have to remember to call TestManager.init_class(TheClass) before accessing the class instances, and that can be done anywhere in your code.
You can also use getters for this:
>>> class TheGetter(object):
... def __init__(self, cls):
... self._cls = cls
... self._inst = None
... def __get__(self, inst, owner):
... if self._inst is None:
... self._inst = self._cls()
... return self._inst
...
>>> class Test(object):
... objects = TheGetter(TestManager)
... def __init__(self, name):
... self.name = name
...
>>> Test.objects.get(5)
<__main__.Test object at 0x7f431690c0d0>

Categories