чтения файла приходит, или имя файла, или входной поток. в этом случае использовать Union и проверять параметр который пришел?
сделать функцию, которая поулчает поток
так я про это же, вот во фласке много где есть, например https://github.com/pallets/flask/blob/41aaaf7fa07f28ef15fd1d343142e96440889a8b/src/flask/config.py#L194
Да, но, скажем так, не все массово применяемые решения бесспорны. Эта магия с угадыванием типа переменной в условиях питона иногда подкидывает сюрпризов и в итоге не соблюдается принцип наименьшего удивления. В целом байты в исходниках почти бесплатные и обычно ничто не мешает сделать две отдельные функции с разными названиями.
А можно поподробнее, какие могут быть сюрпризы с угадыванием типа в python? вот искусственный пример перегрузки функции, разве так плохо делать? def foo(str_or_int: Union[str, int]) -> int: if isinstance(str_or_int, str): number = int(str_or_int) elif isinstance(str_or_int, int): number = str_or_int else: raise TypeError("str_or_int must be either str or int") return number ничего не мешает написать две отдельные функции с разными названиями, кроме лени программиста их реализовывать и необходимости придумать названия функций, что иногда бывает самым сложным
Тут вопрос удобства. Чем вспоминать, как называется нужная функция, которая делает то же, что и основная, но с другими данными, проще сделать перегрузку.
@singledispatch async def boof(arg: int | str): return @boof.register async def _(arg: int) -> str: return str(arg % 2) @boof.register async def _(arg: str) -> str: return f"{arg} {arg}"
Так я же как раз за перегрузку, что это очень удобный механизм, но из-за того что в python нативно её нельзя сделать, то приходится костылить через singledispatch или Union
Извиняюсь. Джун ещё. Раньше в с++ работал. Рад был, когда узнал, что в 2021 добавили match как аналог switch case. Когда учился на питоне был в диссонансе, что этой функции нет
match это не switch case
Разве? Почему не стоит?
зачем? есть же статические методы
А много вы видели проектов, где используется singledispatch? Что-то я не могу найти примеры в реальных больших проектах
Я и генераторы не часто вижу, берут пустой массив делают просто, а потом туда добавляют после каждой итерации
есть же принцип "явное лучше неявного"
и почему этот принцип нарушается, если параметр функции объявлен явно как Union[str, int]?
foo("hello") разве будет работать?
потому что в качестве аргумента может прилететь строка 2.998 например и формально мы ничего не нарушаем, линтер может и не увидеть ошибки, мы обнаружим ее только после запуска
1. В таком виде это не перегрузка, а некая её имитация средствами питона. Перегрузка, как механизм языка, это что-то похожее на пример с singledispatch. И твоим вариантом, и singledispatch иногда пользуются. 2. Теперь о подводных камнях (любой реализации). Для чего изначально она применяется? Для удобства пользователя этой функции. Чтобы не нужно было угадывать, как же называется функция, а просто предусмотреть возможные варианты входных данных. То есть есть у нас lxml.etree.parse — и мы туда туда можем как имя файла передать, так и file-like object (результат open). Круто, да. А вот у нас уже есть содержимое файла в строке, давайте и для этого сделаем поддержку. Но нет, для этого есть отдельно fromstring. Почему — а потому что как мы будем отличать строку с именем файла от строки с содержимимым? Вот и выходит, что мы вроде как умные и сделали поддержку разного формата входных данных, но не до конца. А пользователю потом гадать, что можно, а что нельзя и он путается.
нет, но можно допилить, например так: def foo(str_or_int: Union[str, int]) -> int: if isinstance(str_or_int, str): try: number = int(str_or_int) except ValueError as e: raise TypeError(f"str_or_int '{str_or_int}' is not a number") elif isinstance(str_or_int, int): number = str_or_int else: raise TypeError("str_or_int must be either str or int") return number
Функция все ещё ждет строку но не работает со строкой
оставь проблему приведения типов тому, кто потом будет использовать твой класс ее должен решать не ты, а тот, кто знает, что передает в качестве аргумента методу
ну и да, линтер это может не увидеть, ошибка всплывет только в рантайме соот-но никакого смысла от тайпхинтов тут особо и нет
нет, ну это пример все таки искусственный чтобы показать перегрузку и можно сказать, что пользователь функции сам дурак, что не смотрит в доку, где указано в каком виде должна быть входная строка
это же касается и конструкторов следует не городить монструозный инит с тыщей аргументов на разные случаи жизни, а растащить конструкторы по методам класса например: class Foo(): def __init__(self, arg: str): pass @classmethod def from_file(cls, arg: pathlib.Path): pass return cls(arg.some.method) obj1 = Foo("some string") obj2 = Foo.from_file(pathlib.Path('some/file.txt')) получается как бы два конструктора, которые, тем не менее, явно друг от друга отличаются
Обсуждают сегодня