2012-07-24 73 views
78

我有一個python對象有幾個屬性和方法。我想迭代對象屬性。迭代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 

更新: 帶有屬性我的意思是僅此對象的變量,而不是方法。

+2

http://stackoverflow.com/questions/1251692/how-枚舉一個對象屬性在python可能會有一些幫助。 – sean 2012-07-24 18:49:08

+0

@sean特別是,http://stackoverflow.com/a/1251789/4203是要走的路;你可以使用可選的'predicate'參數來傳遞一個可以過濾出(綁定?)函數的可調用函數(可以去除這些方法)。 – 2012-07-24 19:21:09

回答

133

假設你有一個類如

>>> 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

這是一個壞主意,我甚至不會建議它,但如果你打算,至少提供警告。 – Julian 2012-07-24 18:57:51

+1

@ Julian我認爲代碼是自我解釋的。哪一部分模糊?儘管動態語言的要點是能夠做到這一點,即使java背景的人認爲這是自殺。 – Meitham 2012-07-24 19:00:18

+0

這看起來很簡單。警告是什麼意思?有什麼可能出錯? – 2012-07-24 19:00:35

0

正確的答案是,你不應該這樣做。如果你想要這種類型的東西或者只是使用一個字典,或者你需要明確地將屬性添加到某個容器。你可以通過學習裝飾器來自動化。

特別是,順便說一句,您的示例中的method1與屬性一樣好。

+1

是的,我知道我不應該......但它可以幫助我理解事情的工作方式。我來自一個PHP背景,並且每天都會用這種東西來做這件事 – 2012-07-24 19:01:36

+0

聽起來像是打破舊習慣的好時機:)! – Julian 2012-07-24 19:17:02

+0

你說服了我。保持to_dict()方法更新比迄今爲止的任何答案都要簡單得多。 – 2012-07-24 19:37:42

2

python中的對象將其屬性(包括函數)存儲在字典__dict__中。你可以(但通常不應該)使用它來直接訪問屬性。如果你只是想要一個列表,你也可以調用dir(obj),它返回一個包含所有屬性名稱的迭代器,然後你可以傳遞給getattr

但是,需要對變量的名稱做任何事情通常都是不好的設計。爲什麼不把它們放在一個集合中?

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

然後,您可以通過按鍵重複與for key in obj.special_values:

+0

你能解釋一下我將如何使用集合來實現我想要的? – 2012-07-24 19:03:18

+1

我沒有動態地將屬性添加到對象中。我所擁有的變量在很長一段時間內都會保持不變,但我認爲能夠按照我的意圖做一些事情會很好。 – 2012-07-24 19:30:19

1
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 
+0

這看起來太複雜了。如果我沒有選擇,我寧願堅持我現在正在做的事情。 – 2012-07-24 19:14:07

31
一般

__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'} 
0

對於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 
0

對於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