python:读取一行,然后实例化该行中的类
抱歉如果我在标题上没有表达清楚,如果你有更好的说法,请随时纠正我:
我有一个文件,里面有一些类的名字,比如:
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 个回答
其他的回答都满足了你的要求,但我想加一点灵活性和保护措施。我会使用一个字典,把行名称和类对象对应起来,这样就不会让文本文件随便创建任何东西。它必须是你在代码中允许的类。这样做也更方便,因为你可以在两边随意更改名称而不会出问题(而且如果你想的话,可以把多个行名称映射到一个类名称)。
classes = {'classa': classa, 'classb': classb}
cls = type(classes[line], (object,), {}) ## or whichever method to instantiate you prefer
不过一般来说,我觉得这样做不是很符合Python的风格。
假设你的类已经在当前环境中可以使用(也就是说,它们不在一个单独的模块里),你可以通过 globals()
这个字典很简单地用类名来引用一个类。比如:
class Foo:
pass
foo_cls = globals()['Foo']
foo = foo_cls()
# foo is now an instance of __main__.Foo
既然你已经在使用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文件里,这也是个额外的好处。