Does Python have anonymous classes?

Python

Python Problem Overview


I'm wondering if Python has anything like the C# anonymous classes feature. To clarify, here's a sample C# snippet:

var foo = new { x = 1, y = 2 };
var bar = new { y = 2, x = 1 };
foo.Equals(bar); // "true"

In Python, I would imagine something like this:

foo = record(x = 1, y = 2)
bar = record(y = 2, x = 1)
foo == bar  # true

The specific requirement is being able to create an object with specified fields in expression context (e.g. usable in lambdas and other places where statements aren't allowed), with no additional external declarations, and ability to access individual components by name via the normal member access syntax foo.bar. The created object should also implement structural comparison by component names (not by position, as tuples do).

In particular: tuples isn't it because their components are not named; classes isn't it because they require a declaration; dicts isn't it because they have undesired foo["bar"] syntax to access components.

namedtuple isn't it, because it still requires a name even if you define the type inline, and the comparison is position-based, not name-based. In particular:

 def foo(): return namedtuple("Foo", "x y")(x = 1, y = 2)
 def bar(): return namedtuple("Foo", "y x")(x = 1, y = 2)
 foo() == bar()   # False because fields are compared in order, and not by name
                  # True would be desired instead

I know how to write such a thing in Python if needed. But I would like to know if there's anything like that in the Python standard library, or any popular third-party libraries.

[EDIT]

Just for the sake of it, here's a single-expression solution that combines two very informative answers by Ken and alanlcode, yielding structural equality without any extra outside declarations:

type("", (), { \
    "__init__": (lambda self, **kwargs: self.__dict__.update(kwargs)), \
    "__eq__": (lambda self, other: self.__dict__ == other.__dict__) } \
)(x = 1, y = 2)

Technically, it satisfies all the requirements of the question, but I sincerely hope that no-one ever uses it (I definitely won't).

Python Solutions


Solution 1 - Python

Looks like Python 3.3 has added exactly this thing in the form of types.SimpleNamespace class.

Solution 2 - Python

The pythonic way would be to use a dict:

>>> foo = dict(x=1, y=2)
>>> bar = dict(y=2, x=1)
>>> foo == bar
True

Meets all your requirements except that you still have to do foo['x'] instead of foo.x.

If that's a problem, you could easily define a class such as:

class Bunch(object):
    def __init__(self, **kwds):
        self.__dict__.update(kwds)

    def __eq__(self, other):
        return self.__dict__ == other.__dict__

Or, a nice and short one

class Bunch(dict):
    __getattr__, __setattr__ = dict.get, dict.__setitem__

(but note that this second one has problems as Alex points out in his comment!)

Solution 3 - Python

  1. See <http://uszla.me.uk/space/blog/2008/11/06>;. You can create an anonymous object with slightly ugly syntax by using the type built-in function:

    anon_object_2 = type("", (), {})()

where the 3rd parameter is the dict that will contain the fields of your object.

 foo = type("", (), dict(y=1))()
 foo.y == 1

2) Another variation is proposed by Peter Norvig at <http://norvig.com/python-iaq.html>;. It is also similar to the answer posted by Ken.

class Struct:
    def __init__(self, **entries): self.__dict__.update(entries)

>>> options = Struct(answer=42, linelen = 80, font='courier')
>>> options.answer
42

The benefit of this method is that you can implement equality by contents of the dict, which the first option doesn't have.

Solution 4 - Python

I don't remember offhand if there's a built-in but writing it yourself is shorter than typing your question. :-)

class record(object):
  def __init__(self, **kwargs): self.__dict__ = kwargs
  def __eq__(self, r2): return self.__dict__ == r2.__dict__
  def __ne__(self, r2): return self.__dict__ != r2.__dict__

foo = record(x=1, y=2)
bar = record(y=2, x=1)
foo == bar  # => true

Solution 5 - Python

The type(...) form will fail the structural comparison requirement (without getting really ugly). The dict(...) form doesn't meet the attribute accessor requirement.

The attrdict seems to fall in the middle somewhere:

class attrdict(dict):
    def __init__(self, *args, **kwargs):
        dict.__init__(self, *args, **kwargs)
        self.__dict__ = self

a = attrdict(x=1, y=2)
b = attrdict(y=2, x=1)

print a.x, a.y
print b.x, b.y
print a == b

But it means defining a special class.

OK, I just noticed the update to the question. I'll just note that you can specify dict for the bases parameter and only need to specify the constructor then (in the icky type expression). I prefer attrdict. :-)

Solution 6 - Python

Quoted from this page:

 class Struct:
     def __init__(self, **entries): self.__dict__.update(entries)
     def __eq__(self, other): return self.__dict__ == other.__dict__
     def __ne__(self, other): return self.__dict__ != other.__dict__
 
 options = Struct(answer=42, linelen = 80, font='courier')
 options.answer
 >>> 42
 options.answer = 'plastics'
 vars(options)
 >>> {'answer': 'plastics', 'font': 'courier', 'linelen': 80}

Solution 7 - Python

If you want the instance to be anonymous as well (using the object directly in an expression), then you're bound to use the type-expression. However in many cases the instance will not be anonymous, but assigned to a variable. This case can be handled in a reasonable way in python by using metaclasses or decorators.

An example using decorator:

def anonymous(cls):
    return cls()

@anonymous
class foo:
     x = 42
     
     def bar(self):
          return self.x

The decorator in this case causes the class foo to be instantiated an put into the variable foo instead of the class itself. The class itself will not be accessible from any namespace although it has a name:

>>> foo
<__main__.foo instance at 0x7fd2938d8320>
>>> foo.bar()
42

Another feature in python that accomodates for many use cases is that it's legal to define classes locally, which means that they would become a symbol local to that function, which in turns gives it some degree of anonymity.

Solution 8 - Python

enter image description here

As show above, I get a good intellisense from pycharm for this and I love this solution...

>>> def anonymous(cls):
...     return cls()
>>> class fooo:
...     @anonymous
...     class c:
...             D=10
>>> fooo.c.D
10

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
QuestionPavel MinaevView Question on Stackoverflow
Solution 1 - PythonPavel MinaevView Answer on Stackoverflow
Solution 2 - PythondF.View Answer on Stackoverflow
Solution 3 - PythonalanlcodeView Answer on Stackoverflow
Solution 4 - PythonKenView Answer on Stackoverflow
Solution 5 - PythonarsView Answer on Stackoverflow
Solution 6 - Pythonuser136565View Answer on Stackoverflow
Solution 7 - PythonskykingView Answer on Stackoverflow
Solution 8 - PythonTooGeekyView Answer on Stackoverflow