Is it possible to create anonymous objects in Python?

PythonAnonymous Types

Python Problem Overview


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.

Python Solutions


Solution 1 - Python

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

Solution 2 - Python

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

Solution 3 - Python

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

EDIT: Well okay, 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 instance immediately:

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

Solution 4 - Python

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

print_foo(MiniMock(foo=3))

Solution 5 - Python

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

Solution 6 - Python

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.

Solution 7 - Python

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.

Solution 8 - Python

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.

Solution 9 - Python

I will use lambda

obj = lambda: None
obj.s = 'abb'
obj.i = 122

Solution 10 - Python

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

Solution 11 - Python

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'

Solution 12 - Python

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.

Solution 13 - Python

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionmikeView Question on Stackoverflow
Solution 1 - PythonNerdmasterView Answer on Stackoverflow
Solution 2 - PythonDzinXView Answer on Stackoverflow
Solution 3 - PythonDanny RaufeisenView Answer on Stackoverflow
Solution 4 - PythonTethaView Answer on Stackoverflow
Solution 5 - PythonHuachaoView Answer on Stackoverflow
Solution 6 - Pythonvlad-ardeleanView Answer on Stackoverflow
Solution 7 - PythonW. MarshallView Answer on Stackoverflow
Solution 8 - PythonwoodyView Answer on Stackoverflow
Solution 9 - PythonNam G VUView Answer on Stackoverflow
Solution 10 - PythonRabih KodeihView Answer on Stackoverflow
Solution 11 - PythonAsaf PinhassiView Answer on Stackoverflow
Solution 12 - PythonGlauco AquinoView Answer on Stackoverflow
Solution 13 - PythonJohn WhiteView Answer on Stackoverflow