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() будет успешным, то есть не потерпит неудачу по любой другой причине.

Другие вопросы по тегам