214

我有一个带有多个属性和方法的 python 对象。我想迭代对象属性。

class my_python_obj(object):
    attr1='a'
    attr2='b'
    attr3='c'

    def method1(self, etc, etc):
        #Statements

我想生成一个包含所有对象属性及其当前值的字典,但我想以动态方式进行(所以如果稍后我添加另一个属性,我也不必记住更新我的函数)。

在 php 中,变量可以用作键,但在 python 中的对象是不可接受的,如果我为此使用点表示法,它会创建一个带有我的 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

更新:对于属性,我只指这个对象的变量,而不是方法。

4

8 回答 8

300

假设您有一个课程,例如

>>> 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__'])
于 2012-07-24T18:54:44.790 回答
64

通常在您的类中放置一个__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'}
于 2013-11-26T10:29:39.443 回答
52

正如已经在一些答案/评论中提到的,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__),那就太好了。然而,这似乎不是你想要的,即使是接受的答案也很糟糕,通过应用一些脆弱的过滤来尝试删除方法并只留下属性;您可以看到A上面定义的类会如何失败。

(使用__dict__已经在几个答案中完成,但它们都定义了不必要的方法而不是直接使用它。只有评论建议使用vars)。

于 2019-03-24T04:08:23.120 回答
4

python 中的对象将它们的属性(包括函数)存储在一个名为__dict__. 您可以(但通常不应该)使用它直接访问属性。如果您只想要一个列表,您也可以调用dir(obj),它返回一个包含所有属性名称的可迭代对象,然后您可以将其传递给getattr.

然而,需要对变量名做任何事情通常是糟糕的设计。为什么不把它们收藏起来呢?

class Foo(object):
    def __init__(self, **values):
        self.special_values = values

然后,您可以使用for key in obj.special_values:

于 2012-07-24T18:56:16.607 回答
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
于 2012-07-24T19:05:21.833 回答
0

正确的答案是你不应该。如果你想要这种类型的东西,要么只使用一个 dict,要么你需要显式地将属性添加到某个容器。你可以通过学习装饰器来自动化它。

特别是,顺便说一下,您的示例中的 method1 也是一个很好的属性。

于 2012-07-24T18:55:52.190 回答
-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
于 2018-03-09T16:23:39.407 回答
-5

对于所有 Pythonian 狂热者,我相信 Johan Cleeze 会赞同你的教条主义;)。我要留下这个答案,继续记过它它实际上让我更加知己。给小鸡留言!

对于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
于 2018-03-09T15:54:50.480 回答