酸洗课方法 [英] pickling class method

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

问题描述

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

  class A:
def __init __(self,params):
# ...
#默认情况下将所有浮点值打印为2位小数的百分比
self.format_functions = {float:lambda x:'{:.2%}'。format(x)}
def __str __(self):
#使用self.format_functions格式输出
#...

a = A(params)
print(a)#uses默认输出格式

#覆盖默认输出格式
#float打印为百分比3位数字; bool打印为Y / N
a.format_functions = {float:lambda x:'{:.3%}'。format(x),
bool:lambda x:'Y'if x else' N'}
print(a)

是吗?让我知道如果有更好的方法来设计这个。



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



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

  class A:
@classmethod
def default_float_format(cls,x):
return'{:.2%}'。format(x)
def __init __(self, params):
#...
#默认情况下将所有浮点值打印为2位小数的百分比
self.format_functions = {float:self.default_float_format}
def __str __(self ):
#使用self.format_functions格式输出
#...

a = A(params)
pickle.dump(a)#不能腌< class'method'> ;:属性查询builtins.method失败

请注意,即使我不覆盖默认值也可以工作;只是事实上,我分配了 self.format_functions = {float:self.default_float_format} 打破它。



做?我不想污染命名空间并通过在模块级别定义 default_float_format 来打破封装。



顺便提一下,为什么在世界上, pickle 创建这个限制?

解决方案

对于酸洗实例或函数(因此,方法),Python的pickle取决于它们的名称可用作全局变量 - 对字典中的方法的引用指向全局名称空间中不可用的名称 - 我更好地说module namespace -



通过创建__setstate__和__getstate__方法,可以定制你的类的酸洗,但是我认为你会更好,因为格式化函数不依赖于任何对象或类本身的信息(即使某些格式化函数可以将其作为参数传递),也可以在类范围之外定义一个函数。



这样做(Python 3.2):

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

class A:

def __init __(self,params):
#...
#默认情况下将所有浮点值打印为2位小数的百分比
self.format_functions = {float: default_float_format}
def __str __(self):
#使用self.format_functions格式输出
pass

a = A(1)
pickle.dumps a)


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.

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.

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

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.

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

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

解决方案

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" -

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.

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天全站免登陆