在Python中创建真正的空类型

Tra*_*rks 4 python dictionary types

我经常想在Python中创建完全空的对象.基本上,我想要一个键是属性的字典.在Python 2.x中,我可以创建一个这样的旧式类型:

class Empty: pass
Run Code Online (Sandbox Code Playgroud)

这将创建一个只有两个属性(__doc____module__)的类型.在Python 3.x中,一切都是新式的类,所以我得到了18个属性.

在我目前的情况下,我有一个类,允许您指定在单元测试中需要猴子修补的类型.应用补丁时,我正在创建一个带有属性的类型,其中包含每个模拟类型的名称.这几乎是我当前的实现正在做的事情:

class EmptyType: pass
...
mocks = EmptyType()
for mock_name, mock in patches:
    setattr(mocks, mock_name, mock)
Run Code Online (Sandbox Code Playgroud)

我担心的是,如果有人嘲笑私人成员,他们可能会遇到与EmptyType对象中的名称命名冲突.这就是为什么我想保留尽可能少的属性EmptyType.并且它mocks.find_users比说它更容易说mocks["find_users"],特别是当我知道名称必须是有效的标识符时.

现在,我已经提供了为mocks提供不同名称的能力,除了默认值之外.不过,首先避免混淆错误会很好.在JavaScript中创建几乎空的类型非常容易,我希望在Python中有类似的东西,因为我一直在寻找它们的好用途.

jdi*_*jdi 6

如何创建自己的自定义容器?

class Empty(object):

    def __init__(self, **kwargs):
        object.__setattr__(self, '_obj', kwargs)

    def __getattribute__(self, name):
        obj = object.__getattribute__(self, '_obj')
        try:
            return obj[name]
        except KeyError:
            cls_name = object.__getattribute__(self, '__class__').__name__
            raise AttributeError(
                "'%(cls_name)s' object has no attribute '%(name)s'" % locals())

    def __setattr__(self, name, val):
        obj = object.__getattribute__(self, '_obj')
        obj[name] = val

    def __getitem__(self, key):
        return getattr(self, key)

    def __setitem__(self, key, val):
        return setattr(self, key, val)
Run Code Online (Sandbox Code Playgroud)

用法:

e = Empty(initial='optional-value')
e.initial
# 'optional-value'
e.val = 'foo'
e.val
# 'foo'
e.bad
# AttributeError: 'Empty' object has no attribute 'bad'
setattr(e, 'user', 'jdi')
e.user
# 'jdi'
e['user']
# 'jdi'

# note that you dont even see anything when you dir()
dir(e)
# []

# and trying to access _obj is protected
e._obj
#AttributeError: 'Empty' object has no attribute '_obj'

# But you could even set your own _obj attribute
e._obj = 1
e._obj
# 1
Run Code Online (Sandbox Code Playgroud)

它会将所有内容存储在_obj字典下,因此您基本上可以获得与实际实例属性不冲突的干净空间.

  • +1使用`__getattribute__`而不是更常见的`__getattr__`.(我不得不查看差异来说服自己'__getattribute__`真的是你想要的......) (2认同)
  • 我想这是我最后的评论.您可以使用"100"或其他不是有效标识符的东西,而不是使用"_obj"作为单个属性的名称.然后你完全消除了命名空间冲突问题(因为`a.100`是无效的语法). (2认同)