[python] एक वर्ग बनाम एक समारोह का उपयोग कर पाइथन सजावट सर्वोत्तम अभ्यास



Answers

मैं ज्यादातर jsbueno से सहमत हूं: कोई भी सही तरीका नहीं है। यह स्थिति पर निर्भर करता है। लेकिन मुझे लगता है कि अधिकांश मामलों में __call__ शायद बेहतर है, क्योंकि यदि आप कक्षा के साथ जाते हैं, तो अधिकांश "असली" काम __call__ भी तरह से __call__ में किया जा रहा है। साथ ही, कॉलबेल जो फ़ंक्शंस नहीं हैं वे बहुत दुर्लभ हैं (कक्षा को तुरंत चालू करने के उल्लेखनीय अपवाद के साथ), और आम तौर पर लोग इसकी अपेक्षा नहीं करते हैं। साथ ही, लोगों के लिए बनाम आवृत्ति चर का ट्रैक रखने के लिए स्थानीय चर आमतौर पर आसान होते हैं, क्योंकि उनके पास अधिक सीमित गुंजाइश है, हालांकि इस मामले में, आवृत्ति चर संभवतया केवल __call__ में उपयोग की __call__ ( __init__ साथ बस उन्हें तर्क से कॉपी करते हैं)।

हालांकि मुझे अपने संकर दृष्टिकोण से असहमत होना है। यह एक दिलचस्प डिजाइन है, लेकिन मुझे लगता है कि यह शायद आपके या किसी अन्य व्यक्ति के बकवास को भ्रमित करने जा रहा है जो इसे कुछ महीने बाद देखता है।

टेंगेंट: भले ही आप कक्षा या फ़ंक्शन के साथ जाएं, आपको functools.wraps उपयोग करना चाहिए, जिसे स्वयं functools.wraps रूप में उपयोग किया जाना है (हमें गहरा जाना चाहिए!) जैसे:

import functools

def require_authorization(f):
    @functools.wraps(f)
    def decorated(user, *args, **kwargs):
        if not is_authorized(user):
            raise UserIsNotAuthorized
        return f(user, *args, **kwargs)
    return decorated

@require_authorization
def check_email(user, etc):
    # etc.

यह decorated दिखता है जैसे check_email उदाहरण के लिए func_name विशेषता बदलकर।

वैसे भी, यह आमतौर पर मैं करता हूं और जो कुछ मैं अपने आस-पास के अन्य लोगों को देखता हूं, जब तक कि मैं एक सजावटी कारखाना नहीं चाहता। उस स्थिति में, मैं सिर्फ डीफ़ का एक और स्तर जोड़ता हूं:

def require_authorization(action):
    def decorate(f):
        @functools.wraps(f):
        def decorated(user, *args, **kwargs):
            if not is_allowed_to(user, action):
                raise UserIsNotAuthorized(action, user)
            return f(user, *args, **kwargs)
        return decorated
    return decorate

वैसे, मैं सजावटी के अत्यधिक उपयोग के खिलाफ भी सावधान रहूंगा, क्योंकि वे स्टैक निशान का पालन करना वाकई मुश्किल बना सकते हैं।

घृणास्पद स्टैक निशान के प्रबंधन के लिए एक दृष्टिकोण है कि सजावट के व्यवहार को काफी हद तक बदलना न हो। उदाहरण के लिए

def log_call(f):
    @functools.wraps(f)
    def decorated(*args, **kwargs):
        logging.debug('call being made: %s(*%r, **%r)',
                      f.func_name, args, kwargs)
        return f(*args, **kwargs)
    return decorated

अपने स्टैक निशान कोने रखने के लिए एक और चरम दृष्टिकोण सजावट के लिए सजावट को असम्बद्ध करने के लिए है, जैसे:

import threading

DEPRECATED_LOCK = threading.Lock()
DEPRECATED = set()

def deprecated(f):
    with DEPRECATED_LOCK:
        DEPRECATED.add(f)
    return f

@deprecated
def old_hack():
    # etc.

यह उपयोगी है अगर फ़ंक्शन को ढांचे के भीतर बुलाया जाता है जो deprecated सजावट के बारे में जानता है। उदाहरण के लिए

class MyLamerFramework(object):
    def register_handler(self, maybe_deprecated):
        if not self.allow_deprecated and is_deprecated(f):
            raise ValueError(
                'Attempted to register deprecated function %s as a handler.'
                % f.func_name)
        self._handlers.add(maybe_deprecated)
Question

जैसा कि मैंने समझा है कि एक वर्ग के __call__ का उपयोग करने के लिए या एक सजावट के रूप में एक समारोह को परिभाषित करने और कॉल करने के लिए पाइथन सजावट करने के दो तरीके हैं। इन तरीकों के फायदे / नुकसान क्या हैं? क्या कोई पसंदीदा तरीका है?

उदाहरण 1

class dec1(object):
    def __init__(self, f):
        self.f = f
    def __call__(self):
        print "Decorating", self.f.__name__
        self.f()

@dec1
def func1():
    print "inside func1()"

func1()

# Decorating func1
# inside func1()

उदाहरण 2

def dec2(f):
    def new_f():
        print "Decorating", f.__name__
        f()
    return new_f

@dec2
def func2():
    print "inside func2()"

func2()

# Decorating func2
# inside func2()





Links