LINUX.ORG.RU

Generic (?) и typing в Python3

 ,


0

1

Тут в в соседнем треде человек спрашивал «что нельзя описать тайпхинтами» в python.

Вот в примере из документации: https://docs.python.org/3/library/typing.html#typing.Type

функция:

def make_new_user(user_class: Type[User]) -> User:
    # ...
    return user_class()

Вот тут явно неправильный возвращаемый тип. Мы не возвращаем объект типа User, мы возвращаем объект типа user_class, которым может быть User, а может быть и его потомком.

p = make_new_user(ProUser)
p.  # вот на этом месте PyCharm мне ничего не подсказывает из методов ProUser, думая, что у меня в p сидит User.

Статическая типизация это благо с какой стороны ни смотри.

anonymous
()

Все правильно PyCharm делает.
у тебя

<T extends User> User makeNewUser(Supplier<T> userClass);

а не
<T extends User> T makeNewUser(Supplier<T> userClass);

Там конечно не Supplier, а конструкторы, но сути это не меняет.
я хз как это правильно на питоне выражается.

Deleted
()
Последнее исправление: Deleted (всего исправлений: 2)

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

pawnhearts ★★★★★
()
Ответ на: комментарий от Deleted

В питоне isinstance(ProUser(), User) вернет тру. Вообще оп может возвращать там Union[ProUser,User] или типа того. Но и так правильно.

pawnhearts ★★★★★
()
Ответ на: комментарий от pawnhearts

проверка типов работает

«работает»

def make_new_user(user_class: Type[User]) -> User:
    return user_class()

def process_pro_user(user: ProUser):
    pass

process_pro_user(make_new_user(ProUser))  # WARNING: expected ProUser got User
omegatype ★★★
() автор топика
Ответ на: комментарий от pawnhearts

Правильно вот так:

def make_new_user(user_class: Type[User]) -> user_class:

Но так нельзя. IMO это как раз тот случай, которым ты интересовался.

omegatype ★★★
() автор топика
Ответ на: комментарий от omegatype

У тебя make_new_user всегда возвращает только User, и непонятно по какой причине ты ждешь, что у тебя возвращаймый тип этой функции будет зависеть от входящих значений.

Deleted
()
Последнее исправление: Deleted (всего исправлений: 1)
Ответ на: комментарий от Deleted

по какой причине ты ждешь, что у тебя возвращаймый тип этой функции будет зависеть от входящих значений.

Так ведь это и происходит. Возвращаемый тип завит от значений на входе. На самом деле тут просто нужна была бы generic-функция:

def make_new_user<T>() -> T
    where T: User:
    ...
Но так опять нельзя.

omegatype ★★★
() автор топика
Ответ на: комментарий от omegatype

Возвращаемый тип завит от значений на входе.

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

Deleted
()
Ответ на: комментарий от omegatype

А вот тут вообще спорная ситуация, у тебя make_new_user может вернуть AnyUser и решается это в рантайме как ни крути. Твое T тут равносильно Any, потому что ты не знаешь какие могут быть методы и поля у этого класса и не знаешь как с ними работать, какой вообще в этом смысл.

Правильней было бы описать протокол https://www.python.org/dev/peps/pep-0544/ и использовать его как тип.

pawnhearts ★★★★★
()
Ответ на: комментарий от Deleted

Ну в тайпдефе у тебя это не указано.

У меня - да, но только потому, что не ясно, как писать иначе? А в это пример из документации.

Ну, не то, что бы «осуждаю», просто увидел в треде вопрос - и вспомнил про ситуацию, в которой возможностей тайпдефа не хватает для адекватного определения.

omegatype ★★★
() автор топика
Ответ на: комментарий от pawnhearts

решается это в рантайме как ни крути

разве тут нельзя вывести _явно_ тип? Generic (?) и typing в Python3 (комментарий)

T (мне кажется) как раз и нужен был бы для того, что бы _заставить_ анализатор пытаться выводить, а не просто постулировать, что у меня тут User и все расслабьтесь.

omegatype ★★★
() автор топика
Ответ на: комментарий от omegatype

Так пример из доки вообще не про женерик, но да беглый просмотр документации не дайет ответа на вопрос - как написать

<T extends User> T makeNewUser(Supplier<T> userClass);

Deleted
()
Последнее исправление: Deleted (всего исправлений: 1)
Ответ на: комментарий от omegatype

Не, T - это Any, ты должен явно задать для него определенные ограничения.
Ну и вообще с таким подходом - добро пожаловать в ocaml. Он вместо T подставит все что подойдет.

Deleted
()
Последнее исправление: Deleted (всего исправлений: 1)
Ответ на: комментарий от omegatype

Толку его выводить? Это имело бы смысл в статически типизированном языке. Тебе же нужны типы тут, чтобы проверить, что ты не вызываешь у объекта, например, метода, которого там нет. Для этого надо явно задавать ограничения на типы или создавать протокол(интерфейс по сути). Иначе это по сути Any

pawnhearts ★★★★★
()
Ответ на: комментарий от Deleted

Не, T - это Any, ты должен явно задать для него определенные ограничения.

Ну я (фантазируя) и задаю:

where T: User:

omegatype ★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.