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

Существует три основные причины.

  1. FacesServlet не вызывается.
  2. Недопустимые URI пространства имен XML.
  3. Несколько JSF были загружены.

1. Убедитесь, что URL-адрес соответствует FacesServlet mapping

. URL-адрес ссылки (URL-адрес, который вы видите в адресной строке браузера) должен соответствовать файла FacesServlet, как определено в web.xml чтобы все работы JSF выполнялись. FacesServlet - это тот, который отвечает за разбор файла XHTML, сбор представленных значений формы, выполнение преобразования / проверки, обновление моделей, вызывание действий и создание выходных данных HTML. Если вы не вызываете FacesServlet по URL-адресу, то все, что вы получили (и увидите через rightclick, View Source в браузере), действительно является исходным исходным кодом XHTML.

Если , например, *.jsf, ссылка должна указывать на /register.jsf, а не на /register.xhtml. Если это, например, /faces/*, как и у вас, ссылка должна указывать на /faces/register.xhtml, а не на /register.xhtml. Один из способов избежать этой путаницы - просто изменить с /faces/* на *.xhtml. Таким образом, нижестоящее является идеальным отображением:


    facesServlet
    javax.faces.webapp.FacesServlet


    facesServlet
    *.xhtml

Если вы по какой-то причине не можете поменять на *.xhtml, то вы, вероятно, также хотели бы, чтобы конечные пользователи не могли напрямую обращаться к источнику XHTML кодировать файлы по URL-адресу. В этом случае вы можете добавить в в *.xhtml с пустым в web.xml, который предотвращает это:


    Restrict direct access to XHTML files
    
        XHTML files
        *.xhtml
    
    
 

Предстоящий JSF 2.3 решит все из вышеперечисленного, автоматически регистрируя FacesServlet в шаблоне URL-адреса *.xhtml во время запуска webapp.

См. также:


2. Убедитесь, что пространства имен XML соответствуют версии JSF

. С введением JSF 2.2 еще одна вероятная причина заключается в том, что пространства имен XML не соответствуют версии JSF. xmlns.jcp.org, как показано ниже, является новым с JSF 2.2 и не работает в старых версиях JSF. Символы почти такие же, как если бы FacesServlet не вызывался.


Если вы не можете перейти на JSF 2.2, вам нужно вместо этого использовать старые пространства имен java.sun.com XML:


См. также:


3. Было загружено несколько реализаций JSF

. Еще одна вероятная причина заключается в том, что несколько реализаций JSF были загружены вашим webapp, конфликтуя и разлагая друг друга. Например, когда ваш путь к классу среды выполнения Webapp загрязнен несколькими различными версиями JSF-библиотек или в конкретной комбинации Mojarra 2.x + Tomcat 8.x, когда в файле web.xml веб-приложения есть ненужная запись ConfigureListener, вызывающая ее загрузку дважды.





    com.sun.faces.config.ConfigureListener

При использовании Maven убедитесь, что вы правильно определяете зависимости и понимаете области зависимостей. Важно: не связывайте зависимости в webapp, если они уже предоставлены целевым сервером.

См. Также:


Убедитесь, что вы учитесь JSF правильный путь

JSF имеет очень крутую кривую обучения для тех, кто не знаком с базовыми HTTP , HTML и сервлетами . В Интернете много ресурсов низкого качества. Пожалуйста, игнорируйте фрагменты скриншотов кода, поддерживаемые любителями, в основном ориентированные на доход от рекламы, а не на обучение, такие как розы, учебник, javabeat и т. Д. Они легко узнаваемы, нарушая рекламные ссылки / баннеры. Также, пожалуйста, игнорируйте ресурсы, связанные с юрским JSF 1.x. Они легко узнаваемы с помощью JSP-файлов вместо файлов XHTML. JSP как технология просмотра устарела с тех пор, как JSF 2.0 уже в 2009 году.

Чтобы начать правильно, начните с нашей вики-страницы JSF и закажите авторитетную книгу .

См. также:

59
задан xian 4 October 2009 в 13:37
поделиться

7 ответов

Ответ Claudiu корректен, но можно также обмануть путем получения имени класса от self аргумент. Это даст вводящие в заблуждение операторы журнала в случаях наследования, но скажет Вам класс объекта, метод которого называют. Например:

from functools import wraps  # use this to preserve function signatures and docstrings
def logger(func):
    @wraps(func)
    def with_logging(*args, **kwargs):
        print "Entering %s.%s" % (args[0].__class__.__name__, func.__name__)
        return func(*args, **kwargs)
    return with_logging

class C(object):
    @logger
    def f(self):
        pass

C().f()

, Поскольку я сказал, это не будет работать правильно в случаях, где Вы наследовали функцию от родительского класса; в этом случае Вы могли бы сказать

class B(C):
    pass

b = B()
b.f()

и получить сообщение Entering B.f, где Вы на самом деле хотите получить сообщение Entering C.f, так как это - корректный класс. С другой стороны, это могло бы быть приемлемо, в этом случае я рекомендую этот подход по предложению Claudiu.

45
ответ дан Eli Courtwright 24 November 2019 в 18:22
поделиться

Функции только становятся методами во времени выполнения. Таким образом, когда Вы добираетесь C.f, Вы получаете связанную функцию (и C.f.im_class is C). В то время, когда Ваша функция определяется, это - просто простая функция, это не связывается ни с каким классом. Эта несвязанная и разъединенная функция - то, что украшено регистратором.

self.__class__.__name__ даст Вам название класса, но можно также использовать дескрипторы для выполнения этого несколько более общим способом. Этот шаблон описан в сообщении в блоге на Декораторах и Дескрипторах , и реализация Вашего декоратора регистратора в особенности была бы похожа:

class logger(object):
    def __init__(self, func):
        self.func = func
    def __get__(self, obj, type=None):
        return self.__class__(self.func.__get__(obj, type))
    def __call__(self, *args, **kw):
        print 'Entering %s' % self.func
        return self.func(*args, **kw)

class C(object):
    @logger
    def f(self, x, y):
        return x+y

C().f(1, 2)
# => Entering <bound method C.f of <__main__.C object at 0x...>>

, Очевидно, вывод может быть улучшен (при помощи, например, getattr(self.func, 'im_class', None)), но этот общий шаблон будет работать и на методы и на функции. Однако это будет не работа для классов старого стиля (но просто не используйте тех;)

28
ответ дан Community 24 November 2019 в 18:22
поделиться

Кажется, что, в то время как класс создается, Python создает объекты регулярной функции. В них только превращаются несвязанные объекты метода впоследствии. Зная это, это - единственный способ, которым я мог найти, чтобы сделать то, что Вы хотите:

def logger(myFunc):
    def new(*args, **keyargs):
        print 'Entering %s.%s' % (myFunc.im_class.__name__, myFunc.__name__)
        return myFunc(*args, **keyargs)

    return new

class C(object):
    def f(self):
        pass
C.f = logger(C.f)
C().f()

Это производит желаемый результат.

, Если Вы хотите обернуть все методы в класс, тогда Вы, вероятно, хотите создать функцию wrapClass, которую Вы могли тогда использовать как это:

C = wrapClass(C)
7
ответ дан Claudiu 24 November 2019 в 18:22
поделиться

Функции класса должны всегда брать сам в качестве своего первого аргумента, таким образом, можно использовать это вместо меня am_class.

def logger(myFunc):
    def new(self, *args, **keyargs):
        print 'Entering %s.%s' % (self.__class__.__name__, myFunc.__name__)
        return myFunc(self, *args, **keyargs)

    return new 

class C(object):
    @logger
    def f(self):
        pass
C().f()

сначала я хотел использовать self.__name__, но это не работает, потому что экземпляр не имеет никакого имени. необходимо использовать self.__class__.__name__ для получения названия класса.

6
ответ дан Asa Ayers 24 November 2019 в 18:22
поделиться

Можно также использовать new.instancemethod() для создания метода экземпляра (или связанный или развязанный) от функции.

0
ответ дан Andrew Beyer 24 November 2019 в 18:22
поделиться

Я нашел другое решение очень похожей проблемы, используя библиотеку inspect. Когда вызывается декоратор, даже если функция еще не привязана к классу, вы можете просмотреть стек и определить, какой класс вызывает декоратор. Вы можете, по крайней мере, получить строковое имя класса, если это все, что вам нужно (вероятно, вы еще не можете ссылаться на него, поскольку он находится в процессе создания). Тогда вам не нужно будет ничего вызывать после того, как класс будет создан.

import inspect

def logger(myFunc):
    classname = inspect.getouterframes(inspect.currentframe())[1][3]
    def new(*args, **keyargs):
        print 'Entering %s.%s' % (classname, myFunc.__name__)
        return myFunc(*args, **keyargs)
    return new

class C(object):
    @logger
    def f(self):
        pass

C().f()

Хотя этот способ не обязательно лучше, чем другие, это единственный способ, который я могу найти, чтобы узнать имя класса будущего метода во время вызова декоратора. Обратите внимание на то, что в документации по библиотеке inspect нельзя оставлять ссылки на фреймы.

6
ответ дан 24 November 2019 в 18:22
поделиться

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

  1. inspect.getouterframes и args [0] .__ class __.__ name __ не подходят для простого функции и статические методы.
  2. __ get __ должен быть в классе, который отклонен @wraps .
  3. @wraps должен лучше скрывать следы.

Итак, я объединил некоторые идеи с этой страницы, ссылки, документы и свою собственную голову,
и наконец нашли решение, в котором отсутствуют все три вышеупомянутых недостатка.

В результате method_decorator :

  • знает класс, к которому привязан декорированный метод.
  • Скрывает трассировки декораторов, отвечая на системные атрибуты более правильно, чем functools.wraps () .
  • Охватывается модульными тестами для связанных несвязанных методов экземпляра, методов класса, статических методов и простых функций.

Использование:

pip install method_decorator
from method_decorator import method_decorator

class my_decorator(method_decorator):
    # ...

Подробнее об использовании см. полные юнит-тесты .

А вот только код класса method_decorator :

class method_decorator(object):

    def __init__(self, func, obj=None, cls=None, method_type='function'):
        # These defaults are OK for plain functions
        # and will be changed by __get__() for methods once a method is dot-referenced.
        self.func, self.obj, self.cls, self.method_type = func, obj, cls, method_type

    def __get__(self, obj=None, cls=None):
        # It is executed when decorated func is referenced as a method: cls.func or obj.func.

        if self.obj == obj and self.cls == cls:
            return self # Use the same instance that is already processed by previous call to this __get__().

        method_type = (
            'staticmethod' if isinstance(self.func, staticmethod) else
            'classmethod' if isinstance(self.func, classmethod) else
            'instancemethod'
            # No branch for plain function - correct method_type for it is already set in __init__() defaults.
        )

        return object.__getattribute__(self, '__class__')( # Use specialized method_decorator (or descendant) instance, don't change current instance attributes - it leads to conflicts.
            self.func.__get__(obj, cls), obj, cls, method_type) # Use bound or unbound method with this underlying func.

    def __call__(self, *args, **kwargs):
        return self.func(*args, **kwargs)

    def __getattribute__(self, attr_name): # Hiding traces of decoration.
        if attr_name in ('__init__', '__get__', '__call__', '__getattribute__', 'func', 'obj', 'cls', 'method_type'): # Our known names. '__class__' is not included because is used only with explicit object.__getattribute__().
            return object.__getattribute__(self, attr_name) # Stopping recursion.
        # All other attr_names, including auto-defined by system in self, are searched in decorated self.func, e.g.: __module__, __class__, __name__, __doc__, im_*, func_*, etc.
        return getattr(self.func, attr_name) # Raises correct AttributeError if name is not found in decorated self.func.

    def __repr__(self): # Special case: __repr__ ignores __getattribute__.
        return self.func.__repr__()
18
ответ дан 24 November 2019 в 18:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: