Pickle errors with Python 3 - python

I'm converting some code from Python 2 to Python 3, and I have hard time with a pickle problem! Here is a simple example of what I'm trying to do:
class test(str):
def __new__(self, value, a):
return (str.__new__(self, value))
def __init__(self, value, a):
self.a = a
if __name__ == '__main__':
import pickle
t = test("abs", 5)
print (t)
print( t.a)
wdfh = open("./test.dump", "wb")
pickle.dump(t, wdfh)
wdfh.close()
awfh = open("./test.dump", "rb")
newt = pickle.load(awfh)
awfh.close()
print (t)
print (newt.a)
This works just fine with Python 2 but I have the following error with Python 3:
Traceback (most recent call last):
File "test.py", line 21, in
newt = pickle.load(awfh)
TypeError: new() takes exactly 3 arguments (2 given)
I do not understand what is the difference, any idea?

The problem here is that your code only works with protocol 0 or 1. By default, Python 2 uses protocol 0, whereas Python 3 uses protocol 3.
For protocol 2 and above you can't have additional arguments to the __new__ method unless you implement the __getnewargs__ method.
In this case simply adding:
def __getnewargs__(self):
return (str(self),self.a)
should do the trick.
Or you could stick with protocol 0 or 1 and change the dump call:
pickle.dump(t, wdfh, 0)

Related

Why is it in python so easy to overwrite a class method?

How can I protect in Python class methods from beeing mistakenly changed? Is there some kind of a "write protection"?
Example:
class bar():
def blob(self):
return 2
if __name__ == "__main__":
foo = bar()
print(foo.blob()) # Returns 2
foo.blob = 1 # Overwrites the method "blob" without a warning!
# foo.blob returns 1, foo.blob() is not callabele anymore :(
foo.blib = 1 # Is also possible
print(foo.blob)
print(foo.blob())
When I call this script returns:
2
1
Traceback (most recent call last):
File "blob.py", line 18, in <module>
print(foo.blob())
TypeError: 'int' object is not callable
I would prefer do get a warning.

Creating functions dynamically in Python -- f(2) cannot resolve (f1)

I am trying to dynamically create 2 functions defined within a string. Code:
def main():
fns = '''
def plus_one(x):
return x + 1
def plus_two(x):
return plus_one(x) + 1
'''
exec(fns)
result = eval('plus_two(11)')
print(result)
if __name__ == '__main__':
main()
Saving this code to a file called dyn_code.py and running it gives me the following error:
python dyn_code.py
Traceback (most recent call last):
File "dyn_code.py", line 19, in <module>
main()
File "dyn_code.py", line 14, in main
result = eval('plus_two(11)')
File "<string>", line 1, in <module>
File "<string>", line 7, in plus_two
NameError: name 'plus_one' is not defined
Problem here is that plus_one cannot be resolved inside plus_two.
plus_one on its own is fine here and can be called with the correct result.
Can anybody please give me an idea on how to inject code like this into the local namespace? Specifically, I want to create 2 functions, with one referring to the other.
I have intentionally used the most open form of both exec and eval, I do know how to restrict them, etc. I have also verified that after the call to exec both functions are present in the local namespace.
What makes this more frustrating is that the code works fine in an interpreter session! That is, after injecting these 2 functions into the interpreter namespace via exec, plus_two runs without any issues.
Ideally, I would like to avoid a function-in-function scenario i.e.
def plus_two(x):
def plus_one(x):
return x + 1
return plus_one(x) + 1
This technique actually works but I want 2 explicitly named and standalone functions.
indentations of your function in fns matters! and you have to pass globals() optional argument for mapping!
def main():
fns = '''def plus_one(x):
return x + 1
def plus_two(x):
return plus_one(x) + 1
'''
exec(fns,globals())
result = eval('plus_two(11)')
print(result)
if __name__ == '__main__':
main()
Output:
13
Hope it helps!
You need to add the globals() dictionary in your call to exec(). You can also omit the eval call for plus_two, like so:
def main():
exec('def plus_one(x):\n return x + 1\n\ndef plus_two(x): return plus_one(x) + 1', globals())
print(plus_two(11))
if __name__ == '__main__':
main()

TypeError: 'dict' object is not callable from main

I wrote a code which is going to store occurrences of words from a text file and store it to a dictionary:
class callDict(object):
def __init__(self):
self.invertedIndex = {}
then I write a method
def invertedIndex(self):
print self.invertedIndex.items()
and here is how I am calling:
if __name__ == "__main__":
c = callDict()
c.invertedIndex()
But it gives me the error:
Traceback (most recent call last):
File "E\Project\xyz.py", line 56, in <module>
c.invertedIndex()
TypeError: 'dict' object is not callable
How can I resolve this?
You are defining a method and an instance variable in your code, both with the same name. This will result in a name clash and hence the error.
Change the name of one or the other to resolve this.
So for example, this code should work for you:
class CallDict(object):
def __init__(self):
self.inverted_index = {}
def get_inverted_index_items(self):
print self.inverted_index.items()
And check it using:
>>> c = CallDict()
>>> c.get_inverted_index_items()
[]
Also check out ozgur's answer for doing this using #property decorator.
In addition to mu's answer,
#property
def invertedIndexItems(self):
print self.invertedIndex.items()
then here is how you'll cal it:
if __name__ == "__main__":
c = callDict()
print c.invertedIndexItems
Methods are attributes in Python, so you can't share the same name between them. Rename one of them.

Function into a Python class

I am new in Python and I wrote the following code:
class Frazione:
def __init__(self, Numeratore, Denominatore=1):
mcd=MCD(Numeratore,Denominatore)
self.Numeratore=Numeratore/mcd
self.Denominatore=Denominatore/mcd
def MCD(m,n):
if m%n==0:
return n
else:
return MCD(n,m%n)
def __str__(self):
return "%d/%d" %(self.Numeratore, self.Denominatore)
def __mul__(self, AltraFrazione):
if type(AltraFrazione)==type(5):
AltraFrazione=Frazione(AltraFrazione)
return Frazione(self.Numeratore*AltraFrazione.Numeratore, self.Denominatore*AltraFrazione.Denominatore)
__rmul__=__mul__
Open shell at the same folder of Frazione.py:
>>> from Frazione import Frazione
end then
>>> f=Frazione(10,5)
When I press Enter, I receive this output:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File ".\Frazione.py", line 5, in __init__
mcd=MCD(Numeratore,Denominatore)
NameError: global name 'MCD' is not defined
PS. I apologize for my english!
MCD is a method of Frazione, but you're calling it as if it were a global function. The easiest (and cleanest, IMHO) fix is to just move it outside the class, because it doesn't need to access any class or instance members.
So:
def MCD(m, n):
if m % n == 0:
return n
else:
return MCD(n, m % n)
class Frazione:
# as before but without MCD
If you do want to keep it in the class, then you might rewrite it to be iterative instead of recursive and call it as self.MCD in __init__. That's a good idea anyway, as Python's support for recursion is rather weak.

unit tests python "__init__() takes exactly 2 arguments (1 given)"

i'm having a problem in my unit tests, i don't know why, I'm gotting the following stack:
Traceback (most recent call last):
File "novaapiclient_tests.py", line 11, in test_create_server
nova = novaapiclient.NovaAPIClient()
TypeError: __init__() takes exactly 2 arguments (1 given)
follow my test code:
class TestFunction(unittest.TestCase):
def setUp(self):
self.nova = novaapiclient.NovaAPIClient()
def test_create_server(self):
self.setUp()
lsbf = self.nova.lst_of_servers(self.nova.listServers())
image = "3f9e6696-2ed2-4e06-ae16-c828062addbe"
flavor = "m1.tiny"
name = "testing_unit"
self.nova.createServer(image, flavor, name)
time.sleep(60)
lsaf = self.nova.lst_of_servers(self.nova.listServers())
if(len(lsbf) < len(lsaf)):
assertTrue(True)
else:
assertTrue(False)
def delete_server(self):
self.setUp()
serv_id = "13e0c3de-d736-47ec-bc22-3a794aa3e2a9"
self.nova.deleteServer(serv_id)
ls = self.nova.lst_of_servers(self.nova.listServers())
j = 0
fin = False
while(j < 3 and not fin):
time.sleep(75)
for i in range(len(ls)):
if(serv_id == str(ls[i])):
assertTrue(False)
break
assertTrue(True)
fin = True
break
j += 1
I tried to create a init method and cut the "self" in the methods, but i continues printing the error.
The novaapiclient.NovaAPIClient constructor needs to receive an argument, but you aren't passing any.
In this question of yours you did pass an argument to novaapiclient.NovaAPIClient, so I assume you need to do something similar.

Categories

Resources