【问题标题】:Adding class attributes using a for loop in Python在 Python 中使用 for 循环添加类属性
【发布时间】:2011-01-16 22:45:58
【问题描述】:

我试图从字典中生成一个类:

class attr:
    for key in objects_type:
        setattr(attr, key, lambda cl: list())

这给出了在 for 循环期间未定义 attr 的错误。我知道我可以写:

class attr:
    pass
for key in objects_type:
    setattr(attr, key, lambda cl: list())

但我确信我记得在某处看到过类似于第一个示例的代码。有谁知道是否可以编写类似于第一种形式的东西?

【问题讨论】:

    标签: python metaprogramming


    【解决方案1】:

    虽然不是很优雅,但是可以使用locals()

    >>> class c(object):
    ...     for i in range(10):
    ...         locals()['A' + str(i)] = i
    ... 
    >>> c.A0
    0
    >>> c.A7
    7
    

    【讨论】:

    • 那一定是我记得看到的。谢谢
    • 事实上,我认为它比使用 setattr 更好 - 所以我不会说它不优雅
    • 你不应该改变 locals() 字典:docs.python.org/library/functions.html#locals
    • 我忘了 :-(。你认为破损的风险是多少?
    【解决方案2】:

    假设你想动态添加诸如这些的类属性

    classDict = {}
    for i in range(2):
        classDict["func%s"%(i+1)] = lambda self:"X"
    

    您可以通过多种方式做到这一点,例如只需在创建类后添加属性,因为您可以轻松访问类中的类名

    class Attr2(object):
        pass
    
    for n,v in classDict.iteritems():
        setattr(Attr2, n, v)
    
    print Attr2().func1(), Attr2().func2()
    

    或者更好的是动态创建类,例如

    Attr3 = type("Attr3",(), classDict)
    print Attr3().func1(), Attr3().func2()
    

    或者如果您希望使用元类,例如

    class AttrMeta(type):
        def __new__(cls, name, bases, dct):
            dct.update(classDict)
            return type.__new__(cls, name, bases, dct)
    
    class Attr4(object):
        __metaclass__ = AttrMeta
    
    print Attr4().func1(), Attr4().func2()
    

    【讨论】:

    • 我认为type 方法是最好的解决方案,考虑到问题。它确实需要程序员重新构造类属性的其余定义方式。另一方面,它避免深入研究locals(),避免定义自定义元类,并避免与正在使用的任何 other 元类的逻辑混为一谈。 IMO,这使它适合其他人将使用和贡献的图书馆。
    【解决方案3】:

    我不完全知道,你在做什么。我可以举个例子,在 for 循环中为类添加类属性:

    attributes = ('x', 5), ('y', 6), ('name', 'Cls')
    
    class Cls:
      pass
    for key, value in attributes:
      setattr(Cls, key, value)
    

    请记住,for 必须在定义整个类之后运行。你会得到错误,那个 attr 没有定义,因为你想在创建它之前访问类 beforeclass ... 是 python 中的一个语句,它创建一个类对象)。创建类后必须添加属性并记住,这些将是类属性,而不是实例属性。

    【讨论】:

      【解决方案4】:
      newmeths = {
        'two': lambda self: 2,
      }
      
      class MC(type):
        def __init__(cls, name, bases, dict):
          for k, v in newmeths.iteritems():
            setattr(cls, k, v)
          super(MC, cls).__init__(name, bases, dict)
      
      class C(object):
        __metaclass__ = MC
        pass
      
      c=C()
      print c.two()
      

      【讨论】:

        【解决方案5】:
        class Attr:
          def __init__(self):
            for key in objects_type:
              setattr(Attr, key, lambda cl: list())
        

        【讨论】:

        • +1:很好。为什么不是继承自object 的“新风格”类?
        • 这是错误的地方。不仅浪费,而且现有的绑定方法将不同于稍后实例化的对象的绑定方法。嗯,比平时更不一样了。
        【解决方案6】:

        我为此苦苦挣扎了很长时间,最终我使用一个示例解决了这个问题(因为我对编码很陌生):

        names = ['Cuba I', 'San Felipe II Okeechobee', 'Bahamas', 'Cuba II', 'CubaBrownsville', 'Tampico', 'Labor Day', 
        'New England', 'Carol', 'Janet', 'Carla', 'Hattie', 'Beulah', 'Camille', 'Edith', 'Anita', 'David', 'Allen', 
        'Gilbert', 'Hugo', 'Andrew', 'Mitch', 'Isabel', 'Ivan', 'Emily', 'Katrina', 'Rita', 'Wilma', 'Dean', 'Felix', 
        'Matthew', 'Irma', 'Maria', 'Michael']
        
        for i in range(len(names)):
            namev                                      =                    names[i]
            locals()[''+str(namev.replace(' ',''))+''] =                  Hurricane(
                name                                   =                      namev)
        

        所以“Cuba I”将是“Hurricane”类下的“CubaI”。根据我对其他开发人员的研究,强烈不建议这样做,至于为什么我还不确定。对于手头的挑战,似乎工作得很好。无论如何,随心所欲。

        【讨论】:

          猜你喜欢
          • 2021-01-26
          • 2019-02-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-08-11
          • 1970-01-01
          • 2021-12-31
          • 1970-01-01
          相关资源
          最近更新 更多