Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Class extension in Python like in Swift?

I am new to Python, coming from Swift, and I am wondering about the following. In Swift, if I would like to add functionality to an existing class, I can do something like this (as in the book example):

extension Double {
    var km: Double { return self * 1_000.0 }
    var m: Double { return self }
    var cm: Double { return self / 100.0 }
    var mm: Double { return self / 1_000.0 }
    var ft: Double { return self / 3.28084 }
}
let oneInch = 25.4.mm

I really like this functionality and I was wondering if there is something similar in Python. Or if there is some other way much better that I do not see and hence this does not make any sense in Python.

like image 618
dre_84w934 Avatar asked Dec 17 '25 19:12

dre_84w934


2 Answers

For the sake of completeness, I think this is what you should do (In Swift as well!):

class Meter(float):
    def to_km(self): return self * 1000.0 
    def to_m (self): return self 
    def to_cm(self): return self / 100.0 
    def to_mm(self): return self / 1000.0 
    def to_ft(self): return self / 3.28084 

oneInch = Meter(25.4).to_mm()
print(oneInch)

Make it clear that your object represents a meter, and that you are converting it to something.

If you want some syntactic sugar, that I am not sure is helpful, you can override the item getter so you do not have to use ():

class Meter(float):
    conversions = {
        'km':1000,
        'cm':.01,
        'mm':.001,
        'ft':1/3.28084
    }
    def __getattr__(self,x):
        try:
            return self*Meter.conversions[x]
        except KeyError:
            raise KeyError("No such conversion!")

oneInch = Meter(25.4).mm
print(oneInch)

Adding conversions is as simple as:

Meter.conversions['whatever'] = 123.123
like image 144
kabanus Avatar answered Dec 19 '25 08:12

kabanus


No, you can't extend builtin classes like float or int.

>>> int.double = lambda self: self * 2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't set attributes of built-in/extension type 'int'

(You can modify non-builtin classes though, but you really shouldn't, as code doing that is hard to reason about.)

Your particular example is better served by an unit library like pint -- using libraries like that prevents you from making $125 million mistakes doing math between metric and imperial units, too.

like image 28
AKX Avatar answered Dec 19 '25 10:12

AKX



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!