How to create inline objects with properties?
42,819
Solution 1
obj = type('obj', (object,), {'propertyName' : 'propertyValue'})
there are two kinds of type
function uses.
Solution 2
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.
Solution 3
Peter's answer
obj = lambda: None
obj.propertyName = 'propertyValue'
Solution 4
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'})
Solution 5
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
.
Comments
-
Jader Dias almost 2 years
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
-
Smashery over 14 yearsYep, you can do that - but for some strange reason, you just can't use object() - you have to create your own class.
-
Peter over 14 yearsif you want an inline class, you can use
obj = lambda: None
, which is bizarre, but will perform the necessary tasks... -
visual_learner over 14 years@Peter - I didn't know that. However, now that I see it, I like SilentGhost's answer much better.
-
Smashery over 14 years+1 - Very interesting! I wasn't familiar with that use of the type function - could you please link me to some documentation on that?
-
SilentGhost over 14 yearsoopsm Chris was faster, but I've added link to answer anyway
-
SilentGhost over 14 yearshow is this obfuscatory? it's a proper documented behaviour.
-
Jader Dias over 14 yearsI removed the constructor to show the shortest way to achieve it
-
visual_learner over 14 years@Jader - Fair enough. It looks better without it.
-
Laurence Gonsalves over 14 yearsDocumented but obscure behavior. I'm pretty sure 99.9% of Python programmers' initial reaction to seeing this in real code would be "WTF!?".
-
visual_learner over 14 yearsActually, @Laurence, my reaction was, "Woah, I bet that creates a new instance of a made up
'obj'
class that inherits from theobject
with a'propertyName'
member set to'propertyValue'
." And what do you know? I was right! I don't think it's too unintuitive. -
Tom Leys over 14 yearsIt is flexible, terse and yet readable code like this that makes me choose python.
-
Laurence Gonsalves over 14 yearsChris: 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.
-
Greg Hewgill over 14 yearsFor 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'})()
-
visual_learner over 14 years@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.
-
Jonathan Feinberg over 14 yearsIn 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!
-
Laurence Gonsalves over 14 yearsIt's interesting that this "readable" code has been upvoted so much despite the bug that Greg Hewgill points out.
-
steveha over 14 years@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. -
SilentGhost over 14 years@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.
-
Jader Dias over 14 yearsThere is no need to define setattr, see Chris response
-
Lo-Tan about 12 yearsTo the contrary, my initial reaction was WTF. Especially at the comma after 'object'
-
zakdances over 11 yearsThis gives me an error: TypeError: type() argument 2 must be tuple, not type
-
Rupert Angermeier almost 8 yearsfor python 3.3+, have a look at Sylvain Leroux answer below
-
Rafe over 7 yearsThe 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 over 7 yearsIgnore my comment about keyword args. Tested and this won't take keyword arguments #unhappydevface (couldn't edit my last comment to correct it, sorry)
-
jeremyjjbrown almost 7 years@ManelClos he is creating a function object that returns none which you could see with obj(). The function object can have properties.
-
ramki almost 5 yearsSince attributes are mostly valid identifiers
obj = type('obj', (object,), dict(propertyName='propertyValue'))
Just in case if you want you avoid those curly braces -
Boris Verkhovskiy about 4 yearsIn Python 3, you don't need to inherit from
object
, you can just doobj = type('obj', (), {'property_name' : 'property_value'})
-
Moe about 4 years@GregHewgill I like completeness.
-
Sam about 3 years@jeremyjjbrown What are you trying to say?
-
Chris Collett almost 3 yearsThis should be the accepted answer. Far more readable than creating a new
type
and intuitive.