简体   繁体   English

在Python中创建真正为空的类型

[英]Creating Truly Empty Types in Python

On a regular basis, I want to create completely empty objects in Python. 定期地,我想在Python中创建完全空的对象。 Basically, I want to have a dict where the keys are attributes. 基本上,我想定义一个键,键是属性。 In Python 2.x, I can create an old-style type like this: 在Python 2.x中,我可以创建一个老式的类型,如下所示:

class Empty: pass

This will create a type that only has two attributes ( __doc__ and __module__ ). 这将创建仅具有两个属性( __doc____module__ )的类型。 In Python 3.x, everything is a new-style class, so I get 18 attributes. 在Python 3.x中,所有内容都是一个新式类,因此我得到18个属性。

In my current situation, I have a class that allows you to specify types that need monkey patched within a unit test. 在当前情况下,我有一个类,可让您指定需要在单元测试中修补的猴子的类型。 When the patches are applied, I am creating a type with attributes with the names of each mocked-out type. 应用补丁程序后,我将创建一个带有每个模拟类型名称的属性的类型。 This is pretty much what my current implementation is doing: 这几乎就是我当前的实现方式:

class EmptyType: pass
...
mocks = EmptyType()
for mock_name, mock in patches:
    setattr(mocks, mock_name, mock)

My concern is that should someone be mocking a private member, they might run into naming collisions with the names in the EmptyType object. 我担心的是,如果有人嘲笑私有成员,他们可能会与EmptyType对象中的名称发生命名冲突。 That's why I'd like to keep as few attributes in the EmptyType as possible. 这就是为什么我想在EmptyType保留尽可能少的属性。 And it is way easier to say mocks.find_users than it is to say mocks["find_users"] , especially when I know the name has to be a valid identifier. 而且,比起说mocks["find_users"]mocks["find_users"] mocks.find_users要容易得多,尤其是当我知道名称必须是一个有效的标识符时。

Right now, I have provided the ability to give mocks different names, other than what would otherwise be the default. 现在,除了提供默认名称外,我还提供了给模拟提供不同名称的功能。 Still, it would be nice to avoid confusing errors in the first place. 尽管如此,最好还是避免混淆错误。 It is very easy to create almost empty types in JavaScript and I was hoping there was something similar in Python, since I keep finding good uses for them. 在JavaScript中创建几乎为空的类型非常容易,我一直希望在Python中有类似的东西,因为我一直在为它们寻找好的用法。

What about creating your own custom container? 如何创建自己的自定义容器?

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)

Usage: 用法:

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

It will store everything under a _obj dictionary so you basically get a clean space that doesn't conflict with the actual instance attributes. 它将所有内容存储在_obj字典下,因此您基本上可以获得一个与实际实例属性没有冲突的干净空间。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM