问题描述
例如,如果我们有
class Hello:
NAME = "HELLO TOTO"
def method(self) -> int:
return 5
@classmethod
def cls_method(cls) -> str:
return "Hi"
class Bonjour(Hello):
NOM = "BONJOUR TOTO"
def new_method(self) -> int:
return 0
我会得到:
我搜索了SO,但找不到任何直接答案。
如何实现这种功能(如果重要的话,在Python 3.6+中)?
谢谢
解决方法
我相信没有万无一失的方法,但这在大多数情况下都适用:
def get_class_of_bound_self(f):
assert hasattr(f,'__self__')
return f.__self__ if isinstance(f.__self__,type) else type(f.__self__)
请注意,如果f
是元类M
的方法,则此方法将失效;它将返回M
而不是type
。
我提供了以下解决方案:
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[...,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")