views:

112

answers:

5

I was trying to generate a class from a dictionary:

class attr:
    for key in objects_type:
        setattr(attr, key, lambda cl: list())

This gives the error that attr is not defined during the for loop. I know I could write:

class attr:
    pass
for key in objects_type:
    setattr(attr, key, lambda cl: list())

But I am sure I remember seeing code similar to the first example somewhere. Does anyone know if it is possible to write something similar to the first form?

+1  A: 

I don't exactly know, what you are doing. I can give you example of adding class attributes to a class in a for loop:

attributes = ('x', 5), ('y', 6), ('name', 'Cls')

class Cls:
  pass
for key, value in attributes:
  setattr(Cls, key, value)

Remember that for must be run after whole class is defined. You get error, that attr is not defined, because you want to access the class before you create it (class ... is a statement in python, which creates a class object). You must add attributes after you create a class and rememeber, those will be class attributes, not instance attributes.

gruszczy
+1  A: 
class Attr:
  def __init__(self):
    for key in objects_type:
      setattr(Attr, key, lambda cl: list())
shuvalov
+1: Good. Why not a "new style" class that inherits from `object`?
S.Lott
This is the wrong place to do this. Not only is it wasteful, but existing bound methods will be different from bound methods from objects instantiated later. Well, more different than usual.
Ignacio Vazquez-Abrams
+1  A: 

Although it's not very elegant, you can use locals():

>>> class c(object):
...     for i in range(10):
...         locals()['A' + str(i)] = i
... 
>>> c.A0
0
>>> c.A7
7
Max Shawabkeh
That must have been what I remember seeing. Thanks
Casebash
In fact, I think it is nicer than using setattr - so I wouldn't say its inelegant at all
Casebash
You are not supposed to change the locals() dict: http://docs.python.org/library/functions.html#locals
stephan
@Stephan, that's why it's inelegant. Still works, though.
Max Shawabkeh
I forgot about that :-(. What do you reckon the risk of breakage is?
Casebash
This is disgusting ;-)
gruszczy
+2  A: 
newmeths = {
  'two': lambda self: 2,
}

class MC(type):
  def __init__(cls, name, bases, dict):
    for k, v in newmeths.iteritems():
      setattr(cls, k, v)
    super(MC, cls).__init__(name, bases, dict)

class C(object):
  __metaclass__ = MC
  pass

c=C()
print c.two()
Ignacio Vazquez-Abrams
+1  A: 

suppose you want to dynamically add class attributes such as these

classDict = {}
for i in range(2):
    classDict["func%s"%(i+1)] = lambda self:"X"

you can do this in several ways e.g. just add attributes after class has been created because you can'y easily access class name inside class

class Attr2(object):
    pass

for n,v in classDict.iteritems():
    setattr(Attr2, n, v)

print Attr2().func1(), Attr2().func2()

or better just create class on the fly e.g.

Attr3 = type("Attr3",(), classDict)
print Attr3().func1(), Attr3().func2()

or if you wish use metaclass e.g

class AttrMeta(type):
    def __new__(cls, name, bases, dct):
        dct.update(classDict)
        return type.__new__(cls, name, bases, dct)

class Attr4(object):
    __metaclass__ = AttrMeta

print Attr4().func1(), Attr4().func2()
Anurag Uniyal