Saya ingin membuat kelas dasar abstrak dengan metode abstrak yang mengembalikan turunan dari setiap subkelas yang mengimplementasikan antarmuka. Apakah ada cara yang lebih Pythonic untuk mencapai ini untuk mypy selain dari yang saya buat di bawah ini?

Dalam contoh kode saya, saya membuat kelas Animal generik. Subclass dapat mewarisi dari Animal dan menentukan parameter generik sebagai dirinya sendiri tetapi tampaknya kikuk dan salah bagi saya. Saya pikir saya mungkin kehilangan sesuatu yang jelas.

Perhatikan bahwa dalam kode di bawah ini, ketika saya membuat subkelas Animal definisi kelas menggunakan sesuatu seperti Dog(Animal["Dog"]). Itu tidak terlihat benar bagi saya, tetapi berfungsi untuk pengecekan tipe. Apakah ada cara untuk menunjukkan metode abstrak yang harus mengembalikan tipe yang sama dengan self?

import abc
from typing import Generic, TypeVar
from __future__ import annotations

T = TypeVar('T')

class Animal(abc.ABC, Generic[T]):

    @abc.abstractmethod
    def procreate(self: T, other: T) -> T:
        pass


class Dog(Animal["Dog"]):

    def procreate(self, other: "Dog"):
        return Dog()

class Cat(Animal["Cat"]):

    def procreate(self, other: "Cat"):
        return Cat()


dog = Dog()

dog.procreate(Cat())
0
Zelazny7 26 Mei 2021, 13:41

1 menjawab

Jawaban Terbaik

AFAIK Anda tidak perlu kelas Animal Anda menjadi Generic kecuali itu semacam wadah, mis. Sequence, kita bisa menggunakan TypeVar untuk metode tertentu

Jadi ini harus berfungsi sebagaimana dimaksud

import abc
from typing import TypeVar
from __future__ import annotations

T = TypeVar('T')


class Animal(abc.ABC):
    @abc.abstractmethod
    def procreate(self: T, other: T) -> T:
        pass


class Dog(Animal):
    def procreate(self, other: "Dog") -> "Dog":
        return Dog()


class Cat(Animal):
    def procreate(self, other: "Cat") -> "Cat":
        return Cat()


dog = Dog()

dog.procreate(Cat())

mypy akan menginformasikan tentang kesalahan pada baris terakhir:

> mypy test.py
test.py:26: error: Argument 1 to "procreate" of "Dog" has incompatible type "Cat"; expected "Dog"
Found 1 error in 1 file (checked 1 source file)
1
Azat Ibrakov 27 Mei 2021, 08:14