Related
I read an article about the getattr function, but I still can't understand what it's for.
The only thing I understand about getattr() is that getattr(li, "pop") is the same as calling li.pop.
When and how do I use this exactly? The book said something about using it to get a reference to a function whose name isn't known until runtime, but when and why would I use this?
Objects in Python can have attributes -- data attributes and functions to work with those (methods). Actually, every object has built-in attributes (try dir(None), dir(True), dir(...), dir(dir) in Python console).
For example you have an object person, that has several attributes: name, gender, etc.
You access these attributes (be it methods or data objects) usually writing: person.name, person.gender, person.the_method(), etc.
But what if you don't know the attribute's name at the time you write the program? For example you have attribute's name stored in a variable called attr_name.
if
attr_name = 'gender'
then, instead of writing
gender = person.gender
you can write
gender = getattr(person, attr_name)
Some practice:
Python 3.4.0 (default, Apr 11 2014, 13:05:11)
>>> class Person():
... name = 'Victor'
... def say(self, what):
... print(self.name, what)
...
>>> getattr(Person, 'name')
'Victor'
>>> attr_name = 'name'
>>> person = Person()
>>> getattr(person, attr_name)
'Victor'
>>> getattr(person, 'say')('Hello')
Victor Hello
getattr will raise AttributeError if attribute with the given name does not exist in the object:
>>> getattr(person, 'age')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Person' object has no attribute 'age'
But you can pass a default value as the third argument, which will be returned if such attribute does not exist:
>>> getattr(person, 'age', 0)
0
You can use getattr along with dir to iterate over all attribute names and get their values:
>>> dir(1000)
['__abs__', '__add__', ..., '__trunc__', '__xor__', 'bit_length', 'conjugate', 'denominator', 'from_bytes', 'imag', 'numerator', 'real', 'to_bytes']
>>> obj = 1000
>>> for attr_name in dir(obj):
... attr_value = getattr(obj, attr_name)
... print(attr_name, attr_value, callable(attr_value))
...
__abs__ <method-wrapper '__abs__' of int object at 0x7f4e927c2f90> True
...
bit_length <built-in method bit_length of int object at 0x7f4e927c2f90> True
...
>>> getattr(1000, 'bit_length')()
10
A practical use for this would be to find all methods whose names start with test and call them.
Similar to getattr there is setattr which allows you to set an attribute of an object having its name:
>>> setattr(person, 'name', 'Andrew')
>>> person.name # accessing instance attribute
'Andrew'
>>> Person.name # accessing class attribute
'Victor'
>>>
getattr(object, 'x') is completely equivalent to object.x.
There are only two cases where getattr can be useful.
you can't write object.x, because you don't know in advance which attribute you want (it comes from a string). Very useful for meta-programming.
you want to provide a default value. object.y will raise an AttributeError if there's no y. But getattr(object, 'y', 5) will return 5.
For me, getattr is easiest to explain this way:
It allows you to call methods based on the contents of a string instead of typing the method name.
For example, you cannot do this:
obj = MyObject()
for x in ['foo', 'bar']:
obj.x()
because x is not of the type builtin, but str. However, you CAN do this:
obj = MyObject()
for x in ['foo', 'bar']:
getattr(obj, x)()
It allows you to dynamically connect with objects based on your input. I've found it useful when dealing with custom objects and modules.
A pretty common use case for getattr is mapping data to functions.
For instance, in a web framework like Django or Pylons, getattr makes it straightforward to map a web request's URL to the function that's going to handle it. If you look under the hood of Pylons's routing, for instance, you'll see that (by default, at least) it chops up a request's URL, like:
http://www.example.com/customers/list
into "customers" and "list". Then it searches for a controller class named CustomerController. Assuming it finds the class, it creates an instance of the class and then uses getattr to get its list method. It then calls that method, passing it the request as an argument.
Once you grasp this idea, it becomes really easy to extend the functionality of a web application: just add new methods to the controller classes, and then create links in your pages that use the appropriate URLs for those methods. All of this is made possible by getattr.
Here's a quick and dirty example of how a class could fire different versions of a save method depending on which operating system it's being executed on using getattr().
import os
class Log(object):
def __init__(self):
self.os = os.name
def __getattr__(self, name):
""" look for a 'save' attribute, or just
return whatever attribute was specified """
if name == 'save':
try:
# try to dynamically return a save
# method appropriate for the user's system
return getattr(self, self.os)
except:
# bail and try to return
# a default save method
return getattr(self, '_save')
else:
return getattr(self, name)
# each of these methods could have save logic specific to
# the system on which the script is executed
def posix(self): print 'saving on a posix machine'
def nt(self): print 'saving on an nt machine'
def os2(self): print 'saving on an os2 machine'
def ce(self): print 'saving on a ce machine'
def java(self): print 'saving on a java machine'
def riscos(self): print 'saving on a riscos machine'
def _save(self): print 'saving on an unknown operating system'
def which_os(self): print os.name
Now let's use this class in an example:
logger = Log()
# Now you can do one of two things:
save_func = logger.save
# and execute it, or pass it along
# somewhere else as 1st class:
save_func()
# or you can just call it directly:
logger.save()
# other attributes will hit the else
# statement and still work as expected
logger.which_os()
Other than all the amazing answers here, there is a way to use getattr to save copious lines of code and keeping it snug. This thought came following the dreadful representation of code that sometimes might be a necessity.
Scenario
Suppose your directory structure is as follows:
- superheroes.py
- properties.py
And, you have functions for getting information about Thor, Iron Man, Doctor Strange in superheroes.py. You very smartly write down the properties of all of them in properties.py in a compact dict and then access them.
properties.py
thor = {
'about': 'Asgardian god of thunder',
'weapon': 'Mjolnir',
'powers': ['invulnerability', 'keen senses', 'vortex breath'], # and many more
}
iron_man = {
'about': 'A wealthy American business magnate, playboy, and ingenious scientist',
'weapon': 'Armor',
'powers': ['intellect', 'armor suit', 'interface with wireless connections', 'money'],
}
doctor_strange = {
'about': ' primary protector of Earth against magical and mystical threats',
'weapon': 'Magic',
'powers': ['magic', 'intellect', 'martial arts'],
}
Now, let's say you want to return capabilities of each of them on demand in superheroes.py. So, there are functions like
from .properties import thor, iron_man, doctor_strange
def get_thor_weapon():
return thor['weapon']
def get_iron_man_bio():
return iron_man['about']
def get_thor_powers():
return thor['powers']
...and more functions returning different values based on the keys and superhero.
With the help of getattr, you could do something like:
from . import properties
def get_superhero_weapon(hero):
superhero = getattr(properties, hero)
return superhero['weapon']
def get_superhero_powers(hero):
superhero = getattr(properties, hero)
return superhero['powers']
You considerably reduced the number of lines of code, functions and repetition!
Oh and of course, if you have bad names like properties_of_thor for variables , they can be made and accessed by simply doing
def get_superhero_weapon(hero):
superhero = 'properties_of_{}'.format(hero)
all_properties = getattr(properties, superhero)
return all_properties['weapon']
NOTE: For this particular problem, there can be smarter ways to deal with the situation, but the idea is to give an insight about using getattr in right places to write cleaner code.
# getattr
class hithere():
def french(self):
print 'bonjour'
def english(self):
print 'hello'
def german(self):
print 'hallo'
def czech(self):
print 'ahoj'
def noidea(self):
print 'unknown language'
def dispatch(language):
try:
getattr(hithere(),language)()
except:
getattr(hithere(),'noidea')()
# note, do better error handling than this
dispatch('french')
dispatch('english')
dispatch('german')
dispatch('czech')
dispatch('spanish')
I sometimes use getattr(..) to lazily initialise attributes of secondary importance just before they are used in the code.
Compare the following:
class Graph(object):
def __init__(self):
self.n_calls_to_plot = 0
#...
#A lot of code here
#...
def plot(self):
self.n_calls_to_plot += 1
To this:
class Graph(object):
def plot(self):
self.n_calls_to_plot = 1 + getattr(self, "n_calls_to_plot", 0)
The advantage of the second way is that n_calls_to_plot only appears around the place in the code where it is used. This is good for readability, because (1) you can immediately see what value it starts with when reading how it's used, (2) it doesn't introduce a distraction into the __init__(..) method, which ideally should be about the conceptual state of the class, rather than some utility counter that is only used by one of the function's methods for technical reasons, such as optimisation, and has nothing to do with the meaning of the object.
Quite frequently when I am creating an XML file from data stored in a class I would frequently receive errors if the attribute didn't exist or was of type None. In this case, my issue wasn't not knowing what the attribute name was, as stated in your question, but rather was data ever stored in that attribute.
class Pet:
def __init__(self):
self.hair = None
self.color = None
If I used hasattr to do this, it would return True even if the attribute value was of type None and this would cause my ElementTree set command to fail.
hasattr(temp, 'hair')
>>True
If the attribute value was of type None, getattr would also return it which would cause my ElementTree set command to fail.
c = getattr(temp, 'hair')
type(c)
>> NoneType
I use the following method to take care of these cases now:
def getRealAttr(class_obj, class_attr, default = ''):
temp = getattr(class_obj, class_attr, default)
if temp is None:
temp = default
elif type(temp) != str:
temp = str(temp)
return temp
This is when and how I use getattr.
Another use of getattr() in implementing a switch statement in Python. It uses both reflection to get the case type.
import sys
class SwitchStatement(object):
""" a class to implement switch statement and a way to show how to use gettattr in Pythion"""
def case_1(self):
return "value for case_1"
def case_2(self):
return "value for case_2"
def case_3(self):
return "value for case_3"
def case_4(self):
return "value for case_4"
def case_value(self, case_type=1):
"""This is the main dispatchmethod, that uses gettattr"""
case_method = 'case_' + str(case_type)
# fetch the relevant method name
# Get the method from 'self'. Default to a lambda.
method = getattr(self, case_method, lambda: "Invalid case type")
# Call the method as we return it
return method()
def main(_):
switch = SwitchStatement()
print swtich.case_value(_)
if __name__ == '__main__':
main(int(sys.argv[1]))
setattr()
We use setattr to add an attribute to our class instance. We pass the class instance, the attribute name, and the value.
getattr()
With getattr we retrive these values
For example
Employee = type("Employee", (object,), dict())
employee = Employee()
# Set salary to 1000
setattr(employee,"salary", 1000 )
# Get the Salary
value = getattr(employee, "salary")
print(value)
I think this example is self explanatory. It runs the method of first parameter, whose name is given in the second parameter.
class MyClass:
def __init__(self):
pass
def MyMethod(self):
print("Method ran")
# Create an object
object = MyClass()
# Get all the methods of a class
method_list = [func for func in dir(MyClass) if callable(getattr(MyClass, func))]
# You can use any of the methods in method_list
# "MyMethod" is the one we want to use right now
# This is the same as running "object.MyMethod()"
getattr(object,'MyMethod')()
It is also clarifying from https://www.programiz.com/python-programming/methods/built-in/getattr
class Person:
age = 23
name = "Adam"
person = Person()
print('The age is:', getattr(person, "age"))
print('The age is:', person.age)
The age is: 23
The age is: 23
class Person:
age = 23
name = "Adam"
person = Person()
# when default value is provided
print('The sex is:', getattr(person, 'sex', 'Male'))
# when no default value is provided
print('The sex is:', getattr(person, 'sex'))
The sex is: Male
AttributeError: 'Person' object has no attribute 'sex'
I have tried in Python2.7.17
Some of the fellow folks already answered. However I have tried to call
getattr(obj, 'set_value') and this didn't execute the set_value method, So i changed to getattr(obj, 'set_value')() --> This helps to invoke the same.
Example Code:
Example 1:
class GETATT_VERIFY():
name = "siva"
def __init__(self):
print "Ok"
def set_value(self):
self.value = "myself"
print "oooh"
obj = GETATT_VERIFY()
print getattr(GETATT_VERIFY, 'name')
getattr(obj, 'set_value')()
print obj.value
How do I declare a constant in Python?
In Java, we do:
public static final String CONST_NAME = "Name";
You cannot declare a variable or value as constant in Python.
To indicate to programmers that a variable is a constant, one usually writes it in upper case:
CONST_NAME = "Name"
To raise exceptions when constants are changed, see Constants in Python by Alex Martelli. Note that this is not commonly used in practice.
As of Python 3.8, there's a typing.Final variable annotation that will tell static type checkers (like mypy) that your variable shouldn't be reassigned. This is the closest equivalent to Java's final. However, it does not actually prevent reassignment:
from typing import Final
a: Final[int] = 1
# Executes fine, but mypy will report an error if you run mypy on this:
a = 2
There's no const keyword as in other languages, however it is possible to create a Property that has a "getter function" to read the data, but no "setter function" to re-write the data. This essentially protects the identifier from being changed.
Here is an alternative implementation using class property:
Note that the code is far from easy for a reader wondering about constants. See explanation below.
def constant(f):
def fset(self, value):
raise TypeError
def fget(self):
return f()
return property(fget, fset)
class _Const(object):
#constant
def FOO():
return 0xBAADFACE
#constant
def BAR():
return 0xDEADBEEF
CONST = _Const()
print(hex(CONST.FOO)) # -> '0xbaadfaceL'
CONST.FOO = 0
##Traceback (most recent call last):
## File "example1.py", line 22, in <module>
## CONST.FOO = 0
## File "example1.py", line 5, in fset
## raise TypeError
##TypeError
Code Explanation:
Define a function constant that takes an expression, and uses it to construct a "getter" - a function that solely returns the value of the expression.
The setter function raises a TypeError so it's read-only
Use the constant function we just created as a decoration to quickly define read-only properties.
And in some other more old-fashioned way:
(The code is quite tricky, more explanations below)
class _Const(object):
def FOO():
def fset(self, value):
raise TypeError
def fget(self):
return 0xBAADFACE
return property(**locals())
FOO = FOO() # Define property.
CONST = _Const()
print(hex(CONST.FOO)) # -> '0xbaadfaceL'
CONST.FOO = 0
##Traceback (most recent call last):
## File "example2.py", line 16, in <module>
## CONST.FOO = 0
## File "example2.py", line 6, in fset
## raise TypeError
##TypeError
To define the identifier FOO, firs define two functions (fset, fget - the names are at my choice).
Then use the built-in property function to construct an object that can be "set" or "get".
Note hat the property function's first two parameters are named fset and fget.
Use the fact that we chose these very names for our own getter & setter and create a keyword-dictionary using the ** (double asterisk) applied to all the local definitions of that scope to pass parameters to the property function
In Python instead of language enforcing something, people use naming conventions e.g __method for private methods and using _method for protected methods.
So in same manner you can simply declare the constant as all caps, e.g.:
MY_CONSTANT = "one"
If you want that this constant never changes, you can hook into attribute access and do tricks, but a simpler approach is to declare a function:
def MY_CONSTANT():
return "one"
Only problem is everywhere you will have to do MY_CONSTANT(), but again MY_CONSTANT = "one" is the correct way in Python (usually).
You can also use namedtuple() to create constants:
>>> from collections import namedtuple
>>> Constants = namedtuple('Constants', ['pi', 'e'])
>>> constants = Constants(3.14, 2.718)
>>> constants.pi
3.14
>>> constants.pi = 3
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: can't set attribute
I've recently found a very succinct update to this which automatically raises meaningful error messages and prevents access via __dict__:
class CONST(object):
__slots__ = ()
FOO = 1234
CONST = CONST()
# ----------
print(CONST.FOO) # 1234
CONST.FOO = 4321 # AttributeError: 'CONST' object attribute 'FOO' is read-only
CONST.__dict__['FOO'] = 4321 # AttributeError: 'CONST' object has no attribute '__dict__'
CONST.BAR = 5678 # AttributeError: 'CONST' object has no attribute 'BAR'
We define over ourselves as to make ourselves an instance and then use slots to ensure that no additional attributes can be added. This also removes the __dict__ access route. Of course, the whole object can still be redefined.
Edit - Original solution
I'm probably missing a trick here, but this seems to work for me:
class CONST(object):
FOO = 1234
def __setattr__(self, *_):
pass
CONST = CONST()
#----------
print CONST.FOO # 1234
CONST.FOO = 4321
CONST.BAR = 5678
print CONST.FOO # Still 1234!
print CONST.BAR # Oops AttributeError
Creating the instance allows the magic __setattr__ method to kick in and intercept attempts to set the FOO variable. You could throw an exception here if you wanted to. Instantiating the instance over the class name prevents access directly via the class.
It's a total pain for one value, but you could attach lots to your CONST object. Having an upper class, class name also seems a bit grotty, but I think it's quite succinct overall.
Python doesn't have constants.
Perhaps the easiest alternative is to define a function for it:
def MY_CONSTANT():
return 42
MY_CONSTANT() now has all the functionality of a constant (plus some annoying braces).
Properties are one way to create constants. You can do it by declaring a getter property, but ignoring the setter. For example:
class MyFinalProperty(object):
#property
def name(self):
return "John"
You can have a look at an article I've written to find more ways to use Python properties.
In addition to the two top answers (just use variables with UPPERCASE names, or use properties to make the values read-only), I want to mention that it's possible to use metaclasses in order to implement named constants. I provide a very simple solution using metaclasses at GitHub which may be helpful if you want the values to be more informative about their type/name:
>>> from named_constants import Constants
>>> class Colors(Constants):
... black = 0
... red = 1
... white = 15
...
>>> c = Colors.black
>>> c == 0
True
>>> c
Colors.black
>>> c.name()
'black'
>>> Colors(0) is c
True
This is slightly more advanced Python, but still very easy to use and handy. (The module has some more features, including constants being read-only, see its README.)
There are similar solutions floating around in various repositories, but to the best of my knowledge they either lack one of the fundamental features that I would expect from constants (like being constant, or being of arbitrary type), or they have esoteric features added that make them less generally applicable. But YMMV, I would be grateful for feedback. :-)
Edit: Added sample code for Python 3
Note: this other answer looks like it provides a much more complete implementation similar to the following (with more features).
First, make a metaclass:
class MetaConst(type):
def __getattr__(cls, key):
return cls[key]
def __setattr__(cls, key, value):
raise TypeError
This prevents statics properties from being changed. Then make another class that uses that metaclass:
class Const(object):
__metaclass__ = MetaConst
def __getattr__(self, name):
return self[name]
def __setattr__(self, name, value):
raise TypeError
Or, if you're using Python 3:
class Const(object, metaclass=MetaConst):
def __getattr__(self, name):
return self[name]
def __setattr__(self, name, value):
raise TypeError
This should prevent instance props from being changed. To use it, inherit:
class MyConst(Const):
A = 1
B = 2
Now the props, accessed directly or via an instance, should be constant:
MyConst.A
# 1
my_const = MyConst()
my_const.A
# 1
MyConst.A = 'changed'
# TypeError
my_const.A = 'changed'
# TypeError
Here's an example of above in action. Here's another example for Python 3.
PEP 591 has the 'final' qualifier. Enforcement is down to the type checker.
So you can do:
MY_CONSTANT: Final = 12407
Note: Final keyword is only applicable for Python 3.8 version
from enum import Enum
class StringConsts(str,Enum):
ONE='one'
TWO='two'
print(f'Truth is {StringConsts.ONE=="one"}') #Truth is True
StringConsts.ONE="one" #Error: Cannot reassign
This mixin of Enum and str gives you the power of not having to reimplement setattr (through Enum) and comparison to other str objects (through str).
This might deprecate http://code.activestate.com/recipes/65207-constants-in-python/?in=user-97991 completely.
I declare constant values using frozen data class like this:
from dataclasses import dataclass
#dataclass(frozen=True)
class _Const:
SOME_STRING = 'some_string'
SOME_INT = 5
Const = _Const()
# In another file import Const and try
print(Const.SOME_STRING) # ITS OK!
Const.SOME_INT = 6 # dataclasses.FrozenInstanceError: cannot assign to field 'SOME_INT'
You can use a namedtuple as a workaround to effectively create a constant that works the same way as a static final variable in Java (a Java "constant"). As workarounds go, it's sort of elegant. (A more elegant approach would be to simply improve the Python language --- what sort of language lets you redefine math.pi? -- but I digress.)
(As I write this, I realize another answer to this question mentioned namedtuple, but I'll continue here because I'll show a syntax that more closely parallels what you'd expect in Java, as there is no need to create a named type as namedtuple forces you to do.)
Following your example, you'll remember that in Java we must define the constant inside some class; because you didn't mention a class name, let's call it Foo. Here's the Java class:
public class Foo {
public static final String CONST_NAME = "Name";
}
Here's the equivalent Python.
from collections import namedtuple
Foo = namedtuple('_Foo', 'CONST_NAME')('Name')
The key point I want to add here is that you don't need a separate Foo type (an "anonymous named tuple" would be nice, even though that sounds like an oxymoron), so we name our namedtuple _Foo so that hopefully it won't escape to importing modules.
The second point here is that we immediately create an instance of the nametuple, calling it Foo; there's no need to do this in a separate step (unless you want to). Now you can do what you can do in Java:
>>> Foo.CONST_NAME
'Name'
But you can't assign to it:
>>> Foo.CONST_NAME = 'bar'
…
AttributeError: can't set attribute
Acknowledgement: I thought I invented the namedtuple approach, but then I see that someone else gave a similar (although less compact) answer. Then I also noticed What are "named tuples" in Python?, which points out that sys.version_info is now a namedtuple, so perhaps the Python standard library already came up with this idea much earlier.
Note that unfortunately (this still being Python), you can erase the entire Foo assignment altogether:
>>> Foo = 'bar'
(facepalm)
But at least we're preventing the Foo.CONST_NAME value from being changed, and that's better than nothing. Good luck.
Here is an implementation of a "Constants" class, which creates instances with read-only (constant) attributes. E.g. can use Nums.PI to get a value that has been initialized as 3.14159, and Nums.PI = 22 raises an exception.
# ---------- Constants.py ----------
class Constants(object):
"""
Create objects with read-only (constant) attributes.
Example:
Nums = Constants(ONE=1, PI=3.14159, DefaultWidth=100.0)
print 10 + Nums.PI
print '----- Following line is deliberate ValueError -----'
Nums.PI = 22
"""
def __init__(self, *args, **kwargs):
self._d = dict(*args, **kwargs)
def __iter__(self):
return iter(self._d)
def __len__(self):
return len(self._d)
# NOTE: This is only called if self lacks the attribute.
# So it does not interfere with get of 'self._d', etc.
def __getattr__(self, name):
return self._d[name]
# ASSUMES '_..' attribute is OK to set. Need this to initialize 'self._d', etc.
#If use as keys, they won't be constant.
def __setattr__(self, name, value):
if (name[0] == '_'):
super(Constants, self).__setattr__(name, value)
else:
raise ValueError("setattr while locked", self)
if (__name__ == "__main__"):
# Usage example.
Nums = Constants(ONE=1, PI=3.14159, DefaultWidth=100.0)
print 10 + Nums.PI
print '----- Following line is deliberate ValueError -----'
Nums.PI = 22
Thanks to #MikeGraham 's FrozenDict, which I used as a starting point. Changed, so instead of Nums['ONE'] the usage syntax is Nums.ONE.
And thanks to #Raufio's answer, for idea to override __ setattr __.
Or for an implementation with more functionality, see #Hans_meine 's
named_constants at GitHub
A tuple technically qualifies as a constant, as a tuple will raise an error if you try to change one of its values. If you want to declare a tuple with one value, then place a comma after its only value, like this:
my_tuple = (0 """Or any other value""",)
To check this variable's value, use something similar to this:
if my_tuple[0] == 0:
#Code goes here
If you attempt to change this value, an error will be raised.
Here it is a collection of idioms that I created as an attempt to improve some of the already available answers.
I know the use of constant is not pythonic, and you should not do this at home!
However, Python is such a dynamic language! This forum shows how it is possible the creation of constructs that looks and feels like constants. This answer has as the primary purpose to explore what can be expressed by the language.
Please do not be too harsh with me :-).
For more details I wrote a accompaniment blog about these idioms.
In this post, I will call a constant variable to a constant reference to values (immutable or otherwise). Moreover, I say that a variable has a frozen value when it references a mutable object that a client-code cannot update its value(s).
A space of constants (SpaceConstants)
This idiom creates what looks like a namespace of constant variables (a.k.a. SpaceConstants). It is a modification of a code snippet by Alex Martelli to avoid the use of module objects. In particular, this modification uses what I call a class factory because within SpaceConstants function, a class called SpaceConstants is defined, and an instance of it is returned.
I explored the use of class factory to implement a policy-based design look-alike in Python in stackoverflow and also in a blogpost.
def SpaceConstants():
def setattr(self, name, value):
if hasattr(self, name):
raise AttributeError(
"Cannot reassign members"
)
self.__dict__[name] = value
cls = type('SpaceConstants', (), {
'__setattr__': setattr
})
return cls()
sc = SpaceConstants()
print(sc.x) # raise "AttributeError: 'SpaceConstants' object has no attribute 'x'"
sc.x = 2 # bind attribute x
print(sc.x) # print "2"
sc.x = 3 # raise "AttributeError: Cannot reassign members"
sc.y = {'name': 'y', 'value': 2} # bind attribute y
print(sc.y) # print "{'name': 'y', 'value': 2}"
sc.y['name'] = 'yprime' # mutable object can be changed
print(sc.y) # print "{'name': 'yprime', 'value': 2}"
sc.y = {} # raise "AttributeError: Cannot reassign members"
A space of frozen values (SpaceFrozenValues)
This next idiom is a modification of the SpaceConstants in where referenced mutable objects are frozen. This implementation exploits what I call shared closure between setattr and getattr functions. The value of the mutable object is copied and referenced by variable cache define inside of the function shared closure. It forms what I call a closure protected copy of a mutable object.
You must be careful in using this idiom because getattr return the value of cache by doing a deep copy. This operation could have a significant performance impact on large objects!
from copy import deepcopy
def SpaceFrozenValues():
cache = {}
def setattr(self, name, value):
nonlocal cache
if name in cache:
raise AttributeError(
"Cannot reassign members"
)
cache[name] = deepcopy(value)
def getattr(self, name):
nonlocal cache
if name not in cache:
raise AttributeError(
"Object has no attribute '{}'".format(name)
)
return deepcopy(cache[name])
cls = type('SpaceFrozenValues', (),{
'__getattr__': getattr,
'__setattr__': setattr
})
return cls()
fv = SpaceFrozenValues()
print(fv.x) # AttributeError: Object has no attribute 'x'
fv.x = 2 # bind attribute x
print(fv.x) # print "2"
fv.x = 3 # raise "AttributeError: Cannot reassign members"
fv.y = {'name': 'y', 'value': 2} # bind attribute y
print(fv.y) # print "{'name': 'y', 'value': 2}"
fv.y['name'] = 'yprime' # you can try to change mutable objects
print(fv.y) # print "{'name': 'y', 'value': 2}"
fv.y = {} # raise "AttributeError: Cannot reassign members"
A constant space (ConstantSpace)
This idiom is an immutable namespace of constant variables or ConstantSpace. It is a combination of awesomely simple Jon Betts' answer in stackoverflow with a class factory.
def ConstantSpace(**args):
args['__slots__'] = ()
cls = type('ConstantSpace', (), args)
return cls()
cs = ConstantSpace(
x = 2,
y = {'name': 'y', 'value': 2}
)
print(cs.x) # print "2"
cs.x = 3 # raise "AttributeError: 'ConstantSpace' object attribute 'x' is read-only"
print(cs.y) # print "{'name': 'y', 'value': 2}"
cs.y['name'] = 'yprime' # mutable object can be changed
print(cs.y) # print "{'name': 'yprime', 'value': 2}"
cs.y = {} # raise "AttributeError: 'ConstantSpace' object attribute 'x' is read-only"
cs.z = 3 # raise "AttributeError: 'ConstantSpace' object has no attribute 'z'"
A frozen space (FrozenSpace)
This idiom is an immutable namespace of frozen variables or FrozenSpace. It is derived from the previous pattern by making each variable a protected property by closure of the generated FrozenSpace class.
from copy import deepcopy
def FreezeProperty(value):
cache = deepcopy(value)
return property(
lambda self: deepcopy(cache)
)
def FrozenSpace(**args):
args = {k: FreezeProperty(v) for k, v in args.items()}
args['__slots__'] = ()
cls = type('FrozenSpace', (), args)
return cls()
fs = FrozenSpace(
x = 2,
y = {'name': 'y', 'value': 2}
)
print(fs.x) # print "2"
fs.x = 3 # raise "AttributeError: 'FrozenSpace' object attribute 'x' is read-only"
print(fs.y) # print "{'name': 'y', 'value': 2}"
fs.y['name'] = 'yprime' # try to change mutable object
print(fs.y) # print "{'name': 'y', 'value': 2}"
fs.y = {} # raise "AttributeError: 'FrozenSpace' object attribute 'x' is read-only"
fs.z = 3 # raise "AttributeError: 'FrozenSpace' object has no attribute 'z'"
I would make a class that overrides the __setattr__ method of the base object class and wrap my constants with that, note that I'm using python 2.7:
class const(object):
def __init__(self, val):
super(const, self).__setattr__("value", val)
def __setattr__(self, name, val):
raise ValueError("Trying to change a constant value", self)
To wrap a string:
>>> constObj = const("Try to change me")
>>> constObj.value
'Try to change me'
>>> constObj.value = "Changed"
Traceback (most recent call last):
...
ValueError: Trying to change a constant value
>>> constObj2 = const(" or not")
>>> mutableObj = constObj.value + constObj2.value
>>> mutableObj #just a string
'Try to change me or not'
It's pretty simple, but if you want to use your constants the same as you would a non-constant object (without using constObj.value), it will be a bit more intensive. It's possible that this could cause problems, so it might be best to keep the .value to show and know that you are doing operations with constants (maybe not the most 'pythonic' way though).
Unfortunately the Python has no constants so yet and it is shame. ES6 already added support constants to JavaScript (https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/const) since it is a very useful thing in any programming language.
As answered in other answers in Python community use the convention - user uppercase variable as constants, but it does not protect against arbitrary errors in code.
If you like, you may be found useful a single-file solution as next
(see docstrings how use it).
file constants.py
import collections
__all__ = ('const', )
class Constant(object):
"""
Implementation strict constants in Python 3.
A constant can be set up, but can not be changed or deleted.
Value of constant may any immutable type, as well as list or set.
Besides if value of a constant is list or set, it will be converted in an immutable type as next:
list -> tuple
set -> frozenset
Dict as value of a constant has no support.
>>> const = Constant()
>>> del const.temp
Traceback (most recent call last):
NameError: name 'temp' is not defined
>>> const.temp = 1
>>> const.temp = 88
Traceback (most recent call last):
...
TypeError: Constanst can not be changed
>>> del const.temp
Traceback (most recent call last):
...
TypeError: Constanst can not be deleted
>>> const.I = ['a', 1, 1.2]
>>> print(const.I)
('a', 1, 1.2)
>>> const.F = {1.2}
>>> print(const.F)
frozenset([1.2])
>>> const.D = dict()
Traceback (most recent call last):
...
TypeError: dict can not be used as constant
>>> del const.UNDEFINED
Traceback (most recent call last):
...
NameError: name 'UNDEFINED' is not defined
>>> const()
{'I': ('a', 1, 1.2), 'temp': 1, 'F': frozenset([1.2])}
"""
def __setattr__(self, name, value):
"""Declaration a constant with value. If mutable - it will be converted to immutable, if possible.
If the constant already exists, then made prevent againt change it."""
if name in self.__dict__:
raise TypeError('Constanst can not be changed')
if not isinstance(value, collections.Hashable):
if isinstance(value, list):
value = tuple(value)
elif isinstance(value, set):
value = frozenset(value)
elif isinstance(value, dict):
raise TypeError('dict can not be used as constant')
else:
raise ValueError('Muttable or custom type is not supported')
self.__dict__[name] = value
def __delattr__(self, name):
"""Deny against deleting a declared constant."""
if name in self.__dict__:
raise TypeError('Constanst can not be deleted')
raise NameError("name '%s' is not defined" % name)
def __call__(self):
"""Return all constans."""
return self.__dict__
const = Constant()
if __name__ == '__main__':
import doctest
doctest.testmod()
If this is not enough, see full testcase for it.
import decimal
import uuid
import datetime
import unittest
from ..constants import Constant
class TestConstant(unittest.TestCase):
"""
Test for implementation constants in the Python
"""
def setUp(self):
self.const = Constant()
def tearDown(self):
del self.const
def test_create_constant_with_different_variants_of_name(self):
self.const.CONSTANT = 1
self.assertEqual(self.const.CONSTANT, 1)
self.const.Constant = 2
self.assertEqual(self.const.Constant, 2)
self.const.ConStAnT = 3
self.assertEqual(self.const.ConStAnT, 3)
self.const.constant = 4
self.assertEqual(self.const.constant, 4)
self.const.co_ns_ta_nt = 5
self.assertEqual(self.const.co_ns_ta_nt, 5)
self.const.constant1111 = 6
self.assertEqual(self.const.constant1111, 6)
def test_create_and_change_integer_constant(self):
self.const.INT = 1234
self.assertEqual(self.const.INT, 1234)
with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):
self.const.INT = .211
def test_create_and_change_float_constant(self):
self.const.FLOAT = .1234
self.assertEqual(self.const.FLOAT, .1234)
with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):
self.const.FLOAT = .211
def test_create_and_change_list_constant_but_saved_as_tuple(self):
self.const.LIST = [1, .2, None, True, datetime.date.today(), [], {}]
self.assertEqual(self.const.LIST, (1, .2, None, True, datetime.date.today(), [], {}))
self.assertTrue(isinstance(self.const.LIST, tuple))
with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):
self.const.LIST = .211
def test_create_and_change_none_constant(self):
self.const.NONE = None
self.assertEqual(self.const.NONE, None)
with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):
self.const.NONE = .211
def test_create_and_change_boolean_constant(self):
self.const.BOOLEAN = True
self.assertEqual(self.const.BOOLEAN, True)
with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):
self.const.BOOLEAN = False
def test_create_and_change_string_constant(self):
self.const.STRING = "Text"
self.assertEqual(self.const.STRING, "Text")
with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):
self.const.STRING += '...'
with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):
self.const.STRING = 'TEst1'
def test_create_dict_constant(self):
with self.assertRaisesRegexp(TypeError, 'dict can not be used as constant'):
self.const.DICT = {}
def test_create_and_change_tuple_constant(self):
self.const.TUPLE = (1, .2, None, True, datetime.date.today(), [], {})
self.assertEqual(self.const.TUPLE, (1, .2, None, True, datetime.date.today(), [], {}))
with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):
self.const.TUPLE = 'TEst1'
def test_create_and_change_set_constant(self):
self.const.SET = {1, .2, None, True, datetime.date.today()}
self.assertEqual(self.const.SET, {1, .2, None, True, datetime.date.today()})
self.assertTrue(isinstance(self.const.SET, frozenset))
with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):
self.const.SET = 3212
def test_create_and_change_frozenset_constant(self):
self.const.FROZENSET = frozenset({1, .2, None, True, datetime.date.today()})
self.assertEqual(self.const.FROZENSET, frozenset({1, .2, None, True, datetime.date.today()}))
with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):
self.const.FROZENSET = True
def test_create_and_change_date_constant(self):
self.const.DATE = datetime.date(1111, 11, 11)
self.assertEqual(self.const.DATE, datetime.date(1111, 11, 11))
with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):
self.const.DATE = True
def test_create_and_change_datetime_constant(self):
self.const.DATETIME = datetime.datetime(2000, 10, 10, 10, 10)
self.assertEqual(self.const.DATETIME, datetime.datetime(2000, 10, 10, 10, 10))
with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):
self.const.DATETIME = None
def test_create_and_change_decimal_constant(self):
self.const.DECIMAL = decimal.Decimal(13123.12312312321)
self.assertEqual(self.const.DECIMAL, decimal.Decimal(13123.12312312321))
with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):
self.const.DECIMAL = None
def test_create_and_change_timedelta_constant(self):
self.const.TIMEDELTA = datetime.timedelta(days=45)
self.assertEqual(self.const.TIMEDELTA, datetime.timedelta(days=45))
with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):
self.const.TIMEDELTA = 1
def test_create_and_change_uuid_constant(self):
value = uuid.uuid4()
self.const.UUID = value
self.assertEqual(self.const.UUID, value)
with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):
self.const.UUID = []
def test_try_delete_defined_const(self):
self.const.VERSION = '0.0.1'
with self.assertRaisesRegexp(TypeError, 'Constanst can not be deleted'):
del self.const.VERSION
def test_try_delete_undefined_const(self):
with self.assertRaisesRegexp(NameError, "name 'UNDEFINED' is not defined"):
del self.const.UNDEFINED
def test_get_all_defined_constants(self):
self.assertDictEqual(self.const(), {})
self.const.A = 1
self.assertDictEqual(self.const(), {'A': 1})
self.const.B = "Text"
self.assertDictEqual(self.const(), {'A': 1, 'B': "Text"})
Advantages:
1. Access to all constants for whole project
2. Strict control for values of constants
Lacks:
1. Not support for custom types and the type 'dict'
Notes:
Tested with Python3.4 and Python3.5 (I am use the 'tox' for it)
Testing environment:
.
$ uname -a
Linux wlysenko-Aspire 3.13.0-37-generic #64-Ubuntu SMP Mon Sep 22 21:28:38 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
We can create a descriptor object.
class Constant:
def __init__(self,value=None):
self.value = value
def __get__(self,instance,owner):
return self.value
def __set__(self,instance,value):
raise ValueError("You can't change a constant")
1) If we wanted to work with constants at the instance level then:
class A:
NULL = Constant()
NUM = Constant(0xFF)
class B:
NAME = Constant('bar')
LISTA = Constant([0,1,'INFINITY'])
>>> obj=A()
>>> print(obj.NUM) #=> 255
>>> obj.NUM =100
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: You can't change a constant
2) if we wanted to create constants only at the class level, we could use a metaclass that serves as a container for our constants (our descriptor objects); all the classes that descend will inherit our constants (our descriptor objects) without any risk that can be modified.
# metaclass of my class Foo
class FooMeta(type): pass
# class Foo
class Foo(metaclass=FooMeta): pass
# I create constants in my metaclass
FooMeta.NUM = Constant(0xff)
FooMeta.NAME = Constant('FOO')
>>> Foo.NUM #=> 255
>>> Foo.NAME #=> 'FOO'
>>> Foo.NUM = 0 #=> ValueError: You can't change a constant
If I create a subclass of Foo, this class will inherit the constant without the possibility of modifying them
class Bar(Foo): pass
>>> Bar.NUM #=> 255
>>> Bar.NUM = 0 #=> ValueError: You can't change a constant
The Pythonic way of declaring "constants" is basically a module level variable:
RED = 1
GREEN = 2
BLUE = 3
And then write your classes or functions. Since constants are almost always integers, and they are also immutable in Python, you have a very little chance of altering it.
Unless, of course, if you explicitly set RED = 2.
There is a cleaner way to do this with namedtuple:
from collections import namedtuple
def make_consts(name, **kwargs):
return namedtuple(name, kwargs.keys())(**kwargs)
Usage Example
CONSTS = make_consts("baz1",
foo=1,
bar=2)
With this exactly approach you can namespace your constants.
Here's a trick if you want constants and don't care their values:
Just define empty classes.
e.g:
class RED:
pass
class BLUE:
pass
There's no perfect way to do this. As I understand it most programmers will just capitalize the identifier, so PI = 3.142 can be readily understood to be a constant.
On the otherhand, if you want something that actually acts like a constant, I'm not sure you'll find it. With anything you do there will always be some way of editing the "constant" so it won't really be a constant. Here's a very simple, dirty example:
def define(name, value):
if (name + str(id(name))) not in globals():
globals()[name + str(id(name))] = value
def constant(name):
return globals()[name + str(id(name))]
define("PI",3.142)
print(constant("PI"))
This looks like it will make a PHP-style constant.
In reality all it takes for someone to change the value is this:
globals()["PI"+str(id("PI"))] = 3.1415
This is the same for all the other solutions you'll find on here - even the clever ones that make a class and redefine the set attribute method - there will always be a way around them. That's just how Python is.
My recommendation is to just avoid all the hassle and just capitalize your identifiers. It wouldn't really be a proper constant but then again nothing would.
I am trying different ways to create a real constant in Python and perhaps I found the pretty solution.
Example:
Create container for constants
>>> DAYS = Constants(
... MON=0,
... TUE=1,
... WED=2,
... THU=3,
... FRI=4,
... SAT=5,
... SUN=6
... )
Get value from container
>>> DAYS.MON
0
>>> DAYS['MON']
0
Represent with pure python data structures
>>> list(DAYS)
['WED', 'SUN', 'FRI', 'THU', 'MON', 'TUE', 'SAT']
>>> dict(DAYS)
{'WED': 2, 'SUN': 6, 'FRI': 4, 'THU': 3, 'MON': 0, 'TUE': 1, 'SAT': 5}
All constants are immutable
>>> DAYS.MON = 7
...
AttributeError: Immutable attribute
>>> del DAYS.MON
...
AttributeError: Immutable attribute
Autocomplete only for constants
>>> dir(DAYS)
['FRI', 'MON', 'SAT', 'SUN', 'THU', 'TUE', 'WED']
Sorting like list.sort
>>> DAYS.sort(key=lambda (k, v): v, reverse=True)
>>> list(DAYS)
['SUN', 'SAT', 'FRI', 'THU', 'WED', 'TUE', 'MON']
Copability with python2 and python3
Simple container for constants
from collections import OrderedDict
from copy import deepcopy
class Constants(object):
"""Container of constant"""
__slots__ = ('__dict__')
def __init__(self, **kwargs):
if list(filter(lambda x: not x.isupper(), kwargs)):
raise AttributeError('Constant name should be uppercase.')
super(Constants, self).__setattr__(
'__dict__',
OrderedDict(map(lambda x: (x[0], deepcopy(x[1])), kwargs.items()))
)
def sort(self, key=None, reverse=False):
super(Constants, self).__setattr__(
'__dict__',
OrderedDict(sorted(self.__dict__.items(), key=key, reverse=reverse))
)
def __getitem__(self, name):
return self.__dict__[name]
def __len__(self):
return len(self.__dict__)
def __iter__(self):
for name in self.__dict__:
yield name
def keys(self):
return list(self)
def __str__(self):
return str(list(self))
def __repr__(self):
return '<%s: %s>' % (self.__class__.__name__, str(self.__dict__))
def __dir__(self):
return list(self)
def __setattr__(self, name, value):
raise AttributeError("Immutable attribute")
def __delattr__(*_):
raise AttributeError("Immutable attribute")
Python dictionaries are mutable, so they don't seem like a good way to declare constants:
>>> constants = {"foo":1, "bar":2}
>>> print constants
{'foo': 1, 'bar': 2}
>>> constants["bar"] = 3
>>> print constants
{'foo': 1, 'bar': 3}
In python, a constant is simply a variable with a name in all capitals, with words separated by the underscore character,
e.g
DAYS_IN_WEEK = 7
The value is mutable, as in you can change it. But given the rules for the name tell you is a constant, why would you? I mean, it is your program after all!
This is the approach taken throughout python. There is no private keyword for the same reason. Prefix the name with an underscore and you know it is intended to be private. Code can break the rule....just as a programmer could remove the private keyword anyway.
Python could have added a const keyword... but a programmer could remove keyword and then change the constant if they want to, but why do that? If you want to break the rule, you could change the rule anyway. But why bother to break the rule if the name makes the intention clear?
Maybe there is some unit test where it makes sense to apply a change to value? To see what happens for an 8 day week even though in the real world the number of days in the week cannot be changed. If the language stopped you making an exception if there is just this one case you need to break the rule...you would then have to stop declaring it as a constant, even though it still is a constant in the application, and there is just this one test case that sees what happens if it is changed.
The all upper case name tells you it is intended to be a constant. That is what is important. Not a language forcing constraints on code you have the power to change anyway.
That is the philosophy of python.
(This paragraph was meant to be a comment on those answers here and there, which mentioned namedtuple, but it is getting too long to be fit into a comment, so, here it goes.)
The namedtuple approach mentioned above is definitely innovative. For the sake of completeness, though, at the end of the NamedTuple section of its official documentation, it reads:
enumerated constants can be implemented with named tuples, but it is simpler and more efficient to use a simple class declaration:
class Status:
open, pending, closed = range(3)
In other words, the official documentation kind of prefers to use a practical way, rather than actually implementing the read-only behavior. I guess it becomes yet another example of Zen of Python:
Simple is better than complex.
practicality beats purity.
Maybe pconst library will help you (github).
$ pip install pconst
from pconst import const
const.APPLE_PRICE = 100
const.APPLE_PRICE = 200
[Out] Constant value of "APPLE_PRICE" is not editable.
You can use StringVar or IntVar, etc, your constant is const_val
val = 'Stackoverflow'
const_val = StringVar(val)
const.trace('w', reverse)
def reverse(*args):
const_val.set(val)
You can do it with collections.namedtuple and itertools:
import collections
import itertools
def Constants(Name, *Args, **Kwargs):
t = collections.namedtuple(Name, itertools.chain(Args, Kwargs.keys()))
return t(*itertools.chain(Args, Kwargs.values()))
>>> myConstants = Constants('MyConstants', 'One', 'Two', Three = 'Four')
>>> print myConstants.One
One
>>> print myConstants.Two
Two
>>> print myConstants.Three
Four
>>> myConstants.One = 'Two'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: can't set attribute
In Python, constants do not exist, but you can indicate that a variable is a constant and must not be changed by adding CONST_ to the start of the variable name and stating that it is a constant in a comment:
myVariable = 0
CONST_daysInWeek = 7 # This is a constant - do not change its value.
CONSTANT_daysInMonth = 30 # This is also a constant - do not change this value.
Alternatively, you may create a function that acts like a constant:
def CONST_daysInWeek():
return 7;
I want to implement function which takes as argument any object and trackes changes of value for specific attribute. Than saves old value of attribute in old_name attribute.
For example:
class MyObject(object):
attr_one = None
attr_two = 1
Lets name my magic function magic_function()
Sot than i can do like this:
obj = MyObject()
obj = magic_function(obj)
obj.attr_one = 'new value'
obj.attr_two = 2
and it saves old values so i can get like this
print obj.old_attr_one
None
print obj.attr_one 'new value'
and
print obj.old_attr_two
1
print obj.attr_two
2
Something like this.. I wonder how can i do this by not touching the class of instance?
This is a start:
class MagicWrapper(object):
def __init__(self, wrapped):
self._wrapped = wrapped
def __getattr__(self, attr):
return getattr(self._wrapped, attr)
def __setattr__(self, attr, val):
if attr == '_wrapped':
super(MagicWrapper, self).__setattr__('_wrapped', val)
else:
setattr(self._wrapped, 'old_' + attr, getattr(self._wrapped, attr))
setattr(self._wrapped, attr, val)
class MyObject(object):
def __init__(self):
self.attr_one = None
self.attr_two = 1
obj = MyObject()
obj = MagicWrapper(obj)
obj.attr_one = 'new value'
obj.attr_two = 2
print obj.old_attr_one
print obj.attr_one
print obj.old_attr_two
print obj.attr_two
This isn't bullet-proof when you're trying to wrap weird objects (very little in Python is), but it should work for "normal" classes. You could write a lot more code to get a little bit closer to fully cloning the behaviour of the wrapped object, but it's probably impossible to do perfectly. The main thing to be aware of here is that many special methods will not be redirected to the wrapped object.
If you want to do this without wrapping obj in some way, it's going to get messy. Here's an option:
def add_old_setattr_to_class(cls):
def __setattr__(self, attr, val):
super_setattr = super(self.__class__, self).__setattr__
if attr.startswith('old_'):
super_setattr(attr, val)
else:
super_setattr('old_' + attr, getattr(self, attr))
super_setattr(attr, val)
cls.__setattr__ = __setattr__
class MyObject(object):
def __init__(self):
self.attr_one = None
self.attr_two = 1
obj = MyObject()
add_old_setattr_to_class(obj.__class__)
obj.attr_one = 'new value'
obj.attr_two = 2
print obj.old_attr_one
print obj.attr_one
print obj.old_attr_two
print obj.attr_two
Note that this is extremely invasive if you're using it on externally provided objects. It globally modifies the class of the object you're applying the magic to, not just that one instance. This is because like several other special methods, __setattr__ is not looked up in the instance's attribute dictionary; the lookup skips straight to the class, so there's no way to just override __setattr__ on the instance. I would characterise this sort of code as a bizarre hack if I encountered it in the wild (it's "nifty cleverness" if I write it myself, of course ;) ).
This version may or may not play nicely with objects that already play tricks with __setattr__ and __getattr__/__getattribute__. If you end up modifying the same class several times, I think this still works, but you end up with an ever-increasing number of wrapped __setattr__ definitions. You should probably try to avoid that; maybe by setting a "secret flag" on the class and checking for it in add_old_setattr_to_class before modifying cls. You should probably also use a more-unlikely prefix than just old_, since you're essentially trying to create a whole separate namespace.
You can substitute all attributes with custom properties at runtime. What are you trying to achieve though? Maybe migrating to completely immutable types would be a better choice?
Why does Python not support a record type natively? It's a matter of having a mutable version of namedtuple.
I could use namedtuple._replace. But I need to have these records in a collection and since namedtuple._replace creates another instance, I also need to modify the collection which becomes messy quickly.
Background:
I have a device whose attributes I need to get by polling it over TCP/IP. i.e. its representation is a mutable object.
Edit:
I have a set of devices for whom I need to poll.
Edit:
I need to iterate through the object displaying its attributes using PyQt. I know I can add special methods like __getitem__ and __iter__, but I want to know if there is an easier way.
Edit:
I would prefer a type whose attribute are fixed (just like they are in my device), but are mutable.
Python <3.3
You mean something like this?
class Record(object):
__slots__= "attribute1", "attribute2", "attribute3",
def items(self):
"dict style items"
return [
(field_name, getattr(self, field_name))
for field_name in self.__slots__]
def __iter__(self):
"iterate over fields tuple/list style"
for field_name in self.__slots__:
yield getattr(self, field_name)
def __getitem__(self, index):
"tuple/list style getitem"
return getattr(self, self.__slots__[index])
>>> r= Record()
>>> r.attribute1= "hello"
>>> r.attribute2= "there"
>>> r.attribute3= 3.14
>>> print r.items()
[('attribute1', 'hello'), ('attribute2', 'there'), ('attribute3', 3.1400000000000001)]
>>> print tuple(r)
('hello', 'there', 3.1400000000000001)
Note that the methods provided are just a sample of possible methods.
Python ≥3.3 update
You can use types.SimpleNamespace:
>>> import types
>>> r= types.SimpleNamespace()
>>> r.attribute1= "hello"
>>> r.attribute2= "there"
>>> r.attribute3= 3.14
dir(r) would provide you with the attribute names (filtering out all .startswith("__"), of course).
Is there any reason you can't use a regular dictionary? It seems like the attributes don't have a specific ordering in your particular situation.
Alternatively, you could also use a class instance (which has nice attribute access syntax). You could use __slots__ if you wish to avoid having a __dict__ created for each instance.
I've also just found a recipe for "records", which are described as mutable named-tuples. They are implemented using classes.
Update:
Since you say order is important for your scenario (and you want to iterate through all the attributes) an OrderedDict seems to be the way to go. This is part of the standard collections module as of Python 2.7; there are other implementations floating around the internet for Python < 2.7.
To add attribute-style access, you can subclass it like so:
from collections import OrderedDict
class MutableNamedTuple(OrderedDict):
def __init__(self, *args, **kwargs):
super(MutableNamedTuple, self).__init__(*args, **kwargs)
self._initialized = True
def __getattr__(self, name):
try:
return self[name]
except KeyError:
raise AttributeError(name)
def __setattr__(self, name, value):
if hasattr(self, '_initialized'):
super(MutableNamedTuple, self).__setitem__(name, value)
else:
super(MutableNamedTuple, self).__setattr__(name, value)
Then you can do:
>>> t = MutableNamedTuple()
>>> t.foo = u'Crazy camels!'
>>> t.bar = u'Yay, attribute access'
>>> t.foo
u'Crazy camels!'
>>> t.values()
[u'Crazy camels!', u'Yay, attribute access']
This can be done using an empty class and instances of it, like this:
>>> class a(): pass
...
>>> ainstance = a()
>>> ainstance.b = 'We want Moshiach Now'
>>> ainstance.b
'We want Moshiach Now'
>>>
There's a library similar to namedtuple, but mutable, called recordtype.
Package home: http://pypi.python.org/pypi/recordtype
Simple example:
from recordtype import recordtype
Person = recordtype('Person', 'first_name last_name phone_number')
person1 = Person('Trent', 'Steele', '637-3049')
person1.last_name = 'Terrence';
print person1
# Person(first_name=Trent, last_name=Terrence, phone_number=637-3049)
Simple default value example:
Basis = recordtype('Basis', [('x', 1), ('y', 0)])
Iterate through the fields of person1 in order:
map(person1.__getattribute__, Person._fields)
This question is old, but just for the sake of completeness, Python 3.7 has dataclasses which are pretty much records.
>>> from dataclasses import dataclass
>>>
>>> #dataclass
... class MyRecord:
... name: str
... age: int = -1
...
>>> rec = MyRecord('me')
>>> rec.age = 127
>>> print(rec)
MyRecord(name='me', age=127)
The attrs third party library provides more functionality for both Python 2 and Python 3. Nothing wrong with vendoring dependencies either if the requirement is more around things you can't keep locally rather than specifically only using the stdlib. dephell has a nice helper for doing that.
This answer duplicates another one.
There is a mutable alternative to collections.namedtuple - recordclass.
It has same API and minimal memory footprint (actually it also faster). It support assignments. For example:
from recordclass import recordclass
Point = recordclass('Point', 'x y')
>>> p = Point(1, 2)
>>> p
Point(x=1, y=2)
>>> print(p.x, p.y)
1 2
>>> p.x += 2; p.y += 3; print(p)
Point(x=3, y=5)
There is more complete example (it also include performance comparisons).
In the closely related Existence of mutable named tuple in Python? question 13 tests are used for comparing 6 mutable alternatives to namedtuple.
The latest namedlist 1.7 passes all of these tests with both Python 2.7 and Python 3.5 as of Jan 11, 2016. It is a pure python implementation.
The second best candidate according to these tests is the recordclass which is a C extension. Of course, it depends on your requirements whether a C extension is preferred or not.
For further details, especially for the tests, see Existence of mutable named tuple in Python?
Based on several useful tricks gathered over time, this "frozenclass" decorator does pretty much everything needed: http://pastebin.com/fsuVyM45
Since that code is over 70% documentation and tests, I won't say more here.
Here is a complete mutable namedtuple I made, which behaves like a list and is totally compatible with it.
class AbstractNamedArray():
"""a mutable collections.namedtuple"""
def __new__(cls, *args, **kwargs):
inst = object.__new__(cls) # to rename the class
inst._list = len(cls._fields)*[None]
inst._mapping = {}
for i, field in enumerate(cls._fields):
inst._mapping[field] = i
return inst
def __init__(self, *args, **kwargs):
if len(kwargs) == 0 and len(args) != 0:
assert len(args) == len(self._fields), 'bad number of arguments'
self._list = list(args)
elif len(args) == 0 and len(kwargs) != 0:
for field, value in kwargs.items():
assert field in self._fields, 'field {} doesn\'t exist'
self._list[self._mapping[field]] = value
else:
raise ValueError("you can't mix args and kwargs")
def __getattr__(self, x):
return object.__getattribute__(self, '_list')[object.__getattribute__(self, '_mapping')[x]]
def __setattr__(self, x, y):
if x in self._fields:
self._list[self._mapping[x]] = y
else:
object.__setattr__(self, x, y)
def __repr__(self):
fields = []
for field, value in zip(self._fields, map(self.__getattr__, self._fields)):
fields.append('{}={}'.format(field, repr(value)))
return '{}({})'.format(self._name, ', '.join(fields))
def __iter__(self):
yield from self._list
def __list__(self):
return self._list[:]
def __len__(self):
return len(self._fields)
def __getitem__(self, x):
return self._list[x]
def __setitem__(self, x, y):
self._list[x] = y
def __contains__(self, x):
return x in self._list
def reverse(self):
self._list.reverse()
def copy(self):
return self._list.copy()
def namedarray(name, fields):
"""used to construct a named array (fixed-length list with named fields)"""
return type(name, (AbstractNamedarray,), {'_name': name, '_fields': fields})
You could do something like thisdictsubclass which is its own __dict__. The basic concept is the same as that of the ActiveState AttrDict recipe, but the implementation is simpler. The result is something more mutable than you need since both an instance's attributes and their values are changeable. Although the attributes aren't ordered, you can iterate through the current ones and/or their values.
class Record(dict):
def __init__(self, *args, **kwargs):
super(Record, self).__init__(*args, **kwargs)
self.__dict__ = self
As tzot stated, since Python ≥3.3, Python does have a mutable version of namedtuple: types.SimpleNamespace.
These things are very similar to the new C# 9 Records.
Here are some usage examples:
Positional constructor arguments
>>> import types
>>>
>>> class Location(types.SimpleNamespace):
... def __init__(self, lat=0, long=0):
... super().__init__(lat=lat, long=long)
...
>>> loc_1 = Location(49.4, 8.7)
Pretty repr
>>> loc_1
Location(lat=49.4, long=8.7)
Mutable
>>> loc_2 = Location()
>>> loc_2
Location(lat=0, long=0)
>>> loc_2.lat = 49.4
>>> loc_2
Location(lat=49.4, long=0)
Value semantics for equality
>>> loc_2 == loc_1
False
>>> loc_2.long = 8.7
>>> loc_2 == loc_1
True
Can add attributes at runtime
>>> loc_2.city = 'Heidelberg'
>>> loc_2
Is there a built-in method in Python to get an array of all a class' instance variables? For example, if I have this code:
class hi:
def __init__(self):
self.ii = "foo"
self.kk = "bar"
Is there a way for me to do this:
>>> mystery_method(hi)
["ii", "kk"]
Edit: I originally had asked for class variables erroneously.
Every object has a __dict__ variable containing all the variables and its values in it.
Try this
>>> hi_obj = hi()
>>> hi_obj.__dict__.keys()
Output
dict_keys(['ii', 'kk'])
Use vars()
class Foo(object):
def __init__(self):
self.a = 1
self.b = 2
vars(Foo()) #==> {'a': 1, 'b': 2}
vars(Foo()).keys() #==> ['a', 'b']
You normally can't get instance attributes given just a class, at least not without instantiating the class. You can get instance attributes given an instance, though, or class attributes given a class. See the 'inspect' module. You can't get a list of instance attributes because instances really can have anything as attribute, and -- as in your example -- the normal way to create them is to just assign to them in the __init__ method.
An exception is if your class uses slots, which is a fixed list of attributes that the class allows instances to have. Slots are explained in http://www.python.org/2.2.3/descrintro.html, but there are various pitfalls with slots; they affect memory layout, so multiple inheritance may be problematic, and inheritance in general has to take slots into account, too.
Both the Vars() and dict methods will work for the example the OP posted, but they won't work for "loosely" defined objects like:
class foo:
a = 'foo'
b = 'bar'
To print all non-callable attributes, you can use the following function:
def printVars(object):
for i in [v for v in dir(object) if not callable(getattr(object,v))]:
print '\n%s:' % i
exec('print object.%s\n\n') % i
You can also test if an object has a specific variable with:
>>> hi_obj = hi()
>>> hasattr(hi_obj, "some attribute")
False
>>> hasattr(hi_obj, "ii")
True
>>> hasattr(hi_obj, "kk")
True
Your example shows "instance variables", not really class variables.
Look in hi_obj.__class__.__dict__.items() for the class variables, along with other other class members like member functions and the containing module.
class Hi( object ):
class_var = ( 23, 'skidoo' ) # class variable
def __init__( self ):
self.ii = "foo" # instance variable
self.jj = "bar"
Class variables are shared by all instances of the class.
Suggest
>>> print vars.__doc__
vars([object]) -> dictionary
Without arguments, equivalent to locals().
With an argument, equivalent to object.__dict__.
In otherwords, it essentially just wraps __dict__
Although not directly an answer to the OP question, there is a pretty sweet way of finding out what variables are in scope in a function. take a look at this code:
>>> def f(x, y):
z = x**2 + y**2
sqrt_z = z**.5
return sqrt_z
>>> f.func_code.co_varnames
('x', 'y', 'z', 'sqrt_z')
>>>
The func_code attribute has all kinds of interesting things in it. It allows you todo some cool stuff. Here is an example of how I have have used this:
def exec_command(self, cmd, msg, sig):
def message(msg):
a = self.link.process(self.link.recieved_message(msg))
self.exec_command(*a)
def error(msg):
self.printer.printInfo(msg)
def set_usrlist(msg):
self.client.connected_users = msg
def chatmessage(msg):
self.printer.printInfo(msg)
if not locals().has_key(cmd): return
cmd = locals()[cmd]
try:
if 'sig' in cmd.func_code.co_varnames and \
'msg' in cmd.func_code.co_varnames:
cmd(msg, sig)
elif 'msg' in cmd.func_code.co_varnames:
cmd(msg)
else:
cmd()
except Exception, e:
print '\n-----------ERROR-----------'
print 'error: ', e
print 'Error proccessing: ', cmd.__name__
print 'Message: ', msg
print 'Sig: ', sig
print '-----------ERROR-----------\n'
Sometimes you want to filter the list based on public/private vars. E.g.
def pub_vars(self):
"""Gives the variable names of our instance we want to expose
"""
return [k for k in vars(self) if not k.startswith('_')]
built on dmark's answer to get the following, which is useful if you want the equiv of sprintf and hopefully will help someone...
def sprint(object):
result = ''
for i in [v for v in dir(object) if not callable(getattr(object, v)) and v[0] != '_']:
result += '\n%s:' % i + str(getattr(object, i, ''))
return result
You will need to first, examine the class, next, examine the bytecode for functions, then, copy the bytecode, and finally, use the __code__.co_varnames. This is tricky because some classes create their methods using constructors like those in the types module. I will provide code for it on GitHub.
Based on answer of Ethan Joffe
def print_inspect(obj):
print(f"{type(obj)}\n")
var_names = [attr for attr in dir(obj) if not callable(getattr(obj, attr)) and not attr.startswith("__")]
for v in var_names:
print(f"\tself.{v} = {getattr(obj, v)}\n")