user defined class serialization and deserialization in python - python

I am very new to python : I want to serialize and deserialize my custom object in python. Please guide me on the same. I have a sample class :
import pickle
import json
class MyClass():
variable = "blah"
num = 10
def function(self):
print("this is a message inside the class.")
def get_variable():
return variable
def get_num():
return num
def main():
myObj = MyClass()
with open('/opt/infi/deeMyObj.txt', 'w') as output:
pickle.dump(myObj, output,pickle.HIGHEST_PROTOCOL)
with open('/opt/infi/deeMyObj.txt', 'r') as input:
myObjread = pickle.load(input)
print myObjread.get_variable()
print myObjread.get_num()
main()
I am getting following error :
Traceback (most recent call last):
File "sample.py", line 30, in
main()
File "sample.py", line 27, in main
print myObjread.get_variable()
TypeError: get_variable() takes no arguments (1 given)
Main intention is to read the object back.

To expand on jasonharper's comment, your get_variable and get_num methods aren't referring to the class's member variables. They should take the object as their first argument, e.g.
class MyClass:
...
def get_variable(self):
return self.variable
I think your serialization code is OK, but I might be wrong.
(Aside)
This is a bit off-topic, but another thing to note: when you define variables directly within the class block, they're defined on the class, not on objects of that class. That happens to work out in this case, since Python will look for a class-level variable of the same name if it can't find one on the object. However, if you store, say, a list in one of them and start modifying it, you'd end up sharing it between objects, which is probably not what you want. Instead you want to define them on in an __init__ method:
class MyClass:
def __init__(self):
self.variable = "blah"

Related

Is `self` actually mandatory for class methods in Python?

I saw a code snippet in Python 3.6.5 that can be replicated with this simplified example below and I do not understand if this is something concerning or not. I am surprised it works honestly...
class Foo:
def bar(numb):
return numb
A1 = bar(1)
print(Foo)
print(Foo.A1)
print(Foo.bar(17))
In all python guides that I have seen, self appears as the first argument for all the purposes we know and love. When it is not, the methods are decorated with a static decorator and all is well. This case works as it is, however. If I were to use the static decorator on bar, I get a TypeError when setting A1:
Traceback (most recent call last):
File "/home/user/dir/understanding_classes.py", line 1, in <module>
class Foo:
File "/home/user/dir/understanding_classes.py", line 7, in Foo
A1 = bar(1)
TypeError: 'staticmethod' object is not callable
Is this something that is OK keeping in the code or is this a potential problem? I hope the question is not too broad, but how and why does this work?
The first parameter of the method will be set to the receiver. We call it self by convention, but self isn't a keyword; any valid parameter name would work just as well.
There's two different ways to invoke a method that are relevant here. Let's say we have a simple Person class with a name and a say_hi method
class Person:
def __init__(self, name):
self.name = name
def say_hi(self):
print(f'Hi my name is {self.name}')
p = Person('J.K.')
If we call the method on p, we'll get a call to say_hi with self=p
p.say_hi() # self=p, prints 'Hi my name is J.K.'
What you're doing in your example is calling the method via the class, and passing that first argument explicitly. The equivalent call here would be
Person.say_hi(p) # explicit self=p, also prints 'Hi my name is J.K.'
In your example you're using a non-static method then calling it through the class, then explicitly passing the first parameter. It happens to work but it doesn't make a lot of sense because you should be able to invoke a non-static method by saying
f = Foo()
f.bar() # numb = f, works, but numb isn't a number it's a Foo
If you want to put a function inside of a class that doesn't have a receiver, that's when you want to use #staticmethod (or, #classmethod more often)
class Person:
def __init__(self, name):
self.name = name
def say_hi(self):
print(f'Hi my name is {self.name}')
#staticmethod
def say_hello():
print('hello')
p = Person('J.K.')
Person.say_hello()
p.say_hello()

Python: how to automatically create an instance in another class

In writing a Python (2.5) program, I tried to create a class and, in its __init__ function, automatically create an instance of another class with its name as an argument to the __init__ function, something like this:
class Class1:
def __init__(self,attribute):
self.attribute1=attribute
class Class2:
def __init__(self,instanceName):
#any of Class2's attributes
exec instanceName + '=Class1('attribute1')'
# this should produce an instance of Class1 whose name is instanceName
But when I make an instance of Class2, instance=Class2('instance2'), and try to get attribute1 of instance2 (which should have been created from Class2's __init__ function) I get an error message:
Traceback (most recent call last):
File "<pyshell#29>", line 1, in <module>
print instance2.attribute1
NameError: name 'instance2' is not defined
I don't know what the problem is, since name='instance3' and
exec name+'=Class1('attribute1') does work, though this is probably because I don't have much experience with Python. How would I be able to do something like this automatically when an instance is created?
I have to run, so hopefully, someone else can fix any mistakes in this post:
class Class1:
def __init__(self, attribute):
self.attribute1 = attribute
class Class2:
def __init__(self, instanceName):
setattr(self, instanceName, Class1(...)) # replace ... with whatever parameters you want

How can I get child classes to use parent variables without redefining them?

Long time reader, first time asker. Anyway, Here's the code I'm working with:
class Person(object):
def __init__(self, s):
self.name = s
self.secret = 'I HAVE THE COOKIES'
#classmethod
def shout(self):
print self.name.upper()
class Kid(Person):
def __init__(self, s):
super(Kid,self).__init__(s)
self.age = 12
b = Person('Bob')
k = Kid('Bobby')
print b.name
print k.name
print k.age
print k.secret
k.shout()
Which results in this output and error:
Bob
Bobby
12
I HAVE THE COOKIES
Traceback (most recent call last):
File "a.py", line 22, in <module>
k.shout()
File "a.py", line 8, in shout
print self.name.upper()
AttributeError: type object 'Kid' has no attribute 'name'
I assumed that Kid would be able to use the Person's shout method substituting its (the kid's) "self" for parent (where the method lives). Apparently, that's not the case. I know I could declare name outside of init, but that's both unable to accomodate inputted data and a no-no. Another alternative would be to redefine shout for every child of Person, but that's a lot of repeated code that I'm trying to avoid.
Thanks very much in advance!
The issue is that #classmethod is a method on a class. It does not have access to an instance's attributes. Specifically the method is actually passed the class object, thus self is misnamed. You should really call shout's argument cls. If you remove the #classmethod then this would all make sense and your code would work as expected.
As it is, you can think of k.shout() as equivalent to Kid.shout().

Why am I unable to perform a simple operation in the __init__ of my class?

Given below is a snippet from a class of which I am trying to create objects and getting error:
class FoF(object):
def __init__(self,path):
filepath=[]
filepath.append(self.FileOrFolder(path))
Upon executing which I get the following error:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "PathOps.py", line 6, in __init__
def __init__(self,path):
NameError: global name 'filepath' is not defined
After which I tried:
filepath=[]
class FoF(object):
def __init__(self,path):
global filepath.append(self.FileOrFolder(path))
And again:
File "<stdin>", line 1, in <module>
File "PathOps.py", line 6, in __init__
global filepath.append(self.FileOrFolder(path))
NameError: global name 'filepath' is not defined
What is causing the error and how do I fix it?
Try using insted of global the special word self.
So something like this
class FoF(object):
def __init__(self,path):
self.filepath=[]
self.filepath.append(self.FileOrFolder(path))
The reason this error comes up is because what python thinks you're trying to do is one of two things:
Either you're trying to reference a global variable called filepath -- which is clear that's not what you're trying
What's not so clear is that you could also define a class attribute called filepath -- the only problem with that is that you can't define a class attribute with a function of that class. You can only do so within the class -- outside a class function
So in order to declare variables within a function you have to use the word self before it.
Edit** if you want it to be an attribute of the class -- as I'm assuming is what you meant you could do so like this:
class FoF(object):
filepath=[]
def __init__(self,path):
self.filepath.append(self.FileOrFolder(path))
I don't think you're giving us enough information. For example:
>>> class FoF(object):
... def __init__(self, path):
... junk = []
... junk.append(path)
...
>>> foo = FoF('bar/path')
produces no error.
What, exactly, are you trying to do?

Error: "x instance has no attribute y" when trying to inherit from class

I can't really understand what I'm doing wrong, since when I try it in "small scale" and it is working there.
I have a class named Play()
I goes like this:
class Play():
def __init__(self):
file = open("/home/trufa/Desktop/test", "r")
self.word = random.choice(file.readlines()).rstrip()
self.errAllowed = 7
self.errMade = 0
self.errList = []
self.cheatsAllowed = 2##chetas not incrementing
self.cheatsMade =0
self.wordList = ["*"]*len(self.word) ##this one is the one I want to have available in another class
...
Then I have another class called Score()
class Score(Play):
def __init__(self):
self.initialScore = 0
def letterGuess(self):
self.initialScore += 1
return self.errList
...
I instantiated both:
game = Play()
points = Score()
And if I do:
print points.letterGuess()
It gives me an error:
Traceback (most recent call last):
File "/home/trufa/workspace/hangpy/src/v2.py", line 188, in <module>
startGame()
File "/home/trufa/workspace/hangpy/src/v2.py", line 134, in startGame
print points.letterGuess()
File "/home/trufa/workspace/hangpy/src/v2.py", line 79, in letterGuess
return self.errList
AttributeError: Score instance has no attribute 'errList'
I don't understand why since I can do this without any trouble:
class One():
def __init__(self):
self.list= [1,2]
class Two(One):
def meth(self):
return self.list
uan = One()
tu = Two()
print uan.list
print tu.meth() ## Both output [1,2]
I'm very new to OOP so I could be doing all kinds of silly mistakes but I can't figure out where!
I think I have posted all the relevant code, but I you think the error might be elsewhere, I can provide it.
As I said I'm very new, so this might have nothing to do with inheritance I just think it called that when you get "something" from within another class (you must be shouting at the screen by now)
You overwrite the original __init__, which is then never called and doesn't initialize the members. You must call the parent's __init__ separately, usually with this snippet:
def __init__(self):
super(Score, self).__init__()
See the docs for super() for details. However, super() only works for so-called new-style classes. You must therefore either change the definition of Play to inherit from object:
class Play(object)
or you call the parent's method directly:
def __init__(self):
Play.__init__(self)
When you inherit from the class Play, you automatically get the attributes that you've created in the definition of Play, but you don't get the attributes that you've created in Play.__init__. You have to explicitly call it like so:
class Score(Play):
def __init__(self):
Play.__init__(self)
self.initialScore = 0
See Boldewyn's suggestion for using super to do this; but IMO you should probably get used to the basic way inheritance works before fiddling with super.
To further clarify, if you don't override __init__ as you have in this case, then it's inherited and called automatically.
You forgot to initialize the superclass.
class Score(Play):
def __init__(self):
super(Score, self).__init__()
self.initialScore = 0

Categories