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.

Share:
42,819
Jader Dias
Author by

Jader Dias

Perl, Javascript, C#, Go, Matlab and Python Developer

Updated on July 05, 2022

Comments

  • Jader Dias
    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
    Smashery over 14 years
    Yep, you can do that - but for some strange reason, you just can't use object() - you have to create your own class.
  • Peter
    Peter over 14 years
    if you want an inline class, you can use obj = lambda: None, which is bizarre, but will perform the necessary tasks...
  • visual_learner
    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
    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
    SilentGhost over 14 years
    oopsm Chris was faster, but I've added link to answer anyway
  • SilentGhost
    SilentGhost over 14 years
    how is this obfuscatory? it's a proper documented behaviour.
  • Jader Dias
    Jader Dias over 14 years
    I removed the constructor to show the shortest way to achieve it
  • visual_learner
    visual_learner over 14 years
    @Jader - Fair enough. It looks better without it.
  • Laurence Gonsalves
    Laurence Gonsalves over 14 years
    Documented 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
    visual_learner over 14 years
    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.
  • Tom Leys
    Tom Leys over 14 years
    It is flexible, terse and yet readable code like this that makes me choose python.
  • Laurence Gonsalves
    Laurence Gonsalves over 14 years
    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.
  • Greg Hewgill
    Greg Hewgill over 14 years
    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'})()
  • visual_learner
    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
    Jonathan Feinberg over 14 years
    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!
  • Laurence Gonsalves
    Laurence Gonsalves over 14 years
    It's interesting that this "readable" code has been upvoted so much despite the bug that Greg Hewgill points out.
  • steveha
    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
    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
    Jader Dias over 14 years
    There is no need to define setattr, see Chris response
  • Lo-Tan
    Lo-Tan about 12 years
    To the contrary, my initial reaction was WTF. Especially at the comma after 'object'
  • zakdances
    zakdances over 11 years
    This gives me an error: TypeError: type() argument 2 must be tuple, not type
  • Rupert Angermeier
    Rupert Angermeier almost 8 years
    for python 3.3+, have a look at Sylvain Leroux answer below
  • Rafe
    Rafe over 7 years
    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
    Rafe over 7 years
    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)
  • jeremyjjbrown
    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
    ramki almost 5 years
    Since 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
    Boris Verkhovskiy about 4 years
    In Python 3, you don't need to inherit from object, you can just do obj = type('obj', (), {'property_name' : 'property_value'})
  • Moe
    Moe about 4 years
    @GregHewgill I like completeness.
  • Sam
    Sam about 3 years
    @jeremyjjbrown What are you trying to say?
  • Chris Collett
    Chris Collett almost 3 years
    This should be the accepted answer. Far more readable than creating a new type and intuitive.