2013-04-09 4 views
1

Допустим, у меня есть:Определение класса метода

class User(): 
    def method(self): 
    pass 

u=User() 

Как извлечь класс из u.method через access декоратора? Все, что я получаю от u.method, это то, что это функция ... но я хотел бы знать, из чего class.

Меня интересует решение python 2.7.

Update: Я забыл упомянуть, что я не дают достаточно информации:

class access(): 
    """ 
    Decorator for specifying which 'access right' must be enforced 
    at the object method level 
    """ 

    def __init__(self, right): 
     self.right=right 

    def __call__(self, method): 
     ### need to grab the method's class name here 

Я на самом деле с помощью декоратора:

class User(): 
    @access("edit" 
    def method(self): 
    pass 
+0

Есть ли причина, по которой вы используете классический класс вместо класса нового стиля? (И, если вы хотите классический класс, почему 'User()' вместо просто 'User'?) Это не влияет на ответ в этом случае, но почти везде, где он _does_ делает разницу, классический класс не то, что вы хотите. – abarnert

+0

Между тем, 'u.method' - это функция _not_, это связанный метод. Если вы видите что-то еще, вы не используете тот же код, который вы нам показывали. И, поскольку функции не имеют классов, ваш вопрос бессмыслен. – abarnert

+0

ОК, после редактирования ... Это совершенно другой вопрос. Декоратор не получает связанный метод 'u.method' или даже несвязанный метод' U.method', потому что 'U.method' не может быть создан до тех пор, пока не вернется декоратор. Он просто получает простую старую функцию. Поэтому вы не можете проверить его для класса. – abarnert

ответ

2

Ваш декоратор не вызывается с помощью метода, он вызывается функцией.

Класс еще не существует, и этот метод не связывает эту функцию с классом, а тем более любой экземпляр класса и связанный метод связывает функцию с этим экземпляром. И даже если существуют методы do, они будут построены вокруг функции, которую возвращает ваш декоратор.

Таким образом, вы не можете понять функцию, которую вы получаете, чтобы попытаться получить ее класс, потому что у нее ее нет.


Есть различные Hacky трюков, которые вы можете использовать, чтобы определить, что вы находитесь в середине определения (хотя они могут быть специфическими для конкретной реализации Python и версию), но нет чистого способа сделать то, что вы хотеть. Например, вот один ужасный взлом:

self.classname = sys._getframe(1).f_code.co_name 

Что это значит? Ну, ваш декоратор - это рамка 0; независимо от того, что называется рамкой 1.Если предмет, называемый им, является определением класса, его объект code будет иметь имя класса в качестве своего класса. Вы все еще не можете на самом деле получить доступ к классу, потому что он не существует (и не будет, пока код не будет выполнен, что находится в середине происходящего прямо сейчас). Но если вы знаете, что имя никогда не будет переопределено, вы можете просто сохранить имя и посмотреть его позже (возможно, вам также понадобится f_locals['__module__'], чтобы посмотреть его) во время вызова, чтобы получить класс.


Однако гораздо более приятным решением является создание декоратора класса и декоратора, который работает с ним. Хитрость заключается в том, что декораторы «регистрации» каким-то образом хотят, чтобы они (функции, которые они возвращают), «фиксировались». Затем декоратор класса выполняет итерацию через зарегистрированные методы и исправляет их.

Например:

def class_deco(cls): 
    for name, method in inspect.getmembers(cls, callable): 
     if hasattr(method, 'class_fixup'): 
      method.class_fixup(cls) 
    return cls 

Теперь ваш метод декоратора все еще не может получить доступ к классу во время вызова, но он может создать функцию «FixUp», который заканчивает украшающие вещи, когда класс готов, то просто сделайте f.class_fixup = fixup прямо перед тем return f.

2

Используйте u.method.im_class:

In [3]: u.method.im_class 
Out[3]: __main__.User 

Documentation

User-defined methods ... Special read-only attributes: im_self is the class instance object, im_func is the function object; im_class is the class of im_self for bound methods or the class that asked for the method for unbound methods.

В Python 3, посмотреть класс через __self__:

>>> u.method.__self__.__class__ 
<class '__main__.User'> 
+0

AttributeError: объект 'function' не имеет атрибута 'im_class' – jldupont

+0

@PavelAnossov: Нет, это просто дает вам 'builtins.method'! Python 3 не имеет эквивалента 'im_class' (потому что он нужен только для несвязанных методов, которые больше не существуют). Вы хотите '__self __.__ class__'. – abarnert

+0

Упс, я имею в виду 'u.method .__ self __.__ class__' –

0

почему бы не просто напечатать?

class User(): 
    def method(self): 
    pass 

u=User() 

print(u.method) 

Выход:

<bound method User.method of <__main__.User object at 0x02D59510>> 

Или, если вы хотите проверить, вы можете использовать:

u.method.__self__.__class__ 

Выход:

<class '__main__.User'> 

Оба метода подтвердили, работая в питона 2.7.3 и python 3.3

+0

IIRC, 'u .__ метод __.__ self__' не документирован для работы в 2.7. Как правило, это работает в CPython 2.7.x для нормально созданных связанных методов, но может не работать для связанных методов, созданных другими способами (или, конечно, настраиваемых объектов, имитирующих связанные методы), и может не работать в других реализациях (PyPy, Jython, IronPython, ...). Поэтому вам, вероятно, лучше использовать 'u.method.im_class' или, по крайней мере,' u.method.im_self .__ class__'. – abarnert

+0

@abarnert У меня новая версия 2.7.3, и это работает без ошибок. Хотя я думаю, что вижу, к чему вы клоните. – Serdalis

+0

Serdalis: Да, как я уже сказал, это работает в CPython 2.7.x для нормально созданных связанных методов. Итак, если вы сделаете новую установку CPython 2.7.3 и создаете связанный метод в обычном режиме, конечно, это сработает. – abarnert

Смежные вопросы