2010-07-20 57 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>)