Create a picklable Python class - python

I am trying to create some custom Python classes for my application. When I try to debug my code I can not pick the instances of my custom classes, I receive the error "Object XXX is not picklable".
I found this page https://docs.python.org/3/library/pickle.html#what-can-be-pickled-and-unpickled but I don't understand how I should implement the methods that make my class picklable.
For example how would you modify the following classes so that I can pick instances of them?
class Point3D:
def __init__ (self, x, y, z):
self.x = x
self.y = y
self.z = z
def move(self, vector):
self.x += vector.x
self.y += vector.y
self.z += vector.z
return
def isValidPoint(self):
isNotValid = False
isNotValid = math.isnan(self.x) or math.isnan(self.y) or math.isnan(self.z)
return not isNotValid
And
class PointCloud3D:
def __init__ (self):
self.points = []
def getNumberOfPoints(self):
return len(self.points)
def addPoint(self, point):
self.points.append(point)
return
def addPointCloud3D(self, additionalPointCloud3D):
for self.point in additionalPointCloud3D:
self.addPoint(point)
def getCloudCenter(self):
numberOfPoints = self.getNumberOfPoints()
centersSumX = 0
centersSumY = 0
centersSumZ = 0
for point in self.points:
centersSumX = centersSumX + point.x
centersSumY = centersSumY + point.y
centersSumZ = centersSumZ + point.z
centerX = centersSumX/numberOfPoints
centerY = centersSumY/numberOfPoints
centerZ = centersSumZ/numberOfPoints
center = Point3D(float(centerX), float(centerY) , float(centerZ))
return center
While here you can find the code that I am trying to debug:
from classDatabase import Point3D, PointCloud3D
testPoint1 = Point3D(1.5, 0.2, 2.3)
testPoint2 = Point3D(3.5, 1.2, 5.3)
testPointCloud3D = PointCloud3D()
testPointCloud3D.addPoint(testPoint1)
testPointCloud3D.addPoint(testPoint2)
Finally a screenshot of the issue:

Related

how to make a temporary object from withing the class function in python?

I'm writing this code and there is a need to send objects as parameters in functions. My problem is one of the objects needs to be resued with its original values but as I need to return an object from the functions.
I don't know how I can send the answer and keep the original values in the object
safe for reuse. Is there any way to make an object from the class declaration itself?
import math
class Points(object):
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
def __sub__(self, no):
no.x = no.x - self.x
no.y = no.y - self.y
no.z = no.z - self.z
return(no)
def dot(self, no):
ans = (self.x * no.x)+(self.y * no.y)+(self.z * no.z)
return ans
def cross(self, no):
x = (self.y * no.z)-(self.z * no.y)
y = (self.x * no.z)-(self.z * no.x)
z = (self.x * no.y)-(self.y * no.x)
self.x = x
self.y = y
self.z = z
return(self)
def absolute(self):
return pow((self.x ** 2 + self.y ** 2 + self.z ** 2), 0.5)
if __name__ == '__main__':
points = list()
for i in range(4):
a = list(map(float, input().split()))
points.append(a)
a, b, c, d = Points(*points[0]), Points(*points[1]), Points(*points[2]), Points(*points[3])
x = (b - a).cross(c - b)
y = (c - b).cross(d - c)
angle = math.acos(x.dot(y) / (x.absolute() * y.absolute()))
print("%.2f" % math.degrees(angle))
I want to do something like:
def function_name(self,other)
temp.x = self.x + other.x
temp.y = self.y + other.y
return temp
This way both input objects will have their original values but I don't know how to get that temp.
Thanks everyone who helped. I got the answer to what I was looking. I wanted an object to act as a container that can store the class variables,
and I didn't knew I can just make a new object of the class from within it!
import math
class Points(object):
def __init__(self, x, y, z):
self.x=x
self.y=y
self.z=z
def __sub__(self, no):
return Points((self.x-no.x),(self.y-no.y),(self.z-no.z))
def dot(self, no):
return (self.x*no.x)+(self.y*no.y)+(self.z*no.z)
def cross(self, no):
return Points((self.y*no.z-self.z*no.y),(self.z*no.x-self.x*no.z),(self.x*no.y-self.y*no.x))
def absolute(self):
return pow((self.x ** 2 + self.y ** 2 + self.z ** 2), 0.5)
As you can see using points, i.e the constructor for class Points, I can store the result of any operations and can return it as an object while not altering my input objects.
If what you're trying to do is reuse a variable that you have passed to a class object, you can just duplicate it in your __init__ statement, or in the function where you use it.
e.g
class Foo:
def __init__(self, my_var1, my_var2):
self.my_var1 = my_var1
self.my_var2 = my_var2
def bar(self):
bar_var1 = self.my_var1
bar_var2 = self.my_var2
bar_var1 = bar_var1 + bar_var2
return bar_var1
Although, I am a little confused by why you are attempting to return self in your cross function, as self is a class parameter, and you don't seem to be using it in its intended purpose. If you're confused about how you should be using self, a brief read through the python class tutorial might be helpful. However, barring that, I hope this answers your question.

Calling method inside __str__ function in python class

'List' object has no attribute 'points' is the error I'm getting. I think I'm not calling points correctly inside the __str__ function, but don't know how to fix it. Before, I had points defined before __str__ and had the same error.
class Persons(object):
def __init__(self,name,radius,home_universe,x,y,dx,dy,current_universe,rewards):
self.name = name
self.radius = radius
self.home_universe = home_universe
self.x = x
self.y = y
self.dx = dx
self.dy = dy
self.current_universe = current_universe
self.rewards = rewards
def __str__(self):
return '{} of {} in universe {}\n at ({},{}) speed ({},{}) with {} rewards and {} points'.\
format(self.name, self.home_universe, self.current_universe, self.x, self.y, self.dx,\
self.dy, len(self.rewards), self.rewards.points())
def points(self):
cnt = 0
if len(self.rewards) == 0:
return 0
else:
for reward in self.rewards:
cnt += reward[2]
return cnt
You use self.rewards.points() but you have only self.points().
Use self.points()

Methods with keywords from the instances's attributes

The perfect, but impossible, scenario would be:
class example(object):
def __init__(self,x,y):
self.x = x
self.y = y
def foo(self, x = self.x, y = self.y):
return x + y
It doesn't work because self isn't defined. I have done lots of research, looked on decorators, descriptors, metaclasses, almost everything. The solution may be the most obvious and known to all, but I couldn't find it. I could manage two workarounds, as follows:
def prep(argslist, argsprovided, attributes):
argsout = []
for name in argslist:
if name in argsprovided:
argsout.append(argsprovided[name])
else:
argsout.append(getattr(attributes,name))
return argsout
class example(object):
# I can create a default instance or a custom one
def __init__(self,x = 1,y = 1,z = 1,w = 1):
self.x = x
self.y = y
self.z = z
self.w = w
# I can wrap a function to use the self argument
def wrapper(self):
def foo(x = self.x, y = self.y, z = self.z, w = self.w):
return x + y + z + w
return foo
# I can wrap 'joo' alongside with foo, and make 'wrapper' return a list
def joo(self, **kwargs):
[x,y,z,w] = prep(['x','y','z','w'],kwargs,self)
return x + y + z + 2*w
# I can use my custom 'prep' function to to the job
def foo(self, **kwargs):
[x,y,z,w] = prep(['x','y','z','w'],kwargs,self)
return x + y + z + w
# Creates a default instance and a custom one
c = example()
d = example(2,2,2,2)
# I can use 'foo' with the instance's default values with both wrapping and 'prepping'
print(c.wrapper()())
print(d.wrapper()())
print(c.foo())
print(d.foo())
# I can use 'foo' with a mix of default values and provided values with both wrapping and 'prepping'
print(c.wrapper()(1,2,3))
print(d.wrapper()(1,2,3))
print(c.foo(y = 3,z = 4,w = 5))
print(d.foo(y = 3,z = 4,w = 5))
The code prints out:
4
8
4
8
7
8
13
14
I have a huge class with lots of functions, every one needs the behavior of 'foo'. My prep solution is too time consuming. After profiling the code, I figured it spent 12 seconds inside prep only. What is a clever and less time consuming way of doing this? I'm completely lost.
I'm not sure it will help but how about using None as a default value and use a clause to determine the value. For example:
def foo(self, x=None, y=None):
real_x = x if x != None else self.x
real_y = y if y != None else self.y
return real_x + real_y
I found six ways of doing what I wanted. After profiling the code, the result was:
afoo foo noo1 noo2 wrap1 wrap2
6.730 28.507 3.98 4.097 10.256 3.468
6.407 28.659 4.096 3.924 9.783 3.529
6.277 28.450 3.946 3.889 10.265 3.685
6.531 30.287 3.964 4.149 10.077 3.674
As you will see ahead, noo1, noo2 and wap2 are quite similar on code. The conventional method afoo is not that efficient. My custom method foo is terrible and wrap1 was just tested for the sake of completeness.
afoo.py
The drawback is that you need an extra line for each function argument.
class example(object):
# I can create a default class or a custom one
def __init__(self,x = 1,y = 1,z = 1,w = 1):
self.x = x
self.y = y
self.z = z
self.w = w
def afoo(self, x = None, y = None, z = None, w = None):
x = x if x != None else self.x
y = y if y != None else self.y
z = z if z != None else self.z
w = w if w != None else self.w
return x + y + z + w
c = example(2,2,2,2)
for i in range(0, 10000000):
c.afoo(1,2,3,4)
foo.py
This one is the slower method.
def prep(argslist, argsprovided, attributes):
argsout = []
for name in argslist:
if name in argsprovided:
argsout.append(argsprovided[name])
else:
argsout.append(getattr(attributes,name))
return argsout
class example(object):
# I can create a default class or a custom one
def __init__(self,x = 1,y = 1,z = 1,w = 1):
self.x = x
self.y = y
self.z = z
self.w = w
def foo(self, **kwargs):
[x,y,z,w] = prep(['x','y','z','w'],kwargs,self)
return x + y + z + w
c = example(2,2,2,2)
for i in range(0, 10000000):
c.foo(x = 1,y = 2,z = 3,w = 4)
wrapper1.py
By far less efficient than wrapper2.py.
class example(object):
# I can create a default class or a custom one
def __init__(self,x = 1,y = 1,z = 1,w = 1):
self.x = x
self.y = y
self.z = z
self.w = w
def wrapper(self):
def foo(x = self.x, y = self.y, z = self.z, w = self.w):
return x + y + z + w
return foo
c = example(2,2,2,2)
for i in range(0, 10000000):
c.wrapper()(1,2,3,4)
wrapper2.py
class example(object):
# I can create a default class or a custom one
def __init__(self,x = 1,y = 1,z = 1,w = 1):
self.x = x
self.y = y
self.z = z
self.w = w
def wrapper(self):
def foo(x = self.x, y = self.y, z = self.z, w = self.w):
return x + y + z + w
return foo
c = example(2,2,2,2)
k = c.wrapper()
for i in range(0, 10000000):
k(1,2,3,4)
noo1.py
class example(object):
# I can create a default class or a custom one
def __init__(self,U,x = 1,y = 1,z = 1,w = 1):
self.x = x
self.y = y
self.z = z
self.w = w
def noo(x = self.x, y = self.y, z = self.z, w = self.w):
return x + y + z + w
self.noo = noo
c = example(2,2,2,2)
for i in range(0, 10000000):
c.noo(1,2,3,4)
noo2.py
class example(object):
# I can create a default class or a custom one
def __init__(self,x = 1,y = 1,z = 1,w = 1):
self.x = x
self.y = y
self.z = z
self.w = w
def __call__(self):
def noo(x = self.x, y = self.y, z = self.z, w = self.w):
return x + y + z + w
self.noo = noo
c = example(2,2,2,2)
c()
for i in range(0, 10000000):
c.noo(1,2,3,4)
When testing these codes I included the prep function in all of them, just to be shure they had the same basic structure, and thus the time difference would be from the loops.

How to create an object in python without using __init__

So for this piece of code
class CircleT:
def __init__(self,x,y,r):
self.x = x
self.y = y
self.r = r
Lets say I want to create a CircleT object named Circle1.
I would just have to do
Circle1 = CircleT(2,4,6)
But if I had this instead
class CircleT:
def CircleT(self,x,y,r):
self.x = x
self.y = y
self.r = r
How would I go about creating the Circle1 object?

Changed all objects value in list in object changed instead of only one

I have problem with my program. When I try to change object value (which is in list) I changed all object's value in that list.
My code:
class obj:
def __init__(self, x, y):
self.x = x
self.y = y
def mirrorise(self, mirror):
self.mirror = mirror
if self.mirror.type == 'teleporterx':
self.x -= (self.x-(self.mirror.x+self.mirror.x1/2))*2
class person(obj):
def __init__(self, x, y):
self.x = x
self.y = y
self.pos = [obj(self.x, self.y)]
def mirrored(self, mirrors):
self.count = 0
self.mirrors = mirrors
self.mens = 0
for men in self.pos:
self.mens += 1
for mirror in self.mirrors:
if self.count == 1:
for men in range(self.mens):
self.pos.append(self.pos[men])
self.count = 1
self.count = 0
for men in self.pos:
men.mirrorise(self.mirrors[self.count])
self.count += 1
if self.mirrors[self.count-1] == self.mirrors[-1]:
self.count = 0
class mirror:
def __init__(self, x, y, x1, y1, type):
self.x = x
self.y = y
self.x1 = x1
self.y1 = y1
self.type = type
After in code I call person object called I and two mirror objects called mirr and mirr2 with type teleportx. When I write:
I.mirrored([mirr, mirr2])
it changes x for all objects in I.pos. If I write
I.pos[3].mirrorise(mirr)
it still changes all x. Even if I write:
I.pos[3].x -= (I.pos[3].x-(mirr2.x+mirr.x1/2))*2
it changes all values. So, is it some Python rule or I have mistake?
You are adding references to your one original obj() instance:
self.pos.append(self.pos[men])
That's not a copy; that's just another reference to the same object.
Create a new obj() instance instead:
self.pos.append(obj(self.pos[men].x, self.pos[men].y))

Categories

Resources