2010-07-20 30 views
15

我有一個Python類,它具有名爲date1,date2,date3等的屬性。如何在Python中動態編寫和訪問類屬性?

在運行時,我有一個變量i,它是一個整數。

我想要做的是根據i的值在運行時訪問相應的日期屬性。

例如,

,如果我== 1,我想訪問myobject.date1

,如果我== 2,我想訪問myobject.date2

我想要做的類而不是屬性類似的東西。

例如,我有一堆類:MyClass1,MyClass2,MyClass3等。我有一個變量k。

如果k == 1,我要實例MyClass1的

的新實例,如果k == 2,我要實例MyClass2

的新實例

我怎麼能做到這一點

編輯

我希望避免使用一個巨大的if-then-else語句來選擇合適的屬性/類。

有沒有在Python中使用變量的值即時編寫類名的方法?

+2

請編輯這個問題。請閱讀頁面右側的格式提示。請正確格式化您的代碼。 – 2010-07-20 00:22:43

+1

請正確格式化此問題。我想將它視爲一個有用的問題,因爲這是元編程和內省的一個很好的例子。但它需要編輯。 – 2010-07-20 02:53:25

回答

19

您可以使用getattr()訪問屬性的時候你不在知道它的名字,直到運行時:

obj = myobject() 
i = 7 
date7 = getattr(obj, 'date%d' % i) # same as obj.date7 

如果你把你的編號類名爲foo模塊中,你可以再次使用getattr()按編號來訪問它們。

foo.py: 
    class Class1: pass 
    class Class2: pass 
    [ etc ] 


bar.py: 
    import foo 
    i = 3 
    someClass = getattr(foo, "Class%d" % i) # Same as someClass = foo.Class3 
    obj = someClass() # someClass is a pointer to foo.Class3 
    # short version: 
    obj = getattr(foo, "Class%d" % i)() 

說了這麼多,你真的應該避免這樣的事情,因爲在那裏被使用,除非通過你的整個代碼庫閱讀這些編號的屬性和類,你將永遠無法找到答案。你最好把所有東西都放在字典中。

+4

要強調最後一段帶有大紅色標記。在最後有兩個具有相同名稱和運行號的標識符?重構它。也就是說,除非你有理由認爲是理想的兩倍。 – delnan 2010-07-20 00:57:28

+0

完全同意。給出一個選擇,我絕不會讓這樣的代碼複審。 – Daenyth 2010-07-20 02:34:23

0

對於第一個示例,我會在該類上添加一個實例方法。

def get_date_for_i(self, i): 
    if i == 1: 
     return self.date1 
    elif i == 2: 
     return self.date2 
    # etc... 

對於第二個我會使用一個工廠函數:

def get_class_for_k(k): 
    if k == 1: 
     return MyClass1 
    if k == 2: 
     return MyClass2 

    # etc... 
+0

嗯,我試圖避免有一個巨大的if-then-else語句。 – Continuation 2010-07-20 00:36:42

4

OK,嗯......好像這需要一些工作。首先,對於你的日期*事物,它們應該被存儲爲屬性的字典。例如,myobj.dates[1],等等。

對於類,它聽起來像你想要多態性。所有的MyClass *類都應該有一個共同的祖先。祖先的__new__方法應該找出它的哪個子實例化。

父母知道該做什麼的一種方法是保留孩子的字典。有一些方法可以讓父類不需要通過搜索它的所有子類來枚舉它的子類,但實現起來要複雜一點。有關如何採取這種方法的更多信息,請參閱here。特別閱讀評論,他們擴展它。

class Parent(object): 
    _children = { 
     1: MyClass1, 
     2: MyClass2, 
    } 

    def __new__(k): 
     return object.__new__(Parent._children[k]) 

class MyClass1(Parent): 
    def __init__(self): 
     self.foo = 1 

class MyClass2(Parent): 
    def __init__(self): 
     self.foo = 2 

bar = Parent(1) 
print bar.foo # 1 
baz = Parent(2) 
print bar.foo # 2 

第三,你真的應該重新考慮你的變量命名。不要用數字來枚舉變量,而要給它們有意義的名字。 ik不好用,因爲它們按照慣例爲循環索引保留。

現有代碼的一個示例將對改進它很有幫助。

+0

祖先的__new__方法如何找出哪些孩子實例化而不訴諸大的if-then-else語句? 我希望能夠使用變量值直接「撰寫」在飛行中的類名稱。在Python中可能嗎? – Continuation 2010-07-20 00:39:45

+0

@Continuation:我已經更新了我的答案,以包含更多信息 – Daenyth 2010-07-20 02:31:09

+0

我有這樣的情況:屬性nameInfo,groupInfo等來自vSphere api,以及在迭代循環中如何動態/編程訪問這些屬性,那麼字典不會' t對我而言很有用 – Hvisage 2017-12-28 07:04:08

5

對於第一種情況,你應該能夠做到:

getattr(myobject, 'date%s' % i) 

對於第二種情況,你可以這樣做:

myobject = locals()['MyClass%s' % k]() 

然而,事實是,你需要做到這一點第一個地方可能是一個跡象,表明你正在以一種非Pythonic的方式處理這個問題。

2

我同意Daenyth,但如果你感到時髦,你可以使用自帶的所有類的字典方法:

>>> class nullclass(object): 
     def nullmethod(): 
      pass 

>>> nullclass.__dict__.keys() 
['__dict__', '__module__', '__weakref__', 'nullmethod', '__doc__'] 

>>> nullclass.__dict__["nullmethod"] 
<function nullmethod at 0x013366A8> 
1

獲得所有屬性的列表,請嘗試:

dir(<class instance>)