看起来
mypy
在考虑所有超类时遇到问题并报告缺少属性。这是一个简单的例子:
import uuid
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import String
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import mapped_column, DeclarativeBase
db = SQLAlchemy()
class Base(DeclarativeBase):
pass
class IdMixin:
id = mapped_column(UUID(as_uuid=True), nullable=False, default=uuid.uuid4, primary_key=True)
class ImageMixin:
image_name = mapped_column(String, default=None)
image_uri = mapped_column(String, default=None)
class Model(IdMixin, Base):
pass
class Post(Model, ImageMixin):
content = mapped_column(String)
class Comment(Model, ImageMixin):
text = mapped_column(String)
def generate_image_uri(image_name: str) -> str:
return f"https://example.com/{image_name}"
models = [Comment, Post]
for model in models:
entities = db.session.query(model).all()
for entity in entities:
entity.image_uri = generate_image_uri(image_name=entity.image_name) # Line 45
Mypy 报告:
mypy-warning.py:45: error: "Model" has no attribute "image_uri" [attr-defined]
mypy-warning.py:45: error: "Model" has no attribute "image_name" [attr-defined]
当我将
ImageMixin
移至 Model
类,然后仅在 Model
和 Post
类中子类 Comment
时,它工作得很好,但这不是我想要的,因为我不一定想要所有模型都可以混合图像功能。
Mypy 将包含
Post
和 Comment
的 List 的类型推断为:
builtins.list[def (**kw: Any) -> t.Model]
这是有道理的,因为
Post
和Comment
都继承自Model
(这也是当您将ImageMixin
移动到Model
类时Mypy不会抱怨的原因)。
用以下方式明确注释列表:
models: list[type[ImageMixin]] = [Comment, Post]
修复了错误,现在只允许在列表中使用继承自
ImageMixin
的类,从而确保在以下 for 循环中访问时可以访问 image_url
属性。