我提供了以下解决方案:
import inspect
def get_class(func: Callable[..., Any]) -> Any:
"""Return class of a method.
Args:
func: callable
Returns:
Class of the method, if the argument is a method
Raises:
AttributeError: if the argument is not callable or not a method
"""
if not callable(func):
raise AttributeError(f"{func} shall be callable")
if not inspect.ismethod(func):
raise AttributeError(f"Callable {func} shall be a method")
first_arg = func.__self__ # type: ignore # method have "self" attribute
return first_arg if inspect.isclass(first_arg) else first_arg.__class__
最后一行return first_arg if inspect.isclass(first_arg) else first_arg.__class__是处理类方法的情况(此时func.__self__对应cls,是类本身)。
没有inspect 模块的另一种选择是捕获异常(非常感谢@Elazar 提出使用isistance(..., type) 的想法):
def get_class(func: Callable[..., Any]) -> Any:
"""Return class of a method.
Args:
func: callable
Returns:
Class of the method, if the argument is a method
Raises:
AttributeError: if the argument is not callable or not a method
"""
if not callable(func):
raise AttributeError(f"{func} shall be callable")
try:
first_arg = func.__self__ # type: ignore # method have "self" attribute
except AttributeError:
raise AttributeError(f"Callable {func} shall be a method")
cls_or_type = first_arg.__class__
return first_arg if isinstance(cls_or_type, type) else cls_or_type
这是我用来检查您是否感兴趣的代码:
def my_func() -> int:
"""It feels like a zero"""
return 0
for method in [
Hello().method,
Bonjour().method,
Hello().cls_method,
Bonjour().cls_method,
Bonjour().new_method,
]:
# MyClass = get_class(func)
MyClass = get_class_2(method)
for attr in ["NAME", "NOM"]:
print(f"... {method} - {attr} ...")
try:
print(getattr(MyClass, attr))
except AttributeError as exp:
print(f"Error when getting attribute: {exp}")
# class_ = get_class(my_func)
for not_method in [my_func, int, Hello]:
try:
MyClass = get_class(not_method)
print(f"{not_method} => NOK (no exception raised)")
except AttributeError:
print(f"{not_method} => OK")