python:读取一行,然后实例化该行中的类

0 投票
6 回答
649 浏览
提问于 2025-04-16 01:59

抱歉如果我在标题上没有表达清楚,如果你有更好的说法,请随时纠正我:

我有一个文件,里面有一些类的名字,比如:

classa
classb
classb
classc
classc
classc

然后我想逐行读取这个文件,并动态地创建这些类。在PHP中,我会这样做:

while (!eof())
{
   $class=fread(..)
   $tab[] = new $class();
}

那么在Python中,你会怎么做呢(如果可以的话)?

非常感谢!

编辑:在阅读了回答后,为了更准确地说明我计划做的事情:我并不打算做这么简单的事情。我的计划要复杂得多:我希望一个不懂编程的用户能够编辑一个简单的文本文件,复制/粘贴一些声明,修改它们的属性,然后重新启动一个解析器,这样就能重新运行一批操作并显示复杂操作的结果。

简化的文件示例:

car:(red,4_wheels,4_places)
bike:(blue,2_wheels,1_place)

然后用户会把它改成:

car:(red,4_wheels,4_places)
car:(yellow,4_wheels,2_places)
bike:(blue,2_wheels,1_place)
bike:(green,2_wheels,2_places)

接着我会用Python读取这个文件,创建两个car类的实例,还有两个bike类的实例。这样一个不懂Python的用户就能编辑这个文件,而不需要动一行代码。

我觉得这是正确的方向,如果你对这段代码有其他建议,欢迎提出!

Olivier Pons

6 个回答

2

其他的回答都满足了你的要求,但我想加一点灵活性和保护措施。我会使用一个字典,把行名称和类对象对应起来,这样就不会让文本文件随便创建任何东西。它必须是你在代码中允许的类。这样做也更方便,因为你可以在两边随意更改名称而不会出问题(而且如果你想的话,可以把多个行名称映射到一个类名称)。

classes = {'classa': classa, 'classb': classb}
cls = type(classes[line], (object,), {})  ## or whichever method to instantiate you prefer

不过一般来说,我觉得这样做不是很符合Python的风格。

3

假设你的类已经在当前环境中可以使用(也就是说,它们不在一个单独的模块里),你可以通过 globals() 这个字典很简单地用类名来引用一个类。比如:

class Foo:
    pass

foo_cls = globals()['Foo']
foo = foo_cls()
# foo is now an instance of __main__.Foo
1

既然你已经在使用YAML了,不妨考虑用PyYAML,并让你的类继承自yaml.YAMLObject这个元类,或者自己注册一个代表器。

根据PyYAML的文档:

class Monster(yaml.YAMLObject):
    yaml_tag = u'!Monster'
    def __init__(self, name, hp, ac, attacks):
        self.name = name
        self.hp = hp
        self.ac = ac
        self.attacks = attacks
    def __repr__(self):
        return "%s(name=%r, hp=%r, ac=%r, attacks=%r)" % (
            self.__class__.__name__, self.name, self.hp, self.ac, self.attacks)

print yaml.load("""
--- !Monster
name: Cave spider
hp: [2,6]    # 2d6
ac: 16
attacks: [BITE, HURT]
""")

这段代码会输出Monster(name='Cave spider', hp=[2, 6], ac=16, attacks=['BITE', 'HURT'])

这样,你就可以省去很多处理错误的代码(比如类不存在的情况),而且你的系统也能更好地抵御恶意的配置文件。此外,你还可以把程序中的对象保存到YAML文件里,这也是个额外的好处。

撰写回答