getattr для объектов класса
class A:
def foo(self):
print "foo()"
getattr(A, foo) # True
A.foo() # error
getattr(A(), foo) # True
A().foo() # prints "foo()"
Это, как говорится, вот моя проблема:
Я хочу хранить метаинформацию теста в качестве атрибутов самих объектов класса Test Case, а не в их экземплярах.
У меня есть список имен атрибутов для извлечения, но если есть метод экземпляра с тем же именем, то getattr(class_obj, attr)
вернет True, но getattr(class_obj, attr)()
выдает ошибку.
Есть ли способ сказать getattr не включать атрибуты экземпляра класса и только самого объекта класса?
РЕДАКТИРОВАТЬ: я пытался получить доступ class_obj.__dict__
напрямую (что, как я понимаю, является плохой практикой), но оно не включает некоторые атрибуты, такие как __name__
РЕДАКТИРОВАТЬ: перефразировать вопрос. Есть ли способ провести различие между методами класса obj и методами экземпляра класса?
3 ответа
Это достаточно хорошо?
import types
class Test(object):
@staticmethod
def foo():
print 'foo'
def bar(self):
print 'bar'
В комбинации с:
>>>(isinstance(getattr(Test, 'foo'), types.FunctionType),
isinstance(getattr(Test, 'bar'), types.FunctionType))
True, False
Вы также можете использовать inspect
модуль:
>>> inspect.isfunction(Test.foo)
True
>>> inspect.isfunction(Test.bar)
False
С небольшой дополнительной работой вы можете даже отличить методы класса от методов экземпляра и статических методов:
import inspect
def get_type(cls, attr):
try:
return [a.kind for a in inspect.classify_class_attrs(cls) if a.name == attr][0]
except IndexError:
return None
class Test(object):
@classmethod
def foo(cls):
print 'foo'
def bar(self):
print 'bar'
@staticmethod
def baz():
print 'baz'
Вы можете использовать его как:
>>> get_type(Test, 'foo')
'class method'
>>> get_type(Test, 'bar')
'method'
>>> get_type(Test, 'baz')
'static method'
>>> get_type(Test, 'nonexistant')
None
Ваши результаты из-за неправильного определения foo
, а не какая-либо основная семантика атрибутов класса. По умолчанию функция, объявленная внутри класса, является методом экземпляра, который должен принимать хотя бы один аргумент, экземпляр класса. Условно это называется self
:
class A:
def foo(self):
print "foo()"
Обычно вы вызываете такой метод, как этот:
a = A()
a.foo() # passes the object 'a' implicitly as the value of the parameter 'self'
но это тоже законно
a = A()
A.foo(a) # pass the object 'a' explicitly as the value of the parameter 'self'
Чтобы определить функцию внутри класса, которая не принимает никаких таких неявных аргументов, вам нужно украсить ее с помощью @staticmethod
декоратор:
class A:
@staticmethod
def foo():
print "foo()"
Теперь вы можете позвонить foo
так, как вы пытались ранее:
>>> A.foo()
foo()
Вы хотите что-то вроде этого:
from inspect import ismethod
from collections import Callable
def can_i_call(func):
if not isinstance(func, Callable):
# not a callable at all
return False
if not ismethod(func):
# regular function or class or whatever
return True
# func is a method
return func.im_self is not None
Примечание: это будет только проверять, будет ли попытка вызова вызывать ошибку, потому что вы вызываете несвязанный метод без self
, Это не гарантирует, что func()
будет успешным, то есть не потерпит неудачу по любой другой причине.