This page looks best with JavaScript enabled

Reflection in Python: getattr

 ·  ☕ 2 min read

1. Application Scenarios

  1. Control the program’s runtime flow through a configuration file. What a configuration file usually holds is a string, not an object.
  2. When debugging a program, inspect all the attribute values of an object.
  3. Dynamic module import.

For the first scenario, reflection is the widely adopted approach. Many Java frameworks use the reflection mechanism, and Django, a Web framework implemented in Python, applies it too — URL routing, for example. In the second scenario, manually adding output for an object’s attributes is extremely tedious and still incomplete. Here you can use dir(object) to list all attributes and then use reflection to access them. The third scenario can also be achieved through reflection.

2. Python’s Reflection

Through reflection, a string can be associated with an object’s attribute. With dir(object) you can view the attribute list of an object.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# -*- coding: utf-8 -*-
class Person:
    '''
    Python反射的一个举例
    '''
    count = 0

    def __init__(self, name="none", salary="0"):
        self.name = name
        self.salary = salary
        Person.count += 1

    def getName(self):
        print "i am in getName() function"
        return self.name


>>> p = Person(name="csw")
>>> dir(p)
['__doc__', '__init__', '__module__', 'count', 'getName', 'name', 'salary']
>>> hasattr(p, 'count')
True
>>> getattr(p, 'count')
1
>>> getattr(p, 'getName')()
i am in getName() function
csw
>>> setattr(p, 'ModifiedName', 'name')
None
>>> delattr(p, 'name')
None
>>> dir(p)
['ModifiedName', '__doc__', '__init__', '__module__', 'count', 'getName', 'salary']
>>> getattr(p, 'getName')()
AttributeError: Person instance has no attribute 'name'

2.1 getattr

Form: getattr(object, ’name’, ‘default’)

Description: if an attribute or method named name exists, return that attribute or method; otherwise return the default.

2.2 hasattr

Form: hasattr(object, ’name')

Description: determine whether the object contains an attribute or method named name; return True if it exists, otherwise False. hasattr is implemented by calling getattr(object, ’name’) and checking whether it throws an exception.

2.3 setattr

Form: setattr(object, ’name’, ‘default’)

Description: set the name attribute of the object to default; if the name attribute does not exist, create a new attribute.

2.4 delattr

Form: delattr(object, ’name')

Description: delete the name attribute of the object.

3. How Python Implements Reflection

The globals() function returns a dictionary { key:value }, where key is the name of the object and value is the instance of the object.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
>>> globals()
{'__builtins__': <module '__builtin__' (built-in)>,
 '__file__': 'E:/code/lab/python-reflection/exapmle.py',
 '__package__': None, 'Person': <class __main__.Person at 0x00215FB8>,
'__name__': '__main__', '__doc__': None}

>>> import test
{'__builtins__': <module '__builtin__' (built-in)>,
 '__file__': 'E:/code/lab/python-reflection/exapmle.py',
'__package__': None, 'Person': <class __main__.Person at 0x02045FB8>,
 'test': <module 'test' from 'D:\Python2711\lib\test\__init__.pyc'>,
'__name__': '__main__', '__doc__': None}

>>> globals()['test']
<module 'test' from 'D:\Python2711\lib\test\__init__.pyc'>

After executing import test, you can see that a new test key has been added. You can use this to implement functionality similar to Java’s Class.forName(). But with this approach you must import first, otherwise it throws an exception.

Python provides the __import__(“functionName”) function: pass the argument “functionName” and the functionName module is imported. Combine it with the getattr function to make the relevant call.

4. Why Not Just Use exec and eval

Those familiar with Python should know that the exec and eval statements can also execute Python statements stored in a string or a file.
For example:

1
2
3
4
>>> eval('2*3')
6
>>> eval("2+3")
5

So why use reflection at all? exec and eval can achieve the same functionality, but reflection is a programming approach, an embodiment of design patterns. Reflection embodies the software design ideas of high cohesion and low coupling, and cannot simply be replaced by a function that executes a string.


WeChat Official Account
WRITTEN BY
WeChat Official Account