假设我有以下课程:
class Foo(object):
def __init__(self, value):
self.d = value
self.a = value
self.s = value
self.k = value
我想按照声明的顺序retrieve the instance variables。
我尝试使用vars()
但没有取得任何成功:
list(vars(Foo('value')).keys())
# ['a', 'k', 's', 'd']
我想要的是什么:
list(magic_method(Foo('value')).keys())
# ['d', 'a', 's', 'k']
修改:
显然,每个字段都会有不同的值。
我的目标是通过对象变量生成XML。为了有效,XML标记必须按正确的顺序排列。
结合__iter__
覆盖,我只需要管理对象的字典就可以生成我的XML。
我们以图书馆为例。想象一下,您有一个课程Book
,Date
,Person
,Author
和Borrower
:
class Book(object):
def self.__init__()
self._borrower = Borrower()
self._author = Author()
class Date(object)
def __init__(self, date):
self._date = date
class Person(object):
def __init__(self, name):
self._name = name
class Author(object):
def __init__(self):
self._person = Person("Daniel")
class Borrower(object):
def __init__(self):
self._person = Person("Jack")
self._date = Date("2016-06-02")
我想创建以下XML:
<Book>
<Borrower>
<Person>Jack</Person>
<Date>2016-06-02</Date>
</Borrower>
<Author>
<Person>Daniel</Person>
</Author>
</Book>
我知道这些类可能看起来很奇怪(比如Date这里),但我想让问题变得尽可能简单(并且有些字段非常有意义)。在实践中,我会查询数据库,并可能在初始化器中传递记录标识符。关键是有一些数据尊重相同的语法(即人在这里)。
总而言之,我想使用Python对象创建这样的XML。订购事项。这就是为什么我想为此目的检索变量的原因:然后我可以提取类并生成XML标记。
答案 0 :(得分:3)
如果您想要对象变量的排序,您可以使用类似的东西:
from collections import OrderedDict
class FooModel(object):
def __new__(cls, *args, **kwargs):
instance = object.__new__(cls)
instance.__odict__ = OrderedDict()
return instance
def __setattr__(self, key, value):
if key != '__odict__':
self.__odict__[key] = value
object.__setattr__(self, key, value)
def keys(self):
return self.__odict__.keys()
def iteritems(self):
return self.__odict__.iteritems()
class Foo(FooModel):
def __init__(self, value):
self.d = value
self.a = value
self.s = value
self.k = value
输出:
>>> f = Foo('value')
>>> f.x = 5
>>> f.y = 10
>>> f.a = 15
>>> f2 = Foo('value')
>>> print "f.keys()", f.keys()
f.keys() ['d', 'a', 's', 'k', 'x', 'y']
>>> print "f2.keys()", f2.keys()
f2.keys() ['d', 'a', 's', 'k']
print list(f.iteritems())
[('d', 'value'), ('a', 15), ('s', 'value'), ('k', 'value'), ('x', 5), ('y', 10)]
答案 1 :(得分:0)
如果不使用元类,你就不能轻易做到这一点(正如@Daniel所说)。但是如果你想要一个产生类似效果的解决方法,你可以存储所有的&#34;实例变量&#34;在collections.OrderedDict
中:
from collections import OrderedDict
class Foo(object):
def __init__(self, value):
self.instvars = OrderedDict()
self.instvars['d'] = value
self.instvars['a'] = value
self.instvars['s'] = value
self.instvars['k'] = value
print(list(Foo('value').instvars.keys()))
# OUT: ['d', 'a', 's', 'k']
答案 2 :(得分:0)
您可以为您的班级提供类似于__dict__
的方法,但该方法会返回OrderedDict。
from collections import OrderedDict
class Foo(object):
def __init__(self, d, a, s, k):
self.d = d
self.a = a
self.s = s
self.k = k
def ordered_dict(self):
return OrderedDict(
(key, getattr(self, key)) for key in ('d', 'a', 's', 'k')
)
这样工作原理如下:
>>> myfoo = Foo('bar', 1, 7, 'foo')
>>> myfoo.ordered_dict()
OrderedDict([('d', 'bar'),('a', 1), ('s', 7), ('k', 'foo')])
>>> list(myfoo.ordered_dict())
['d', 'a', 's', 'k']
答案 3 :(得分:0)
您可以实施__setattr__
方法来跟踪这些事情:
#!python3
class OrderedAttrs:
def __init__(self, d, a, s, k):
self._order = []
self.d = d
self.a = a
self.s = s
self.k = k
def __setattr__(self, name, value):
super().__setattr__(name, value)
if not name in self._order:
self._order.append(name)
return value
def ordered_attrs(self, with_order=False):
return [(k,getattr(self, k)) for k in self._order if k != '_order' or with_order]
oa = OrderedAttrs('dee', 'eh', 'ess', 'kay')
oa.foo = 'bar'
oa.baz = 'moo'
print("Default:",oa.ordered_attrs())
print("With _order:", oa.ordered_attrs(with_order=True))