Setting a class attribute with a given name in python while defining the class

16,098

Solution 1

You'll need to use a metaclass for this:

property = 'foo'
value = 'bar'

class MC(type):
  def __init__(cls, name, bases, dict):
    setattr(cls, property, value)
    super(MC, cls).__init__(name, bases, dict)

class C(object):
  __metaclass__ = MC

print C.foo

Solution 2

You can do it even simpler:

class A():
    vars()['key'] = 'value'

In contrast to the previous answer, this solution plays well with external metaclasses (for ex., Django models).

Solution 3

This may be because the class A is not fully initialized when you do your setattr(A, p, v) there.

The first thing to try would be to just move the settattr down to after you close the class block and see if that works, e.g.

class A(object):
    pass

setattr(A, property, value)

Otherwise, that thing Ignacio just said about metaclasses.

Solution 4

So I know this is really old and probably beating a dead horse and this may not have been possible at the time but I cam across this trying to solve my own problem.

I realized this can be accomplished without metaclassing.

The setattr takes and object, accessor name, and value. Well the object is not the class name it's the specific instance of the class, which can be accomplished with self.

class A(object):
    def __init__(self):
        self.a = 'i am a accessor'
        setattr(self, 'key', 'value')

a = A()
print a.a
print a.key
Share:
16,098
prismofeverything
Author by

prismofeverything

Updated on June 07, 2022

Comments

  • prismofeverything
    prismofeverything about 2 years

    I am trying to do something like this:

    property = 'name'
    value = Thing()
    class A:
      setattr(A, property, value)
      other_thing = 'normal attribute'
    
      def __init__(self, etc)
        #etc..........
    

    But I can't seem to find the reference to the class to get the setattr to work the same as just assigning a variable in the class definition. How can I do this?

  • Mike Graham
    Mike Graham over 14 years
    This solution works very well. There is no need to do this in a metaclass when you can do it directly.
  • TomSawyer
    TomSawyer over 6 years
    How do i pass parameter to the file like this a = MC(params) ( mc.py is a particular file), __metaclass__ = MC(params) doesn't work?
  • Ignacio Vazquez-Abrams
    Ignacio Vazquez-Abrams over 6 years
    Unless MC is a callable that returns a metaclass, you don't. And the metaclass will only be set the first time the class is defined so this isn't a way of setting a dynamic metaclass.
  • martineau
    martineau about 6 years
    Your code is setting an instance attribute, which isn't the same as defining a class attribute—since self is an instance of class A not the class itself. In other words, it doesn't answer the question being asked.
  • martineau
    martineau about 6 years
    Another advantage is that it avoids the issues caused by the change in the syntax for specifying metaclasses between Python 2 and 3—so it's a more version independent approach. If you think about it, it effectively gives a self (or cls) argument to the code within a class definition.
  • martineau
    martineau about 6 years
    @TomSawyer: There are at least a couple of ways I know of to pass arguments to a metaclass. Suggest you search here for questions and answers about the subject.
  • martineau
    martineau almost 6 years
    Although it might seem (very slightly) more complicated, as @Vitalik Verhovodov shows in his answer, you can use vars() within the class body itself to get access to the class being defined's __dict__. One you have that, you're pretty much free to modify its contents easily.
  • Eric Smith
    Eric Smith almost 5 years
    This is excellent! I've often wanted to use setattr() on a class under construction, e.g., when doing table-driven construction of a bunch of similar properties. Before I either had to use a metaclass, or define a class method that I call right after the close of the class definition proper. I didn't know about vars().
  • zhy
    zhy about 3 years
    use class C(object, metaclass=MC): pass in python3