如何动态构建和访问Python中的类属性?

29 投票
5 回答
26851 浏览
提问于 2025-04-16 01:32

我有一个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中,有没有办法根据变量的值动态生成类名呢?

5 个回答

4

好的,看来这个代码需要一些改进。首先,你的日期相关的东西,建议把它们存储为一个属性字典。比如说,可以用 myobj.dates[1] 这样的方式来访问。

关于类的部分,听起来你想要实现多态性。所有的 MyClass* 类应该有一个共同的父类。这个父类的 __new__ 方法应该负责决定要实例化哪个子类。

父类知道要创建哪个子类的一种方法是保持一个子类的字典。其实有一些方法可以让父类不需要通过查找所有子类来列举它们,但实现起来会复杂一些。你可以查看 这里,了解更多关于这种方法的信息。特别是评论部分,它们有更详细的解释。

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 这样的名字不太好,因为按照惯例,它们通常用作循环的索引。

如果能提供一段你现有代码的示例,那会对改进它非常有帮助。

7

对于第一种情况,你可以这样做:

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

对于第二种情况,你可以这样做:

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

不过,首先需要这样做,可能说明你处理问题的方式有点不符合Python的风格。

52

你可以使用 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)()

不过,话说回来,你真的应该尽量避免这样做,因为你永远无法知道这些编号的属性和类在哪里被使用,除非你逐行阅读整个代码。把所有东西放在一个字典里会更好。

撰写回答