Привет у меня есть что-то примерно как следующее. В основном я должен получить доступ к классу метода экземпляра от декоратора, используемого на метод экземпляра в его определении.
def decorator(view):
# do something that requires view's class
print view.im_class
return view
class ModelA(object):
@decorator
def a_method(self):
# do some stuff
pass
Код как есть дает
AttributeError: 'function' object has no attribute 'im_class'
Я нашел подобный вопрос/ответы - декоратор Python заставляет функцию забыть, что это принадлежит классу, и Получите класс в декораторе Python - но они полагаются на обходное решение, которое захватывает экземпляр во времени выполнения путем хватания первого параметра. В моем случае я буду называть метод основанным на информации подбираемый из ее класса, таким образом, я буду не мочь ждать, чтобы вызов вошел.
Спасибо.
Если вы используете Python 2.6 или более позднюю версию, вы можете использовать декоратор класса, возможно, что-то вроде этого (предупреждение: непроверенный код).
def class_decorator(cls):
for name, method in cls.__dict__.iteritems():
if hasattr(method, "use_class"):
# do something with the method and class
print name, cls
return cls
def method_decorator(view):
# mark the method as something that requires view's class
view.use_class = True
return view
@class_decorator
class ModelA(object):
@method_decorator
def a_method(self):
# do some stuff
pass
Декоратор методов отмечает метод как тот, который представляет интерес, добавляя атрибут "use_class" - функции и методы также являются объектами, поэтому к ним можно прикрепить дополнительные метаданные.
После создания класса декоратор класса перебирает все методы и делает все необходимое для методов, которые были помечены.
Если вы хотите, чтобы все методы были затронуты, можно обойтись без декоратора методов и использовать только декоратор класса.
Как указали Муравьи, вы не можете получить ссылку на класс изнутри класса. Однако, если вам интересно различать разные классы (а не манипулировать фактическим объектом типа класса), вы можете передать строку для каждого класса. Вы также можете передать декоратору любые другие параметры, которые захотите, используя декораторы в стиле класса.
class Decorator(object):
def __init__(self,decoratee_enclosing_class):
self.decoratee_enclosing_class = decoratee_enclosing_class
def __call__(self,original_func):
def new_function(*args,**kwargs):
print 'decorating function in ',self.decoratee_enclosing_class
original_func(*args,**kwargs)
return new_function
class Bar(object):
@Decorator('Bar')
def foo(self):
print 'in foo'
class Baz(object):
@Decorator('Baz')
def foo(self):
print 'in foo'
print 'before instantiating Bar()'
b = Bar()
print 'calling b.foo()'
b.foo()
Отпечатки:
before instantiating Bar()
calling b.foo()
decorating function in Bar
in foo
Кроме того, см. Страницу Брюса Эккеля о декораторах.
Проблема в том, что при вызове декоратора класс еще не существует. Попробуйте следующее:
def loud_decorator(func):
print("Now decorating %s" % func)
def decorated(*args, **kwargs):
print("Now calling %s with %s,%s" % (func, args, kwargs))
return func(*args, **kwargs)
return decorated
class Foo(object):
class __metaclass__(type):
def __new__(cls, name, bases, dict_):
print("Creating class %s%s with attributes %s" % (name, bases, dict_))
return type.__new__(cls, name, bases, dict_)
@loud_decorator
def hello(self, msg):
print("Hello %s" % msg)
Foo().hello()
Эта программа выведет:
Now decorating <function hello at 0xb74d35dc>
Creating class Foo(<type 'object'>,) with attributes {'__module__': '__main__', '__metaclass__': <class '__main__.__metaclass__'>, 'hello': <function decorated at 0xb74d356c>}
Now calling <function hello at 0xb74d35dc> with (<__main__.Foo object at 0xb74ea1ac>, 'World'),{}
Hello World
Как видите, вам придется придумать другой способ делать то, что вы хотите.
У вас будет доступ к классу объекта, для которого вызывается метод, в декорированном методе, который должен вернуть ваш декоратор. Примерно так:
def decorator(method):
# do something that requires view's class
def decorated(self, *args, **kwargs):
print 'My class is %s' % self.__class__
method(self, *args, **kwargs)
return decorated
Используя ваш класс ModelA, вот что он делает:
>>> obj = ModelA()
>>> obj.a_method()
My class is <class '__main__.ModelA'>