首页 > 解决方案 > 如何在 Python 类型提示中说“此参数需要允许任意属性分配”?

问题描述

我有一个函数,其工作是将任意对象分配给目标对象的任意属性名称。如果tgtquacks 像 a dict(对不起,如果它是一个可变的 hashmap 类型的对象),它应该使用tgt[attrname] = obj,否则它会调用setattr(tgt, attrname, obj). 我如何告诉 mypy 和类型系统我真正需要一个tgt允许分配给任意名称的类型?

from typing import MutableMapping, Any, Union

def assignment_func(tgt : Union[MutableMapping, Any], attrname: str, obj: object):
    """
    assign `obj` to `tgt` using the attrname. 
    setitem dict-type behavior takes precedence
    """

    try:
        if callable(getattr(tgt, "__getitem__", None)):
            tgt[attrname] = obj
        else:
            setattr(tgt, attrname, obj)
        print("yeehaa!     worked with a %s" % (tgt.__class__.__name__))

    except (Exception,) as e:
        print("bummer, dinna work with a %s.  got a %s" % (tgt.__class__.__name__, e.__class__.__name__))

class Foo:
    pass

class BadSlot:
    """unknown `bar` will blow this up"""
    __slots__ = "zoom"

class GoodSlot:
    """
    works.  but the attribute name can be anything 
    so, this, and anything with __slots___ should really be 
    flagged as a problem by mypy
    """
    __slots__ = "bar"

#mypy should complain about list, object, GoodSlot and BadSlot
#Foo and a dict both support arbitrary assignments.
for tgt in [list(), dict(), object(), Foo(), GoodSlot(), BadSlot()]:
    assignment_func(tgt, "bar", "coucou")

输出:

bummer, dinna work with a list.  got a TypeError
yeehaa!     worked with a dict
bummer, dinna work with a object.  got a AttributeError
yeehaa!     worked with a Foo
yeehaa!     worked with a GoodSlot
bummer, dinna work with a BadSlot.  got a AttributeError

mypy 有什么要说的?

没有什么。

但是如果将提示更改为

def assignment_func(tgt : Union[MutableMapping, object], attrname: str, obj: object):

然后它(正确地)提醒我object不支持作业)。

error: Unsupported target for indexed assignment,违规行处于tgt[attrname] = objMutableMapping 条件下。

Python版本:

有问题的代码是 2.7/3.6+ 代码,但让我们将其简化为仅适用于 3.6+。

tgt是我在这里感兴趣的唯一论点。让我们假设attrname已知是一个正确的属性名称(即attrname不是类似的2badcantstartwithnumber,但可能是toobadcantstartwithnumber并且obj没关系(Any实际上我可能想使用它)。

我的代码中一个反复出现的错误来源是使用 SQLAlchemy 来获取只读数据。结果是一个可迭代的 ResultProxy,为了最大限度地减少 RAM 的使用,它没有__dict__. 如果我打算将该 fetch 的行作为 tgt 传递给assignment_func,那么我需要记住包装/处理每一行,否则我会BadSlot退出。 dict(row)很好,但如果可能的话,我想提醒mypy一下。Django ORM fetches 也有同样的问题。

标签: pythontype-hintingmypy

解决方案


推荐阅读