【问题标题】:JavaScript-like Object in Python standard library?Python标准库中的类JavaScript对象?
【发布时间】:2010-04-14 20:29:35
【问题描述】:

很多时候,我发现自己想要一个简单的 Python 中的“转储”对象,它的行为类似于 JavaScript 对象(即,可以使用 .member['member'] 访问其成员)。

通常我会把它贴在.py的顶部:

class DumbObject(dict):
    def __getattr__(self, attr):
        return self[attr]
    def __stattr__(self, attr, value):
        self[attr] = value

但这有点蹩脚,而且该实现至少存在一个错误(虽然我不记得它是什么)。

那么,标准库中是否有类似的东西?

并且,为了记录,简单地实例化 object 是行不通的:

>>> 对象 = 对象() >>> obj.airspeed = 42 回溯(最近一次通话最后): 文件“”,第 1 行,在 AttributeError:“对象”对象没有属性“空速”

编辑:(该死,早该看到这个)……别担心!我不是想用 Python 编写 JavaScript。我最常发现我想要这个的地方是在我还在试验的时候:我收集了一些“东西”,放在字典里不太合适,但拥有自己的类也不合适.

【问题讨论】:

  • 正如我在下面所说的,您正在尝试围绕从另一种语言带来的错误直觉进行编码。在 Python 中,即使在“实验”时,我们也会编写类。试试——停止写 DumbObject,实际写“class Foo”,看看它不咬人。
  • 而且,正如我在下面所说的......这是一个有趣的想法 - 简单地使用,例如,类 Foo: airspeed = 42 - 我没有考虑过。但是,它确实有一个问题,即它的行为不像字典(是的,有 dict...),这使得实验更加困难。
  • 看起来我们都想用 Python 做一些事情 :) stackoverflow.com/questions/2466191/…
  • 我在此表示怀疑,但您是否考虑过使用像 Redis 这样的键/值存储?正如您所说,它擅长作为“东西”的集合。 Python 客户端非常容易使用。

标签: python


【解决方案1】:

在 Python 3.3+ 中,您可以使用 SimpleNamespace,它完全符合您的要求:

from types import SimpleNamespace
obj = SimpleNamespace()
obj.airspeed = 42

https://docs.python.org/3.4/library/types.html#types.SimpleNamespace

【讨论】:

  • 行为与 JavaScript 对象完全一样。应该重新接受这个答案!
【解决方案2】:

你可以试试attrdict:

class attrdict(dict):
    def __init__(self, *args, **kwargs):
        dict.__init__(self, *args, **kwargs)
        self.__dict__ = self

a = attrdict(x=1, y=2)
print a.x, a.y
print a['x'], a['y']

b = attrdict()
b.x, b.y  = 1, 2
print b.x, b.y
print b['x'], b['y']

【讨论】:

  • 应该使用例如print b['x'] 来完成您的示例。表明它支持这两种属性访问方法。
  • 好点,PreludeAndFugue。我更新了代码。谢谢。 :)
  • 改变__dict__?!太恶心了!但是,与此同时,耐人寻味……
  • 警告!这可行,但可能由于循环引用而导致巨大的内存泄漏。将其放入循环中只需几秒钟即可填满我的 8 GB RAM。不要将它用于真正重要的代码!
  • @fletom 让我猜猜...你决定在 python 2 中使用range 创建一个庞大的对象...内存没有从 attrdicts 泄漏,这是因为range 实际上用 python 2 中的数字创建一个列表!垃圾收集器可以很好地处理循环引用:) 我刚刚创建并丢弃了 10**9 个 attrdicts,内存使用量甚至没有改变(直到最后都没有运行,但有足够的时间看到它没有泄漏) .使用xrange,你会没事的;)
【解决方案3】:

这种对象没有“标准库”,但在 ActiveState 上有一个来自 Alex Martelli 的著名配方,称为 "bunch"

注意:pypi 上还有一个名为 bunch 的包,它应该做同样的事情,但我不知道它的实现和质量。

【讨论】:

    【解决方案4】:

    您可能对collections.namedtuple感兴趣

    【讨论】:

      【解决方案5】:

      如果我理解正确,您需要一个可以转储属性的对象。如果我是正确的,您所要做的就是创建一个空类。例如:

      >>> class DumpObject: pass
      ... 
      >>>#example of usage:
      ...
      >>> a = DumpObject()
      >>> a.airspeed = 420
      >>> print a.airspeed
      420
      

      就是这样

      【讨论】:

      • 关闭,但我也希望能够将其视为字典(我想这并不完全清楚)。
      【解决方案6】:

      我不太喜欢这个,因为你会陷入“如果你定义'键'会怎样”:

      foo = DumbObject()
      foo.moshe = 'here'
      foo.keys # --> gives a callable, if you'll call it you'll get ['moshe']
      foo.keys = 'front-door'
      foo.keys # --> oh look, now it's a string 'front-door'
      

      “键”是否应该是您对象上定义的方法,还是只是偶然?如果是,那么您最好将 DumbObject 定义为

      class DumbObject(object):
          def __init__(self):
              self._dict = {}
          def __getitem__(self, key):
              return self._dict[key]
          __getattr__ = __getitem__
          # Ditto for set
      def asDictionary(do):
          return do._dict
      

      但是你为什么要这样做?你确定这是正确的答案吗?也许您应该使用正确类型的对象?

      【讨论】:

      • 啊,我没有考虑过。在这种情况下,我过去使用的实现至少有两个错误:P
      • 我经常喜欢用它来做实验——对于那些在字典中感觉并不“正确”的数据,但将其形式化成一个类感觉有点矫枉过正。
      • 我认为问题在于你的感受——“将其正式化为一个类”可能并不过分。在类至少不是“class Foo(object): pass”的语言中,这感觉像是一种矫枉过正:-D
      • 这是一个有趣的想法——简单地使用,例如,class Foo: airspeed = 42——我没有考虑过。但是,它确实有一个问题,它不像字典(是的,有__dict__...),这使得实验更加困难。
      【解决方案7】:

      好吧,据我所知(如果我错了,请纠正我)这里的每个示例都不会将嵌套字典转换为新类型。所以我做了这个例子:

      class DotDictionary(dict):
      
      def __init__(self, init_value):
          if not isinstance(init_value, dict):
              raise TypeError('Expected dict, got {}'.format(type(init_value)))
      
          self._dict_to_self(init_value)
      
      def __getattr__(self, name):
          return self[name]
      
      def __setattr__(self, name, val):
          self[name] = val
      
      def __delattr__(self, name):
          del self[name]
      
      def _dict_to_self(self, dct):
          for key, value in dct.items():
              if isinstance(value, dict):
                  value = DotDictionary(value)
              if isinstance(value, (tuple, list)):
                  for i, _ in enumerate(value):
                      if isinstance(value[i], dict):
                          value[i] = DotDictionary(value[i])
      
              self[key] = value
      

      ideone

      我不能 100% 确定它是否绝对正确,所以这里不提供任何保证。

      也许这不是pythonic方式,所以我准备好接受建议。

      【讨论】:

        【解决方案8】:

        此方法适用于嵌套字典,非常简洁。

        首先,定义一个空类。该类的实例可以设置任何属性。

        class holder:
            pass
        

        接下来,就用这个函数吧。

        def dotted(object):
        
            if isinstance(object, dict):
                parent = holder()
        
                for key in object:
        
                    child = object.get(key)
                    setattr(parent, key, dotted(child))
        
                return parent
        
            return object
        

        示例用法。

        users = dotted(
        {
            'john': {
                'fullname': 'John Doe'
                'age': 24,
                'hobbies': [
                    'programming',
                    'jogging'
                ]
            }
        }
        
        users.john.fullname # 'John Doe'
        users.john.age      # 24
        users.john.hobbies  # ['programming', 'jogging']
        
        users.john.age = 25
        users.john.age      # 25
        

        【讨论】:

          【解决方案9】:
          DumbObject = lambda: "function is a first-class object And this sentence isn't necessary :), you could simply put None or Pass"
          
          DumbObject.name = "Dumb"
          DumbObject.speak = lambda word: print(word)
          DumbObject.tell_name =  lambda : print(f"I am {DumbObject.name} and have no self")
          
          DumbObject.speak("I speak not")
          DumbObject.tell_name()
          

          【讨论】:

            【解决方案10】:

            这个实现允许你任意嵌套dicts和SimpleNamespaces,并且兼容json.dumps,因为它继承自dict

            from types import SimpleNamespace
            import json
            
            
            class DictNamespace(dict):
            
                def __getattr__(self, key):
                    return self[key]
            
                def __setattr__(self, key, value):
                    self[key] = self.construct_namespace(value)
            
                def __delattr__(self, key):
                    del self[key]
            
                @staticmethod
                def construct_namespace(maybe_dict):
                    if isinstance(maybe_dict, dict):
                        for key, value in maybe_dict.items():
                            if isinstance(value, dict):
                                maybe_dict[key] = DictNamespace(**value)
                            elif isinstance(value, SimpleNamespace):
                                maybe_dict[key] = DictNamespace(**value.__dict__)
                            else:
                                maybe_dict[key] = value
                    return maybe_dict
            
                def __init__(self, **kwargs):
                    super().__init__(**kwargs)
                    DictNamespace.construct_namespace(self)
            
            
            thing = DictNamespace(
                one=1, 
                two=dict(three=3), 
                five=DictNamespace(six=6), 
                eight=SimpleNamespace(nine=9)
            )
            
            thing.eleven = 11
            print(thing.one)
            print(thing.two)
            print(thing.two.three)
            print(thing.five)
            print(thing.five.six)
            print(thing.eight)
            print(thing.eight.nine)
            print(thing["eight"]["nine"])
            print(thing["eight"].nine)
            print(thing.eleven)
            del thing.eleven
            assert thing.get("eleven", None) is None
            print(json.dumps(thing))
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2011-01-05
              • 2013-08-09
              • 2021-09-29
              • 2011-04-14
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2016-09-02
              相关资源
              最近更新 更多