JSON编码/解码GTK枚举 [英] JSON encode/decode GTK enums

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

问题描述

我必须将自定义GTK元素的各种属性保存到一个文件中供将来使用,并决定使用JSON,因为它的格式和嵌套的格式很简单。



许多属性是GTK枚举,如 gtk.PAGE_ORIENTATION_PORTRAIT gtk.ANCHOR_CENTER pango.ALIGN_LEFT 。它们有一个唯一的名称,可以通过 obj.value_name 来获取一个有效的JSON类型。



我的每个元素都有两个方法: to_str()来获取value_name和 from_str(),它将str再次给枚举。我想自动化这个,所以我不会忘记调用这些代码并清理代码。 JSONEncoder和JSONDecodr正在做这件事,所以我认为......



这是Python文档中给出的示例,它按预期工作。

  import json 
$ b $ class ComplexEncoder(json.JSONEncoder):
def default(self,obj):
打印默认方法调用:,obj $ b $如果isinstance(obj,complex):
返回[obj.real,obj.imag]
返回json.JSONEncoder.default (self,obj)

print json.dumps(2 + 1j,cls = ComplexEncoder)

基于此示例,我添加了GTK枚举:

  import json 
import gtk

ENUMS = [gtk.PAGE_ORIENTATION_PORTRAIT,gtk.PAGE_ORIENTATION_LANDSCAPE]

class GtkEncoder(json.JSONEncoder):
def default(self,obj):
打印默认方法调用:,obj
如果obj在ENUMS中:
返回obj.value_name
返回json.JSONEncoder.d efault(self,obj)

print json.dumps(gtk.PAGE_ORIENTATION_LANDSCAPE,cls = GtkEncoder)

请注意默认方法中添加的打印语句。在原始示例中,此方法被调用时没有问题,但不在GTK示例中。从不调用方法,它返回 ,这是无效的JSON ofcourse 。

那么,有没有办法自动编码/解码这些枚举,还是坚持使用当前的手动方法?请注意,我要转储的数据结构不是一个单一的值,而是一个字典或字典。

解决方案

gtk.PAGE_ORIENTATION_LANDSCAPE class'gtk._gtk.PageOrientation'的一个实例,它继承键入'gobject.GEnum',继而继承类型'int'



因此,您的GTK枚举是整数,并且json代码假定它可以处理整数,因此不会调用编码器的默认方法。



不幸的是,当前的json实现在编码这样的子类型时没有什么帮助: - 没有继承和覆盖使得这成为可能(至少我找不到任何解决方案)。太多硬编码的地方,其值被检查为 isinstance(value,(int,long))



但是当然你可以修补json编码器的源代码来实现你的目标,而不必重新实现整个json的功能。为此,从json库中拷贝文件 encoder.py (对于我来说这是 /usr/lib/python2.7/json/encoder.py )到您的工作目录并修补它。


$ b $

在函数 _iterencode_list() _iterencode_dict()(它们对函数 _make_iterencode())是本地的),您可以找到 int long ;如果是这样,当前的实现只是调用 str(value)。将它改为 encodeInt(value)(在三个地方!)并在<$中实现您自己的 encodeInt()函数c $ c> encoder.py

  def encodeInt(value):
尝试:
返回value.value_name
除了:
return str(value)



然后,在你原来的代码中,你将不得不直接导入那个补丁文件:

 导入编码器

您必须确保C实现不再使用,而是修补代码。 (你会发现,通常使用(更快的)C实现,并且我们在其中修补了某些东西的Python代码不是)。要实现这一点,只需在导入后添加:

  encoder.c_make_encoder =无

可以使用:

  print encoder.JSONEncoder()。encode({
gtk.PAGE_ORIENTATION_PORTRAIT:[
gtk.PAGE_ORIENTATION_LANDSCAPE
],
gtk.PAGE_ORIENTATION_LANDSCAPE:gtk.PAGE_ORIENTATION_PORTRAIT})

打印:

  {GTK_PAGE_ORIENTATION_PORTRAIT:[GTK_PAGE_ORIENTATION_LANDSCAPE],GTK_PAGE_ORIENTATION_LANDSCAPE:GTK_PAGE_ORIENTATION_PORTRAIT} 

请注意,Json字典键总是必须是字符串。这就是为什么你的值作为键使用双引号。但这是一个命运,即使正常 int s - 当用作键时 - 共享。他们也被串接。



您可以查看 http:/ /pastebin.com/2HAtN9E8 查看所有来源。


I have to save various properties of custom GTK elements to a file for future use and decided to use JSON because of the simple format and nesting of dicts.

Many properties are GTK enums, like gtk.PAGE_ORIENTATION_PORTRAIT, gtk.ANCHOR_CENTER and pango.ALIGN_LEFT. They have a unique name which can be retrieved with obj.value_name to get a valid JSON type.

Currently I have 2 methods for each of my elements: to_str() to get the value_name and from_str() which maps the str to the enum again. I would like to automate this so I don't forget to call these and clean up the code a bit. The JSONEncoder and JSONDecodr are doing exactly this, or so I thought...

This is the example given in the Python docs and it works as expected.

import json

class ComplexEncoder(json.JSONEncoder):
    def default(self, obj):
        print "default method called for:", obj
        if isinstance(obj, complex):
            return [obj.real, obj.imag]
        return json.JSONEncoder.default(self, obj)

print json.dumps(2 + 1j, cls=ComplexEncoder)

Based on this example I've added the GTK enums:

import json
import gtk

ENUMS = [gtk.PAGE_ORIENTATION_PORTRAIT, gtk.PAGE_ORIENTATION_LANDSCAPE]

class GtkEncoder(json.JSONEncoder):
    def default(self, obj):
        print "default method called for:", obj
        if obj in ENUMS:
            return obj.value_name
        return json.JSONEncoder.default(self, obj)

print json.dumps(gtk.PAGE_ORIENTATION_LANDSCAPE, cls=GtkEncoder)

Notice the added print statement in the default method. In the original example, this method is called without problems, but not in the GTK example. The default method is never called and it returns <enum GTK_PAGE_ORIENTATION_LANDSCAPE of type GtkPageOrientation> which isn't valid JSON ofcourse.

So, is there a way to automatically encode/decode these enums or am I stuck with the current manual approach? Note that my data structure to dump is not a single value, but a dict or dicts.

解决方案

The observed behavior occurs because the value gtk.PAGE_ORIENTATION_LANDSCAPE is an instance of class 'gtk._gtk.PageOrientation' which inherits type 'gobject.GEnum' which in turn inherits type 'int'.

So your GTK-enums are ints, and the json code assumes it can handle ints and thus does not call the default method of your encoder.

Unfortunately the current json implementation isn't that helpful in encoding subclassed types like this :-/ No inheriting and overriding makes this possible (at least I cannot find any solution for this). Just too many hardcoded places where the value is checked for isinstance(value, (int, long)).

But you can of course patch the source of the json encoder to achieve your goal without having to implement the whole json functionality anew. For this copy the file encoder.py from the json library (for me this is /usr/lib/python2.7/json/encoder.py) to your working directory and patch it.

In the functions _iterencode_list() and _iterencode_dict() (they are local to function _make_iterencode()) you can find checks for being of type int or long; if so, the current implementation just calls str(value). Change that to encodeInt(value) (in three places!) and implement your own encodeInt() function in encoder.py:

def encodeInt(value):
  try:
    return value.value_name
  except:
    return str(value)

Then, in your original code, you will have to import directly that patched file:

import encoder

and you will have to make sure the C implementation isn't used anymore but instead the patched code. (You see, normally, the (faster) C implementation is used, and that Python code in which we patched something is not.) To achieve this, just add after the import:

encoder.c_make_encoder = None

Now your patched encoder can be used:

print encoder.JSONEncoder().encode({
  gtk.PAGE_ORIENTATION_PORTRAIT: [
    gtk.PAGE_ORIENTATION_LANDSCAPE
  ],
  gtk.PAGE_ORIENTATION_LANDSCAPE: gtk.PAGE_ORIENTATION_PORTRAIT })

prints:

{"GTK_PAGE_ORIENTATION_PORTRAIT": [GTK_PAGE_ORIENTATION_LANDSCAPE], "GTK_PAGE_ORIENTATION_LANDSCAPE": GTK_PAGE_ORIENTATION_PORTRAIT}

Note that Json dict keys always must be strings. That's why your values get double quotes when used as keys. But that's a fate even normal ints — when used as keys — share. They also get stringified.

You can have a look at http://pastebin.com/2HAtN9E8 to see all the sources.

这篇关于JSON编码/解码GTK枚举的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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