【问题标题】:Referring to class names through strings?通过字符串引用类名?
【发布时间】:2010-08-09 10:23:14
【问题描述】:

我需要解析一些文本文件,为文本中遇到的各种实体创建对象,并将它们放入一些数据结构(例如列表)中以供进一步处理。文本示例:

laptop
 17" dell, weight: 12 lb
desktop
 24" hp

我提前知道文本中可能存在哪些实体,以及它们应该具有哪些属性。在此示例中,我已经定义了笔记本电脑和台式机类(可能是计算机类的子类)。解析器只需要创建对象 laptop('dell', 17, 12) 和 dekstop('hp', 24)。

如果我遵循这条路线,我需要从字符串中检索类名,并创建这些类的对象。它是 Pythonic 的做事方式吗?如果是这样,最好的方法是什么(使用 Python 3.1)?如果没有,我应该怎么做?

谢谢!

什么

【问题讨论】:

    标签: python string class


    【解决方案1】:

    如果类是在computers.py中定义的,比如说,你可以这样做

    import computers
    getattr( computers, "Laptop" )( <params> )
    

    实例化一个computers.Laptop。如果它们是在您运行代码的同一文件中定义的(因此它们是全局变量),您可以这样做

    globals()[ "Laptop" ]
    

    但这不太优雅;将它们放在单独的范围内会更好。

    或者,如果你想要一个更强大的映射(比如你想要“Nettop”、“Lapbook”和“Laptop”都实例化Laptop),你可以维护一个字符串到它们对应的构造函数的映射并使用它:

    mapping = { "Laptop": Laptop, "Nettop": Laptop, ... }
    mapping[ "Laptop" ]()
    

    【讨论】:

      【解决方案2】:

      您可以使用以下代码通过类的名称创建类的实例

      obj = globals()[classname]()
      

      classname 是一个字符串

      【讨论】:

      • 这当然不是你应该轻松​​做的事情,因为如果失败了会很痛苦。但是,如果您绝对必须访问全局命名空间中的某些内容,那么这是要走的路(对于每个其他命名空间,都有 getattr/setattr)。
      【解决方案3】:

      从技术上讲,您所要求的(或至少每个人都在解释它的方式)并不是很好的做法,尤其是如果您可能从不受信任的来源获取输入(请记住,任何来源other比你自己 通常应该被认为是不受信任的!)。您应该明确地将这些事情列入白名单,因为有人可能会触发执行函数或创建您不希望使用您真正不想要的属性的对象...

      你可以做的是这样的事情(这当然是非常不完整的,但应该给你一个大致的想法):

      class Laptop(object):
          pass
      class Desktop(object):
          pass
      
      possible_classes = {
          "laptop": Laptop,
          "desktop": Desktop,
      }
      
      new_object = possible_classes[identifier_string](propA, propB, propC, ...)
      

      然后只需将每种新对象的映射添加到 possible_classes 字典。

      【讨论】:

        【解决方案4】:

        我认为基于检查的方法可能非常脆弱并且难以改变。如果你想使用其他模块中的类怎么办?

        为什么不是对象工厂?它可以是一个简单的函数或一个类。

        例子:

        class ComputerFactory:
        
           def __init__(self):
              self._classes = {}
        
           def register(moniker, creator):
              """Moniker is a name for the class.
              Creator is a callable that creates the object 
              for the moniker.
              """
              self._classes[moniker] = creator
        
           def create(moniker, *args, **kwargs):
              return self._classes[moniker](*args, **kwargs)
        
        # Example usage
        fac = ComputerFactory()
        # Register constructor
        fac.register("laptop", Laptop) # Laptop class is also a callable (the constructor)
        # Register construction proxy
        def sony_laptop_builder(make):
           return Laptop("Sony")
        fac.register("laptop", sony_laptop_builder)
        

        【讨论】:

          【解决方案5】:

          不确定python代码的语法,但这是你想要的吗?

          for item in parsedString:
              if item == "laptop":
                  laptops.add(laptop()) #laptops is a list of laptops you 
                                        #have encountered so far in your list
              # add the next elements to your laptop instance
          
              if item == "desktop":
              # code for desktop...
          

          【讨论】:

          • 假设我有几十个类,而解析器模块甚至不一定知道所有这些类。我喜欢将对象的类型解析为字符串变量,然后让解析器创建相关类的对象。
          • 我认为@katrielalex 已经回答了这个问题
          猜你喜欢
          • 2016-03-09
          • 2013-09-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-11-14
          • 2014-08-11
          相关资源
          最近更新 更多