0

heyo... i'm learning decorators. interesting stuff. i think i'm missing something though, or maybe it's not the decorators but how i'm working with classes? when I do this in terminal it works:

class Client:
    """The main client."""

    def __init__(self, config, creds):
        """Initialize."""
        self.config = config
        self.creds = creds

    def context(func, *args, **kwargs):
        @wraps(func)
        def func_with_context(*args, **kwargs):
            print(f'contextualizing {func.__name__}')
            print(creds.user_name)
            return (args, kwargs)
        return func_with_context

    @context
    def test(self, creds):
        pass 

i have two package objects i can instantiate and pass in:

creds = mypackage.credentials.auto()
config = mypackage.Configuration()

and then when i do:

client = Client(config, creds)
client.test('yo')
>>>contextualizing test
username@org
((<__main__.Client object at 0x101b66208>, 'yo'), {})

but when i do this from the package itself i get

import mypackage as mypackage
client = mypackage.Client(config, creds)
client.test('yo')
contextualizing test
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/dblack/Code/mypackage/mypackage/client.py", line 51, in func_with_context
    creds.user_name,
NameError: name 'creds' is not defined

why would this work when i just declare a class but not when it's in the package namespace?

  • 1
    Shouldn't it be `self.creds` in your `print` function? – Thomas Kühn Feb 16 '18 at 20:30
  • @ThomasKühn i get a similar error: `Traceback (most recent call last): File "", line 1, in File "/Users/dblack/Code/mypackage/mypackage/client.py", line 45, in func_with_context print(self.creds.user_name) NameError: name 'self' is not defined` – Daniel Antonin Black Feb 16 '18 at 20:35
  • Because you also missed `self` out of your method parameters – khelwood Feb 16 '18 at 20:39
  • @khelwood i cannot declare self in that method parameter (why it got removed). by adding it to `def context(self, func, *args, **kwargs):` we get: `TypeError: context() missing 1 required positional argument: 'func'` – Daniel Antonin Black Feb 16 '18 at 20:41
  • 2
    But you could add it to `func_with_context`, since that is supposed to replace a method – khelwood Feb 16 '18 at 20:44
  • @khelwood i want to cry! that worked. and your explanation helped to understand decorators inside a class better (which i see perhaps shouldn't happen though: https://stackoverflow.com/questions/1263451/python-decorators-in-classes – Daniel Antonin Black Feb 16 '18 at 20:50

1 Answers1

3

Since func_with_context is going to take the place of a method, it should have a self parameter. Then inside it, you can reference the creds attribute using self.creds.

def context(func, *args, **kwargs):
    @wraps(func)
    def func_with_context(self, *args, **kwargs):
        print(f'contextualizing {func.__name__}')
        print(self.creds.user_name)
        return (args, kwargs)
    return func_with_context
khelwood
  • 55,782
  • 14
  • 81
  • 108