Есть ли способ получить специальный полиморфизм в Python?
Многие языки поддерживают специальный полиморфизм (перегрузка функций) из коробки. Однако, похоже, что Python отказался от этого. Тем не менее, я могу предположить, что может быть какая-то хитрость или библиотека, способная осуществить это в Python. Кто-нибудь знает такой инструмент?
Например, в Haskell можно использовать это для генерации тестовых данных для разных типов:
-- In some testing library:
class Randomizable a where
genRandom :: a
-- Overload for different types
instance Randomizable String where genRandom = ...
instance Randomizable Int where genRandom = ...
instance Randomizable Bool where genRandom = ...
-- In some client project, we might have a custom type:
instance Randomizable VeryCustomType where genRandom = ...
Прелесть этого в том, что я могу продлить genRandom
для моих собственных пользовательских типов, не касаясь библиотеки тестирования.
Как бы вы достигли чего-то подобного в Python?
3 ответа
Python не является строго типизированным языком, поэтому действительно не имеет значения, есть ли у вас экземпляр Randomizable или экземпляр какого-то другого класса, который имеет те же методы.
Один из способов получить то, что вы хотите, может быть таким:
types_ = {}
def registerType ( dtype , cls ) :
types_[dtype] = cls
def RandomizableT ( dtype ) :
return types_[dtype]
Во-первых, да, я определил функцию с заглавной буквой, но она должна действовать как класс. Например:
registerType ( int , TheLibrary.Randomizable )
registerType ( str , MyLibrary.MyStringRandomizable )
Тогда позже:
type = ... # get whatever type you want to randomize
randomizer = RandomizableT(type) ()
print randomizer.getRandom()
Функция Python не может быть автоматически специализирована на основе статической типизации во время компиляции. Поэтому его результат может зависеть только от его аргументов, полученных во время выполнения и от глобальной (или локальной) среды, если только сама функция не может быть модифицирована на месте и может нести некоторое состояние.
Ваша общая функция genRandom
не принимает аргументов, кроме информации о наборе. Таким образом, в Python он должен по крайней мере получить тип в качестве аргумента. Поскольку встроенные классы не могут быть изменены, реализация обобщенной функции (экземпляра) для таких классов должна каким-либо образом предоставляться через глобальную среду или включаться в саму функцию.
Я обнаружил, что начиная с Python 3.4, есть @functools.singledispatch
декоратор. Однако он работает только для функций, которые получают экземпляр типа (объект) в качестве первого аргумента, поэтому неясно, как его можно применить в вашем примере. Я также немного смущен его обоснованием:
Кроме того, в настоящее время для кода Python является обычным антипаттерном проверять типы полученных аргументов, чтобы решить, что делать с объектами.
Я понимаю, что анти-паттерн - это жаргонный термин для паттерна, который считается нежелательным (и вовсе не означает отсутствие паттерна). Таким образом, обоснование утверждает, что проверка типов аргументов нежелательна, и эта претензия используется для обоснования введения инструмента, который упростит... диспетчеризацию типа аргумента. (Между прочим, обратите внимание, что согласно PEP 20 "явное лучше, чем неявное".)
Раздел "Альтернативные подходы" в PEP 443 "Универсальные функции с одной отправкой", тем не менее, заслуживает прочтения. Есть несколько ссылок на возможные решения, в том числе один на статью "Пятиминутные мультиметоды в Python" Гвидо ван Россума от 2005 года.
Имеет ли это значение полиморфизм рекламы?
class A:
def __init__(self):
pass
def aFunc(self):
print "In A"
class B:
def __init__(self):
pass
def aFunc(self):
print "In B"
f = A()
f.aFunc()
f = B()
f.aFunc()
выход
In A
In B
Еще одна версия полиморфизма
from module import aName
Если два модуля используют один и тот же интерфейс, вы можете импортировать любой из них и использовать его в своем коде. Одним из примеров этого является from xml.etree.ElementTree import XMLParser