Guardando y recuperando datos en Python usando Pickle

Muy fácil de usar. Aquí les muestro como grabar un objeto (Account) el cual tiene otros objetos adentro (lista de objetos tipo ‘Transaction’).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#!/usr/bin/env python3
# @author Jose Vicente Nunez - josevnz@kodeek.com
import os, os.path, pickle, tempfile
 
class Transaction:
 
    def __init__(self, amount, date, currency="USD", conv_rate=1.0, description=None):
        self.__amount = amount
        self.__date = date
        self.__currency = currency
        if conv_rate < 0:
            raise ValueError("Invalid amount:{0}".format(conv_rate))
        self.__conv_rate = float(conv_rate)
        self.__description  = description
 
    @property
    def amount(self):
        return self.__amount
 
    @property
    def date(self):
        return self.__date
 
    @property
    def currency(self):
        return self.__currency
 
    @property
    def description(self):
        return self.__description
 
    @property
    def conv_rate(self):
        return self.__conv_rate
 
    @property
    def usd(self):
        return self.__conv_rate * self.__amount
 
class Account:
 
    def __init__(self, number, name, transactions = []):
        self.__number = number
        self.__name = name
        if transactions == None:
            self.__transactions = []
        else:
            self.__transactions = transactions
 
    @property
    def number(self):
        return self.__number
 
    @property
    def name(self, name):
        if name == None:
            return self.__name
        if len(name) < 6:
            raise ValueError("Account name too short!")
        self.__name = name
 
    def __len__(self):
        return len(self.__transactions)
 
    @property
    def name(self):
        return self.__name
 
    @property
    def balance(self):
        balance = 0
        for bal in self.__transactions:
            balance += bal.usd
        return balance
 
    @property
    def all_usd(self):
        return len([t for t in self.__transactions if t.currency == "USD"]) == len(self.__transactions)
 
    def apply(self, transaction):
        if not isinstance(transaction, Transaction):
            raise ValueError("Invalid argument, can only add transactions!")
        self.__transactions.append(transaction)
 
    def __getFilename(self):
        return os.path.join(tempfile.gettempdir(), str(self.number))
 
    def save(self):
        fn = self.__getFilename()
        fh = None
        try:
            fh = open(fn, 'wb')
            pickle.dump([self.__name, self.__number, self.__transactions], fh, pickle.HIGHEST_PROTOCOL)
        except (EnvironmentError, pickle.PicklingError) as Error:
            raise SaveError(str(err))
        finally:
            if fh is not None:
                fh.close()
 
    def load(self):
        fn = self.__getFilename()
        fh = None
        try:
            fh = open(fn, 'rb')
            (self.__name, self.__number, self.__transactions) = pickle.load(fh)
        except (EnvironmentError, pickle.UnpicklingError) as Error:
            raise LoadError(str(err))
        finally:
            if fh is not None:
                fh.close()
 
if __name__ == "__main__":
    transactions = []
    transactions.append(
                        Transaction(
                                    15.0, 
                                    "06-06-1966", 
                                    "USD", 
                                    1.0, 
                                    description="XXXX paid me some money"))
    transactions.append(
                        Transaction(
                                    -2, 
                                    "06-06-1966", 
                                    "USD", 
                                    1.0, 
                                    description="I had to pay YYYYY some cash"))
    transactions.append(
                        Transaction(
                                    10000, 
                                    "06-06-1966", 
                                    "BsF", 
                                    0.0001, 
                                    description="Maduro paid me some money in Venezuelan BS. LOL"))
    account = Account(666666, "Savings account", transactions)
    account.apply(Transaction(-3, "02-28-1016", "USD", 1.0, "Coffee time"))
    print(
          "'{0}' Balance: ${1}, all in USD: {2}".format(
                                                        account.name, 
                                                        account.balance, 
                                                        account.all_usd))
    account.save()
    account.load()
    print(
          "'{0}' Balance: ${1}, all in USD: {2}".format(
                                                        account.name, 
                                                        account.balance, 
                                                        account.all_usd))

Pickle no es seguro (ya que se lleva a cabo ninguna validación en el código leido desde el archivo), sin embargo es increíblemente conveniente para programas pequeños que requieren guardar datos rápidamente con estructuras de datos complejas, como por ejemplo objetos anidados.