GrahamDumpleton / wrapt

A Python module for decorators, wrappers and monkey patching.
BSD 2-Clause "Simplified" License
2.04k stars 230 forks source link

How to access function for registering? #114

Closed legshort closed 6 years ago

legshort commented 6 years ago

Hi folks! I was trying to access function for registering but I couldn't find an elegant way. Normally, I can do it without wrapt package as below.

I would be very helpful anyone could help me, cheers!

# Plain Decorator
def my_decorator(desc):
    def decorate(func):
        registry.append(func) # <- I would like to access func at this point
        @wraps(func)
        def wrapper(*args, **kwargs):
            return func(*args, **kwargs)
        return wrapper
    return decorate
GrahamDumpleton commented 6 years ago

Can you provide an example of how you use that? It is unclear why you have the outer my_decorator() wrapper when desc isn't used.

legshort commented 6 years ago

First of all thanks for the comment. I was building something with inner function and automatic call. So basically, I wanna make the @child method called from inside of @parent decorator automatically and so as of call @grandchild from @child.

That's why I was trying to register inner_child_function() within @child decorator in order to call them later.

I hope this will help you more to understand the reason why I posted this question.

class NewClass:
    @parnet('this is a parent')
    def main_method(self):
        print('main method')

        @child('this is child)
        def inner_child_function():
            print('this is a child')

            @grandchild('this is a grandchild')
            def inner_grandchild_function():
                print('this is a grandchild')

            # inner_grandchild_function()

        # inner_child_function() 
        # this is a regular way to call inner_child_function()
        # but I was wondering if the method is called by @parent and @child decorator 
        # without calling the method explicitly like commented above like
GrahamDumpleton commented 6 years ago

I can't see how you could even achieve that even if you weren't using wrapt.

The @child decorator on inner_child_function() is only going to be evaluated when the main_method() is called. It is actually evaluated every time main_method() is called.

This is too late to register inner_child_function() so that it is somehow called automatically when main_method() is called.

Do you have a working example which doesn't use wrapt?

Also, what problem are you trying to solve by even have inner_child_function() called automatically when main_method() is called?

legshort commented 6 years ago

haha I'm just building something in my mind not production level problem. You are right, inner_child_function() is evaluated when actually called so I couldn't register with wrap. However, I achieved to register inner_child_function() without wrap but @child decorator was not triggered when it is called from inside of @parent decorator.

def parent(desc):
  @wrapt.decorator
  def wrapper(wrapped, instance, args, kwargs):
    result = wrapped(*args, **kwargs)
    for child in children:
      child() # <- call child function but @child.decorate.wrapper() never triggered
    return result

def child(desc):
  def decorate(func):
    children.append(func) # <- register child function

    @wraps(func):
    def wrapper(*args, **kwargs):
      return func(*args, **kwargs)
    return wrapper
  return decorate

I have looked at the mechanism of inner function of python and I kind of came to this way won't work so trying to solve this other way. I appreciate your support and you are more than welcome to share your any thought.

GrahamDumpleton commented 6 years ago

It will help if you can explain what the overall goal is as then may be able to suggest other ways of doing it.

GrahamDumpleton commented 6 years ago

@dgrigonis1 Can you please create a separate issue rather than adding a new question on an existing issue.

GrahamDumpleton commented 6 years ago

Closing this issue now. Reopen or create new issue if have new question around it.