【问题标题】:python : read a line, then instantiate a class named in the linepython:读取一行,然后实例化一个在该行中命名的类
【发布时间】:2011-03-22 10:10:42
【问题描述】:

对不起,如果我的标题不够清楚,如果您找到更好的表达方式,请随时纠正:

我有一个包含类名的文件,即:

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 类的两个 instances 和类 instances 的两个 instances强>自行车。因此,不理解/不知道 python 的用户将能够在不接触任何代码的情况下编辑文件。 我认为这是正确的方法,如果您对此代码有任何其他建议,欢迎您!

奥利维尔·庞斯

【问题讨论】:

  • 为什么要这样做?我想不出有很多基于文件的空类浮动的理由......并不是说没有一个!
  • 我可能不会这样做,除非我有一个非常很好的理由并且无法以任何其他方式完成它,仅供参考。
  • 你的意思是'根据行创建一个类的实例'?
  • 我调整了你的标题以反映你的问题,希望你不介意。
  • 不,相反:谢谢!

标签: python dynamic


【解决方案1】:

假设您的类已经在范围内(即它们不在单独的模块中),您可以通过 globals() 字典轻松地通过其名称引用一个类。例如:

class Foo:
    pass

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

【讨论】:

  • 这是一个非常好的答案,我只是想知道访问全局变量是否不是一种技巧,因为我一直被教导要避免全局变量...
【解决方案2】:

其他答案按照您的要求进行,但我想增加一点灵活性(和保护)。我会使用字典将行名映射到类对象,因此您不会让文本文件实例化它想要的任何东西。它必须是您允许的类,在您的代码中。这也使它变得更容易,因为您可以轻松更改任一侧的名称(如果需要,您可以将多个行名映射到单个类名。)

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

但总的来说,在我看来,这并不是一件 Python 式的事情。

【讨论】:

  • 这是 classes = {'classa': classa, 'classb': 'classb'} 还是 classes = {'classa': classa, 'classb': classb} 还是 classes = {'classa' : 'classa', 'classb': 'classb'} ?
  • 哎呀,应该是 {'classfilename': classname}。我写了那个走出门。 (上面的答案固定以反映这一点。)
【解决方案3】:

当您使用 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 文件中。

【讨论】:

  • 根据他在做什么,YAML 语法的开销可能比它的价值更大。考虑到他的问题,检查班级是否存在似乎是他唯一需要的检查。但我也喜欢 YAAML。
  • 原始发帖人对这个问题发表了评论:“它要复杂得多:我将阅读一个复杂的 YAML 文件......” - 所以我得出结论“当你使用无论如何,YAML...”
  • 嗯,乍一看,我认为“嘿,这正是我所需要的”,但事实并非如此 100%。它比这更复杂。我认为您让我走上了正确的道路,非常感谢您!
【解决方案4】:

从文件中读取每一行非常简单:

with open(filename) as f:
    for line in f:

创建类首先想到的是type 函数:

        cls = type(line, (object,), {})

这将创建一个新的空类,它是object 的子类,并具有由该行的内容给出的名称。

不过,我想知道您为什么要这样做。像这样的空类在 Python 中似乎不是很有用。

【讨论】:

  • 我猜,“动态创建该类”应该真正理解为“动态创建该类的一个实例”。这就是 OP 中的 PHP sn-p 所做的。
  • 哦,我知道我不应该浏览那个 PHP 代码示例。
  • 错了,我很抱歉,但我必须投反对票,因为它不能正确回答我的问题,但这是一段很好的代码,我会保留它以备将来使用有一天我需要它!再次感谢
  • @Olivier:请记住,这是一件非常“骇人听闻”的事情,如果你能找到它的好用处,我会有点惊讶。回想起来,我很想删除这个......
  • 我会使用你的代码。更准确地说,我的 YAML 文件将具有“类”声明,即“汽车”,然后将具有类实例化,即 car:id=145,color='blue' 等等。我将不得不动态地“创建”新类,然后稍后将它们实例化。再次感谢这个提示!如果我错了,请告诉我,但您的示例说“嘿 Python,请创建一个名为 'line' 的新类”。我对吗?如果是这样,稍后,我将通过以下方式实例化这个类:“myobject=new cls()”。我还对吗?
【解决方案5】:

假设所有类都在一个模块foo中声明:

classname = sys.stdin.read().rstrip()
cls = getattr(foo, classname)()

要访问同一模块中的类,请使用内置 globals() 函数。

【讨论】:

    【解决方案6】:

    使用类字典应该很容易做到这一点(并不是说这不一定是限制,因为每个 python 命名空间都可以作为字典访问,所以如果你希望这些类都在一个模块或另一个类中,只需用类的__dict__ 属性替换类,或者按照其他人的建议使用全局变量):

    classes = dict()
    with open('filename') as f:
        for line in f:
            classes[line] = class()
    

    (实施细节可能有所不同)。

    但是,您可能想考虑使用酸洗,因为从表面上看,这种方法似乎有缺陷(尽管它可能在 PHP 中运行良好 :-))。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-01-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-24
      • 1970-01-01
      相关资源
      最近更新 更多