如何动态组合和访问Python中的类属性?

How to dynamically compose and access class attributes in Python?

本问题已经有最佳答案,请猛点这里访问。

我有一个python类,它具有名为date1、date2、date3等属性。

在运行时,我有一个变量i,它是一个整数。

我要做的是根据i的值在运行时访问适当的日期属性。

例如,

如果i==1,我想访问myObject.date1

如果i==2,我想访问myObject.date2

我想为类而不是属性做类似的事情。

例如,我有很多类:myClass1、myClass2、myClass3等,我有一个变量k。

如果k==1,我想实例化myClass1的新实例

如果k==2,我想实例化myClass2的新实例

我该怎么做?

编辑

我希望避免使用一个巨大的if-then-else语句来选择适当的属性/类。

在python中,有没有一种方法可以使用变量的值动态地组合类名?


运行时不知道属性名称时,可以使用getattr()访问该属性:

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

如果将编号类保存在名为foo的模块中,则可以再次使用getattr()按编号访问它们。

1
2
3
4
5
6
7
8
9
10
11
12
13
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)()

说了这么多之后,您真的应该避免这类事情,因为您将永远无法找到这些编号的属性和类在哪里被使用,除非通过阅读整个代码库。你最好把所有的东西都放在字典里。


对于第一种情况,您应该能够做到:

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

对于第二种情况,您可以执行以下操作:

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

然而,事实上你首先需要这样做,这可能是一个迹象,表明你正在以一种非常非Python的方式来解决这个问题。


好吧,好吧…这似乎需要一些工作。首先,对于日期*的事情,它们应该存储为属性的dict。例如,myobj.dates[1]等。

对于这些类,听起来您需要多态性。所有myclass*类都应该有一个共同的祖先。祖先的__new__方法应该找出要实例化的子代。

父母知道该做什么的一个方法是对孩子们口述。父类有一些方法不需要通过搜索它的所有子类来枚举它的子类,但是实现起来有点复杂。请参阅这里,以了解更多关于您如何采取这种方法的信息。特别是阅读评论,他们会扩展评论。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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不好用,因为它们按惯例是为循环索引保留的。

现有代码的一个示例将对改进它非常有帮助。


我同意Daenyth的观点,但是如果你觉得自己很时髦,你可以使用所有类附带的dict方法:

1
2
3
4
5
6
7
8
9
>>> 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>)


对于第一个示例,我将在类上添加一个实例方法。

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

第二步,我将使用工厂功能:

1
2
3
4
5
6
7
def get_class_for_k(k):
   if k == 1:
       return MyClass1
   if k == 2:
       return MyClass2

   # etc...