2010-07-31 16 views
9

मैं वेब अनुप्रयोग के भीतर संसाधनों तक पहुंचने के तरीके (Google ऐप इंजन पर चलने) के तरीके को प्रबंधित करने के तरीके के प्रबंधन के लिए सजावटी का उपयोग करने की कोशिश कर रहा हूं। कृपया ध्यान दें कि मैं उपयोगकर्ताओं को अपने Google खातों से लॉग इन करने की अनुमति नहीं दे रहा हूं, इसलिए app.yaml के भीतर विशिष्ट मार्गों के विशिष्ट पहुंच अधिकार सेट करना एक विकल्प नहीं है। Bruce Eckel's guide to decorators
- - SO : get-class-in-python-decorator2
- SO : python-decorators-and-inheritance
- SO : get-class-in-python-decoratorपायथन सजावट और कक्षा विरासत

हालांकि मैं अभी भी एक सा उलझन में हूँ ...

यहाँ मेरी कोड है
:

मैं निम्नलिखित संसाधनों का इस्तेमाल किया! निम्न उदाहरण में, current_user एक @property विधि है जो RequestHandler क्लास से संबंधित है। यह डेटा स्तर पर संग्रहीत एक उपयोगकर्ता (डीबी.मोडेल) ऑब्जेक्ट देता है, जिसमें एक स्तर इंटप्रोपर्टी() होता है।

class FoobarController(RequestHandler): 

    # Access decorator 
    def requiredLevel(required_level): 
     def wrap(func): 
      def f(self, *args): 
       if self.current_user.level >= required_level: 
        func(self, *args) 
       else: 
        raise Exception('Insufficient level to access this resource') 
      return f 
     return wrap 

    @requiredLevel(100) 
    def get(self, someparameters): 
     #do stuff here... 

    @requiredLevel(200) 
    def post(self): 
     #do something else here... 

हालांकि, मेरा आवेदन विभिन्न प्रकार के संसाधनों के लिए विभिन्न नियंत्रकों का उपयोग करता है। आदेश सभी उपवर्गों भीतर @requiredLevel डेकोरेटर का उपयोग करने में, मैं माता पिता के वर्ग (RequestHandler) पर ले जाते हैं की जरूरत है:

class RequestHandler(webapp.RequestHandler): 

    #Access decorator 
    def requiredLevel(required_level): 
     #See code above 

मेरा विचार निम्नलिखित कोड का उपयोग कर सभी नियंत्रक उपवर्गों में डेकोरेटर का उपयोग करने की है:

class FoobarController(RequestHandler): 

    @RequestHandler.requiredLevel(100) 
    def get(self): 
     #do stuff here... 

मुझे लगता है कि मैं सिर्फ सजावटी और कक्षा विरासत के बारे में अपने ज्ञान की सीमा तक पहुंच गया :)। कोई विचार ?

+1

क्यों यह वर्ग पर एक विधि है? इससे चीजों को तोड़ने का कारण बन जाएगा, और यह केवल उस कक्षा के अंदर एक नियमित कार्य की तरह काम करेगा जो इसे परिभाषित किया गया था। जब तक कि आप 3.x पर न हों, इस मामले में यह शायद ठीक काम करेगा। –

+0

सजावट कक्षा पर एक विधि है क्योंकि मुझे अभी तक यह नहीं पता है कि सजावटकर्ता को कक्षा 1 के रूप में कैसे कोड करना है/जो कि तर्क (ओं) को स्वीकार करता है और 2/जो वर्तमान वर्ग के तरीकों तक पहुंच सकता है। क्या यही आपका मतलब है ? ज्यादातर आत्म-सिखाए जाने के नाते, मुझे ब्रूस एकल की मार्गदर्शिका, सजावट करने वालों और विरासत को पूरी तरह से समझने में परेशानी हो रही है। – jbmusso

+0

आप कक्षा के बाहर फ़ंक्शन को कॉपी-पेस्ट कर सकते हैं, और यह ठीक और सामान्य काम करेगा। क्या यह आपके प्रश्न का उत्तर देने के लिए पर्याप्त होगा? –

उत्तर

4

आपके मूल कोड, दो छोटे tweaks के साथ, भी काम करना चाहिए। एक वर्ग आधारित दृष्टिकोण के बजाय लगता है इस तरह के एक सरल डेकोरेटर के लिए भारी वजन:

class RequestHandler(webapp.RequestHandler): 

    # The decorator is now a class method. 
    @classmethod  # Note the 'klass' argument, similar to 'self' on an instance method 
    def requiredLevel(klass, required_level): 
     def wrap(func): 
      def f(self, *args): 
       if self.current_user.level >= required_level: 
        func(self, *args) 
       else: 
        raise Exception('Insufficient level to access this resource') 
      return f 
     return wrap 


class FoobarController(RequestHandler): 
    @RequestHandler.requiredLevel(100) 
    def get(self, someparameters): 
     #do stuff here... 

    @RequestHandler.requiredLevel(200) 
    def post(self): 
     #do something else here... 

वैकल्पिक रूप से, आप इस्तेमाल कर सकते हैं एक @staticmethod बजाय:

class RequestHandler(webapp.RequestHandler): 

    # The decorator is now a static method. 
    @staticmethod  # No default argument required... 
    def requiredLevel(required_level): 

कारण मूल कोड काम नहीं किया है कि है आवश्यक लेवल को एक उदाहरण विधि माना जाता था, जो कक्षा-घोषणा समय (जब आप अन्य विधियों को सजाने वाले थे) में उपलब्ध नहीं होने जा रहे हैं, न ही यह कक्षा वस्तु से उपलब्ध होगा (सजावटी को आपके अनुरोध पर रखकर हैंडलर बेस क्लास एक उत्कृष्ट विचार है, और परिणामी सजावटी कॉल अच्छी तरह से स्वयं दस्तावेज है)।

आप @classmethod और @staticmethod के बारे में दस्तावेज़ को पढ़ने में रुचि रखते हैं।

इसके अलावा, बॉयलरप्लेट मैं अपने सज्जाकार में डाल करना चाहते का एक छोटा सा:

@staticmethod 
    def requiredLevel(required_level): 
     def wrap(func): 
      def f(self, *args): 
       if self.current_user.level >= required_level: 
        func(self, *args) 
       else: 
        raise Exception('Insufficient level to access this resource') 
      # This will maintain the function name and documentation of the wrapped function. 
      # Very helpful when debugging or checking the docs from the python shell: 
      wrap.__doc__ = f.__doc__ 
      wrap.__name__ = f.__name__ 
      return f 
     return wrap 
1

स्टैक ओवरव्लो के माध्यम से खुदाई करने के बाद, और ध्यान से Bruce Eckel's guide to decorators पढ़ने के बाद, मुझे लगता है कि मुझे एक संभावित समाधान मिला है।

यह जनक कक्षा में एक वर्ग के रूप में डेकोरेटर को लागू करना शामिल है:

class RequestHandler(webapp.RequestHandler): 

    # Decorator class : 
    class requiredLevel(object): 
     def __init__(self, required_level): 
      self.required_level = required_level 

     def __call__(self, f): 
      def wrapped_f(*f_args): 
       if f_args[0].current_user.level >= self.required_level: 
        return f(*f_args) 
       else: 
        raise Exception('User has insufficient level to access this resource') 
      return wrapped_f 

यह काम करता है! F_args का उपयोग करना [0] मेरे लिए थोड़ा गंदा लगता है, अगर मुझे कुछ सुंदर लगता है तो मैं इस जवाब को संपादित कर दूंगा।

FooController(RequestHandler): 
    @RequestHandler.requiredLevel(100) 
    def get(self, id): 
     # Do something here 

    @RequestHandler.requiredLevel(250) 
    def post(self) 
     # Do some stuff here 

BarController(RequestHandler): 
    @RequestHandler.requiredLevel(500) 
    def get(self, id): 
     # Do something here 

टिप्पणी या बढ़ा हुआ प्रस्ताव करने के लिए स्वतंत्र महसूस:

तो फिर तुम उपवर्गों में तरीकों का पालन रास्ता सजाने कर सकते हैं।

+0

आप फ़ंक्शन हस्ताक्षर के रूप में 'wrapped_f (request_handler, * args, ** kwargs)' का उपयोग कर सकते हैं। इसके अलावा सजावटी वर्ग को आपके RequestHandler क्लास में रखने की कोई आवश्यकता नहीं है। मैं इसे मॉड्यूल स्तर पर रखूंगा। – nils

+0

आपकी टिप्पणी के लिए धन्यवाद! मुझे लगता है कि आपने मुझे समझ लिया है कि विरासत अलग-अलग तरीके से काम करता है (और बहुत बेहतर)। मैं तदनुसार अपना कोड अपडेट करूंगा। – jbmusso

संबंधित मुद्दे