对类对象重新排序的最具python风格的方式是什么';属性?
我正在创建一组Python 2.7/3+工具,以编程方式修改团队经常使用的XML文件的内容。到目前为止,我正在将XML解析为有意义的类对象属性(通过对类对象重新排序的最具python风格的方式是什么';属性?,python,xml,dictionary,attributes,Python,Xml,Dictionary,Attributes,我正在创建一组Python 2.7/3+工具,以编程方式修改团队经常使用的XML文件的内容。到目前为止,我正在将XML解析为有意义的类对象属性(通过**kwargs和和dict\uuuuu.update()或setattr()),我已经将一些相当复杂的方法与之关联。我非常喜欢能够根据方法调用定义我的自动化,例如foo.do\u complex\u modification(x) 现在,我想将修改后的数据写回XML文件,供软件的其余部分使用。文件的内容很好,但不幸的是,我们的遗留工具只接受保留顺序
**kwargs
和和dict\uuuuu.update()
或setattr()
),我已经将一些相当复杂的方法与之关联。我非常喜欢能够根据方法调用定义我的自动化,例如foo.do\u complex\u modification(x)
现在,我想将修改后的数据写回XML文件,供软件的其余部分使用。文件的内容很好,但不幸的是,我们的遗留工具只接受保留顺序的XML,我不能指望Python对象字典提供这一点。在解析XML时,我可以按照“正确”的顺序阅读,而不会出现任何问题,并以某种方式存储,但修改遗留系统不是一种选择
可能是相关的,XML还有一个XSD模式
问题:序列化类属性以保持其原始顺序的最简洁或优雅的方式是什么?如果合适,当从对象的\uuuu dict\uuu
读回时,我将如何编写,比如说,.sort(key=ordering\u函数)
class Foo(object):
def __init__(self, **kwargs):
for k, v in kwargs.items():
setattr(self, k, v)
def really_complex_method(self):
pass
def attrs(cls):
return [(k, v) for k, v in cls.__dict__.items() if k[:1] != '_']
d = dict(bar=1, baz=2, quux=3) # Need them back in this particular order
print(attrs(Foo(**d)))
返回
[('quux', 3), ('bar', 1), ('baz', 2)]
并且在Python 3.6之前的任何版本上都是未排序的。即使您对类属性进行排序,只要它们存储在dict中,顺序就会改变。最好的方法是使用OrderedDict
,它将保留sorted()
方法的顺序
from collections import OrderedDict
class Foo(object):
def __init__(self, **kwargs):
for k, v in kwargs.items():
setattr(self, k, v)
def really_complex_method(self):
pass
def attrs(cls):
return OrderedDict(sorted(cls.__dict__.items()))
d = dict(bar=1, baz=2, quux=3)
print(attrs(Foo(**d)))
最大的问题可能是因为您一直在传递关键字参数,这并没有保留它们的定义顺序。另一个问题是类.\uu dict\uu
是无序的。这里有一种解决这两个问题的方法(并不假设您希望属性按名称的字母顺序排列)。替换类的special\uuuu dict\uuu
属性的技术是允许的,因为正如所说的,它可以是“字典或其他映射对象”(emphasis mine)。在Python2和Python3中都是如此
from collections import OrderedDict
from operator import itemgetter
class Foo(object):
def __init__(self, *keyvalues):
self.__dict__ = OrderedDict(keyvalues)
def really_complex_method(self):
pass
def attrs(instance):
""" Return a list of instance attributes sorted by their value. """
return sorted(instance.__dict__.items(), key=itemgetter(1))
print(attrs(Foo(('bar', 1), ('baz', 2), ('quux', 3), ('question', -42))))
输出:
[('question', -42), ('bar', 1), ('baz', 2), ('quux', 3)]
使用OrderedDict
的替代方法是创建自己的映射类。这里有一个takien(关于Python3中的元类,但与主题无关)。它也适用于Python 2和Python 3):
另一种方法是,让类跟踪添加到实例中的顺序属性,然后按该顺序迭代它们,而不需要更改实例的
from operator import itemgetter
class Foo(object):
def __init__(self, *keyvalues):
self._sequence = []
for (key, value) in keyvalues:
setattr(self, key, value)
self._sequence.append(key) # keep track of order added
def __iter__(self):
for key in self._sequence:
yield key, getattr(self, key)
def really_complex_method(self):
pass
def attrs(instance):
""" Return a list of instance attributes sorted their value. """
return sorted((item for item in instance), key=itemgetter(1))
print(attrs(Foo(('bar', 1), ('baz', 2), ('quux', 3), ('question', -42))))
注意在所有这些实现中,如果未使用sorted()
函数attrs()
函数,则属性将按照添加的顺序进行访问(这是您在修改问题之前最初似乎唯一需要的内容)。您的回答非常感谢realtom。我知道我应该在我的示例中使用一个列表:取消排序实际上是在设置对象属性的\uu dict\uu
时发生的。不幸的是,调用orderedict
从中读取并不能解决这个问题。事实上,我已经更新了这个问题来强调这一点。你能私下告诉我你的口述顺序吗?换句话说,在继续这个过程之前,你能得到你想要的订单吗?@Chiheb-Nexus:当然。将更新问题以反映这一点。好吧,正如我所看到的,整个问题是查找返回dict是否具有与d dict相同的顺序。正确的?如果不返回实质上具有相同顺序的dict,则返回yes。请注意,我使用的实际的\uuuu dict\uuu
包含相当多的元素。但是我黑客攻击的每一种方法似乎都太冗长了,而且都不是pythonesque。我从来没想过你可以将\uuuu dict\uuuu
重新转换为有序的dict
。那是非常非常聪明的马蒂诺先生!弗朗索瓦:谢谢。Python并不总是允许您做这样的事情,但是在\uuuuu dict\uuuu
的情况下,它确实允许您做这样的事情OrderedDict
是内置的dict
类的一个子类,因此它完全适合账单。
from operator import itemgetter
class Foo(object):
def __init__(self, *keyvalues):
self._sequence = []
for (key, value) in keyvalues:
setattr(self, key, value)
self._sequence.append(key) # keep track of order added
def __iter__(self):
for key in self._sequence:
yield key, getattr(self, key)
def really_complex_method(self):
pass
def attrs(instance):
""" Return a list of instance attributes sorted their value. """
return sorted((item for item in instance), key=itemgetter(1))
print(attrs(Foo(('bar', 1), ('baz', 2), ('quux', 3), ('question', -42))))