0

I am somewhat new to decorators in Python and are struggeling with a simple decorator, that is supposed to check for a state of my class (doing the operation once when one of the dependending functions is actually called for the first time). My problem is, that I want to let the decorator function also know about everything in self and pass the actual function as 'argument'(?)

class myClass(object):
    __init__(self):
        self.__isFoo = False
        self.__baz = 0

    def doFoo(self):
        ...  
        self.__isFoo = True

    def fooInit(self,func):
        if not self.__isFoo:
            self.doFoo()
        return func

    @property
    @fooInit
    def getBaz(self):
        return self.__baz

however, with this one, I get an error that

myObj = myClass()
myObj.getBaz

~~> TypeError: fooInit() takes exactly 2 arguments (1 given)

which I somewhat understand, since it is just self.fooinit( self.getBaz ) if I understand decorators correctly, or?

So I am a bit lost now, how I can define the decorator in an easy way, that it also knows the other objects in the class namespace?

THX
  • 553
  • 2
  • 8
  • 18
  • 2
    possible duplicate of [Decorating a class method after @property](http://stackoverflow.com/questions/4923706/decorating-a-class-method-after-property) – aruisdante Oct 17 '14 at 15:45
  • This actually has to do with the fact that you're decorating a property. See the linked duplicate. – aruisdante Oct 17 '14 at 15:45
  • 1
    And remember, your arguments to the decorator are actually going to be ``(func, *args, **kwargs)``, where ``args[0]`` is going to be ``self``. Generally speaking, the [decorator functions](http://simeonfranklin.com/blog/2012/jul/1/python-decorators-in-12-steps/) themselves aren't defined as part of the class name-space. – aruisdante Oct 17 '14 at 15:47
  • And you have to remember to call the passed in function as well. Decorators are just syntactic sugar around writing ``wrapper(func, *args, **kwargs)``, where ``func`` will always be the decorated function. They don't change python's call mechanics at all. – aruisdante Oct 17 '14 at 15:53
  • You have a typo which missing `def` before `__init__(self)` – Anzel Oct 17 '14 at 16:13
  • @aruisdante thanks for the duplicate link and the suggestions – THX Oct 20 '14 at 14:47
  • however, it seems that I still struggle with the decorator vs. namespace wrapping even when omitting the @property decorator. I.e., I still would rely on fooInit to be in the classes namespace, def fooInit(self,func): def _wrapped(*args, **kwargs): if not self.doFoo: func(*args, **kwargs) return _wrapped if you are right and a decorator cannot be defined within the class namespace I have to find another way (without the syntactic sugar) :-/ – THX Oct 20 '14 at 14:53
  • @aruisdante sorry for the noise -- finally I got it. self will be the first of the *args arguments... took a while for me ;) – THX Oct 20 '14 at 14:59

1 Answers1

0

following @aruisdante's suggestions I managed to get a proper decorator working

def fooInit(func):
    def _wrapped(self,*args, **kwargs):
        if not self.__isFoo:
            self.fooInit()
            return func(self,*args, **kwargs)
    return _wrapped

(defined within my class)

THX
  • 553
  • 2
  • 8
  • 18