在Python中创建一个空对象

126

在Python中是否有定义空对象的快捷方式,还是总是需要创建自定义空类的实例?

编辑:我指的是可用于鸭子类型的空对象。


1
你应该回到这个问题并接受使用SimpleNamespace的答案,这是现在最好的方法! - Francesco Marchetti-Stasi
10个回答

145

是的,在Python 3.3中添加了SimpleNamespace

与object不同,使用SimpleNamespace可以添加和删除属性。如果使用关键字参数初始化SimpleNamespace对象,则这些参数将直接添加到基础命名空间中。

示例:

import types

x = types.SimpleNamespace()
x.happy = True

print(x.happy) # True

del x.happy
print(x.happy) # AttributeError. object has no attribute 'happy'

6
这应该是被采纳的答案。请注意,这比那个涉及 t = type('test', (object,), {})() 的答案要简单得多。 - philologon
不,这不应该是被接受的答案。在Python中,类型提示是可选的。了解类型机制是可选的知识。许多人可能无法理解代码。单一命名空间这个词根本不直观。 - habrewning
@habrewning,这里没有涉及类型提示(typing)。Types与打字无关。https://docs.python.org/3/library/types.html 该模块定义了实用函数,以帮助动态创建新类型。 - Vlad Bezden

130
你可以使用 type 来动态创建一个新类并实例化它。像这样:
>>> t = type('test', (object,), {})()
>>> t
<__main__.test at 0xb615930c>

type的参数包括:类名,基类元组和对象字典。字典中可以包含函数(对象的方法)或属性。

事实上,你可以将第一行缩短为

>>> t = type('test', (), {})()
>>> t.__class__.__bases__
(object,)

因为默认情况下,类型创建新的样式类,这些类继承自对象。

type 在 Python 中用于元编程

但是,如果您只想创建一个对象实例。那么,只需创建该实例。就像lejlot建议的那样。

像这样创建一个新类的实例具有一个重要的区别,可能会很有用。

>>> a = object()
>>> a.whoops = 1
Traceback (most recent call last):
   File "<stdin>", line 1, in <module>
AttributeError: 'object' object has no attribute 'whoops'

然而:

>>> b = type('', (), {})()
>>> b.this_works = 'cool'
>>> 

72

创建一个空(大致为空)对象的一种简单而不那么可怕的方法是利用Python中函数是对象的事实,包括Lambda函数:

obj = lambda: None
obj.test = "Hello, world!"
例如:
In [18]: x = lambda: None

In [19]: x.test = "Hello, world!"

In [20]: x.test
Out[20]: 'Hello, world!'

我喜欢这个解决方案,因为不需要给它命名。 - Hugh Perkins
5
嗯,但这种方法的缺点是你不能将函数赋值给 x.__class__.somefunc - Hugh Perkins
5
使用copy.deepcopy()复制对象时,这个解决方案存在问题。在Python 3中,types.SimpleNamespace()是更好的解决方案。 - cn123h

23

你在问题中已经提到了它,但是由于没有答案提供相应的代码,所以这可能是最干净的解决方案之一:

class Myobject:
    pass

x = Myobject()
x.test = "Hello, world!"  # working


3
不确定为什么这不是首选答案,看起来是最符合Python风格的答案。 - StanKosy

12

您所说的“空对象”是什么意思?是指 object 类的实例吗?您可以直接运行以下代码

a = object()

或者您是指将初始化为 null 引用?那么您可以使用

a = None

28
我想知道如果“a”被定义为“object()”或“None”,OP能做些什么,因为在这种情况下,“a”没有命名空间“__dict__”,也不能像“a.x = 10”那样向“a”添加属性。 - eyquem
2
实际上,a = object(); a.foo = 'bar' 会报错 AttributeError: 'object' object has no attribute 'foo' - Basj

4
所有提出的解决方案都有些笨拙。
我找到了一种既不破坏原始设计又不太技巧性的方法。
>>> from mock import Mock
>>> foo = Mock(spec=['foo'], foo='foo')
>>> foo.foo
'foo'
>>> foo.bar
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/.../virtualenv/local/lib/python2.7/site-packages/mock/mock.py", line 698, in __getattr__
    raise AttributeError("Mock object has no attribute %r" % name)
AttributeError: Mock object has no attribute 'bar'

在此处查看unittest.mock的文档。


4

您可以使用

x = lambda: [p for p in x.__dict__.keys()]

那么
x.p1 = 2
x.p2 = "Another property"

在...

x()
# gives
# ['p1', 'p2']

And

[(p, getattr(x,p)) for p in x()]
# gives
# [('p1', 2), ('p2', 'Another property')]

2
构造一个新的空集合对象。如果提供了可选的iterable参数,则使用从迭代中获取的元素更新集合。iterable中的所有元素都应该是不可变的,或者可以使用在“自动转换为不可变的协议”一节中描述的协议进行转换为不可变的。
例如:
myobj = set()
for i in range(1,10): myobj.add(i)
print(myobj)

2
在我看来,最简单的方法是:
def x():pass
x.test = 'Hello, world!'

0

如果您想要创建一个特定类型的空对象,也就是说,您想要创建它但不调用__init__初始化程序,则可以使用__new__

class String(object):
    ...

uninitialized_empty_string = String.__new__(String)

来源:https://dev59.com/e3I95IYBdhLWcg3wwwyY#2169191


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接