简体   繁体   中英

Using decorator specified in Child class on Parent class methods

Let's say I have two classes Child and Parent (which is base class for Child ). I have another class Dec which contains a decorator dec I'd like to be used over Parent methods. I want to be able to specify a Dec object that should be used in Child .

Here's what I've tried so far:

class Dec():
    def dec(self, func):
        def wrapper(self):
            print("Before func call")
            func(self)
            print("After func call")

        return wrapper

class Parent():
    dec = None

    @dec.dec
    def p(self):
        print('hello')

dec = Dec()

class Child(Parent):
    a = dec

t = Child()
t.p()

So, I got

AttributeError: 'NoneType' object has no attribute 'dec'

at @dec.dec .

Is there any option to specify a class with decorator that should be used in Child class?

The issue you are experiencing here has to do with scoping.

When I ran this code, I received this error:

...<stack trace>...
  File ".\__main__.py", line 10, in <module>
    class Parent():
  File ".\__main__.py", line 13, in Parent
    @dec.dec
AttributeError: 'NoneType' object has no attribute 'dec'

Using that, you can see that you have some scoping issues. In this file, you define dec several times. Rather than instantiate Dec like you do on line 11, define Dec.dec(...) as a @classmethod , callable from the class itself, instead of just an instance of the class.

here is a potential solution:

class Dec():
    @classmethod
    def dec(self, func):
        def wrapper(self):
            print("Before func call")
            func(self)
            print("After func call")

        return wrapper

class Parent():
    @Dec.dec
    def p(self):
        print('hello')


class Child(Parent):
    pass # you didn't really need anything here.

t = Child()
t.p()

This provides what I believe to be the expected behavior:

Before func call
hello
After func call

As an alternative to the other solution, here's another approach:

define some sort of generic structure for your process, and then change the "decorator" or "extended processor" for your classes...

class Parent:
    extended_processor = None

    def p(self):
        if (self.extended_processor is not None and 
            hasattr(self.extended_processor, "before") and 
            callable(self.extended_processor.before)):
            self.extended_processor.before()

        print('parent says hello')

        if (self.extended_processor is not None and 
            hasattr(self.extended_processor, "after") and 
            callable(self.extended_processor.after)):
            self.extended_processor.after()

class ex_proc:
    @classmethod
    def before(cls):
        print("ex_proc before")

    @classmethod
    def after(cls):
        print("ex_proc after")

class Child(Parent):
    extended_processor = ex_proc

print("\n=== PARENT ===")
par = Parent()
par.p()

print("\n=== CHILD ===")
chi = Child()
chi.p()

this provides the following output:

=== PARENT ===
parent says hello

=== CHILD ===
ex_proc before
parent says hello
ex_proc after

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM