#How to get class instance self inside a decorator method?

1 messages · Page 1 of 1 (latest)

azure iron
#

Your get_things_wrapped decorator is being passed the function as its self parameter. The self parameter acts like a normal parameter when you call the function directly as you are

#

You can't use a decorator the way you are. What are you trying to accomplish exactly?

#

You're also not using async functions correctly, the way you're using them they could more easily be implemented as standard functions...

azure iron
#

Yeah because you're passing self to wrapper and self is the function since you're calling the get_things_wrapped directly

#

!exec ```py
class Example:
def example(self):
print(self)

# call it directly with a random argument
example("hi")

call it on an instance

instance = Example()
instance.example()

wintry drumBOT
azure iron
#

See how when I called it directly self had to be passed in since it acts like a normal parameter but then I created an instance and called the function on the instance self was set automatically

#

!exec ```py
class Example:
def example(self):
""" do nothing """

# print out the function directly
print(example)

print the function on an instance

instance = Example()
print(instance.example)

wintry drumBOT
azure iron
#

See how when I print the function directly it's a function object but when I print it from on the instance it's a bound method.

When you create a method all the functions become bound methods. That just means that their first parameter will be automatically set to the instance the function is bound to.

#

So if you want to use a decorator on a function and to get access to the self parameter you need to figure out how to do it such that at some point one of your functions gets bound to an instance of the class.

#

If I understand correctly you want a decorator that will handle calling your function using asyncio.run?

#

When you use a decorator it's just a fancy way of calling the decorator function and passing it the decorated function

#

!exec ```py
def decorator(func):
print(func)

@decorator
def example_at_decorator():
""" do nothing """

def example_whats_actually_happening ():
""" do nothing """

example_whats_actually_happening = decorator(example_whats_actually_happening)

wintry drumBOT
azure iron
#

The @ syntax is just syntactic sugar for that second function and the call to decorator after it.

#
def make_sync_callable(func):
    def wrapper(self):
        return asyncio.run(func(self))

    return wrapper

class Example:
    @make_sync_callable
    async def example(self):
        ...
#

That's how you'd do what you want

#

The make_sync_callable will replace the example function with a copy of the wrapper function that is in a closure that contains the old version of example as func. When you create an instance of Example the copy of wrapper that replaced example will be bound to the instance and calling example on the instance will pass the instance to wrapper which will pass self to the original version of example.

#

Essentially doing make_sync_callable causes example to be replaced by wrapper.

#

I think you should consider making your code async compatible rather than trying to get clever like this though.

#

This approach will break your code editor's linting and type hinting

#

It'll tell you that you've not awaited your function even though you don't need to because your decorator is running it inside of an event loop

#

If your code were async you'd not need to use async.run to call a method on your class. You'd only use it once to start your entire application.

#

Yes because your editor's linting and type checking will see that the function is async and expect you to await it. You never will because your decorator implicitly swaps the async function for a standard function that calls the async function using asyncio.run

#

You can modify wrapper to do whatever you want. The self inside wrapper is the actual self

#

Self doesn't exist only inside the class

#

!exec ```py
class Example:
""" do nothing """

def outside_the_class(self):
print(self)

Example.example = outside_the_class

instance = Example()
instance.example()

wintry drumBOT
azure iron
#

See how self was implicitly passed to the function even though it was declared outside the class

#

No because you never return wrapper

#

You can't

#

You need an instance to call the method on

#

What do you need to do that must happen before the class is instantiated???

#

I don't understand what you're trying to accomplish that needs to happen before you have an instance

#

Are you trying to run the function immediately for some reason?

#

I really don't get what you're trying to accomplish

#

!exec ```py
print("This is what your decorator is doing. It calls the decorated function immediately.")
print("Starting")
class Example:
def decorator(func):
def wrapper():
func("ran immediately")

    wrapper()

@decorator
def example(self):
    print(self)

print("Done")

wintry drumBOT
azure iron
#

See how ran immediately is printed after Starting but before Done.

#

I don't think that's what you want

#

My decorator requires you to create an instance of the class and then call the function

example = Example()
example.example()
#

You can't use an async function as a decorator

#

Python will let you but it's not gonna work how you think

#

It is, it's exactly what your code was doing but instead of passing a string in place of self you just passed the function as self.

#

After nearly 20 years of using Python I can confirm you have some python stuff going on lol

#

I just can't understand what you're trying to accomplish with this code so I can't tell you how to correct it

#

They're functions. The values are assigned later when you call the function, so the values you want the function to use don't have to exist when the function is created.

azure iron
#

Ah, you want to sync the weather before actually running the function

#

return func(self)

#

I'd rename the decorator update_weather

#

I'd just make the name something that makes it clear what it's doing

#

My decorator was making an async function sync, hence the name I chose