How to serialise both positional and non-positional arguments of Python objects? - python

How can I serialise test below:
class Foo:
a = 0
b = {}
def __init__(self, a, b=None):
self.a = a
if b:
self.b = b
test = Foo(1)
test.b['c'] = 2
so that the output is:
{"a": 1, "b": {"c": 2}}
I've tried:
print(json.dumps(test, default=lambda x: x.__dict__))
but it returns:
{"a": 1}
I understand that test.b['c'] = 2 does not add b or c to Foo.__dict__, which is probably why x.__dict__ in the lambda doesn't pick them up. So is the answer one of:
Do not assign key-value pairs to arbitrary objects; use setattr instead.
Do not define arbitrary classes, if its property set can evolve at runtime; use a simple dict instead.

The problem here is test.b is not a instance variable. So when you serialize the object test using json.dumps, its not finding an instance variable b at all.
If you redefine the constructor like below:
class Foo:
a = 0 #this is not instance variable - this is a class variable
b = {} #this is not instance variable - this is a class variable
def __init__(self, a, b=None):
self.a = a
self.b = {} #declared the instance variable b also
if b:
self.b = b
test = Foo(1)
test.b['c'] = 2
Now, if you run you get the desired output.

Related

looping through member variables and changing their type (in Python)?

Is it possible to iterate theough some member variables of a defined class, and then change the member variable type?
For instance something like the below:
def __init__(self, a, b, c):
self.A = a
self.B = b
self.C = c
self.memberVarsToChange = {self.A: float, self.B: float}
def convertTypes(self):
for item, t in self.memberVarsToChange.items():
item = t(item)
The item obviously doesn't refer to the member variable, it's local to the loop. Is there a way to refer to the actual member variable?
Many thanks.
FYI, in Python member variables are called attributes.
You need to store the attribute names in self.memberVarsToChange, not the attribute values. Then you can use getattr() and setattr() to update the attributes dynamically.
def __init__(self, a, b, c):
self.A = a
self.B = b
self.C = c
self.memberVarsToChange = {"A": float, "B": float}
def convertTypes(self):
for attr, t in self.memberVarsToChange.items():
setattr(self, attr, t(getattr(self, attr)))

Python bind method to another instance

I need to merge two methods from different instances of different classes to a single instance of a class.
For example I define two classes:
class A:
def __init__(self):
self.name = "a"
def print_name(self):
print(self.name)
class B:
def __init__(self):
self.name = "b"
def print_name(self):
print(self.name)
and then I will try to make another object c and its print_name method must return the results of a.print_name() and b.print_name() so I tried the following :
a = A()
b = B()
c = A()
c.name = "c"
c.print_name_1 = a.print_name
c.print_name_2 = b.print_name
def final_print(self):
self.print_name_1()
self.print_name_2()
c.print_name = MethodType(final_print, c)
c.print_name()
Expected output:
c
c
but I get :
a
b
I tried to use types.MethodType as described here but it creates some kind of a method which takes two arguments : the first one will be the 'a' instance and the second one will be the 'c' instance.
Any help to do that properly?
I managed to succeed with this, thanks to this answer. I am using the __func__ attribute of a method. So here is the code :
c.name = "c"
c.print_name_1 = MethodType(lambda instance: copy.deepcopy(a.print_name).__func__(instance), c)
c.print_name_2 = MethodType(lambda instance: copy.deepcopy(b.print_name).__func__(instance), c)
def final_print(self):
self.print_name_1()
self.print_name_2()
c.print_name = MethodType(final_print, c)
c.print_name()

Pass Arguments from Function to Class Method

I think this is programming 101, but the class I missed:
I have a class where roughly 50 default arguments are passed to init. The user can then provide different values for those arguments at the time of construction, or they can modify the resulting attributes in the normal way.
What I would like to do is create a function, probably outside of that class that allows the user to create multiple versions of the class, and then return useful information. However, each iteration of the class in the function will have different arguments for the constructor.
How best to allow the user of the function to supply arguments to the function that get passed on to the class constructor.
Here is what I am trying to achieve:
class someClass(object):
def __init__(self, a=None, b=None, c=None, d=None, e=None):
self.a = a
self.b = b
self.c = c
self.d = d
self.e = e
def some_method(self):
# do something
return # something useful
simulations = {'1': {'a':3, 'e':6},
'2': {'b':2, 'c':1}}
def func(simulations=simulations):
results = []
for sim in simulations.keys():
sc = someClass(simulations[sim]) # use the arguments in the dict to pass to constructor
results.append(sc.some_method())
return results
You can use ** to unpack a dictionary into named keywords:
sc = someClass(**simulations[sim])
would provide 3 as a, 6 as e the first time, then 2 as b and 1 as c the second time.

Getting the class a variable resides in

Lets say I have something like this -
class A(object):
c = C()
class B(A):
pass
class C(object):
def __init__(self):
pass
def get_parent_class(self):
# This should return B
How would I implement get_parent_class, so that it will work as following -
B.c.get_parent_class() # Returns the class type B (not the instance b!)
Is this even possible?
I basically have a parent class (class A in our example), which contains a variable (var c in the example). I then have a child-class (class B which inherits A)
I want to use functions that C exposes on B, but in order to be used properly, I need C to know it's running on B
(Hope I didn't complicate things in the last explanation...)
Edit -
Please note that I'm not trying to get the class of C, that's an easy c.__class__. I need the class holding c
Thanks!
AFAIK, you cannot do that.
B.c just returns a reference to a C object. Same object can be a member of a list, of an instance of another class (say D) and of another class (say E)
Just add to your example :
class D:
def __init__(self, c):
self.c = c
class E:
c = C()
Then :
>>> c = B.c
>>> E.c = c
>>> d = D(c)
>>> c.a = 1
>>> B.c.a
1
>>> d.c.a
1
>>> E.c.a
1
At that point, c object itself does not know that it belongs to B, d and E. And what should c.get_parent_class() return ? How to decide between B and E ?
You could try to make C aware of its container :
class C(object):
def __init__(self, clazz):
self.clazz = clazz
def get_parent_class(self):
return self.clazz
class A(object):
c = C(A)
You would get A.c.get_parent_class() giving <class '__main__.A'> but as it would be the same object, B.c.get_parent_class() will also give<class '__main__.A'> ...
You could take a look at the __bases__ attribute of your object. It returns a tuple of base classes for an object.
You can see it in the docs here.
You can get the class from the name attribute, example:
>>> import itertools
>>> x = itertools.count(0)
>>> x.__class__.__name__
'count'
Or this way:
>>> type(x).__name__
'count'

Dictionary in a child class to update the dictionary with same name defined in parent class instead of over-riding

I have existing classes which inherit from each other…they already have a attribute which is being overridden in subclasses . I want the dictionary attribute to be updated instead of overridden…code below …
class A:
d = {1:2}
class B(A):
d = {3:4}
b=B()
print b.d[1]
2
print b.d[3]
4
Is this possible at all? Say using metaclasses in a way that I can't think of readily.
class A(object):
d = {1:2}
class B(A):
d = {3:4}
def __init__(self):
dtemp = self.d
self.d = A.d.copy() # warning: shallow
self.d.update(dtemp)
b=B()
print b.d[1]
# 2
print b.d[3]
# 4
a=A()
print a.d[1]
# 2
print a.d[3]
# KeyError
Don't know what exactly you're trying to do here, but looks like collections.ChainMap may come in handy if you're on py3.3+:
from collections import ChainMap
...
dic = ChainMap(B.d, A.d)
Demo:
>>> dic[1]
2
>>> dic[3]
4
Any modification done to either A.d or B.d would reflect in dic
>>> A.d[4] = 5
>>> dic[4]
5
Modifying the dict itself would modify B.d(First dict passed to ChainMap):
>>> dic[6] = 7
>>> B.d
{3: 4, 6: 7}
Found this based on some of the ideas around:
class B(A):
_d = {}
def __init__(self):
for parent_klass in inspect.getmro(self.__class__):
_d.update(getattr(parent_klass, 'd', {}))
_d.update(self.d)
self.d = _d

Categories