.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "auto_examples/oop/__getattr__.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note Click :ref:`here ` to download the full example code or to run this example in your browser via Binder .. rst-class:: sphx-glr-example-title .. _sphx_glr_auto_examples_oop___getattr__.py: ================== 3.15 __getattr__ ================== This lesson describes the usage of ``__getattr__`` .. GENERATED FROM PYTHON SOURCE LINES 11-13 If a ``class`` (more correctly ab object) does not have an attribute and we try to access this attribute we will get ``AttributeError``. .. GENERATED FROM PYTHON SOURCE LINES 13-23 .. code-block:: default class Human: pass h = Human() # uncomment following 1 line # h.horns .. GENERATED FROM PYTHON SOURCE LINES 24-26 The `Human` class does not have an attribute `horns` and therefore when we run `h.horns`, we will get AttributeError .. GENERATED FROM PYTHON SOURCE LINES 28-31 However, if we want to avoid such an error, we can overwrite ``__getattr__`` method of the class. This method must take one input argument. .. GENERATED FROM PYTHON SOURCE LINES 31-42 .. code-block:: default class Human: def __getattr__(self, item): print(f"attribute {item} has not been set to Human") return h = Human() print(h.horns) .. rst-class:: sphx-glr-script-out .. code-block:: none attribute horns has not been set to Human None .. GENERATED FROM PYTHON SOURCE LINES 43-47 When python tries to search attributes of a class, then ``__getattr__`` method is called at the end of its search. If this method is not overwritten by the user, python will raise ``AttributeError``, as it was done earlier. .. GENERATED FROM PYTHON SOURCE LINES 50-51 One advantage/usage of this method is what we can call *dynamic attribute creation*. .. GENERATED FROM PYTHON SOURCE LINES 51-119 .. code-block:: default TempUnitConverter = { "FAHRENHEIT": { "Fahrenheit": lambda fahrenheit: fahrenheit, # fahrenheit to Centigrade "Kelvin": lambda fahrenheit: [(x + 459.67) * 5/9 for x in fahrenheit], # fahrenheit to kelvin "Centigrade": lambda fahrenheit: [(x - 32.0) / 1.8 for x in fahrenheit] # fahrenheit to Centigrade }, "KELVIN": { "Fahrenheit": lambda kelvin: [x * 9/5 - 459.67 for x in kelvin], # kelvin to fahrenheit "Kelvin": lambda k: k, # Kelvin to Kelvin "Centigrade": lambda kelvin: [x - 273.15 for x in kelvin] # kelvin to Centigrade} }, "CENTIGRADE": { "Fahrenheit": lambda centigrade: [x * 1.8 + 32.0 for x in centigrade], # Centigrade to fahrenheit "Kelvin": lambda centigrade: [x + 273.15 for x in centigrade], # Centigrade to kelvin "Centigrade": lambda centigrade: centigrade } } class Temperature(object): """ The idea is to write the conversion functions in a dictionary and then dynamically create attribute if the attribute is present in converter as key otherwise raise WongUnitError. converts temperature among units [kelvin, centigrade, fahrenheit] """ def __init__(self, val, input_unit): self.val = val self.input_unit = input_unit def __getattr__(self, out_unit): # pycharm calls this method for its own working, executing default behaviour at such calls if out_unit.startswith('_'): return self.__getattribute__(out_unit) else: if out_unit not in TempUnitConverter[self.input_unit]: raise ValueError(f"output in {out_unit} is not allowed. Allowed units are: ", self.allowed) val = TempUnitConverter[self.input_unit][str(out_unit)](self.val) return val @property def allowed(self): return list(list(TempUnitConverter.values())[0].keys()) @property def input_unit(self): return self._input_unit @input_unit.setter def input_unit(self, in_unit): if in_unit.upper() == 'CELSIUS': in_unit = 'CENTIGRADE' if in_unit.upper() not in TempUnitConverter: raise ValueError(f"Input in {in_unit} is not allowed", self.allowed) self._input_unit = in_unit.upper() temp = [i for i in range(10)] T = Temperature(temp, 'Centigrade') print(T.Kelvin) .. rst-class:: sphx-glr-script-out .. code-block:: none [273.15, 274.15, 275.15, 276.15, 277.15, 278.15, 279.15, 280.15, 281.15, 282.15] .. GENERATED FROM PYTHON SOURCE LINES 120-123 .. code-block:: default print(T.Fahrenheit) .. rst-class:: sphx-glr-script-out .. code-block:: none [32.0, 33.8, 35.6, 37.4, 39.2, 41.0, 42.8, 44.6, 46.4, 48.2] .. GENERATED FROM PYTHON SOURCE LINES 124-127 .. code-block:: default print(T.Centigrade) .. rst-class:: sphx-glr-script-out .. code-block:: none [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] .. GENERATED FROM PYTHON SOURCE LINES 128-131 Above we did not explicitly defined ``Kelvin``, ``Fahrenheit`` or ``Centigrade`` attributes of the ``Temperature`` class. but these attributes are created after ``__getattr__`` method is called. .. GENERATED FROM PYTHON SOURCE LINES 131-138 .. code-block:: default T = Temperature(temp, 'Fahrenheit') print(T.Centigrade) print(T.Kelvin) .. rst-class:: sphx-glr-script-out .. code-block:: none [-17.77777777777778, -17.22222222222222, -16.666666666666668, -16.11111111111111, -15.555555555555555, -15.0, -14.444444444444445, -13.88888888888889, -13.333333333333332, -12.777777777777777] [255.3722222222222, 255.92777777777778, 256.48333333333335, 257.0388888888889, 257.59444444444443, 258.15, 258.7055555555555, 259.2611111111111, 259.81666666666666, 260.3722222222222] .. GENERATED FROM PYTHON SOURCE LINES 139-144 .. code-block:: default T = Temperature(temp, 'Kelvin') print(T.Centigrade) print(T.Fahrenheit) .. rst-class:: sphx-glr-script-out .. code-block:: none [-273.15, -272.15, -271.15, -270.15, -269.15, -268.15, -267.15, -266.15, -265.15, -264.15] [-459.67, -457.87, -456.07, -454.27000000000004, -452.47, -450.67, -448.87, -447.07, -445.27000000000004, -443.47] .. GENERATED FROM PYTHON SOURCE LINES 145-149 **Questions:** * Why `Temperature(temp, 'Celsius').Kelvin` works but not `Temperature(temp, 'Celsius').Celsius`? * Change the `Temperature` class so that T.centigrade gives same answer as that of `T.Centigrade`. * Change the `Temperature` class so that `T.Celsius` also works. .. rst-class:: sphx-glr-timing **Total running time of the script:** ( 0 minutes 0.004 seconds) .. _sphx_glr_download_auto_examples_oop___getattr__.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: binder-badge .. image:: images/binder_badge_logo.svg :target: https://mybinder.org/v2/gh/AtrCheema/python-seekho/master?urlpath=lab/tree/notebooks/auto_examples/oop/__getattr__.ipynb :alt: Launch binder :width: 150 px .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: __getattr__.py <__getattr__.py>` .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: __getattr__.ipynb <__getattr__.ipynb>` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_