38

I need to make a bunch of class variables and I would like to do it by looping through a list like that:

vars = ('tx', 'ty', 'tz')  # plus plenty more

class Foo():
    for v in vars:
        setattr(no_idea_what_should_go_here, v, 0)

is it possible? I don't want to make them for an instance (using self in the __init__) but as class variables.

4
  • 2
    Why not to hold them in dict? Commented Nov 29, 2011 at 8:15
  • Do you want to share theses variables between different instances? Commented Nov 29, 2011 at 8:17
  • not sure. most likely. the requirement comes from an API and I don't know how they are used in there. Commented Nov 29, 2011 at 8:28
  • could this possibly be called in __new__? Commented Oct 29, 2022 at 20:51

7 Answers 7

62

You can run the insertion code immediately after a class is created:

class Foo():
     ...

vars = ('tx', 'ty', 'tz')  # plus plenty more
for v in vars:
    setattr(Foo, v, 0)

Also, you can dynamically store the variable while the class is being created:

class Bar:
    locals()['tx'] = 'texas'
Sign up to request clarification or add additional context in comments.

5 Comments

ah. that's cool. I will give it a go and see if the API I work with can handle that. thanks mate!
What if you've overridden __setattr__()?
Update... I figured it out. Within __setattr__() you can call super(ThisClass, self).__setattr__(varname, varvalue).
Regarding the last part of the answer,locals()['tx'] = 'texas'. It should be said that the Python documentation specifically warns against this: Note: The contents of this dictionary should not be modified; changes may not affect the values of local and free variables used by the interpreter. Link: docs.python.org/3/library/functions.html#locals
The locals for a class dictionary are modifiable. It is the locals for a function that will be ignored.
12

Use the type class constructor!

Foo = type("Foo", (), {k: 0 for k in ("tx", "ty", "tz")})

Comments

9

If for any reason you can't use Raymond's answer of setting them up after the class creation then perhaps you could use a metaclass:

class MetaFoo(type):
    def __new__(mcs, classname, bases, dictionary):
        for name in dictionary.get('_extra_vars', ()):
            dictionary[name] = 0
        return type.__new__(mcs, classname, bases, dictionary)
    
class Foo():  # For python 3.x use 'class Foo(metaclass=MetaFoo):'
    __metaclass__ = MetaFoo  # For Python 2.x only
    _extra_vars = 'tx ty tz'.split()

2 Comments

This will not work as your solution has hard coded the values for _extra_vars.
@MSS you don't have to use 'tx ty tz'.split(), you are allow to substitute your own expression which could reference a variable.
1

setattr(object, name, value)

This is the counterpart of getattr(). The arguments are an object, a string and an arbitrary value. The string may name an existing attribute or a new attribute. The function assigns the value to the attribute, provided the object allows it.

For example, these are equivalent:

setattr(x, 'name', value)
x.name = value

Comments

0

The locals() version did not work for me in a class.

The following can be used to dynamically create the attributes of the class:

class namePerson:
    def __init__(self, value):
        exec("self.{} = '{}'".format("name", value)

me = namePerson(value='my name')
me.name # returns 'my name'

1 Comment

This is an awfully wrong approach. You are setting an instance variable, not a class variable. Also why don't you simply use setattr?
0

The function you need is:

setattr(obj, name, value)

This allows you to set named attributes for a given class (this can be self).

The built in documentation for this function is pretty self-explanatory:

Signature: setattr(obj, name, value, /)
Docstring:
Sets the named attribute on the given object to the specified value.

setattr(x, 'y', v) is equivalent to ``x.y = v''
Type:      builtin_function_or_method

Example use

One use of this is to use a dictionary to set multiple class attributes, in my case this was from xpath definitions. I felt this improved maintainability by keeping potentially more fragile xpath definitions all in one place:

class Person:
    def _extract_fields(self):
        ''' Process the page using XPath definitions '''
        logging.debug("_extract_fields(): {}".format(repr(self)))
        # describe how to extract data from the publicly available site
        # (kept together for maintainability)
        fields = {
            'staff_name':
            '//div[@id="staff_name"]//text()',
            'staff_dob':
            '(//div[@id="staff_dob"]//text())[1]'
        }
        # populate named class attributes from the dict
        for key in fields:
            setattr(self, key, self._parsed_content.xpath(fields[key]))

    def __init__(self):
        self._extract_fields()

Comments

-1

You can create global variables with "foo." (or the name of your class) at the beggining of the name:

vars=('tx','ty','tz') #plus plenty more

class Foo():
    pass

foo = Foo() # Instance the class

for i in vars:
    globals () ["foo." + i] = value

1 Comment

This is wrong in two different ways: 1) A global that looks like an attribute is not an attribute. Check the result: print(foo.tx)AttributeError: 'Foo' object has no attribute 'tx' while globals() contains 'foo.tx': 0. 2) foo is an instance, not a class. Foo is the class.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.