84

In Javascript it would be:

var newObject = { 'propertyName' : 'propertyValue' };
newObject.propertyName;  // returns "propertyValue"

But the same syntax in Python would create a dictionary, and that's not what I want

new_object = {'propertyName': 'propertyValue'}
new_object.propertyName  # raises an AttributeError
martineau
  • 119,623
  • 25
  • 170
  • 301
Jader Dias
  • 88,211
  • 155
  • 421
  • 625

9 Answers9

125
obj = type('obj', (object,), {'propertyName' : 'propertyValue'})

there are two kinds of type function uses.

SilentGhost
  • 307,395
  • 66
  • 306
  • 293
  • +1 - Very interesting! I wasn't familiar with that use of the type function - could you please link me to some documentation on that? – Smashery Oct 07 '09 at 01:10
  • oopsm Chris was faster, but I've added link to answer anyway – SilentGhost Oct 07 '09 at 01:14
  • 5
    how is this obfuscatory? it's a proper documented behaviour. – SilentGhost Oct 07 '09 at 01:16
  • 19
    Documented but obscure behavior. I'm pretty sure 99.9% of Python programmers' initial reaction to seeing this in real code would be "WTF!?". – Laurence Gonsalves Oct 07 '09 at 01:22
  • 19
    Actually, @Laurence, my reaction was, "Woah, I bet that creates a new instance of a made up `'obj'` class that inherits from the `object` with a `'propertyName'` member set to `'propertyValue'` ." And what do you know? I was right! I don't think it's too unintuitive. – Chris Lutz Oct 07 '09 at 01:27
  • 4
    It is flexible, terse and yet readable code like this that makes me choose python. – Tom Leys Oct 07 '09 at 01:32
  • 1
    Chris: You admit that you didn't know what the code did. You were only able to guess correctly given the fact that you knew it was supposed to do what the question was asking for. You wouldn't have had that context in real code. – Laurence Gonsalves Oct 07 '09 at 01:37
  • 29
    For completeness, to create an actual *instance* of the type instead of just a type object, this needs a trailing `()`: `obj = type('obj', (object,), {'propertyName' : 'propertyValue'})()` – Greg Hewgill Oct 07 '09 at 01:41
  • @Laurence - I guessed because I didn't know what else it could reasonably do. Context may help, but this statement will probably never be used without context. – Chris Lutz Oct 07 '09 at 01:52
  • 1
    In my opinion, this is an example of code that "accidentally" does something, without in any way **meaning** what it's being used for, and definitely without addressing the design that the OP seems to be struggling with. That's why I downvoted it. I don't think solutions like that should be rewarded or imitated. I cheerfully accept and acknowledge that I'm in the minority! – Jonathan Feinberg Oct 07 '09 at 02:21
  • 2
    It's interesting that this "readable" code has been upvoted so much despite the bug that Greg Hewgill points out. – Laurence Gonsalves Oct 07 '09 at 02:41
  • 1
    @Laurence: there's no *bug*, it works perfectly fine w/o instantiation. I personally don't see why would you want to instantiate this object at all, but of course Python is not preventing you from doing so. – SilentGhost Oct 07 '09 at 10:05
  • 1
    To the contrary, my initial reaction was WTF. Especially at the comma after 'object' – Lo-Tan May 08 '12 at 19:42
  • This gives me an error: TypeError: type() argument 2 must be tuple, not type – zakdances Mar 09 '13 at 15:03
  • for python 3.3+, have a look at Sylvain Leroux [answer](http://stackoverflow.com/questions/1528932/how-to-create-inline-objects-with-properties-in-python#answer-27931360) below – Rupert Angermeier Jul 28 '16 at 08:00
  • The best reason to chose this over the lambda trick is that when I typed the lambda line I was compelled to explain what it was with a code comment. When I use this answer I don't need that comment. That should prove this is the better choice. However, a couple keyword args may help people unfamiliar with the signature: `type('obj', bases=(object,), dict={})` (the first arg name is actually "what" in python 2.6, so omitted to avoid confusion. – Rafe Mar 14 '17 at 16:59
  • Ignore my comment about keyword args. Tested and this won't take keyword arguments #unhappydevface (couldn't edit my last comment to correct it, sorry) – Rafe Mar 14 '17 at 17:09
  • 1
    Since attributes are mostly valid identifiers `obj = type('obj', (object,), dict(propertyName='propertyValue'))` Just in case if you want you avoid those curly braces – ramki Aug 28 '19 at 08:39
  • 2
    In Python 3, you don't need to inherit from `object`, you can just do `obj = type('obj', (), {'property_name' : 'property_value'})` – Boris Verkhovskiy Apr 16 '20 at 14:34
  • @GregHewgill I like completeness. – Moe May 30 '20 at 01:25
70

Python 3.3 added the SimpleNamespace class for that exact purpose:

>>> from types import SimpleNamespace

>>> obj = SimpleNamespace(propertyName='propertyValue')
>>> obj
namespace(propertyName='propertyValue')

>>> obj.propertyName
'propertyValue'

In addition to the appropriate constructor to build the object, SimpleNamespace defines __repr__ and __eq__ (documented in 3.4) to behave as expected.

Boris Verkhovskiy
  • 14,854
  • 11
  • 100
  • 103
Sylvain Leroux
  • 50,096
  • 7
  • 103
  • 125
38

Peter's answer

obj = lambda: None
obj.propertyName = 'propertyValue'
Jader Dias
  • 88,211
  • 155
  • 421
  • 625
14

I don't know if there's a built-in way to do it, but you can always define a class like this:

class InlineClass(object):
    def __init__(self, dict):
        self.__dict__ = dict

obj = InlineClass({'propertyName' : 'propertyValue'})
heemayl
  • 39,294
  • 7
  • 70
  • 76
Smashery
  • 57,848
  • 30
  • 97
  • 128
7

I like Smashery's idea, but Python seems content to let you modify classes on your own:

>>> class Inline(object):
...     pass
...
>>> obj = Inline()
>>> obj.test = 1
>>> obj.test
1
>>>

Works just fine in Python 2.5 for me. Note that you do have to do this to a class derived from object - it won't work if you change the line to obj = object.

Community
  • 1
  • 1
Chris Lutz
  • 73,191
  • 16
  • 130
  • 183
  • 2
    Yep, you can do that - but for some strange reason, you just can't use object() - you have to create your own class. – Smashery Oct 07 '09 at 01:02
  • 6
    if you want an inline class, you can use `obj = lambda: None`, which is bizarre, but will perform the necessary tasks... – Peter Oct 07 '09 at 01:04
  • @Peter - I didn't know that. However, now that I see it, I like SilentGhost's answer much better. – Chris Lutz Oct 07 '09 at 01:08
  • I removed the constructor to show the shortest way to achieve it – Jader Dias Oct 07 '09 at 01:18
  • @Jader - Fair enough. It looks better without it. – Chris Lutz Oct 07 '09 at 01:21
  • @Smashery: the "strange reason" is that type `object` is the root of the object inheritance tree, and if it had an associated dict to hold properties, all objects in Python would have to have an associated dict. I do actually wish there was a standard type that just made an empty container class, but it's pretty darn easy to just declare your own. – steveha Oct 07 '09 at 06:31
4

It is easy in Python to declare a class with an __init__() function that can set up the instance for you, with optional arguments. If you don't specify the arguments you get a blank instance, and if you specify some or all of the arguments you initialize the instance.

I explained it here (my highest-rated answer to date) so I won't retype the explanation. But, if you have questions, ask and I'll answer.

If you just want a generic object whose class doesn't really matter, you can do this:

class Generic(object):
    pass

x = Generic()
x.foo = 1
x.bar = 2
x.baz = 3

An obvious extension would be to add an __str__() function that prints something useful.

This trick is nice sometimes when you want a more-convenient dictionary. I find it easier to type x.foo than x["foo"].

Community
  • 1
  • 1
steveha
  • 74,789
  • 21
  • 92
  • 117
4

SilentGhost had a good answer, but his code actually creates a new object of metaclass type, in other words it creates a class. And classes are objects in Python!

obj = type('obj', (object,), {'propertyName' : 'propertyValue'})
type(obj) 

gives

<class 'type'>

To create a new object of a custom or build-in class with dict attributes (aka properties) in one line I'd suggest to just call it:

new_object = type('Foo', (object,), {'name': 'new object'})()

and now

type(new_object) 

is

<class '__main__.Foo'>

which means it's an object of class Foo

I hope it helps those who are new to Python.

Leo Skhrnkv
  • 1,513
  • 16
  • 27
2

Another viable option is to use namedtuple:

from collections import namedtuple

message = namedtuple('Message', ['propertyName'], verbose=True)
messages = [
    message('propertyValueOne'),
    message('propertyValueTwo')
]
b.b3rn4rd
  • 8,494
  • 2
  • 45
  • 57
-1
class test:
    def __setattr__(self,key,value):
        return value


myObj = test()
myObj.mykey = 'abc' # set your property and value
user149513
  • 1,732
  • 2
  • 11
  • 11