我有一个包含多个属性和方法的python对象。我想迭代对象属性。
class my_python_obj(object):
attr1='a'
attr2='b'
attr3='c'
def method1(self, etc, etc):
#Statements
我想生成一个包含所有对象属性及其当前值的字典,但我想以动态的方式进行(所以如果以后我添加另一个属性,我不必记得将我的函数更新为孔)。
在PHP中,变量可以用作键,但是python中的对象是不可写入的,如果我使用点符号,它会创建一个名为my var的新属性,这不是我的意图。
只是为了让事情更清楚:
def to_dict(self):
'''this is what I already have'''
d={}
d["attr1"]= self.attr1
d["attr2"]= self.attr2
d["attr3"]= self.attr3
return d
·
def to_dict(self):
'''this is what I want to do'''
d={}
for v in my_python_obj.attributes:
d[v] = self.v
return d
更新: 对于属性,我只是指该对象的变量,而不是方法。
答案 0 :(得分:182)
假设您有一个类
>>> class Cls(object):
... foo = 1
... bar = 'hello'
... def func(self):
... return 'call me'
...
>>> obj = Cls()
在对象上调用dir
会返回该对象的所有属性,包括python特殊属性。尽管某些对象属性是可调用的,例如方法。
>>> dir(obj)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'bar', 'foo', 'func']
您始终可以使用列表推导过滤掉特殊方法。
>>> [a for a in dir(obj) if not a.startswith('__')]
['bar', 'foo', 'func']
或者您更喜欢地图/过滤器。
>>> filter(lambda a: not a.startswith('__'), dir(obj))
['bar', 'foo', 'func']
如果您想过滤掉这些方法,可以使用内置callable
作为检查。
>>> [a for a in dir(obj) if not a.startswith('__') and not callable(getattr(obj,a))]
['bar', 'foo']
您还可以使用。
检查您的班级与其家长之间的差异>>> set(dir(Cls)) - set(dir(object))
set(['__module__', 'bar', 'func', '__dict__', 'foo', '__weakref__'])
答案 1 :(得分:41)
通常会在类中添加__iter__
方法并遍历对象属性或将此mixin类放在您的类中。
class IterMixin(object):
def __iter__(self):
for attr, value in self.__dict__.iteritems():
yield attr, value
你的班级:
>>> class YourClass(IterMixin): pass
...
>>> yc = YourClass()
>>> yc.one = range(15)
>>> yc.two = 'test'
>>> dict(yc)
{'one': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14], 'two': 'test'}
答案 2 :(得分:3)
python中的对象将其属性(包括函数)存储在名为__dict__
的dict中。您可以(但通常不应该)使用它来直接访问属性。如果您只想要一个列表,您也可以调用dir(obj)
,它返回一个包含所有属性名称的iterable,然后您可以将其传递给getattr
。
但是,需要对变量名称进行任何操作通常都是糟糕的设计。为什么不将它们保存在集合中?
class Foo(object):
def __init__(self, **values):
self.special_values = values
然后,您可以使用for key in obj.special_values:
答案 3 :(得分:2)
对此的正确答案是你不应该。如果你想要这种类型的东西要么只是使用dict,要么你需要显式地向某个容器添加属性。您可以通过了解装饰器来自动化。
顺便说一下,你的例子中的method1和属性一样好。
答案 4 :(得分:2)
class someclass:
x=1
y=2
z=3
def __init__(self):
self.current_idx = 0
self.items = ["x","y","z"]
def next(self):
if self.current_idx < len(self.items):
self.current_idx += 1
k = self.items[self.current_idx-1]
return (k,getattr(self,k))
else:
raise StopIteration
def __iter__(self):
return self
然后将其称为可迭代的
s=someclass()
for k,v in s:
print k,"=",v
答案 5 :(得分:2)
正如已经在一些答案/评论中提到的那样,Python对象已经存储了其属性的字典(不包括方法)。可以通过__dict__
进行访问,但是更好的方法是使用vars
(尽管输出是相同的)。请注意,修改此字典将修改实例的属性!这可能很有用,但也意味着您在使用此字典时应格外小心。这是一个简单的示例:
class A():
def __init__(self, x=3, y=2, z=5):
self.x = x
self._y = y
self.__z__ = z
def f(self):
pass
a = A()
print(vars(a))
# {'x': 3, '_y': 2, '__z__': 5}
# all of the attributes of `a` but no methods!
# note how the dictionary is always up-to-date
a.x = 10
print(vars(a))
# {'x': 10, '_y': 2, '__z__': 5}
# modifying the dictionary modifies the instance attribute
vars(a)["_y"] = 20
print(vars(a))
# {'x': 10, '_y': 20, '__z__': 5}
使用dir(a)
是解决这个问题的一种奇怪的方法,即使不是完全不好的方法。如果确实需要遍历该类的所有属性和方法(包括诸如__init__
之类的特殊方法),那将是很好的。但是,这似乎并不是您想要的,甚至accepted answer都通过应用一些易碎的过滤来尝试删除方法并仅保留属性来解决此问题。您将看到上面定义的类A
失败的原因。
(使用__dict__
已经完成了几个回答,但是它们都定义了不必要的方法,而不是直接使用它。只有a comment建议使用vars
)。
答案 6 :(得分:1)
对于python 3.6
class SomeClass:
def attr_list(self, should_print=False):
items = self.__dict__.items()
if should_print:
[print(f"attribute: {k} value: {v}") for k, v in items]
return items
答案 7 :(得分:-1)
对于python 3.6
class SomeClass:
def attr_list1(self, should_print=False):
for k in self.__dict__.keys():
v = self.__dict__.__getitem__(k)
if should_print:
print(f"attr: {k} value: {v}")
def attr_list(self, should_print=False):
b = [(k, v) for k, v in self.__dict__.items()]
if should_print:
[print(f"attr: {a[0]} value: {a[1]}") for a in b]
return b