【问题标题】:Creating class instance properties from a dictionary?从字典创建类实例属性?
【发布时间】:2010-12-10 23:36:35
【问题描述】:

我正在从 CSV 导入数据并获取大致格式的数据

{ 'Field1' : 3000, 'Field2' : 6000, 'RandomField' : 5000 }

字段的名称是动态的。 (嗯,它们是动态的,因为可能不止 Field1 和 Field2,但我知道 Field1Field2 总是会在那里。

我希望能够将此字典传递给我的类allMyFields,以便我可以将上述数据作为属性访问。

class allMyFields:
    # I think I need to include these to allow hinting in Komodo. I think.
    self.Field1 = None
    self.Field2 = None

    def __init__(self,dictionary):
        for k,v in dictionary.items():
            self.k = v
            #of course, this doesn't work. I've ended up doing this instead
            #self.data[k] = v
            #but it's not the way I want to access the data.

q = { 'Field1' : 3000, 'Field2' : 6000, 'RandomField' : 5000 }
instance = allMyFields(q)
# Ideally I could do this.
print q.Field1

有什么建议吗?至于为什么——我希望能够利用代码提示,并将数据导入到名为data 的字典中,就像我一直在做的那样,我没有任何能力。

(由于变量名直到运行时才被解析,我仍然不得不向 Komodo 扔骨头 - 我认为 self.Field1 = None 应该足够了。)

那么 - 我该如何做我想做的事?还是我在咆哮一棵设计不佳的非 python 树?

【问题讨论】:

  • 科莫多编辑提示不需要类属性。它可以读取__init__ 方法体来查找self. 变量。更根本的是,您为什么不为此使用简单的csv.DictReader 并从每一行创建字典?
  • SLott - 我使用 re.sub() 手动修改标题并添加“假”标题。这不是一个很好的理由,但是在 DictReader 之后重命名密钥要昂贵得多。

标签: class python komodo


【解决方案1】:

您可以使用setattr(但请注意:并非每个字符串都是有效的属性名称!):

>>> class AllMyFields:
...     def __init__(self, dictionary):
...         for k, v in dictionary.items():
...             setattr(self, k, v)
... 
>>> o = AllMyFields({'a': 1, 'b': 2})
>>> o.a
1

编辑:让我解释一下上面的代码和SilentGhost's answer的区别。上面的代码 sn-p 创建了一个类,其中 instance attributes 基于给定的字典。 SilentGhost 的代码创建了一个类,其类属性基于给定的字典。

根据您的具体情况,这些解决方案中的任何一个都可能更合适。您是否打算创建一个或多个类实例?如果答案是 1,您不妨完全跳过对象创建,只构造类型(因此选择 SilentGhost 的答案)。

【讨论】:

  • 带有奖金编辑的代码解释了两个好的答案之间的差异真的很有帮助,谢谢!
  • 我惊喜地发现这个解决方案与 form_dict = flask.form.to_dict() 一起使用,从一个长的 web 表单创建一个 db.Model 实例。太棒了!
  • 注意-在表单上输入的整数和浮点数作为字符串返回到 form_dict 但在类使用之前很容易修复。
【解决方案2】:
>>> q = { 'Field1' : 3000, 'Field2' : 6000, 'RandomField' : 5000 }
>>> q = type('allMyFields', (object,), q)
>>> q.Field1
3000

type 的文档很好地解释了这里发生了什么(请参阅用作构造函数)。

编辑:如果您需要实例变量,以下方法也可以:

>>> a = q()             # first instance
>>> a.Field1
3000
>>> a.Field1 = 1
>>> a.Field1
1
>>> q().Field1           # second instance
3000

【讨论】:

  • +1,但我认为您应该向 OP 解释此代码的作用和/或提供文档链接。
  • 好吧,我猜他的名字“SilentGhost”
  • 简洁的方法,但它们是类变量这一事实不如实例变量引人注目。
  • 如果需要,您可以实例化q
【解决方案3】:

您也可以使用dict.update 而不是手动循环遍历items(如果要循环,iteritems 更好)。

class allMyFields(object):
    # note: you cannot (and don't have to) use self here
    Field1 = None
    Field2 = None

    def __init__(self, dictionary):
        self.__dict__.update(dictionary)

q = { 'Field1' : 3000, 'Field2' : 6000, 'RandomField' : 5000 }
instance = allMyFields(q)

print instance.Field1      # => 3000
print instance.Field2      # => 6000
print instance.RandomField # => 5000

【讨论】:

  • 如果键中有空格,有什么简单的解决方法吗?示例:instance.Something Else 因空间问题而无法工作。我想知道是否有一个优雅的解决方案。
  • @Jarad 而不是仅仅dictionary,使用map(lambda kv: (kv[0].replace(' ', '_'), kv[1]), dictionary.items())。这会将所有键名中的所有空格替换为下划线。
【解决方案4】:

你可以创建一个dict 的子类,它允许键的属性查找:

class AttributeDict(dict):
    def __getattr__(self, name):
        return self[name]

q = AttributeDict({ 'Field1' : 3000, 'Field2' : 6000, 'RandomField' : 5000 })
print q.Field1              
print q.Field2              
print q.RandomField

如果您尝试查找dict 已经具有的属性(例如keysget),您将获得dict 类属性(一种方法)。如果dict 类中不存在您要求的密钥,则将调用__getattr__ 方法并执行您的密钥查找。

【讨论】:

    【解决方案5】:

    使用命名元组 (Python 2.6):

    >>> from collections import namedtuple
    
    >>> the_dict = {'Field1': 3, 'Field2': 'b', 'foo': 4.9}
    >>> fields = ' '.join(the_dict.keys())
    >>> AllMyFields = namedtuple('AllMyFields', fields)
    >>> instance = AllMyFields(**the_dict)
    
    >>> print instance.Field1, instance.Field2, instance.foo
    3 b 4.9
    

    【讨论】:

      【解决方案6】:

      以漂亮的方式使用 setattr。 quick-n-dirty 方法是更新实例内部字典:

      >>> class A(object):
      ...    pass
      ...
      >>> a = A()
      >>> a.__dict__.update({"foo": 1, "bar": 2})
      >>> a.foo
      1
      >>> a.bar
      2
      >>>
      

      【讨论】:

        【解决方案7】:
        class SomeClass:
            def __init__(self,
                         property1,
                         property2):
               self.property1 = property1
               self.property2 = property2
        
        
        property_dict = {'property1': 'value1',
                         'property2': 'value2'}
        sc = SomeClass(**property_dict)
        print(sc.__dict__)
        

        【讨论】:

          【解决方案8】:

          或者你可以试试这个

          class AllMyFields:
              def __init__(self, field1, field2, random_field):
                  self.field1 = field1
                  self.field2 = field2
                  self.random_field = random_field
          
              @classmethod
              def get_instance(cls, d: dict):
                  return cls(**d)
          
          
          a = AllMyFields.get_instance({'field1': 3000, 'field2': 6000, 'random_field': 5000})
          print(a.field1)
          

          【讨论】:

            【解决方案9】:

            增强了sub class of dict

            recurrence dict 有效!

            class AttributeDict(dict):
                """https://stackoverflow.com/a/1639632/6494418"""
            
                def __getattr__(self, name):
                    return self[name] if not isinstance(self[name], dict) \
                        else AttributeDict(self[name])
            
            
            if __name__ == '__main__':
                d = {"hello": 1, "world": 2, "cat": {"dog": 5}}
                d = AttributeDict(d)
                print(d.cat)
                print(d.cat.dog)
                print(d.cat.items())
            
                """
                {'dog': 5}
                5
                dict_items([('dog', 5)])
                """
            

            【讨论】:

              【解决方案10】:

              如果您愿意添加新库,pydantic 是一个非常有效的解决方案。它使用python注解来构造对象并验证类型考虑以下代码:

              from pydantic import BaseModel
              
              class Person(BaseModel):
                  name: str
                  age: str
              
              
              data = {"name": "ahmed", "age": 36}
              
              p = Person(**data)
              

              pydantic:https://pydantic-docs.helpmanual.io/

              【讨论】:

                猜你喜欢
                • 2015-07-18
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2021-12-07
                • 2020-10-22
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多