Skip to content

Instantly share code, notes, and snippets.

@devforfu

devforfu/new_simple.py

Last active Feb 14, 2018
Embed
What would you like to do?
Simple example of __new__ method usage
"""
An example of usage of __new__ magic method to implement dynamic computational
logic dispatching.
For more information see: https://iliazaitsev.me/blog/2018/02/14/python-new
"""
import abc
class TemperatureConverter(metaclass=abc.ABCMeta):
"""
Base class of temperature converters which supports dynamic substitution
of implementations.
"""
symbol = 'K'
def __new__(cls, convert_to='celsius'):
if issubclass(cls, TemperatureConverter):
if convert_to == 'celsius':
cls = _CelsiusConverter
elif convert_to == 'fahrenheit':
cls = _FahrenheitConverter
else:
raise ValueError('unexpected converter: %s' % convert_to)
return object.__new__(cls)
def convert(self, value):
"""
Converts temperature from Kelvin degrees into format defined by
concrete implementation.
"""
self.check_value(value)
return self._convert(value)
def format(self, value):
return '%.2f (%s)' % (self.convert(value), self.symbol)
@staticmethod
def check_value(value):
if value < 0:
raise ValueError('temperature should be provided in Kelvin degrees')
@property
def name(self):
return self.__class__.__name__.strip('_')
def _convert(self, value):
raise NotImplementedError()
class _CelsiusConverter(TemperatureConverter):
"""
Concrete implementation of temperature converted which converts from Kelvin
into Celsius degrees.
"""
symbol = '°C'
def _convert(self, value):
return value - 273.15
class _FahrenheitConverter:
"""
Concrete implementation of temperature converter which converts from Kelvin
into Fahrenheit degrees.
Note that this class does not directly inherit base class, but is
registered as derived class using ABCMeta.register method. Though in this
case, there is no a default implementation of `format` method and `name`
property.
"""
symbol = '°F'
def _convert(self, value):
return value * 9./5 - 459.67
def format(self, value):
return '%.2f (%s)' % (self._convert(value), self.symbol)
@property
def name(self):
return 'FahrenheitConverter'
TemperatureConverter.register(_FahrenheitConverter)
def main():
converters = [
TemperatureConverter(convert_to=name)
for name in ('celsius', 'fahrenheit')]
temperature = 300
for converter in converters:
string = converter.format(temperature)
print('%s converted %sK temperature into: %s' % (
converter.name, temperature, string
))
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.