import copyreg, pickle
class cars:
def __init__(self, name):
self.name = name
def myfunc(x):
return cars , (x.name,)
copyreg.pickle(cars, myfunc)
test = cars('hello')
print(pickle.dumps(test))
1 - Why did the class get called twise in this code ?
def myfunc(x):
#why does it need to be called here too ?
return cars , (x.name,)
#we already called the class here!!!
copyreg.pickle(cars, myfunc)
2 - and why comma in the tuple ?
CodePudding user response:
The following is solely based on the documentations of copyreg.pickle and pickle dispatch_table.
The copyreg module offers a way to define functions used while pickling specific objects. The pickle and copy modules use those functions when pickling/copying those objects. The module provides configuration information about object constructors which are not classes.
This is mentioned in the copyreg.pickle
docs, it basically tells that the function defined is used when pickling specified objects, here, it is cars
.
A pickler object’s dispatch table is a registry of reduction functions of the kind which can be declared using copyreg.pickle(). It is a mapping whose keys are classes and whose values are reduction functions.
This is mentioned in the pickle.dispatch_table
docs. It basically tells us that cars
is the class being used as a key
, and myfunc
as the reduction function used as its value
.
Here, to your doubts, copyreg
is not calling your class
. It is just creating/editing the dispatch_table
with the keys
(class) and values
(func).
If you are still confused, here's a little experiment, where I added a print
statement in the function:
import copyreg, pickle
class cars:
def __init__(self, name):
self.name = name
def myfunc(x):
print("This is a test")
return cars, (x.name,)
copyreg.pickle(cars, myfunc)
test = cars('hello')
print(pickle.dumps(test))
Output:
This is a test b'\x80\x04\x95!\x00\x00\x00\x00\x00\x00\x00\x8c\x08__main__\x94\x8c\x04cars\x94\x93\x94\x8c\x05hello\x94\x85\x94R\x94.'
Now, if I just remove the copyreg.pickle
line. The dispatch_table
won't be created:
import copyreg, pickle
class cars:
def __init__(self, name):
self.name = name
def myfunc(x):
print("This is a test")
return cars, (x.name,)
test = cars('hello')
print(pickle.dumps(test))
Ouput:
b'\x80\x04\x95 \x00\x00\x00\x00\x00\x00\x00\x8c\x08__main__\x94\x8c\x04cars\x94\x93\x94)\x81\x94}\x94\x8c\x04name\x94\x8c\x05hello\x94sb.'
As you can see, the function is not at all triggered. Because the relation is not yet created.
To summarize:
copyreg.pickle
just creates adispatch_table
withclass
askey
andfunc
asvalue
, and the function defined is used when pickling specifiedclass
.- For the tuple, the comment by
@Jean-FrançoisFabre
is the most suitable.
EDIT: Upon more research, here are the addons.
copyreg.pickle
makes the myfunc
function act as a reduction function of cars
. You can skip that part if you define __reduce__
method in the class itself.
Reduction functions are used by pickle
for instruction on how to reconstruct the original object from the pickle
object if it fails automatically.
import copyreg, pickle
class cars:
def __init__(self, name):
self.name = name
def __reduce__(self):
print("This is a test")
return cars, (self.name,)
test = cars('hello')
print(pickle.dumps(test))
Output:
This is a test b'\x80\x04\x95!\x00\x00\x00\x00\x00\x00\x00\x8c\x08__main__\x94\x8c\x04cars\x94\x93\x94\x8c\x05hello\x94\x85\x94R\x94.'
You can skip the copyreg.pickle
if a __reduce__
instance is mentioned in your class, and it will act the same.
If you want to know, why these values have to be returned in the function, this documentation will give you insight on it.