Last active
December 24, 2015 09:09
-
-
Save soedar/6775790 to your computer and use it in GitHub Desktop.
Data Abstraction
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ## Data Abstraction | |
| # Variable Naming | |
| # The key idea behind data abstraction is that we want to give meaning to data types. We already have | |
| # seen how the naming your variables more meaninfully would help us give meaning to primitive data. | |
| # For instance, | |
| x = 24 # Not exactly clear what x refers to, and what does 24 mean | |
| # Consider: | |
| room_temperature = 24 # Now, we can probably infer that 24 is degree celsius, just by naming our | |
| # variables meaningfully. | |
| # However, we definitely can do better than that. We have simply inferred that the temperature is | |
| # represented in celsius. We can of course rename it to room_temperature_c, however that is not an | |
| # elegant solution to model the problem. | |
| ######### | |
| # Data Abstraction | |
| ######### | |
| # Clearly, one variable is not enough to represent the temperature of room. We need a way to represent | |
| # the temperature with both the value of the temperature, as well as the unit of the temperature. From | |
| # what we have learned so far in data abstraction, we can make use of a tuple to represent this | |
| # information: | |
| temperature = (24, 'C') # The 2nd parameter determines the type of temperature. | |
| # The thing to note about in this case is that the although technically, the temperature variable | |
| # holds a tuple, but that is not exactly accurate. The more accurate description is that the temperature | |
| # variable now *holds the representation of a temperature*, which in this case happens to be a tuple. | |
| # With this representation, we can define the following: | |
| #Constructor | |
| def make_temperature_c(deg): | |
| return (deg, 'C') | |
| # Accessors. Accessors take in a temperature type, and return the part of the temperature that | |
| # we are interested in. | |
| def temperature_value(temperature): | |
| # Since we know the temperature is represented by the tuple (value, units), we | |
| # return the first element of the tuple. | |
| return temperature[0] | |
| def temperature_unit(temperature) | |
| return temperature[1] | |
| ##################### | |
| # Using temperature | |
| ##################### | |
| # With this, we can create the following function that makes use of the accessors: | |
| # Fan takes in a temperature, and reduces it by 0.5 deg C | |
| def fan(temperature): | |
| new_temp = temperature_value(temperature) - 0.5 | |
| return make_temperature_c(new_temp) | |
| # Note that by making use of the constructors and accessors, we are able to treat the temperature NOT | |
| # as a tuple, but as a REPRESENTATION of the temperature, and that this representation will be | |
| # independent of what is the underlying implementation of the temperature type. | |
| ######################## | |
| # Breaking Abstraction | |
| ######################## | |
| # In your missions, I have commented that some of you have broken abstraction. What I meant by that | |
| # is, that instead of writing the above code, you can techincally write the following and it would work | |
| # as expected (in this case) | |
| # Breaking the abstraction | |
| def fan(temperature): | |
| return (temperature[0]-0.5, temperature[1]) | |
| # By breaking the abstraction, I meant that your functions now 'know' that temperature is represented | |
| # as a tuple, with the first element as value, and the 2nd element as unit. Contrast with the first | |
| # example of fan, when the function know NOTHING about how temperature is implemented, as how it is | |
| # implemented has been has been taken care of by the constructors and accessors | |
| ############ | |
| # Rationale | |
| ############ | |
| # Why do we need the abstraction? Imagine one day, you decide that perhaps the best way to represent | |
| # the data is to put the unit first, as a character. So you decide to re-write your constructors as | |
| # follow: | |
| def make_temperature_c(deg): | |
| return ('C', deg) | |
| def temperature_value(temperature): | |
| return temperature[1] | |
| def temperature_unit(temperature): | |
| return temperature[0] | |
| # Or if I decide to go crazy, and implement it like this: | |
| def make_temperature(deg): | |
| return deg + "_C" | |
| def temperature_value(temperature): | |
| # temperature is a string separated by _ | |
| return temperature.split('_')[0] | |
| def temperature_unit(temperature): | |
| return temperature.split('_')[1] | |
| # Do you notice that although I have changed the representation of the of what a temperature is, the | |
| # fan code in the first case will NOT break, because we are using the accessors to access the parts of | |
| # the temperature 'type', and not making any assumption of what the underlying implementation of the | |
| # data structure? | |
| ############## | |
| # Bonus Question | |
| ############## | |
| # 1) In the most common case of using a tuple to represent a temperature, how can we differentiate a | |
| # tuple that represent a temperature, vs any other tuples? |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment