#How to get class instance self inside a decorator method?
1 messages · Page 1 of 1 (latest)
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...
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()
@azure iron
hi
<__main__.Example object at 0x7f3888e6fc10>
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)
@azure iron
<function Example.example at 0x7efeb5c794e0>
<bound method Example.example of <__main__.Example object at 0x7efeb5c66110>>
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)
@azure iron
<function example_at_decorator at 0x7fd541ff54e0>
<function example_whats_actually_happening at 0x7fd541ff54e0>
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()
@azure iron
<__main__.Example object at 0x7f170e135f90>
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")
@azure iron
This is what your decorator is doing. It calls the decorated function immediately.
Starting
ran immediately
Done
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.