酸洗类方法 [英] pickling class method

查看:23
本文介绍了酸洗类方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个类,它的实例需要按照用户的指示格式化输出.有一个默认格式,可以覆盖.我是这样实现的:

I have a class whose instances need to format output as instructed by the user. There's a default format, which can be overridden. I implemented it like this:

class A:
  def __init__(self, params):
    # ...
    # by default printing all float values as percentages with 2 decimals
    self.format_functions = {float: lambda x : '{:.2%}'.format(x)}
  def __str__(self):
    # uses self.format_functions to format output
    # ...

a = A(params)
print(a) # uses default output formatting

# overriding default output formatting
# float printed as percentages 3 decimal digits; bool printed as Y / N
a.format_functions = {float : lambda x: '{:.3%}'.format(x),
                      bool : lambda x: 'Y' if x else 'N'}
print(a)

可以吗?如果有更好的设计方法,请告诉我.

Is it ok? Let me know if there is a better way to design this.

不幸的是,我需要pickle这个类的实例.但是只有定义在模块顶层的函数才能被pickle;lambda 函数是不可选择的,所以我的 format_functions 实例属性打破了pickling.

Unfortunately, I need to pickle instances of this class. But only functions defined at the top level of the module can be pickled; lambda functions are unpicklable, so my format_functions instance attribute breaks the pickling.

我尝试重写它以使用类方法而不是 lambda 函数,但由于同样的原因仍然没有运气:

I tried rewriting this to use a class method instead of lambda functions, but still no luck for the same reason:

class A:
  @classmethod
  def default_float_format(cls, x):
    return '{:.2%}'.format(x)
  def __init__(self, params):
    # ...
    # by default printing all float values as percentages with 2 decimals
    self.format_functions = {float: self.default_float_format}
  def __str__(self):
    # uses self.format_functions to format output
    # ...

a = A(params)
pickle.dump(a) # Can't pickle <class 'method'>: attribute lookup builtins.method failed

请注意,即使我不覆盖默认值,这里的酸洗也不起作用;只是我分配了 self.format_functions = {float : self.default_float_format} 的事实打破了它.

Note that pickling here doesn't work even if I don't override the defaults; just the fact that I assigned self.format_functions = {float : self.default_float_format} breaks it.

怎么办?我宁愿不污染命名空间并通过在模块级别定义 default_float_format 来破坏封装.

What to do? I'd rather not pollute the namespace and break encapsulation by defining default_float_format at the module level.

顺便说一下,为什么 pickle 会创建这个限制?对于最终用户来说,这无疑是一种无端而巨大的痛苦.

Incidentally, why in the world does pickle create this restriction? It certainly feels like a gratuitous and substantial pain to the end user.

推荐答案

对于类实例或函数(以及方法)的pickle,Python 的pickle 依赖于它们的名称可用作全局变量——字典中方法的引用指向一个在全局命名空间中不可用的名称 - 最好说模块命名空间" -

For pickling of class instances or functions (and therefore methods), Python's pickle depend that their name is available as global variables - the reference to the method in the dictionary points to a name that is not available in the global name space - which iis better said "module namespace" -

您可以通过自定义类的酸洗来规避这一点,通过创建__setstate__"和__getstate__"方法 - 但我认为你会更好,因为格式化功能不依赖于对象或对象的任何信息类本身(即使某些格式化函数这样做,您也可以将其作为参数传递),并在类范围之外定义一个函数.

You could circunvent that by customizing the pickling of your class, by creating teh "__setstate__" and "__getstate__" methods - but I think you be better, since the formatting function does not depend on any information of the object or of the class itself (and even if some formatting function does, you could pass that as parameters), and define a function outside of the class scope.

这确实有效(Python 3.2):

This does work (Python 3.2):

def default_float_format( x):
    return '{:.2%}'.format(x)

class A:

  def __init__(self, params):
    # ...
    # by default printing all float values as percentages with 2 decimals
    self.format_functions = {float: default_float_format}
  def __str__(self):
    # uses self.format_functions to format output
    pass

a = A(1)
pickle.dumps(a)

这篇关于酸洗类方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆