mypy error: "Callable[[VarArg(Any), KwArg(Any)], Any]" has no attribute ***
mypy error: "Callable[[VarArg(Any), KwArg(Any)], Any]" has no attribute ***
我正在定义一个 class,如果没有声明 color
实例属性,将根据收到的调用次数自动设置它。
下面是一个最小的工作示例:
from typing import Callable
import itertools
from plotly.express import colors as px_colors
COLOR_LIST = px_colors.qualitative.Alphabet
# Decorator
def color_setter(func: Callable):
"""Counts how many times `~MyClass` has been called and sets the
instance color accordingly.
Parameters
----------
func : Callable
Returns
-------
Callable
"""
def wrapper(*args, **kwargs):
wrapper.calls += 1
wrapper.color = next(wrapper.cycle_color_list)
# print(f'wrapper called {wrapper.calls} times')
return func(*args, **kwargs)
wrapper.calls = 0 # Adding # type: ignore here suppresses
# the error, but it is not a solution...
wrapper.cycle_color_list = itertools.cycle(COLOR_LIST) # same here
return wrapper
@color_setter
def _set_color(color: str) -> tuple:
"""Sets MyClass color and id.
Parameters
----------
color : str
Color variable, can be RGBA or HEX string format.
Returns
-------
tuple
MyClass color and call id
"""
if color is None:
color = _set_color.color
my_id = _set_color.calls
return color, my_id
class MyClass():
"""Example class.
"""
def __init__(
self,
color: str = None,
) -> None:
"""Define MyClass.
Parameters
----------
color : str, optional
RGBS or HEX string for color, by default None
"""
self.color, self.id = _set_color(color)
代码按预期运行,但是 mypy returns 出现以下两个错误,我不知道如何解决。
example.py:26: error: "Callable[[VarArg(Any), KwArg(Any)], Any]" has no attribute "calls"
wrapper.calls = 0
^
example.py:27: error: "Callable[[VarArg(Any), KwArg(Any)], Any]" has no attribute "cycle_color_list"
wrapper.cycle_color_list = itertools.cycle(COLOR_LIST)
^
Found 2 errors in 1 file (checked 1 source file)
Mypy 抱怨 function attributes 没有正确输入。
您定义了一个包装函数,其类型为 Callable[[VarArg(Any), KwArg(Any)], Any]
。此类型不附带 calls
和 color
属性。所以访问它会导致属性错误。
from typing import Callable, Optional
# Decorator
def color_setter_alt(func: Callable):
"""Counts how many times `~MyClass` has been called and sets the
instance color accordingly.
Parameters
----------
func : Callable
Returns
-------
Callable
"""
class Wrapper:
color: Optional[str]
def __init__(self):
# Wrapper is callable because it has the `__call__` method.
# Not being a plain function allows you to explicitly define the function attributes
self.calls = 0
self.cycle_color_list = itertools.cycle(COLOR_LIST)
def __call__(self, *args, **kwargs):
self.calls += 1
self.color = next(self.cycle_color_list)
# print(f'wrapper called {wrapper.calls} times')
return func(*args, **kwargs)
return Wrapper()
另一种解决方法是使用 setattr
和 getattr
# Decorator
def color_setter(func: Callable):
"""Counts how many times `~MyClass` has been called and sets the
instance color accordingly.
Parameters
----------
func : Callable
Returns
-------
Callable
"""
def wrapper(*args, **kwargs):
setattr(wrapper, "calls", getattr(wrapper, "calls") + 1)
setattr(wrapper, "color", next(getattr(wrapper, "cycle_color_list")))
# print(f'wrapper called {wrapper.calls} times')
return func(*args, **kwargs)
setattr(wrapper, "calls", 0)
setattr(wrapper, "cycle_color_list", itertools.cycle(COLOR_LIST))
return wrapper
这种方法的优点是您可以在以后修改附加属性而无需修改原始函数。但缺点是它不会为您提供类型提示。
我正在定义一个 class,如果没有声明 color
实例属性,将根据收到的调用次数自动设置它。
下面是一个最小的工作示例:
from typing import Callable
import itertools
from plotly.express import colors as px_colors
COLOR_LIST = px_colors.qualitative.Alphabet
# Decorator
def color_setter(func: Callable):
"""Counts how many times `~MyClass` has been called and sets the
instance color accordingly.
Parameters
----------
func : Callable
Returns
-------
Callable
"""
def wrapper(*args, **kwargs):
wrapper.calls += 1
wrapper.color = next(wrapper.cycle_color_list)
# print(f'wrapper called {wrapper.calls} times')
return func(*args, **kwargs)
wrapper.calls = 0 # Adding # type: ignore here suppresses
# the error, but it is not a solution...
wrapper.cycle_color_list = itertools.cycle(COLOR_LIST) # same here
return wrapper
@color_setter
def _set_color(color: str) -> tuple:
"""Sets MyClass color and id.
Parameters
----------
color : str
Color variable, can be RGBA or HEX string format.
Returns
-------
tuple
MyClass color and call id
"""
if color is None:
color = _set_color.color
my_id = _set_color.calls
return color, my_id
class MyClass():
"""Example class.
"""
def __init__(
self,
color: str = None,
) -> None:
"""Define MyClass.
Parameters
----------
color : str, optional
RGBS or HEX string for color, by default None
"""
self.color, self.id = _set_color(color)
代码按预期运行,但是 mypy returns 出现以下两个错误,我不知道如何解决。
example.py:26: error: "Callable[[VarArg(Any), KwArg(Any)], Any]" has no attribute "calls"
wrapper.calls = 0
^
example.py:27: error: "Callable[[VarArg(Any), KwArg(Any)], Any]" has no attribute "cycle_color_list"
wrapper.cycle_color_list = itertools.cycle(COLOR_LIST)
^
Found 2 errors in 1 file (checked 1 source file)
Mypy 抱怨 function attributes 没有正确输入。
您定义了一个包装函数,其类型为 Callable[[VarArg(Any), KwArg(Any)], Any]
。此类型不附带 calls
和 color
属性。所以访问它会导致属性错误。
from typing import Callable, Optional
# Decorator
def color_setter_alt(func: Callable):
"""Counts how many times `~MyClass` has been called and sets the
instance color accordingly.
Parameters
----------
func : Callable
Returns
-------
Callable
"""
class Wrapper:
color: Optional[str]
def __init__(self):
# Wrapper is callable because it has the `__call__` method.
# Not being a plain function allows you to explicitly define the function attributes
self.calls = 0
self.cycle_color_list = itertools.cycle(COLOR_LIST)
def __call__(self, *args, **kwargs):
self.calls += 1
self.color = next(self.cycle_color_list)
# print(f'wrapper called {wrapper.calls} times')
return func(*args, **kwargs)
return Wrapper()
另一种解决方法是使用 setattr
和 getattr
# Decorator
def color_setter(func: Callable):
"""Counts how many times `~MyClass` has been called and sets the
instance color accordingly.
Parameters
----------
func : Callable
Returns
-------
Callable
"""
def wrapper(*args, **kwargs):
setattr(wrapper, "calls", getattr(wrapper, "calls") + 1)
setattr(wrapper, "color", next(getattr(wrapper, "cycle_color_list")))
# print(f'wrapper called {wrapper.calls} times')
return func(*args, **kwargs)
setattr(wrapper, "calls", 0)
setattr(wrapper, "cycle_color_list", itertools.cycle(COLOR_LIST))
return wrapper
这种方法的优点是您可以在以后修改附加属性而无需修改原始函数。但缺点是它不会为您提供类型提示。