82

I'm debugging some Python that takes, as input, a list of objects, each with some attributes.

I'd like to hard-code some test values -- let's say, a list of four objects whose "foo" attribute is set to some number.

Is there a more concise way than this?

x1.foo = 1
x2.foo = 2
x3.foo = 3
x4.foo = 4
myfunc([x1, x2, x3, x4])

Ideally, I'd just like to be able to say something like:

myfunc([<foo=1>, <foo=2>, <foo=3>, <foo=4>])

(Obviously, that is made-up syntax. But is there something similar that really works?)

Note: This will never be checked in. It's just some throwaway debug code. So don't worry about readability or maintainability.

Rabih Kodeih
  • 9,361
  • 11
  • 47
  • 55
mike
  • 46,876
  • 44
  • 102
  • 112

14 Answers14

80

I found this: http://www.hydrogen18.com/blog/python-anonymous-objects.html, and in my limited testing it seems like it works:

>>> obj = type('',(object,),{"foo": 1})()
>>> obj.foo
1
Nerdmaster
  • 4,287
  • 1
  • 22
  • 16
  • 1
    Brilliant! And is true one-liner! – Bostone Feb 27 '19 at 21:17
  • 1
    Love it. This also works with other classes and initializing, for example here’s an anonymous object derived from Python’s dictionary and initialized with two entries: `type("", (dict,), {})({"a": 1, "b": 2})` – Jens Apr 30 '20 at 05:01
  • using mock object it's even simpler, see https://stackoverflow.com/a/75360777/1161025 – maciek Feb 06 '23 at 11:40
57

I like Tetha's solution, but it's unnecessarily complex.

Here's something simpler:

>>> class MicroMock(object):
...     def __init__(self, **kwargs):
...         self.__dict__.update(kwargs)
...
>>> def print_foo(x):
...     print x.foo
...
>>> print_foo(MicroMock(foo=3))
3
theonlygusti
  • 11,032
  • 11
  • 64
  • 119
Dzinx
  • 55,586
  • 10
  • 60
  • 78
  • However, if you're creating a whole bunch of these, you might save some time/memory by using the given dictionary instead of creating a new one and copying all the entries. Doesn't *really* matter, though. – Josh Lee Mar 16 '09 at 22:56
  • 3
    well, I might be subjective, but I see no substantial simplification. Yes, you use __init__ and update, but youre still fiddling around with __dict__. – Tetha Mar 17 '09 at 08:35
  • 1
    You're right, there's no significant simplification. It's just shorter and doesn't use __new__, that's all. – Dzinx Mar 17 '09 at 16:16
  • If you want convenient syntax, `_` is a valid class name in python, and isn't really any more indecipherable than the version posited in the question. – RoadieRich Jul 17 '13 at 12:52
  • 2
    With recent Python feature, you can use "def mock(**kwargs): return type('',(),kwargs)()", and do "a = mock(foo=1)" – Taisuke Yamada Aug 18 '14 at 10:19
  • Since Python 3.3 (2012) you can just use Mock class from the standard library (unittest.mock.Mock) instead of a custom class https://stackoverflow.com/a/75360777/1161025 – maciek Feb 09 '23 at 09:56
41

Wow, so brief, such Python! O.o

>>> Object = lambda **kwargs: type("Object", (), kwargs)

Then you can use Object as a generic object constructor:

>>> person = Object(name = "Bernhard", gender = "male", age = 42)
>>> person.name
'Bernhard'
>>>

Now technically this creates a class object, not an object object. But you can treat it like an anonymous object or you modify the first line by appending a pair of parenthesis to create an immediate instance:

>>> Object = lambda **kwargs: type("Object", (), kwargs)()
Danny Raufeisen
  • 953
  • 8
  • 21
16

Maybe you can use namedtuple to solve this as following:

from collections import namedtuple
Mock = namedtuple('Mock', ['foo'])

mock = Mock(foo=1)
mock.foo  // 1
Huachao
  • 300
  • 3
  • 10
16

Have a look at this:


class MiniMock(object):
    def __new__(cls, **attrs):
        result = object.__new__(cls)
        result.__dict__ = attrs
        return result

def print_foo(x):
    print x.foo

print_foo(MiniMock(foo=3))
Tetha
  • 4,826
  • 1
  • 16
  • 17
10

I will use lambda

obj = lambda: None
obj.s = 'abb'
obj.i = 122
Nam G VU
  • 33,193
  • 69
  • 233
  • 372
  • 1
    What is the difference with `obj = {}`? – Anders Lindén Sep 17 '21 at 09:08
  • 2
    @AndersLindén You'll get AttributeError with `{}`, one cannot set attributes on a `dict`. – maciek Feb 06 '23 at 10:56
  • 1
    aaaand we have a real answer. +million.. I'm done using a dict as a container for relatively simple objects that I don't want to create a class for. One minor inconvenience: if you need to JSON serialize this, you need to use obj.__dict__ That's an inconvenience I'm willing to live with. – horace May 13 '23 at 14:26
8

Another obvious hack:

class foo1: x=3; y='y'
class foo2: y=5; x=6

print(foo1.x, foo2.y)

But for your exact usecase, calling a function with anonymous objects directly, I don't know any one-liner less verbose than

myfunc(type('', (object,), {'foo': 3},), type('', (object,), {'foo': 4}))

Ugly, does the job, but not really.

vlad-ardelean
  • 7,480
  • 15
  • 80
  • 124
8

As of Python 3.3, there's types.SimpleNamespace that does exactly what you want:

myfunc([types.SimpleNamespace(foo=1), types.SimpleNamespace(foo=2), types.SimpleNamespace(foo=3), types.SimpleNamespace(foo=4)])

That's a tad wordy, but you can clean it up with an alias:

_ = types.SimpleNamespace
myfunc([_(foo=1), _(foo=2), _(foo=3), _(foo=4)])

And now that's actually pretty close to the fictional syntax in your question.

W. Marshall
  • 120
  • 1
  • 7
  • Credit to @RoadieRich for suggesting `_` as the class name in an earlier comment. – W. Marshall Jul 18 '17 at 22:37
  • 4
    If using _ bothers you (it feels a bit icky and unpythonic to me), and you really don't want to type so much, you can also just `from types import SimpleNamespace as Nsp` and use Nsp like _ in your answer. – JJC Aug 23 '18 at 19:18
  • @JJC of course! The coding standards I currently work under don't allow renaming on import like that, so I tend to forget that's even an option. – W. Marshall Oct 11 '18 at 16:31
8
anonymous_object = type('',(),{'name':'woody', 'age':'25'})()
anonymous_object.name
> 'woody'

There is a cool way but hard to understand. It use type() create a no-named class with default init params, then init it without any param and get the anonymous object.

woody
  • 422
  • 1
  • 4
  • 12
  • 1
    Python should support anonymous types. They are very handy in C#. This is the cleanest solution out of all the answers. – michael Feb 16 '20 at 01:57
  • @michael Yes, it's one of C# 's cool features. C# has a really nice syntax design. – woody May 06 '20 at 08:29
3

Non classy:

def mock(**attrs):
    r = lambda:0
    r.__dict__ = attrs
    return r 

def test(a, b, c, d):
    print a.foo, b.foo, c.foo, d.foo

test(*[mock(foo=i) for i in xrange(1,5)])
# or
test(mock(foo=1), mock(foo=2), mock(foo=3), mock(foo=4))
Rabih Kodeih
  • 9,361
  • 11
  • 47
  • 55
1
>>> from unittest.mock import Mock
>>> obj = Mock(foo=1)
>>> obj.foo
1

I was surprised to not find this in the answers already.

myfunc([Mock(foo=1), Mock(foo=2), Mock(foo=3), Mock(foo=4)])

I think it and SimpleNamespace are the most straight-forward and "canonical" ways to create a dummy/anonymous object in Python. They work since Python 3.3 (2012). I would base the choice of one of them depending on the context of usage.

maciek
  • 3,198
  • 2
  • 26
  • 33
-1

This is how I did it:

from mock import patch
import requests

class MockResponse:

    def __init__(self, text, status_code):
        self.text = text
        self.status_code = status_code


class TestSomething(unittest.TestCase):

    @patch('requests.get',return_value=MockResponse('the result',200))
    def test_some_request(self, *args, **kwargs):
        response = requests.get('some.url.com')
        assert response.text=='the result'
        assert response.status_code=='200'
Asaf Pinhassi
  • 15,177
  • 12
  • 106
  • 130
-1

If you are using Python 3.7 or above, you can use named tuples to enhance the created object with immutability, docstring, and handy tuple methods:

from collections import namedtuple

PyObj = lambda **kwargs: namedtuple('PyObj', kwargs.keys())._make(kwargs.values())

o = PyObj(foo = 1)
print(o)
# prints: PyObj(foo=1)
o.foo
# returns: 1
o.foo = 0
# exception:
# Traceback (most recent call last):
#   File "<stdin>", line 1, in <module>
# AttributeError: can't set attribute

print(PyObj(foo = 1, bar = 'baz'))
# prints: PyObj(foo=1, bar='baz')

Python 3.7+ is required to ensure keys and values are in the same order.

However, if the list of attributes is predefined, you can use namedtuple directly, as Huachao suggested, there's no need to define the PyObj function and you can use it in v2.7.

from collections import namedtuple
foo = namedtuple('Foo', 'foo')

myfunc = lambda l: [x.foo * 10 for x in l]
myfunc([foo(1), foo(2), foo(3), foo(4)])
# returns [10, 20, 30, 40]

Plus, it looks more like the syntax you are looking for.

-2

Yes, I very much missed the straightforward anonymous objects in JavaScript, particularly in function return values, where you can just say

function george() { 
    return {fred:6, jim:9}; 
}
x = george();
y = x.fred;

You can use a dictionary to get the same effect, but all those square brackets and single quotes look muddly. So I now do the following, which works:

def fred():
    class rv:
        x=0
    rv.y = 6
    return rv

def jim():
    class rv:
        x=0
    rv.y = 9
    return rv
a = fred()
b = jim()
print(a.y, b.y, id(a.y), id(b.y))

It would feel nicer to have a global class RV, and instantiate it to get the same effect, but this way the function has no external dependencies.

John White
  • 131
  • 1
  • 3
  • 19