Расширение класса в Python, как в Swift?

Я новичок в Python, пришедший из swift, и меня интересует следующее. В быстром, если я хотел бы добавить функциональность к существующему классу, я могу сделать что-то вроде этого (как в примере с книгой):

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

Мне действительно нравится эта функциональность, и мне было интересно, есть ли что-то подобное в python, или есть какой-то другой способ, который я не вижу лучше, и, следовательно, это не имеет никакого смысла в python.

3 ответа

Решение

Ради полноты я думаю, что именно это вам и следует сделать (и в Swift!):

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)

Дайте понять, что ваш объект представляет собой метр, и что вы конвертируете его во что-то.

Если вам нужен синтаксический сахар, который, я не уверен, полезен, вы можете переопределить средство получения элементов, чтобы вам не приходилось использовать ():

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)

Добавить конверсию так же просто, как:

Meter.conversions['whatever'] = 123.123

Нет, вы не можете расширять встроенные классы, такие как float или же 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'

(Вы можете модифицировать не встроенные классы, но на самом деле не следует этого делать, так как в коде сложно об этом думать.)

Ваш конкретный пример лучше обслуживается такой библиотекой, как pint - использование таких библиотек не позволяет вам делать ошибки в 125 миллионов долларов, делая математику между метрическими и имперскими единицами.

Вы можете создавать дочерние классы родительских классов. Если вы пишете свой собственный код, иногда это хорошая идея, но расширение чего-то вроде фрейма данных Pandas, вероятно, плохая идея.

Я не тратил много времени на поиск в Google, но это лучшее, что я нашел: https://docs.python.org/3/tutorial/classes.html

Это также действительно плохой код, который я написал, пытаясь объяснить наследование классов моей девушке. Обратите внимание, что Car класс все равно будет car.roll_up_windows() а также car.roll_down_windows() и __repr__:

class Plant(object):
    def __init__(self, color, seeds):
        self.color = color
        self.seeds = seeds

class Fruit(Plant):
    def __init__(self, color, defense):
        self.color = color
        self.seeds = True
        self.defense = defense

class Vehicle(object):
    def __init__(self, num_tires, engine_size, fuel_type):
        self.num_tires = num_tires
        self.engine_size = engine_size
        self.fuel_type = fuel_type
        self.windows = 'up'

    def roll_down_windows(self):
        self.windows = 'down'
    def roll_up_windows(self):
        self.windows = 'up'

    def __repr__(self):
        print("This is a vehicle. \nIt has {} tires. \nIts engine has {} liters. \nIt runs on {}. \nIt's windows are {}.".format(self.num_tires, self.engine_size, self.fuel_type, self.windows))

class Car(Vehicle):
    def __init__(self, num_tires=4, engine_size, fuel_type):
        self.num_tires = num_tires
        self.engine_size = engine_size
        self.fuel_type = fuel_type
        self.windows = 'up'
Другие вопросы по тегам