迭代python中的对象属性

Pab*_*her 137 python oop iteration attributes

我有一个python对象,有几个属性和方法.我想迭代对象属性.

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

    def method1(self, etc, etc):
        #Statements
Run Code Online (Sandbox Code Playgroud)

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

在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
Run Code Online (Sandbox Code Playgroud)

·

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
Run Code Online (Sandbox Code Playgroud)

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

Mei*_*ham 204

假设你有一个类如

>>> class Cls(object):
...     foo = 1
...     bar = 'hello'
...     def func(self):
...         return 'call me'
...
>>> obj = Cls()
Run Code Online (Sandbox Code Playgroud)

调用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']
Run Code Online (Sandbox Code Playgroud)

您始终可以使用列表推导过滤掉特殊方法.

>>> [a for a in dir(obj) if not a.startswith('__')]
['bar', 'foo', 'func']
Run Code Online (Sandbox Code Playgroud)

或者如果你喜欢地图/过滤器.

>>> filter(lambda a: not a.startswith('__'), dir(obj))
['bar', 'foo', 'func']
Run Code Online (Sandbox Code Playgroud)

如果要过滤掉方法,可以使用内置callable检查作为检查.

>>> [a for a in dir(obj) if not a.startswith('__') and not callable(getattr(obj, a))]
['bar', 'foo']
Run Code Online (Sandbox Code Playgroud)

您还可以使用检查您的类与其父级之间的差异.

>>> set(dir(Cls)) - set(dir(object))
set(['__module__', 'bar', 'func', '__dict__', 'foo', '__weakref__'])
Run Code Online (Sandbox Code Playgroud)

  • 实际上obj .__ dict__(可能)更好地用于此目的. (23认同)
  • @Julian`dir()`当传递元类(极端边缘情况)_or_类时,只有"谎言",其属性由[`@ DynamicClassAttribute`](https://docs.python.org/3/library/types.html)修饰#styments.DynamicClassAttribute)(另一个极端边缘情况).在这两种情况下,调用`dirs()`包装器`inspect.getmembers()`解决了这个问题.但是,对于标准对象,此解决方案的列表理解方法过滤掉非可调用_absolutely_就足够了.一些Pythonistas会将它标记为"糟糕的主意"让我感到困惑,但我认为......对于每个人来说都是如此? (5认同)
  • @Julian上面的代码将选择`_foo`和`name`,因为它们现在是对象的属性.如果您不想包含它们,可以在列表解析条件中排除它们.上面的代码是一种常见的python习惯用法和内省python对象的流行方式. (3认同)
  • 你也可以使用 `vars(obj)`,它返回 `__dict__`,而不是 `dir(obj)`:/sf/answers/1902681581/ (3认同)
  • @Meitham @Pablo出问题的主要是,您不需要这样做。您感兴趣的属性应该*包含*而不是*专有*。正如您已经看到的那样,您将包含方法,并且试图排除它们的任何尝试都是有缺陷的,因为它们将涉及诸如callable或types.MethodType之类的令人讨厌的事物。如果我添加一个名为“ _foo”的属性来存储一些中间结果或内部数据结构,会发生什么情况?如果我只是在类中无害地添加一个属性,比如说一个“名称”,然后突然将其包括在内,会发生什么。 (2认同)
  • 是的,`__dict__` 是一个实现细节。有些对象甚至没有,比如带有 `__slots__` 但仍然可以响应 `dir` 的对象。两者都不是理想的,因为 `dir` 也可以[撒谎](http://docs.python.org/library/functions.html#dir) (2认同)

Sma*_*ron 47

通常__iter__在你的类中放置一个方法并遍历对象属性或将这个mixin类放在你的类中.

class IterMixin(object):
    def __iter__(self):
        for attr, value in self.__dict__.iteritems():
            yield attr, value
Run Code Online (Sandbox Code Playgroud)

你的班:

>>> 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'}
Run Code Online (Sandbox Code Playgroud)

  • vars(yc)给出相同的结果,而不必从另一个类继承。 (2认同)

Nat*_*han 45

正如一些答案/评论中已经提到的,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}
Run Code Online (Sandbox Code Playgroud)

使用dir(a)这种方法来解决这个问题是一种奇怪的,如果不是完全坏的方法。如果您真的需要遍历类的所有属性和方法(包括像 之类的特殊方法__init__),那就太好了。但是,这似乎不是您想要的,甚至通过应用一些脆弱的过滤来尝试删除方法并仅保留属性,即使已接受的答案也很糟糕;您可以看到A上面定义的类将如何失败。

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

  • 如果您将 `ab` 作为某个自定义类 `B`,则 `vars(a)["b"] 就是 ab`,正如人们所期望的那样;其他任何东西都没有真正意义(将 `ab` 视为 `a.__dict__["b"]` 的语法糖)。如果你有 `d = vars(a)` 并调用 `repr(d)` 那么它会调用 `repr(d["b"])` 作为返回它自己的 repr 字符串的一部分,因为实际上只有类 `B`知道它应该如何表示为字符串。 (2认同)