Tôi đã tạo một đối tượng như thế này:
company1.name = 'banana'
company1.value = 40
Tôi muốn lưu đối tượng này. Làm thế nào tôi có thể làm điều đó?
protocol=pickle.HIGHEST_PROTOCOL. Câu trả lời của tôi cũng đưa ra lựa chọn thay thế cho dưa chua.
Tôi đã tạo một đối tượng như thế này:
company1.name = 'banana'
company1.value = 40
Tôi muốn lưu đối tượng này. Làm thế nào tôi có thể làm điều đó?
protocol=pickle.HIGHEST_PROTOCOL. Câu trả lời của tôi cũng đưa ra lựa chọn thay thế cho dưa chua.
Câu trả lời:
Bạn có thể sử dụng picklemô-đun trong thư viện tiêu chuẩn. Đây là một ứng dụng cơ bản của nó cho ví dụ của bạn:
import pickle
class Company(object):
def __init__(self, name, value):
self.name = name
self.value = value
with open('company_data.pkl', 'wb') as output:
company1 = Company('banana', 40)
pickle.dump(company1, output, pickle.HIGHEST_PROTOCOL)
company2 = Company('spam', 42)
pickle.dump(company2, output, pickle.HIGHEST_PROTOCOL)
del company1
del company2
with open('company_data.pkl', 'rb') as input:
company1 = pickle.load(input)
print(company1.name) # -> banana
print(company1.value) # -> 40
company2 = pickle.load(input)
print(company2.name) # -> spam
print(company2.value) # -> 42
Bạn cũng có thể định nghĩa tiện ích đơn giản của riêng mình như sau sẽ mở tệp và ghi một đối tượng vào đó:
def save_object(obj, filename):
with open(filename, 'wb') as output: # Overwrites any existing file.
pickle.dump(obj, output, pickle.HIGHEST_PROTOCOL)
# sample usage
save_object(company1, 'company1.pkl')
Vì đây là một câu trả lời phổ biến, tôi muốn chạm vào một vài chủ đề sử dụng hơi nâng cao.
cPickle(hoặc _pickle) so vớipickleHầu như luôn luôn thích sử dụng cPicklemô-đun hơn là picklevì trước đây được viết bằng C và nhanh hơn nhiều. Có một số khác biệt tinh tế giữa chúng, nhưng trong hầu hết các tình huống chúng tương đương và phiên bản C sẽ cung cấp hiệu suất vượt trội hơn rất nhiều. Chuyển sang nó không thể dễ dàng hơn, chỉ cần thay đổi importtuyên bố này:
import cPickle as pickle
Trong Python 3, cPickleđã được đổi tên _pickle, nhưng thực hiện điều này không còn cần thiết nữa vì picklebây giờ mô-đun tự động có thể thấy sự khác biệt giữa dưa chua và _pickle trong python 3? .
Tóm tắt là bạn có thể sử dụng một cái gì đó như sau để đảm bảo rằng mã của bạn sẽ luôn sử dụng phiên bản C khi nó có sẵn trong cả Python 2 và 3:
try:
import cPickle as pickle
except ModuleNotFoundError:
import pickle
picklecó thể đọc và ghi các tệp theo nhiều định dạng khác nhau, dành riêng cho Python, được gọi là các giao thức như được mô tả trong tài liệu , "Giao thức phiên bản 0" là ASCII và do đó "có thể đọc được". Các phiên bản> 0 là nhị phân và phiên bản cao nhất có sẵn tùy thuộc vào phiên bản Python nào đang được sử dụng. Mặc định cũng phụ thuộc vào phiên bản Python. Trong Python 2, mặc định là phiên bản Giao thức 0, nhưng trong Python 3.8.1, đó là phiên bản Giao thức 4. Trong Python 3.x, mô-đun đã được pickle.DEFAULT_PROTOCOLthêm vào nó, nhưng điều đó không tồn tại trong Python 2.
May mắn thay, có tốc ký để viết pickle.HIGHEST_PROTOCOLtrong mỗi cuộc gọi (giả sử đó là những gì bạn muốn và bạn thường làm), chỉ cần sử dụng số bằng chữ -1- tương tự như tham chiếu phần tử cuối cùng của chuỗi thông qua chỉ số âm. Vì vậy, thay vì viết:
pickle.dump(obj, output, pickle.HIGHEST_PROTOCOL)
Bạn chỉ có thể viết:
pickle.dump(obj, output, -1)
Dù bằng cách nào, bạn chỉ chỉ định giao thức một lần nếu bạn đã tạo một Picklerđối tượng để sử dụng trong nhiều thao tác dưa chua:
pickler = pickle.Pickler(output, -1)
pickler.dump(obj1)
pickler.dump(obj2)
etc...
Lưu ý : Nếu bạn ở trong môi trường chạy các phiên bản Python khác nhau, thì có lẽ bạn sẽ muốn sử dụng rõ ràng (tức là mã cứng) một số giao thức cụ thể mà tất cả chúng có thể đọc (các phiên bản sau thường có thể đọc các tệp được tạo bởi các phiên bản trước đó) .
Trong khi một file dưa có thể chứa bất kỳ số đối tượng ngâm, như thể hiện trong các mẫu ở trên, khi có một số không rõ trong số họ, nó thường dễ dàng hơn để lưu trữ tất cả chúng trong một số loại của container variably cỡ, giống như một list, tuplehoặc dictvà ghi tất cả chúng vào tập tin trong một cuộc gọi duy nhất:
tech_companies = [
Company('Apple', 114.18), Company('Google', 908.60), Company('Microsoft', 69.18)
]
save_object(tech_companies, 'tech_companies.pkl')
và khôi phục danh sách và mọi thứ trong đó sau:
with open('tech_companies.pkl', 'rb') as input:
tech_companies = pickle.load(input)
Ưu điểm chính là bạn không cần biết có bao nhiêu trường hợp đối tượng được lưu để tải lại chúng sau này (mặc dù làm như vậy mà không có thông tin đó là có thể, nó yêu cầu một số mã chuyên dụng hơi). Xem câu trả lời cho câu hỏi liên quan Lưu và tải nhiều đối tượng trong tệp dưa chua? để biết chi tiết về các cách khác nhau để làm điều này. Cá nhân tôi thích câu trả lời của @Lutz Prechelt nhất. Đây là nó thích nghi với các ví dụ ở đây:
class Company:
def __init__(self, name, value):
self.name = name
self.value = value
def pickled_items(filename):
""" Unpickle a file of pickled data. """
with open(filename, "rb") as f:
while True:
try:
yield pickle.load(f)
except EOFError:
break
print('Companies in pickle file:')
for company in pickled_items('company_data.pkl'):
print(' name: {}, value: {}'.format(company.name, company.value))
company1và company2. Tại sao bạn cũng không xóa Companyvà hiển thị những gì xảy ra?
Tôi nghĩ rằng đó là một giả định khá mạnh mẽ để cho rằng đối tượng là một class. Nếu nó không phải là một class? Cũng có giả định rằng đối tượng không được xác định trong trình thông dịch. Điều gì nếu nó được định nghĩa trong trình thông dịch? Ngoài ra, nếu các thuộc tính được thêm động thì sao? Khi một số đối tượng python có các thuộc tính được thêm vào __dict__sau khi tạo, picklechúng không tôn trọng việc thêm các thuộc tính đó (tức là 'quên' chúng đã được thêm vào - bởi vì pickletuần tự hóa bằng cách tham chiếu đến định nghĩa đối tượng).
Trong tất cả các trường hợp, picklevà cPicklecó thể thất bại bạn khủng khiếp.
Nếu bạn đang tìm cách lưu object(được tạo tùy ý), trong đó bạn có các thuộc tính (được thêm vào trong định nghĩa đối tượng hoặc sau đó), đặt cược tốt nhất của bạn là sử dụng dill, có thể tuần tự hóa hầu hết mọi thứ trong python.
Chúng tôi bắt đầu với một lớp học
Python 2.7.8 (default, Jul 13 2014, 02:29:54)
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import pickle
>>> class Company:
... pass
...
>>> company1 = Company()
>>> company1.name = 'banana'
>>> company1.value = 40
>>> with open('company.pkl', 'wb') as f:
... pickle.dump(company1, f, pickle.HIGHEST_PROTOCOL)
...
>>>
Bây giờ hãy tắt và khởi động lại ...
Python 2.7.8 (default, Jul 13 2014, 02:29:54)
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import pickle
>>> with open('company.pkl', 'rb') as f:
... company1 = pickle.load(f)
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 1378, in load
return Unpickler(file).load()
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 858, in load
dispatch[key](self)
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 1090, in load_global
klass = self.find_class(module, name)
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 1126, in find_class
klass = getattr(mod, name)
AttributeError: 'module' object has no attribute 'Company'
>>>
Rất tiếc picklekhông thể xử lý nó. Hãy thử xem dill. Chúng tôi sẽ ném vào một loại đối tượng khác (a lambda) cho biện pháp tốt.
Python 2.7.8 (default, Jul 13 2014, 02:29:54)
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import dill
>>> class Company:
... pass
...
>>> company1 = Company()
>>> company1.name = 'banana'
>>> company1.value = 40
>>>
>>> company2 = lambda x:x
>>> company2.name = 'rhubarb'
>>> company2.value = 42
>>>
>>> with open('company_dill.pkl', 'wb') as f:
... dill.dump(company1, f)
... dill.dump(company2, f)
...
>>>
Và bây giờ đọc các tập tin.
Python 2.7.8 (default, Jul 13 2014, 02:29:54)
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import dill
>>> with open('company_dill.pkl', 'rb') as f:
... company1 = dill.load(f)
... company2 = dill.load(f)
...
>>> company1
<__main__.Company instance at 0x107909128>
>>> company1.name
'banana'
>>> company1.value
40
>>> company2.name
'rhubarb'
>>> company2.value
42
>>>
Nó hoạt động. Lý do picklethất bại, và dillkhông, là dillđối xử __main__như một mô-đun (đối với hầu hết các phần), và cũng có thể chọn các định nghĩa lớp thay vì chọn theo tham chiếu (như picklekhông). Lý do dillcó thể gây rắc rối lambdalà vì nó mang lại cho nó một cái tên, sau đó phép thuật ngâm có thể xảy ra.
Trên thực tế, có một cách dễ dàng hơn để lưu tất cả các đối tượng này, đặc biệt là nếu bạn có nhiều đối tượng bạn đã tạo. Chỉ cần đổ toàn bộ phiên python, và quay lại sau.
Python 2.7.8 (default, Jul 13 2014, 02:29:54)
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import dill
>>> class Company:
... pass
...
>>> company1 = Company()
>>> company1.name = 'banana'
>>> company1.value = 40
>>>
>>> company2 = lambda x:x
>>> company2.name = 'rhubarb'
>>> company2.value = 42
>>>
>>> dill.dump_session('dill.pkl')
>>>
Bây giờ hãy tắt máy tính của bạn, thưởng thức espresso hoặc bất cứ thứ gì, và quay lại sau ...
Python 2.7.8 (default, Jul 13 2014, 02:29:54)
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import dill
>>> dill.load_session('dill.pkl')
>>> company1.name
'banana'
>>> company1.value
40
>>> company2.name
'rhubarb'
>>> company2.value
42
>>> company2
<function <lambda> at 0x1065f2938>
Hạn chế lớn duy nhất dilllà không phải là một phần của thư viện chuẩn python. Vì vậy, nếu bạn không thể cài đặt gói python trên máy chủ của mình, thì bạn không thể sử dụng nó.
Tuy nhiên, nếu bạn có thể cài đặt các gói python trên hệ thống của mình, bạn có thể nhận được bản mới nhất dillvới git+https://github.com/uqfoundation/dill.git@master#egg=dill. Và bạn có thể nhận được phiên bản phát hành mới nhất với pip install dill.
TypeError: __new__() takes at least 2 arguments (1 given)khi cố gắng sử dụng dill(có vẻ đầy hứa hẹn) với một đối tượng khá phức tạp bao gồm tệp âm thanh.
TypeErrorkhi bạn làm gì, chính xác? Đó thường là dấu hiệu của việc có số lượng đối số sai khi khởi tạo một thể hiện của lớp. Nếu đây không phải là một phần của quy trình làm việc của câu hỏi trên, bạn có thể đăng nó dưới dạng câu hỏi khác không, gửi cho tôi qua email hoặc thêm nó dưới dạng một vấn đề trên dilltrang github?
dillvấn đề.
dilTôi cho tôi MemoryErrormặc dù! cũng vậy cPickle, picklevà hickle.
Bạn có thể sử dụng anycache để thực hiện công việc cho bạn. Nó xem xét tất cả các chi tiết:
picklemô-đun python để xử lý lambdavà tất cả các tính năng python đẹp.Giả sử bạn có một hàm myfunctạo cá thể:
from anycache import anycache
class Company(object):
def __init__(self, name, value):
self.name = name
self.value = value
@anycache(cachedir='/path/to/your/cache')
def myfunc(name, value)
return Company(name, value)
Anycache gọi myfunclần đầu tiên và chọn kết quả cho một tệp cachedirbằng cách sử dụng một mã định danh duy nhất (tùy thuộc vào tên hàm và đối số của nó) làm tên tệp. Trên bất kỳ lần chạy liên tiếp nào, đối tượng ngâm được tải. Nếu cachedirđược bảo tồn giữa các lần chạy trăn, đối tượng được lấy sẽ được lấy từ lần chạy trăn trước đó.
Để biết thêm chi tiết, xem tài liệu
anycacheđể lưu nhiều hơn một ví dụ, ví dụ, classhoặc một thùng chứa, chẳng hạn như list(đó không phải là kết quả của việc gọi hàm)?
Ví dụ nhanh sử dụng company1từ câu hỏi của bạn, với python3.
import pickle
# Save the file
pickle.dump(company1, file = open("company1.pickle", "wb"))
# Reload the file
company1_reloaded = pickle.load(open("company1.pickle", "rb"))
Tuy nhiên, như câu trả lời này lưu ý, dưa chua thường thất bại. Vì vậy, bạn nên thực sự sử dụng dill.
import dill
# Save the file
dill.dump(company1, file = open("company1.pickle", "wb"))
# Reload the file
company1_reloaded = dill.load(open("company1.pickle", "rb"))