Diferències
Ací es mostren les diferències entre la revisió seleccionada i la versió actual de la pàgina.
| Ambdós costats versió prèvia Revisió prèvia | |||
| info:cursos:pue:python-pcpp1:m1:4.2 [05/11/2023 21:34] – suprimit - edició externa (Unknown date) 127.0.0.1 | info:cursos:pue:python-pcpp1:m1:4.2 [05/11/2023 21:34] (actual) – ↷ Page moved from info:cursos:pue:python-pcpp1:4.2 to info:cursos:pue:python-pcpp1:m1:4.2 mate | ||
|---|---|---|---|
| Línia 1: | Línia 1: | ||
| + | = 4.2 Serialization of Python objects using the pickle module | ||
| + | In this section, you will learn how to persist Python objects for later use. | ||
| + | **Pickling** is the process of preserving or extending the lifespan of food. The resulting food is called a pickle, and to prevent ambiguity, prefaced with the ' | ||
| + | |||
| + | Have you ever considered saving the output of your data processing for later use? | ||
| + | |||
| + | The simplest way to persist outcomes is to generate a flat text file and to write your outcomes. It’s a very simple thing to do way which is not suitable for persisting sets of different types of objects or nested structures. | ||
| + | |||
| + | In Python, object **serialization** is the process of converting an object structure into a stream of bytes to store the object in a file or database, or to transmit it via a network. This byte stream contains all the information necessary to reconstruct the object in another Python script. | ||
| + | |||
| + | This reverse process is called **deserialization**. | ||
| + | |||
| + | Python objects can also be serialized using a module called ' | ||
| + | |||
| + | The ' | ||
| + | |||
| + | So, what can be pickled and then unpickled? | ||
| + | |||
| + | The following types can be pickled: | ||
| + | |||
| + | * None, booleans; | ||
| + | * integers, floating-point numbers, complex numbers; | ||
| + | * strings, bytes, bytearrays; | ||
| + | * tuples, lists, sets, and dictionaries containing pickleable objects; | ||
| + | * objects, including objects with references to other objects (remember to avoid cycles!) | ||
| + | * references to functions and classes, but not their definitions. | ||
| + | |||
| + | Let's pickle our first set of data consisting of: | ||
| + | * a nested dictionary carrying some information about currencies; | ||
| + | * a list containing a string, an integer, and a list. | ||
| + | |||
| + | When you run the code presented in the right pane, a new file should be created. Remember to run the code locally. | ||
| + | <code python> | ||
| + | import pickle | ||
| + | |||
| + | a_dict = dict() | ||
| + | a_dict[' | ||
| + | a_dict[' | ||
| + | a_dict[' | ||
| + | a_dict[' | ||
| + | |||
| + | a_list = [' | ||
| + | |||
| + | with open(' | ||
| + | pickle.dump(a_dict, | ||
| + | pickle.dump(a_list, | ||
| + | |||
| + | </ | ||
| + | | ||
| + | The code starts with the import statement responsible for loading the pickle module: | ||
| + | <code python> | ||
| + | import pickle | ||
| + | </ | ||
| + | |||
| + | Later you can see that the file handle ' | ||
| + | <code python> | ||
| + | with open(' | ||
| + | </ | ||
| + | Now it’s time to persist the first object with the '' | ||
| + | <code python> | ||
| + | pickle.dump(a_dict, | ||
| + | </ | ||
| + | |||
| + | And the second object is persisted in the same way: | ||
| + | <code python> | ||
| + | pickle.dump(a_list, | ||
| + | </ | ||
| + | |||
| + | Now it’s time to unpickle the contents of the file. | ||
| + | |||
| + | <code python> | ||
| + | import pickle | ||
| + | |||
| + | with open(' | ||
| + | data1 = pickle.load(file_in) | ||
| + | data2 = pickle.load(file_in) | ||
| + | |||
| + | print(type(data1)) | ||
| + | print(data1) | ||
| + | print(type(data2)) | ||
| + | print(data2) | ||
| + | |||
| + | </ | ||
| + | |||
| + | The presented code is quite simple: | ||
| + | |||
| + | * we’re importing a pickle module; | ||
| + | * the file is opened in binary mode and the file handle is associated with the file; | ||
| + | * we consecutively read some portions of data and deserialize it with the '' | ||
| + | * finally, we examine the type and contents of the objects. | ||
| + | |||
| + | Pay attention to the fact that with the ' | ||
| + | |||
| + | <code ; output> | ||
| + | <class ' | ||
| + | {' | ||
| + | <class ' | ||
| + | [' | ||
| + | </ | ||
| + | |||
| + | At the beginning of the serialization module, we mentioned that serialized objects could be persisted in a database or sent via a network. This implies another two functions corresponding to the '' | ||
| + | |||
| + | * '' | ||
| + | * '' | ||
| + | |||
| + | An example of in situ serialization and deserialization is presented in the right pane. | ||
| + | |||
| + | <code python> | ||
| + | import pickle | ||
| + | |||
| + | a_list = [' | ||
| + | bytes = pickle.dumps(a_list) | ||
| + | print(' | ||
| + | |||
| + | # now pass ' | ||
| + | |||
| + | # therefore when you receive a bytes object from an appropriate driver you can deserialize it | ||
| + | b_list = pickle.loads(bytes) | ||
| + | print(' | ||
| + | print(' | ||
| + | |||
| + | </ | ||
| + | |||
| + | <code ; output> | ||
| + | Intermediate object type, used to preserve data: <class ' | ||
| + | A type of deserialized object: <class ' | ||
| + | Contents: [' | ||
| + | </ | ||
| + | |||
| + | Remember that attempts to pickle non-pickleable objects will raise the '' | ||
| + | |||
| + | Trying to pickle a highly recursive data structure (mind the cycles) may exceed the maximum recursion depth, and a '' | ||
| + | |||
| + | Note that functions (both built-in and user-defined) are pickled by their name reference, not by any value. This means that only the function name is pickled; neither the function’s code, nor any of its function attributes, are pickled. | ||
| + | |||
| + | Similarly, classes are pickled by named reference, so the same restrictions in the unpickling environment apply. Note that none of the class’s code or data are pickled. | ||
| + | |||
| + | This is done on purpose, so you can fix bugs in a class or add methods to the class, and still load objects that were created with an earlier version of the class. | ||
| + | |||
| + | Hence, your role is to ensure that the environment where the class or function is unpickled is able to import the class or function definition. In other words, the function or class must be available in the namespace of your code reading the pickle file. | ||
| + | |||
| + | Otherwise, an '' | ||
| + | |||
| + | The following code demonstrates the situation for function definition pickling: | ||
| + | <code python> | ||
| + | import pickle | ||
| + | |||
| + | def f1(): | ||
| + | print(' | ||
| + | |||
| + | with open(' | ||
| + | pickle.dump(f1, | ||
| + | </ | ||
| + | We see no errors, so we might conclude that '' | ||
| + | |||
| + | Run the code in the editor and see what happens. | ||
| + | |||
| + | <code python> | ||
| + | import pickle | ||
| + | |||
| + | with open(' | ||
| + | data = pickle.load(file_in) | ||
| + | |||
| + | print(type(data)) | ||
| + | print(data) | ||
| + | data() | ||
| + | |||
| + | </ | ||
| + | Unfortunately, | ||
| + | <code ; output> | ||
| + | Traceback (most recent call last): | ||
| + | File " | ||
| + | data = pickle.load(file_in) | ||
| + | AttributeError: | ||
| + | </ | ||
| + | |||
| + | Here’s the same example regarding class definition and object pickling: | ||
| + | |||
| + | <code python> | ||
| + | import pickle | ||
| + | |||
| + | class Cucumber: | ||
| + | def __init__(self): | ||
| + | self.size = ' | ||
| + | |||
| + | def get_size(self): | ||
| + | return self.size | ||
| + | |||
| + | cucu = Cucumber() | ||
| + | |||
| + | with open(' | ||
| + | pickle.dump(cucu, | ||
| + | </ | ||
| + | |||
| + | We see no errors, so we might conclude that the '' | ||
| + | |||
| + | <code python> | ||
| + | import pickle | ||
| + | |||
| + | with open(' | ||
| + | data = pickle.load(file_in) | ||
| + | |||
| + | print(type(data)) | ||
| + | print(data) | ||
| + | print(data.size) | ||
| + | print(data.get_size()) | ||
| + | |||
| + | </ | ||
| + | |||
| + | If you run the code, you receive: | ||
| + | <code ; output> | ||
| + | Traceback (most recent call last): | ||
| + | File " | ||
| + | data = pickle.load(file_in) | ||
| + | AttributeError: | ||
| + | </ | ||
| + | The remedy for the above problems is: the code that calls the '' | ||
| + | |||
| + | A few additional words about the pickle module: | ||
| + | |||
| + | * it’s a Python implementation of the serialization process, so the pickled data cannot be exchanged with programs written in other languages like Java or C++. In such cases, you should think about the JSON or XML formats, which could be less convenient than pickling, but when assimilated are more powerful than pickling; | ||
| + | * the pickle module is constantly evolving, so the binary format may differ between different versions of Python. Pay attention that both serializing and deserializing parties are making use of the same pickle versions; | ||
| + | * the pickle module is not secured against erroneous or maliciously constructed data. Never unpickle data received from an untrusted or unauthenticated source. | ||