28

How do I create objects on the fly in Python? I often want to pass information to my Django templates which is formatted like this:

{'test': [a1, a2, b2], 'test2': 'something else', 'test3': 1}

which makes the template look untidy. so I think it's better to just create an object which is like:

class testclass():
    self.test = [a1,a2,b2]
    self.test2 = 'someting else'
    self.test3 = 1
testobj = testclass()

so I can do:

{{ testobj.test }}
{{ testobj.test2 }}
{{ testobj.test3 }}

instead of calling the dictionary.

Since I just need that object once, is it possible to create it without writing a class first? Is there any short-hand code? Is it ok to do it like that or is it bad Python?

JasonTS
  • 2,479
  • 4
  • 32
  • 48

9 Answers9

34

You can use built-in type function:

testobj = type('testclass', (object,), 
                 {'test':[a1,a2,b2], 'test2':'something else', 'test3':1})()

But in this specific case (data object for Django templates), you should use @Xion's solution.

number5
  • 15,913
  • 3
  • 54
  • 51
29

There is another solution in Python 3.3+ types.SimpleNamespace

from types import SimpleNamespace
test_obj = SimpleNamespace(a=1, b=lambda: {'hello': 42})

test_obj.a
test_obj.b()
t_io
  • 1,952
  • 1
  • 19
  • 27
27

In Django templates, the dot notation (testobj.test) can resolve to the Python's [] operator. This means that all you need is an ordinary dict:

testobj = {'test':[a1,a2,b2], 'test2':'something else', 'test3':1}

Pass it as testobj variable to your template and you can freely use {{ testobj.test }} and similar expressions inside your template. They will be translated to testobj['test']. No dedicated class is needed here.

Xion
  • 22,400
  • 10
  • 55
  • 79
  • thank you, that solved the django related part of my problem :) i just checked the other answer because people coming here from google would probably prefer to see the python related answer. – JasonTS Dec 20 '11 at 13:34
  • 1
    @JasonTS, the python related answer would be to use Karl Knechtel's answer of `collections.namedtuple`. – Duncan Dec 20 '11 at 13:47
17

Use collections.namedtuple.

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
3

use building function type: document

>>> class X:
...     a = 1
...
>>> X = type('X', (object,), dict(a=1))

first and second X are identical

confiq
  • 2,795
  • 1
  • 26
  • 43
2

Here's a rogue, minimalist way to create an object. A class is an object, so just commandeer the class definition syntax as if it were a Python object literal:

class testobj(object):
    test = [a1,a2,b2]
    test2 = 'something else'
    test3 = 1

Class variables are the members of the object, and are easily referenced:

assert testobj.test3 == 1

This is weird, a class never used as a class: it's never instantiated. But it's a low-clutter way to make an ad hoc, singleton object: The class itself is your object.

Bob Stein
  • 16,271
  • 10
  • 88
  • 101
  • Note thant the class as an object have large memory footprint and sensible amount of time for it's creation. – intellimath Jun 22 '21 at 09:30
  • @intellimath your point that a class comes with a lot of baggage is a good one, and one should be aware of its consequences. I would note that computer memory gets cheaper while **human memory trends ever more precious**. A singleton object that's not used repetitively has little cost. A lean syntax that's quick to read and understand has solid benefits. – Bob Stein Jun 22 '21 at 12:01
1

for the sake of completeness, there is also recordclass:

from recordclass import recordclass
Test = recordclass('Test', ['test', 'test1', 'test2'])
foo = Test(test=['a1','a2','b2'], test1='someting else', test2=1)

print(foo.test)
.. ['a1', 'a2', 'b2']
Daniel Schneider
  • 1,797
  • 7
  • 20
1

if you just need a "QuickRecord" you can simply declare a empty class
and you can use it without having to instantiate an object...
(just seize the dynamic features of python language... "á la Javascript")

# create an empty class...
class c1:pass

# then just add/change fields at your will
c1.a = "a-field"
c1.b = 1
c1.b += 10
print( c1.a, " -> ", c1.b )

# this has even the 'benesse' of easealy taking a 
# snapshot whenever you want

c2 = c1()
print( c2.a, " -> ", c2.b )
ZEE
  • 2,931
  • 5
  • 35
  • 47
0

The code below also require a class to be created however it is shorter:

 >>>d = {'test':['a1','a2','b2'], 'test2':'something else', 'test3':1}
 >>> class Test(object):
 ...  def __init__(self):
 ...   self.__dict__.update(d)
 >>> a = Test()
 >>> a.test
 ['a1', 'a2', 'b2']
 >>> a.test2
 'something else'
Vader
  • 3,675
  • 23
  • 40