Cha*_*ker 6 python pickle dill
对我来说,我所做的就是检测不可选取的内容并将其放入字符串中(我想我也可以将其删除,但随后它会错误地告诉我该字段不存在,但我宁愿让它存在但成为字符串) )。但我想知道是否有一种不那么老套、更正式的方式来做到这一点。
我当前使用的代码:
def make_args_pickable(args: Namespace) -> Namespace:
"""
Returns a copy of the args namespace but with unpickable objects as strings.
note: implementation not tested against deep copying.
ref:
- /sf/ask/4908983481/
"""
pickable_args = argparse.Namespace()
# - go through fields in args, if they are not pickable make it a string else leave as it
# The vars() function returns the __dict__ attribute of the given object.
for field in vars(args):
field_val: Any = getattr(args, field)
if not dill.pickles(field_val):
field_val: str = str(field_val)
setattr(pickable_args, field, field_val)
return pickable_args
Run Code Online (Sandbox Code Playgroud)
背景:我认为我这样做主要是为了删除我随身携带的烦人的张量板对象(但.tb由于wandb/权重和偏差,我认为我不再需要该字段)。这并不是很重要,但背景总是好的。
有关的:
编辑:
由于我决定放弃 dill - 因为有时它无法恢复类/对象(可能是因为它无法保存他们的代码或其他东西) - 我决定只使用pickle(这似乎是在 PyTorch 中完成的推荐方法)。
那么,检查没有莳萝或官方泡菜的可采摘物的官方(可能是优化的)方法是什么?
这是最好的吗:
def is_picklable(obj):
try:
pickle.dumps(obj)
except pickle.PicklingError:
return False
return True
Run Code Online (Sandbox Code Playgroud)
因此当前的解决方案:
def make_args_pickable(args: Namespace) -> Namespace:
"""
Returns a copy of the args namespace but with unpickable objects as strings.
note: implementation not tested against deep copying.
ref:
- /sf/ask/4908983481/
"""
pickable_args = argparse.Namespace()
# - go through fields in args, if they are not pickable make it a string else leave as it
# The vars() function returns the __dict__ attribute of the given object.
for field in vars(args):
field_val: Any = getattr(args, field)
# - if current field value is not pickable, make it pickable by casting to string
if not dill.pickles(field_val):
field_val: str = str(field_val)
elif not is_picklable(field_val):
field_val: str = str(field_val)
# - after this line the invariant is that it should be pickable, so set it in the new args obj
setattr(pickable_args, field, field_val)
return pickable_args
def make_opts_pickable(opts):
""" Makes a namespace pickable """
return make_args_pickable(opts)
def is_picklable(obj: Any) -> bool:
"""
Checks if somehting is pickable.
Ref:
- /sf/ask/4908983481/
"""
import pickle
try:
pickle.dumps(obj)
except pickle.PicklingError:
return False
return True
Run Code Online (Sandbox Code Playgroud)
注意:我想要“官方”/测试的原因之一是因为我在 try catch 上停止了 pycharm:如何在已处理的异常上停止 PyCharm 的中断/停止/停止功能(即仅在 python 未处理的异常上中断)?这不是我想要的......我希望它只在未处理的异常上停止。
使具有不可选取字段的对象可选取的正确方法是什么?
我相信这个问题的答案属于您链接的问题 - Python - 如何使这个不可腌制的对象可腌制?。我为该问题添加了一个新答案__reduce__,解释了如何以正确的方式使不可腌制的对象可腌制,而不使用.
那么,检查没有莳萝或官方泡菜的可采摘物的官方(可能是优化的)方法是什么?
可picklable 的对象在文档中定义如下:
None,True, 和False- 整数、浮点数、复数
- 字符串、字节、字节数组
- 仅包含可腌制对象的元组、列表、集合和字典
- 在模块顶层定义的函数(使用
def, notlambda)- 在模块顶层定义的内置函数
- 在模块顶层定义的类
- 此类的实例,其字典或调用getstate ()的结果是可挑选的(有关详细信息,请参阅“挑选类实例”部分)。
棘手的部分是(1)了解如何定义函数/类(您可能可以使用inspect该模块)和(2)递归对象,根据上述规则进行检查。
对此有很多注意事项,例如 pickle协议版本、对象是否是扩展类型(例如在 numpy 等 C 扩展中定义)或“用户定义”类的实例。使用__slots__还会影响对象是否可腌制(因为__slots__意味着没有__dict__),但可以使用 进行腌制__getstate__。某些对象还可以使用自定义函数注册以进行酸洗。因此,您需要知道这种情况是否也发生过。
从技术上讲,您可以在 Python 中实现一个函数来检查所有这些,但相比之下,它会相当慢。最简单的(也可能pickle是最高效的,如在 C 中实现的)方法是简单地尝试 pickle 您想要检查的对象。
我用 PyCharm 对各种东西进行了测试...它不会用这种方法停止。关键是您必须预见到几乎所有类型的异常(请参阅文档中的脚注 3 )。警告是可选的,它们主要是对该问题的上下文的解释。
def is_picklable(obj: Any) -> bool:
try:
pickle.dumps(obj)
return True
except (pickle.PicklingError, pickle.PickleError, AttributeError, ImportError):
# https://docs.python.org/3/library/pickle.html#what-can-be-pickled-and-unpickled
return False
except RecursionError:
warnings.warn(
f"Could not determine if object of type {type(obj)!r} is picklable"
"due to a RecursionError that was supressed. "
"Setting a higher recursion limit MAY allow this object to be pickled"
)
return False
except Exception as e:
# https://docs.python.org/3/library/pickle.html#id9
warnings.warn(
f"An error occurred while attempting to pickle"
f"object of type {type(obj)!r}. Assuming it's unpicklable. The exception was {e}"
)
return False
Run Code Online (Sandbox Code Playgroud)
使用我上面链接的其他答案中的示例,您可以通过实现__getstate__和__setstate__(或子类化并添加它们,或制作包装器类)调整您的make_args_pickable...来使您的对象可挑选。
class Unpicklable:
"""
A simple marker class so we can distinguish when a deserialized object
is a string because it was originally unpicklable
(and not simply a string to begin with)
"""
def __init__(self, obj_str: str):
self.obj_str = obj_str
def __str__(self):
return self.obj_str
def __repr__(self):
return f'Unpicklable(obj_str={self.obj_str!r})'
class PicklableNamespace(Namespace):
def __getstate__(self):
"""For serialization"""
# always make a copy so you don't accidentally modify state
state = self.__dict__.copy()
# Any unpicklables will be converted to a ``Unpicklable`` object
# with its str format stored in the object
for key, val in state.items():
if not is_picklable(val):
state[key] = Unpicklable(str(val))
return state
def __setstate__(self, state):
self.__dict__.update(state) # or leave unimplemented
Run Code Online (Sandbox Code Playgroud)
在实际操作中,我将腌制一个其属性包含文件句柄(通常不可腌制)的名称空间,然后加载腌制数据。
# Normally file handles are not picklable
p = PicklableNamespace(f=open('test.txt'))
data = pickle.dumps(p)
del p
loaded_p = pickle.loads(data)
# PicklableNamespace(f=Unpicklable(obj_str="<_io.TextIOWrapper name='test.txt' mode='r' encoding='cp1252'>"))
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1527 次 |
| 最近记录: |