Python对象字段中的字典
你知道是否有一个内置的函数来从任意对象build立一个字典? 我想要做这样的事情:
>>> class Foo: ... bar = 'hello' ... baz = 'world' ... >>> f = Foo() >>> props(f) { 'bar' : 'hello', 'baz' : 'world' }
注意:它不应该包括方法。 只有领域。
请注意,Python 2.7中的最佳做法是使用新式类(Python 3不需要),即
class Foo(object): ...
另外,“对象”和“类”之间也有区别。 要从任意对象构build字典,使用__dict__
就足够了。 通常,你将在类级别声明你的方法,在实例级声明你的属性,所以__dict__
应该没问题。 例如:
>>> class A(object): ... def __init__(self): ... self.b = 1 ... self.c = 2 ... def do_nothing(self): ... pass ... >>> a = A() >>> a.__dict__ {'c': 2, 'b': 1}
更好的方法(由罗伯特在评论中提出)是内buildvars
函数:
>>> vars(a) {'c': 2, 'b': 1}
另外,取决于你想做什么,它可能是很好的从dict
inheritance。 那么你的类已经是一个字典,如果你想要,你可以重写getattr
和/或setattr
来调用,并设置字典。 例如:
class Foo(dict): def __init__(self): pass def __getattr__(self, attr): return self[attr] # etc...
dir
builtin会给你所有对象的属性,包括特殊的方法,如__str__
, __str__
和其他一些你可能不想要的东西。 但是你可以做一些事情:
>>> class Foo(object): ... bar = 'hello' ... baz = 'world' ... >>> f = Foo() >>> [name for name in dir(f) if not name.startswith('__')] [ 'bar', 'baz' ] >>> dict((name, getattr(f, name)) for name in dir(f) if not name.startswith('__')) { 'bar': 'hello', 'baz': 'world' }
所以可以扩展这个只返回数据属性而不是方法,通过定义你的props
函数是这样的:
import inspect def props(obj): pr = {} for name in dir(obj): value = getattr(obj, name) if not name.startswith('__') and not inspect.ismethod(value): pr[name] = value return pr
而不是x.__dict__
,实际上使用vars(x)
更加pythonic。
我已经解决了两个答案的组合:
dict((key, value) for key, value in f.__dict__.iteritems() if not callable(value) and not key.startswith('__'))
要从任意对象构build字典,使用
__dict__
就足够了。
这忽略了对象从它的类inheritance的属性。 例如,
class c(object): x = 3 a = c()
hasattr(a,'x')为真,但'x'不出现在.__ dict__中
我想我会花一些时间来告诉你如何通过dict(obj)
将对象转换为字典。
class A(object): d = '4' e = '5' f = '6' def __init__(self): self.a = '1' self.b = '2' self.c = '3' def __iter__(self): # first start by grabbing the Class items iters = dict((x,y) for x,y in A.__dict__.items() if x[:2] != '__') # then update the class items with the instance items iters.update(self.__dict__) # now 'yield' through the items for x,y in iters.items(): yield x,y a = A() print(dict(a)) # prints "{'a': '1', 'c': '3', 'b': '2', 'e': '5', 'd': '4', 'f': '6'}"
这段代码的关键部分是__iter__
函数。
正如评论所解释的那样,我们要做的第一件事就是抓住Class项目,并防止以“__”开头的任何内容。
一旦你创build了这个dict
,那么你可以使用update
字典function,并传递实例__dict__
。
这些会给你一个完整的类+实例字典的成员。 现在剩下的就是遍历它们并产生回报。
另外,如果你打算使用这个,你可以创build一个@iterable
类装饰器。
def iterable(cls): def iterfn(self): iters = dict((x,y) for x,y in cls.__dict__.items() if x[:2] != '__') iters.update(self.__dict__) for x,y in iters.items(): yield x,y cls.__iter__ = iterfn return cls @iterable class B(object): d = 'd' e = 'e' f = 'f' def __init__(self): self.a = 'a' self.b = 'b' self.c = 'c' b = B() print(dict(b))
迟到的答案,但提供了完整性和谷歌的好处:
def props(x): return dict((key, getattr(x, key)) for key in dir(x) if key not in dir(x.__class__))
这不会显示在类中定义的方法,但它仍然会显示字段,包括分配给lambdaexpression式的字段或以双下划线开头的字段。
如果您想列出部分属性,请覆盖__dict__
:
def __dict__(self): d = { 'attr_1' : self.attr_1, ... } return d # Call __dict__ d = instance.__dict__()
如果你的instance
得到了一些大的块数据,并且你想把d
推到Redis,比如消息队列,这会有很大帮助。
我认为最简单的方法是为这个类创build一个getitem属性。 如果您需要写入对象,则可以创build自定义setattr 。 这里是一个getitem的例子:
class A(object): def __init__(self): self.b = 1 self.c = 2 def __getitem__(self, item): return self.__dict__[item] # Usage: a = A() a.__getitem__('b') # Outputs 1 a.__dict__ # Outputs {'c': 2, 'b': 1} vars(a) # Outputs {'c': 2, 'b': 1}
dict将对象属性生成为一个字典,字典对象可以用来获取你需要的项目。