简体   繁体   中英

Python decorator to limit a method to a particular class?

I've got a large library of Django apps that are shared by a handful of Django projects/sites. Within each project/site there is an option to define a 'Mix In' class that will be mixed in to one of the in-library base classes (which many models sub-class from).

For this example let's say the in-library base class is PermalinkBase and the mix-in class is ProjectPermalinkBaseMixIn .

Because so many models subclass from PermalinkBase , not all the methods/properities defined in ProjectPermalinkBaseMixIn will be utilitized by all of PermalinkBase 's subclasses.

I'd like to write a decorator that can be applied to methods/properties within ProjectPermalinkBaseMixIn in order to limit them from running (or at least returning None ) if they are accessed from a non-approved class.

Here's how I'm doing it now:

class ProjectPermalinkBaseMixIn(object):
    """
    Project-specific Mix-In Class to `apps.base.models.PermalinkBase`
    """

    def is_video_in_season(self, season):
        # Ensure this only runs if it is being called from the video model
        if self.__class__.__name__ != 'Video':
            to_return = None
        else:
            videos_in_season = season.videos_in_this_season.all()
            if self in list(videos_in_season):
                to_return = True
            else:
                to_return False

        return to_return

Here's how I'd like to do it:

class ProjectPermalinkBaseMixIn(object):
    """
    Project-specific Mix-In Class to `apps.base.models.PermalinkBase`
    """

    @limit_to_model('Video')
    def is_video_in_season(self, season):
        videos_in_season = season.videos_in_this_season.all()
        if self in list(videos_in_season):
            to_return = True
        else:
            to_return = False

        return to_return

Is this possible with decorators? This answer helped me to better understand decorators but I couldn't figure out how to modify it to solve the problem I listed above.

Are decorators the right tool for this job? If so, how would I write the limit_to_model decorator function? If not, what would be the best way to approach this problem?

was looking at your problem and I think this might be an overcomplicated way to achieve what you are trying to do. However I wrote this bit of code:

def disallow_class(*klass_names):
    def function_handler(fn):
        def decorated(self, *args, **kwargs):
            if self.__class__.__name__ in klass_names:
                print "access denied to class: %s" % self.__class__.__name__
                return None
            return fn(self, *args, **kwargs)
        return decorated
    return function_handler


class MainClass(object):

    @disallow_class('DisallowedClass', 'AnotherDisallowedClass')
    def my_method(self, *args, **kwargs):
        print "my_method running!! %s" % self


class DisallowedClass(MainClass): pass

class AnotherDisallowedClass(MainClass): pass

class AllowedClass(MainClass): pass


if __name__ == "__main__":
    x = DisallowedClass()
    y = AnotherDisallowedClass()
    z = AllowedClass()
    x.my_method()
    y.my_method()
    z.my_method()

If you run this bit of code on your command line the output will be something like:

access denied to class: DisallowedClass
access denied to class: AnotherDisallowedClass
my_method running!! <__main__.AllowedClass object at 0x7f2b7105ad50>

Regards

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