How to create inline objects with properties?
Asked Answered
D

9

85

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
Dimpledimwit answered 7/10, 2009 at 0:43 Comment(1)
Possible duplicate: How can I create an object and add attributes to it?Bonspiel
B
128
obj = type('obj', (object,), {'propertyName' : 'propertyValue'})

there are two kinds of type function uses.

Busyness answered 7/10, 2009 at 1:4 Comment(16)
Documented but obscure behavior. I'm pretty sure 99.9% of Python programmers' initial reaction to seeing this in real code would be "WTF!?".Changeable
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.Larrup
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.Changeable
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'})()Kamasutra
@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.Larrup
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!Kristelkristen
It's interesting that this "readable" code has been upvoted so much despite the bug that Greg Hewgill points out.Changeable
@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.Busyness
To the contrary, my initial reaction was WTF. Especially at the comma after 'object'Kempf
This gives me an error: TypeError: type() argument 2 must be tuple, not typeCasiano
for python 3.3+, have a look at Sylvain Leroux answer belowMosesmosey
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.Ptolemaist
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)Ptolemaist
Since attributes are mostly valid identifiers obj = type('obj', (object,), dict(propertyName='propertyValue')) Just in case if you want you avoid those curly bracesCoed
In Python 3, you don't need to inherit from object, you can just do obj = type('obj', (), {'property_name' : 'property_value'})Nisi
@GregHewgill I like completeness.Consignee
R
75

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.

Receiver answered 13/1, 2015 at 20:58 Comment(1)
This should be the accepted answer. Far more readable than creating a new type and intuitive.Headquarters
D
39

Peter's answer

obj = lambda: None
obj.propertyName = 'propertyValue'
Dimpledimwit answered 7/10, 2009 at 1:23 Comment(2)
@ManelClos he is creating a function object that returns none which you could see with obj(). The function object can have properties.Candlemaker
@Candlemaker What are you trying to say?Polychaete
S
15

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'})
Sarina answered 7/10, 2009 at 0:47 Comment(0)
L
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.

Larrup answered 7/10, 2009 at 1:0 Comment(6)
Yep, you can do that - but for some strange reason, you just can't use object() - you have to create your own class.Sarina
if you want an inline class, you can use obj = lambda: None, which is bizarre, but will perform the necessary tasks...Shillelagh
@Shillelagh - I didn't know that. However, now that I see it, I like SilentGhost's answer much better.Larrup
I removed the constructor to show the shortest way to achieve itDimpledimwit
@Jader - Fair enough. It looks better without it.Larrup
@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.Yeanling
D
5

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.

Dagney answered 8/4, 2019 at 19:56 Comment(0)
Y
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"].

Yeanling answered 7/10, 2009 at 6:39 Comment(0)
L
2

Another viable option is to use namedtuple:

from collections import namedtuple

message = namedtuple('Message', ['propertyName'], verbose=True)
messages = [
    message('propertyValueOne'),
    message('propertyValueTwo')
]
Lanctot answered 11/5, 2016 at 7:19 Comment(0)
T
-1
class test:
    def __setattr__(self,key,value):
        return value


myObj = test()
myObj.mykey = 'abc' # set your property and value
Troublemaker answered 7/10, 2009 at 2:4 Comment(1)
There is no need to define setattr, see Chris responseDimpledimwit

© 2022 - 2024 — McMap. All rights reserved.