#!/usr/bin/env python # coding: utf-8 # In[1]: # Copyright 2014 Brett Slatkin, Pearson Education Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Preamble to mimick book environment import logging from pprint import pprint from sys import stdout as STDOUT # ## From other language, we love to use getter and setter, but not in Python! # In[2]: # Example 1 class OldResistor(object): def __init__(self, ohms): self._ohms = ohms def get_ohms(self): return self._ohms def set_ohms(self, ohms): self._ohms = ohms # In[3]: # Example 2 r0 = OldResistor(50e3) print('Before: %5r' % r0.get_ohms()) r0.set_ohms(10e3) print('After: %5r' % r0.get_ohms()) # In[4]: # Example 3 r0.set_ohms(r0.get_ohms() + 5e3) # ## Just use simple public attributes # In[5]: # Example 4 class Resistor(object): def __init__(self, ohms): self.ohms = ohms self.voltage = 0 self.current = 0 r1 = Resistor(50e3) r1.ohms = 10e3 print('%r ohms, %r volts, %r amps' % (r1.ohms, r1.voltage, r1.current)) # In[6]: # Example 5 r1.ohms += 5e3 # In[7]: # Example 6 class VoltageResistance(Resistor): def __init__(self, ohms): super().__init__(ohms) self._voltage = 0 @property def voltage(self): return self._voltage @voltage.setter def voltage(self, voltage): self._voltage = voltage self.current = self._voltage / self.ohms # In[8]: # Example 7 r2 = VoltageResistance(1e3) print('Before: %5r amps' % r2.current) r2.voltage = 10 print('After: %5r amps' % r2.current) # ## @property decorator and its corresponding setter attribute? Why?? # In[9]: # Example 8 class BoundedResistance(Resistor): def __init__(self, ohms): super().__init__(ohms) @property def ohms(self): return self._ohms @ohms.setter def ohms(self, ohms): if ohms <= 0: raise ValueError('%f ohms must be > 0' % ohms) self._ohms = ohms # In[10]: # Example 9 try: r3 = BoundedResistance(1e3) r3.ohms = 0 except: logging.exception('Expected') else: assert False # In[11]: # Example 10 try: BoundedResistance(-5) except: logging.exception('Expected') else: assert False # In[12]: # Example 11 class FixedResistance(Resistor): def __init__(self, ohms): super().__init__(ohms) @property def ohms(self): return self._ohms @ohms.setter def ohms(self, ohms): if hasattr(self, '_ohms'): raise AttributeError("Can't set attribute") self._ohms = ohms # In[13]: # Example 12 try: r4 = FixedResistance(1e3) r4.ohms = 2e3 except: logging.exception('Expected') else: assert False # In[14]: # Example 13 class MysteriousResistor(Resistor): @property def ohms(self): self.voltage = self._ohms * self.current return self._ohms @ohms.setter def ohms(self, ohms): self._ohms = ohms # In[15]: # Example 14 r7 = MysteriousResistor(10) r7.current = 0.01 print('Before: %5r' % r7.voltage) r7.ohms print('After: %5r' % r7.voltage)