Class decorators do not inherit properly

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Chris Fonnesbeck

    Class decorators do not inherit properly

    I have a class that does MCMC sampling (Python 2.5) that uses decorators
    -- one in particular called _add_to_post that appends the output of the
    decorated method to a class attribute. However, when I
    subclass this base class, the decorator no longer works:

    Traceback (most recent call last):
    File "/Users/chris/Projects/CMR/closed.py", line 132, in <module>
    class M0(MetropolisHa stings):
    File "/Users/chris/Projects/CMR/closed.py", line 173, in M0
    @_add_to_post
    NameError: name '_add_to_post' is not defined

    yet, when I look at the dict of the subclass (here called M0), I see the
    decorator method:

    In [5]: dir(M0)
    Out[5]:
    ['__call__',
    '__doc__',
    '__init__',
    '__module__',
    '_add_to_post',
    ....

    I dont see what the problem is here -- perhaps someone could shed
    some light. I thought it might be the underscore preceding the name,
    but I tried getting rid of it and that did not help.

    Thanks.




  • Lee Harr

    #2
    Re: Class decorators do not inherit properly

    Traceback (most recent call last):
    File "/Users/chris/Projects/CMR/closed.py", line 132, in <module>
    class M0(MetropolisHa stings):
    File "/Users/chris/Projects/CMR/closed.py", line 173, in M0
    @_add_to_post
    NameError: name '_add_to_post' is not defined
    >
    yet, when I look at the dict of the subclass (here called M0), I see the
    decorator method:
    >

    I think the term "class decorator" is going to eventually
    mean something other than what you are doing here. I'd
    avoid the term for now.


    When you decorate a class method, the function you use
    needs to be defined before the method definition.

    Using a class method to decorate another class method is
    going to be tricky. The way I usually do it is to create
    a separate function outside of the class definition for
    the decorator function.


    You're going to have to show us the actual code you are
    having trouble with, or else (probably more useful, really)
    try to put together a minimal example of what you are
    trying to do and show us that code.

    Comment

    • Bruno Desthuilliers

      #3
      Re: Class decorators do not inherit properly

      Lee Harr a écrit :
      >Traceback (most recent call last):
      > File "/Users/chris/Projects/CMR/closed.py", line 132, in <module>
      > class M0(MetropolisHa stings):
      > File "/Users/chris/Projects/CMR/closed.py", line 173, in M0
      > @_add_to_post
      >NameError: name '_add_to_post' is not defined
      >>
      >yet, when I look at the dict of the subclass (here called M0), I see the
      >decorator method:
      >>
      >
      >
      I think the term "class decorator" is going to eventually
      mean something other than what you are doing here. I'd
      avoid the term for now.
      >
      >
      When you decorate a class method,
      the function you use
      needs to be defined before the method definition.
      This is true whatever you are decorating - class method, static method,
      instance method, function. And FWIW, the term "class method" has a
      definite meaning in Python.
      Using a class method to decorate another class method is
      going to be tricky. The way I usually do it is to create
      a separate function outside of the class definition for
      the decorator function.
      The problem is then that this function cannot easily access the class
      object - which is what the OP want.
      >
      You're going to have to show us the actual code you are
      having trouble with, or else (probably more useful, really)
      try to put together a minimal example of what you are
      trying to do and show us that code.
      +1 on this

      Comment

      • Bruno Desthuilliers

        #4
        Re: Class decorators do not inherit properly

        Chris Fonnesbeck a écrit :
        I have a class that does MCMC sampling (Python 2.5) that uses decorators
        -- one in particular called _add_to_post that appends the output of the
        decorated method to a class attribute.
        However, when I
        subclass this base class, the decorator no longer works:
        >
        Traceback (most recent call last):
        File "/Users/chris/Projects/CMR/closed.py", line 132, in <module>
        class M0(MetropolisHa stings):
        File "/Users/chris/Projects/CMR/closed.py", line 173, in M0
        @_add_to_post
        NameError: name '_add_to_post' is not defined
        >
        yet, when I look at the dict of the subclass (here called M0), I see the
        decorator method:
        >
        In [5]: dir(M0)
        Out[5]:
        ['__call__',
        '__doc__',
        '__init__',
        '__module__',
        '_add_to_post',
        ...
        >
        I dont see what the problem is here -- perhaps someone could shed
        some light. I thought it might be the underscore preceding the name,
        but I tried getting rid of it and that did not help.
        A minimal runnable code snippet reproducing the problem would *really*
        help, you know...

        Anyway: the body of a class statement is it's own namespace. So in the
        body of your base class, once the _add_to_post function is defined, you
        can use it. But when subclassing, the subclass's class statement creates
        a new namespace, in which _add_to_post is not defined - hence the
        NameError. To access this symbol, you need to use a qualified name, ie:

        class SubClass(BaseCl ass):
        @BaseClass._add _to_post
        def some_method(sel f):
        # code here

        Now there may be better solutions, but it's hard to tell without knowing
        more about your concrete use case.

        HTH

        Comment

        • Diez B. Roggisch

          #5
          Re: Class decorators do not inherit properly

          Chris Fonnesbeck schrieb:
          I have a class that does MCMC sampling (Python 2.5) that uses decorators
          -- one in particular called _add_to_post that appends the output of the
          decorated method to a class attribute. However, when I
          subclass this base class, the decorator no longer works:
          >
          Traceback (most recent call last):
          File "/Users/chris/Projects/CMR/closed.py", line 132, in <module>
          class M0(MetropolisHa stings):
          File "/Users/chris/Projects/CMR/closed.py", line 173, in M0
          @_add_to_post
          NameError: name '_add_to_post' is not defined
          >
          yet, when I look at the dict of the subclass (here called M0), I see the
          decorator method:
          >
          In [5]: dir(M0)
          Out[5]:
          ['__call__',
          '__doc__',
          '__init__',
          '__module__',
          '_add_to_post',
          ...
          >
          I dont see what the problem is here -- perhaps someone could shed
          some light. I thought it might be the underscore preceding the name,
          but I tried getting rid of it and that did not help.
          Does this simple example show your problem?


          class Meta(type):
          def __init__(cls, *args):
          print "Meta.__ini t__ called"
          return super(Meta, cls).__init__(* args)


          class A(object):
          __metaclass__ = Meta

          def decorator(f):
          print "decorator called"
          return f

          @decorator
          def foo(self):
          pass


          class B(A):
          #@decorator
          def bar(self):
          pass


          print dir(A())
          print dir(B())


          then it explains the problem easily: the class-statement (class
          Name(base): <definitions) is evaluated _before_ the actual class is
          created. Thus at that moment, there is no decorator known in the
          surrounding scope.

          Use a function level decorator instead, that delegates it's work to a
          classmethod/instancemethod. Something like this (can't be more precise
          as you didn't show us code):

          def decorator(f):
          def _d(self, *args, **kwargs):
          self._a_decorat or_method()
          return f(self, *args, **kwargs)
          return _d


          Diez

          Comment

          • Lee Harr

            #6
            Re: Class decorators do not inherit properly

            >I think the term "class decorator" is going to eventually
            >mean something other than what you are doing here. I'd
            >avoid the term for now.
            >>
            >>
            >When you decorate a class method,
            >the function you use
            >needs to be defined before the method definition.
            >
            FWIW, the term "class method" has a
            definite meaning in Python.

            Certainly. But "class decorator" is being introduced in
            Python 3000 with PEP 3129:
            This PEP proposes class decorators, an extension to the function and method decorators introduced in PEP 318.


            Comment

            • Bruno Desthuilliers

              #7
              Re: Class decorators do not inherit properly

              Lee Harr a écrit :
              >>>I think the term "class decorator" is going to eventually
              >>>mean something other than what you are doing here. I'd
              >>>avoid the term for now.
              >>>
              >>>
              >>>When you decorate a class method,
              >>>the function you use
              >>>needs to be defined before the method definition.
              >>
              >>FWIW, the term "class method" has a
              >>definite meaning in Python.
              >
              >
              >
              Certainly. But "class decorator" is being introduced in
              Python 3000 with PEP 3129:
              This PEP proposes class decorators, an extension to the function and method decorators introduced in PEP 318.

              >
              Certainly. But [1] "class methods" have been introduced in Python 2.2 !-)

              [1] IIRC - please someone correct me if I'm wrong

              Comment

              Working...