19

I wanted to create a throwaway "struct" object to keep various status flags. My first approach was this (javascript style)

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

Definitely not what I expected, because this works:

>>> class Anon: pass
... 
>>> b=Anon()
>>> b.foo = 4

I guess this is because object() does not have a __dict__. I don't want to use a dictionary, and assuming I don't want to create the Anon object, is there another solution ?

Stefano Borini
  • 138,652
  • 96
  • 297
  • 431
  • 3
    See http://stackoverflow.com/questions/1264833/python-class-factory-to-produce-simple-struct-like-classes – Crescent Fresh Dec 10 '09 at 05:03
  • I'm using python 2.5, and in any case, the named tuple does not allow, as far as I understand, to plug new members dynamically later on. It's not clear from the examples given. – Stefano Borini Dec 10 '09 at 05:14
  • @Stefano Borini: so you're basically asking for a dict where you can say `foo.bar` instead of `foo['bar']`? – Crescent Fresh Dec 10 '09 at 05:20
  • 1
    If you don't want to use a dictionary and you don't want to predeclare the fields, how do you want to store the data? The only other common structure I can think of is an alist which would give you O(n) lookup, but I can't see that being an advantage in this case. (Do note that small dictionaries in Python are rather efficiently stored already.) – Nicholas Riley Dec 10 '09 at 05:25
  • @Stefano Borini: then here you go: http://stackoverflow.com/questions/1325673/python-how-to-add-property-to-a-class-dynamically/1328686#1328686 ;) – Crescent Fresh Dec 10 '09 at 05:41
  • You said it yourself "I want to create a struct object" Go and create it! My comment below explains further. – Escualo Dec 10 '09 at 06:06
  • Does this answer your question? [C-like structures in Python](https://stackoverflow.com/questions/35988/c-like-structures-in-python) – Bergi Feb 27 '20 at 20:48

8 Answers8

32

The most concise way to make "a generic object to which you can assign/fetch attributes" is probably:

b = lambda:0

As most other answers point out, there are many other ways, but it's hard to beat this one for conciseness (lambda:0 is exactly the same number of characters as object()...;-).

Alex Martelli
  • 854,459
  • 170
  • 1,222
  • 1,395
  • 32
    Only if you don't count the characters explaining what the heck it's for! :D – John La Rooy Dec 10 '09 at 05:36
  • 2
    @Stefano, thanks! @gnibbler, lambda's sufficiently mystical that you don't have to explain, you just make mysterious finger gestures in the air and everybody backs off in fear (optionally, darkly murmur "lambda, the Ultimate...!", http://lambda-the-ultimate.org/, and/or see http://en.wikipedia.org/wiki/Lambda for many other obscure references). – Alex Martelli Dec 10 '09 at 05:59
  • 2
    Uh-oh ... the martellibot has been subverted and gone over to the dark side :-( – John Machin Dec 10 '09 at 13:20
  • 6
    At first, this boggled my mind. But it's actually simple. The `lambda` creates a function object; this one happens to be a trivial function that returns 0. Function objects have certain attributes, among them a `func_dict` member. This works because it works for any function object; you can bind values to names associated with any function object. I have used that to provide "enumerated" flags that can be used when calling the function: `foo(0, foo.ALTERNATE_MODE)` This made-up example shows calling a function with an optional flag that requests some sort of alternate mode. – steveha Dec 31 '09 at 22:09
  • 1
    @steveha: +1 - Named constants for function call: excellent use for function attributes. – Don O'Donnell Jan 01 '10 at 01:11
  • Can someone explain a bit more the `foo(0, foo.ALTERNATE_MODE)` call? Also for use just as a C struct, how does the `lambda :0` approach compare to `namedtuple`? – max Jan 29 '11 at 09:30
  • Additional explanation of the foo thing: First, you define a function just like you always do, using `def foo(x, mode=0):` or whatever. Once the function definition is complete, the next line of code looks like this: `foo.DEFAULT_MODE = 0`, then `foo.ALTERNATE_MODE = 1`, then any other mode constants. Since any function object has a `func_dict` that can store stuff, we can put constants in there. For my example I set the constant to ints but the values could be anything. Now you have a function that is callable, and any special flags for the function are tucked into the object itself. – steveha Mar 10 '11 at 21:50
  • @steveha: Thanks. @Alex Martelli: the only problem with this approach is that it results in an unpicklable object. Might become an issue with `multiprocessing`. – max May 16 '11 at 22:42
20

From the Python Official Documentation:

9.7. Odds and Ends

Sometimes it is useful to have a data type similar to the Pascal “record” or C “struct”, bundling together a few named data items. An empty class definition will do nicely:

class Employee:
    pass

john = Employee() # Create an empty employee record

# Fill the fields of the record 
john.name = 'John Doe' 
john.dept = 'computer lab' 
john.salary = 1000

This seems natural and simple: Pythonic. Remember the Zen! "Simple is better than complex" (number 3) and "If the implementation is easy to explain, it may be a good idea" (number 11)

In addition, a struct is nothing but a class with public members (i.e., struct{}; and class{public:}; are the exact same thing (in, say, C++)). Shouldn't you consider this and avoid artificial constructs in your Python program? Python is supposed to be readable, maintainable, and easy to understand.

Escualo
  • 40,844
  • 23
  • 87
  • 135
  • 3
    Ugh, this is old documentation and they should clean it up. This example code creates an "old-style class". This is not recommended practice anymore, and in Python 3.x it will not even work. To do this exact example as a new-style class that will work in Python 3.x: `class Employee(object): pass` That's all you have to do, just inherit from `object` and you have a new-style class. – steveha Dec 10 '09 at 05:28
  • 1
    This is exactly like the Anon example the OP said they don't want to do. – John La Rooy Dec 10 '09 at 05:33
  • Yes, that's good. It was more annoyed by the fact you have to define class Status: pass and then status = Status(). – Stefano Borini Dec 10 '09 at 05:33
  • @gnibbler: but it works better than any alternative presented so far. I just pointed out that in the language design, it was considered that this was the best way to make "struct-like" instances. – Escualo Dec 10 '09 at 05:49
  • @steveha: what is an "old-style class"? – Escualo Dec 10 '09 at 05:51
  • @steveha: At least with Python 3.1.1, the example still works. – nd. Dec 10 '09 at 10:43
  • 2
    @nd and @steveha You shouldn't need to explicitly inherit from object in Python 3. In Python 3, inheriting from object is the default. There are no old-style classes. – AFoglia Dec 10 '09 at 15:09
  • @Arrieta A few versions ago, Python introduced a new class implementation. It does everything the old one did, and more (such as allowing derivation from the standard list and dictionary types, and features such as a real constructor and properties). For backwards compatibility, you had to explicitly derive from `object`. Since Python 3 is not backwards compatible, the derivation is unnecessary. – AFoglia Dec 10 '09 at 15:12
  • As others have noted above, I was mistaken about this syntax no longer working in Python 3.x. In Python 2.x it makes an "old-style class"; in Python 3.x there are no "old-style" vs. "new-style" classes, they are all the new style. If you do this syntax you get the exact same result as if you had explicitly inherited from `object`, but without having to type the characters `(object)` in your class definition. – steveha Mar 11 '11 at 00:05
  • @Steveha Does the answer then still provide an acceptable (and modern) pythonic way of building generic "struct objects"? – Amelio Vazquez-Reina Nov 02 '12 at 18:50
  • 3
    @user273158, the answer is as good as it ever was. I was completely mistaken that this syntax is forbidden in Python 3.x; instead, in Python 3.x, this syntax is exactly equivalent to saying that the new class inherits from `object`. If I could edit my comment to correct it, I would do so. I thought about deleting it but since other comments refer back to it, I think that would be confusing. – steveha Nov 02 '12 at 22:13
10

I had the same question once. I asked it in a mailing list, and Alex Martelli pointed out that object is the basis of all inheritance in Python; if object() created a class instance with its own dictionary, then every object in Python would have to have its own dictionary, and that would waste memory. For example, True and False are objects; clearly they don't have any need for their own dictionaries!

I would be happy if there was some sort of built-in Python feature where I could just say:

x = struct()
x.foo = 1
x.bar = 2

But it is trivial to write struct():

class struct(object):
    pass

Or you could do a slightly more complex one:

class struct(object):
    def __init__(self, **kwargs):
        self.__dict__.update(kwargs)

The more complex one lets you do this:

x = struct(foo=1, bar=2)
print(x.foo) # prints 1
print(x.bar) # prints 2
x.baz = 3
print(x.baz) # prints 3

But it is so trivial to write struct() that I guess it wasn't deemed worth adding to the language. Maybe we should push to have a standard feature added to collections module or something.

steveha
  • 74,789
  • 21
  • 92
  • 117
  • 2
    To encourage pythonic thinking and readable code, you might capitalize `struct`. `Struct` is more clearly a `class` and not a builtin or function. But I can appreciate your thought that you're creating a new personal "builtin" very similar to the builtin `object` class. And lowercase `struct` just looks simpler. – hobs Jan 28 '15 at 21:40
  • Actually, I usually call this trivial class `Box()` when I write it in my programs. Here I was proposing a builtin, and the Python builtins are lowercase (like `deque`) except when they aren't (like `Counter`). I do prefer to capitalize class names, but I guess I won't edit the answer. – steveha Jan 29 '15 at 19:28
  • 1
    @steveha The casing of Python built-ins denotes which language they are implemented in. If they are implemented in C, they are all lowercase, but if they are implemented in Python they are ClassCased. See this answer ( http://stackoverflow.com/a/14974045/1490091 ) for more details. – Pedro Cattori Jan 26 '17 at 04:56
5

I personally think that the cleanest solution is what you already guessed:

class Scratch(object):
    pass

s = Scratch()
s.whatever = 'you want'

I know you said that you don't want a __dict__, but that confuses me as I can't see a reason to care about that. You don't have to reference __dict__, that is an internal Python implementation detail. Anyway, any instance in Python that allows dynamically adding attributes will have a __dict__ because that's how Python does dynamic attributes. Even if the instance is created in a really clever way, it will have a __dict__.

If you have not already done so, I recommend reading PEP 20 and PEP 8. Not that the PEPs directly relate to your question, but I think it's useful in starting to use Python in a Pythonic manner.

Tony Adams
  • 691
  • 1
  • 9
  • 29
Mark Evans
  • 531
  • 4
  • 6
4

Try this

>>> status=type('status',(object,),{})()
>>> status.foo=3
>>> status.foo
3

You don't have to give the class a name if you don't want to

>>> status=type('',(object,),{})()
>>> status.__class__.__name__
''
John La Rooy
  • 295,403
  • 53
  • 369
  • 502
4

Of course there's always a namedtuple. It's cheap and fast, but immutable -- you must know your attribute names and values in advance, and you can't alter their values later. But at least it has the struct/object attribute getters. And it'll work with Python 2 and 3

>>> from collections import namedtuple
>>> Status = namedtuple('Status', 'a b')
>>> s = Status(a=1, b=2)
>>> s.a + s.b
3
Community
  • 1
  • 1
hobs
  • 18,473
  • 10
  • 83
  • 106
3

The mystery here is the difference between objects and class instances.

In Python, everything is an object. Classes are objects, integers are objects, types are objects, and class instances are objects. When you say object() you're getting a plain base-level object. It's nothing. Completely useless. Lower level than anything else you can reference in Python.

You probably thought calling object() gives you a class instance. Which is understandable, because you probably thought object is a class. It's not. Even though you might think so since it's the base "class" used for new-style class definitions like:

class MyClass(object):
    pass

object is in fact a type (like how str and int are types). When you call object() you're not constructing a class instance, your instantiating a special type of object. But in object's case, it's special in how completely blah it is.

Only class instances have the special ability to tack things on with dot notation. That's not a general property of all objects. Imagine if that were the case! You could do crazy stuff like adding properties to strings:

s = "cat"
s.language = "english"

Obviously you can't do that.

jpsimons
  • 27,382
  • 3
  • 35
  • 45
1

If you want the semantics of a Javascript object, you could consider using the namespaces library. You just need to pip install namespaces first.

>>> import namespaces as ns
>>> b = ns.Namespace()
>>> b.foo = 4
>>> b
Namespace(foo=4)

full disclaimer: I am the author of the namespaces library.

Pedro Cattori
  • 2,735
  • 1
  • 25
  • 43