how to create class variable dynamically in python
Question:
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.
Answers:
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'
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()
Late to the party but use the type
class constructor!
Foo = type("Foo", (), {k: 0 for k in ("tx", "ty", "tz")})
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'
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, setattr(x, 'name', value)
is equivalent to x.name = value
.
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()
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.
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'
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()
Late to the party but use the type
class constructor!
Foo = type("Foo", (), {k: 0 for k in ("tx", "ty", "tz")})
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'
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, setattr(x, 'name', value)
is equivalent to x.name = value
.
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()