A basic idea of how you can implement factories in Python, and what they are used for.
#!/usr/bin/env python | |
# Here, we are going to implement a Robot. This robot has a lot of attributes - and | |
# we are going to want to make these accessible through a public interface. | |
# CHANGE LIST: | |
# - Added an object that we are using in order to map strings to indexes | |
# in our data source. This is useful for making things a bit more user | |
# friendly in some cases. Usually with more complicated data sources. | |
# | |
# - Added __getitem__ method, which will allow us to access arbitrary data | |
# without needed any new code added if the data source's data changes. | |
# | |
# - Modified the robot to get properties through a factory to reduce the | |
# amount of code duplication as the number of attributes becomes larger | |
arbitrary_data_source = { | |
'weight': 20.5, | |
'height': 14.3, | |
'arm_count': 2, | |
'leg_count': 4 | |
} | |
def robot_getter_factory(index): | |
""" Given 'index', this returns a function that can be used to get that | |
index from the data attribute of the context passed to it. | |
""" | |
def getter(context): | |
return context.data[index] | |
return getter | |
class Robot(object): | |
""" This is a robot. He is neat. """ | |
data = arbitrary_data_source | |
data_aliases = { | |
'arms': 'arm_count', | |
'legs': 'leg_count', | |
} | |
# Use the getter factory to create our getters, so that we don't need to | |
# repeat ourselves with the same code over and over again. | |
get_weight = robot_getter_factory('weight') | |
get_height = robot_getter_factory('height') | |
get_arm_count = robot_getter_factory('arm_count') | |
get_leg_count = robot_getter_factory('leg_count') | |
def __getitem__(self, index): | |
""" Allows our object to be accessed with [] operators - like a you | |
would access a dict. | |
""" | |
# If the provided index is an alias, get the value of the map that | |
# resolves to it's real identifier in the data source. | |
if index in self.data_aliases: | |
index = self.data_aliases[index] | |
getter_method = robot_getter_factory(index) | |
# We need to pass 'self' explicitly here, since our function isn't | |
# being hosted as an object method - but as a normal function instead. | |
return getter_method(self) | |
if __name__ == '__main__': | |
my_robot = Robot() | |
def robot_status_output(description, value): | |
result = 'My robot ' + description.format(value) | |
return result | |
robot_status_map = { | |
'weighs {0} pounds.': my_robot['weight'], | |
'is {0} feet tall.': my_robot['height'], | |
'has {0} legs.': my_robot['legs'], | |
'has {0} arms.': my_robot['arms'], | |
} | |
# I should probably have used a generator expression here... | |
for description, value in robot_status_map.iteritems(): | |
print robot_status_output(description, value) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment