123

Are there any shortcuts for defining an empty object in Python or do you always have to create an instance of a custom empty class?

Edit: I mean an empty object usable for duck typing.

Smiles
  • 1,733
  • 2
  • 11
  • 13

10 Answers10

139

Yes, in Python 3.3 SimpleNamespace was added

Unlike object, with SimpleNamespace you can add and remove attributes. If a SimpleNamespace object is initialized with keyword arguments, those are directly added to the underlying namespace.

Example:

import types

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

print(x.happy) # True

del x.happy
print(x.happy) # AttributeError. object has no attribute 'happy'
Vlad Bezden
  • 83,883
  • 25
  • 248
  • 179
  • 6
    This should be the accepted answer. Notice how much simpler this is than the answer that involves t = type('test', (object,), {})(). – philologon Jul 22 '21 at 00:54
  • No, this should not be the accepted answer. Type hints are optional in Python. Knowing the type mechanism is optional knowledge. Many people would not understand the code. The word Single Namespace is not intuitive, at all. – habrewning May 07 '23 at 18:00
  • @habrewning, there is no type hints (typing) involved. Types is nothing to do with typing https://docs.python.org/3/library/types.html ```This module defines utility functions to assist in dynamic creation of new types.``` – Vlad Bezden May 08 '23 at 19:17
129

You can use type to create a new class on the fly and then instantiate it. Like so:

>>> t = type('test', (object,), {})()
>>> t
<__main__.test at 0xb615930c>

The arguments to type are: Class name, a tuple of base classes, and the object's dictionary. Which can contain functions (the object's methods) or attributes.

You can actually shorten the first line to

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

Because by default type creates new style classes that inherit from object.

type is used in Python for metaprogramming.

But if you just want to create an instance of object. Then, just create an instance of it. Like lejlot suggests.

Creating an instance of a new class like this has an important difference that may be useful.

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

Where as:

>>> b = type('', (), {})()
>>> b.this_works = 'cool'
>>> 
aychedee
  • 24,871
  • 8
  • 79
  • 83
70

One simple, less-terrifying-looking way to create an empty(-ish) object is to exploit the fact that functions are objects in Python, including Lambda Functions:

obj = lambda: None
obj.test = "Hello, world!"

For example:

In [18]: x = lambda: None

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

In [20]: x.test
Out[20]: 'Hello, world!'
Will
  • 24,082
  • 14
  • 97
  • 108
23

You said it in the question, but as no answer mentioned it with code, this is probably one of the cleanest solutions:

class Myobject:
    pass

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

Basj
  • 41,386
  • 99
  • 383
  • 673
12

What do you mean by "empty object"? Instance of class object? You can simply run

a = object()

or maybe you mean initialization to the null reference? Then you can use

a = None
lejlot
  • 64,777
  • 8
  • 131
  • 164
  • 28
    I wonder what the OP will be able to do with ``a`` defined either as ``object()`` or ``None`` because in such cases, ``a`` has no namespace ``__dict__`` and no attribute can be added to ``a`` like that for example ``a.x = 10``. – eyquem Jan 05 '14 at 23:20
  • 2
    Indeed, `a = object(); a.foo = 'bar'` gives `AttributeError: 'object' object has no attribute 'foo'`. – Basj Apr 07 '20 at 18:51
4

All the proposed solutions are somewhat awkward.

I found a way that is not hacky but is actually according to the original design.

>>> 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'

See the documentation of unittest.mock here.

qben
  • 813
  • 10
  • 22
4

You can use

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

Then

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

After

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

And

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

Constructs a new empty Set object. If the optional iterable parameter is supplied, updates the set with elements obtained from iteration. All of the elements in iterable should be immutable or be transformable to an immutable using the protocol described in section Protocol for automatic conversion to immutable.

Ex:

myobj = set()
for i in range(1,10): myobj.add(i)
print(myobj)
D z
  • 105
  • 1
  • 3
2

In my opinion, the easiest way is:

def x():pass
x.test = 'Hello, world!'
Rastersoft
  • 114
  • 1
  • 6
0

If there is a desired type of the empty object, in other words, you want to create it but don't call the __init__ initializer, you can use __new__:

class String(object):
    ...

uninitialized_empty_string = String.__new__(String)

Source: https://stackoverflow.com/a/2169191/6639500.

SerVB
  • 129
  • 17