क्या एक लंबी फ़ंक्शन नाम को कई लाइनों में तोड़ना संभव है?


83

हमारी विकास टीम PEP8 लिंटर का उपयोग करती है जिसके लिए अधिकतम 80 वर्णों की लाइन की आवश्यकता होती है ।

जब मैं अजगर में यूनिट परीक्षण लिख रहा हूं, तो मुझे यह बताने के लिए वर्णनात्मक विधि के नाम पसंद हैं कि प्रत्येक परीक्षण क्या करता है। हालाँकि यह अक्सर मुझे चरित्र सीमा से अधिक की ओर ले जाता है।

यहाँ एक फ़ंक्शन का एक उदाहरण है जो बहुत लंबा है ...

class ClientConnectionTest(unittest.TestCase):

    def test_that_client_event_listener_receives_connection_refused_error_without_server(self):
        self.given_server_is_offline()
        self.given_client_connection()
        self.when_client_connection_starts()
        self.then_client_receives_connection_refused_error()

मेरे विकल्प:

  • आप बस कम विधि नाम लिख सकते हैं!

    मुझे पता है, लेकिन मैं परीक्षण नामों की वर्णनात्मकता नहीं खोना चाहता।

  • आप लंबे नामों का उपयोग करने के बजाय प्रत्येक परीक्षण के ऊपर मल्टी-लाइन टिप्पणियां लिख सकते हैं!

    यह एक सभ्य विचार है, लेकिन तब मैं अपनी IDE (PyCharm) के अंदर परीक्षण चलाने के दौरान परीक्षण के नाम नहीं देख पाऊंगा।

  • शायद आप बैकस्लैश (एक तार्किक लाइन निरंतरता चरित्र) के साथ लाइनों को जारी रख सकते हैं।

    दुर्भाग्य से यह पायथन में एक विकल्प नहीं है, जैसा कि दान के उत्तर में वर्णित है।

  • आप अपनी परीक्षाओं को रोक सकते हैं।

    यह कुछ तरीकों से समझ में आता है, लेकिन एक अच्छी तरह से स्वरूपित परीक्षण सूट को प्रोत्साहित करना अच्छा है।

  • आप लाइन की लंबाई सीमा बढ़ा सकते हैं।

    हमारी टीम को सीमा रखना पसंद है क्योंकि यह संकीर्ण डिस्प्ले पर कोड को पठनीय रखने में मदद करता है, इसलिए यह सबसे अच्छा विकल्प नहीं है।

  • आप testअपने तरीकों की शुरुआत से हटा सकते हैं ।

    यह एक विकल्प नहीं है। पायथन के परीक्षण धावक को शुरू करने के लिए सभी परीक्षण विधियों की आवश्यकता होती है testया यह उन्हें नहीं उठाएगा।

    संपादित करें: कुछ परीक्षण धावक आपको परीक्षण कार्यों की खोज करते समय एक नियमित अभिव्यक्ति निर्दिष्ट करते हैं, हालांकि मैं ऐसा नहीं करूंगा क्योंकि यह परियोजना पर काम करने वाले सभी के लिए अतिरिक्त सेटअप है।

  • आप EventListener को उसकी अपनी कक्षा में अलग कर सकते हैं और उसका अलग से परीक्षण कर सकते हैं।

    घटना श्रोता है अपने ही वर्ग में (और परीक्षण किया जाता है)। यह सिर्फ एक इंटरफ़ेस है जो क्लाइंटकॉन्क्शन के भीतर होने वाली घटनाओं से ट्रिगर हो जाता है। इस तरह के सुझाव से अच्छा इरादा लगता है, लेकिन यह गलत है और मूल प्रश्न का उत्तर देने में मदद नहीं करता है।

  • आप व्यवहार की तरह एक BDD फ्रेमवर्क का उपयोग कर सकते हैं । इसे अभिव्यंजक परीक्षणों के लिए डिज़ाइन किया गया है।

    यह सच है, और मैं भविष्य में उनमें से अधिक का उपयोग करने की उम्मीद करता हूं। हालाँकि मैं अभी भी जानना चाहता हूँ कि कैसे रेखाओं में फ़ंक्शन नामों को विभाजित किया जाए।

अंततः ...

क्या पायथन में एक तरीका है कि एक लंबी फ़ंक्शन घोषणा को कई लाइनों में विभाजित किया जाए ?

उदाहरण के लिए...

def test_that_client_event_listener_receives_
  connection_refused_error_without_server(self):
    self.given_server_is_offline()
    self.given_client_connection()
    self.when_client_connection_starts()
    self.then_client_receives_connection_refused_error()

या मुझे गोली काटकर खुद को छोटा करना पड़ेगा?


8
एक वर्णनात्मक फ़ंक्शन का उपयोग डॉकस्ट्रिंग में क्यों नहीं किया जाता है? फिर आप इसे प्रिंट कर सकते हैंfunc.__doc__
— जाकुब

62
अपनी इकाई परीक्षणों को पंक्तिबद्ध करना बंद करें।
— जॉन कुगेलमैन

55
फिर इस नियम को बंद कर दें। यह एक मामूली पागलपन है कि आप इसे अक्षम करने के बजाय इस एक प्रकार का वृक्ष नियम के आसपास काम करने की इतनी कोशिश कर रहे हैं।
— जॉन कुगेलमैन

13
फिर से आना PEP8 python.org/dev/peps/pep-0008 , दिशानिर्देशों को नजरअंदाज करने के अच्छे कारण: When applying the guideline would make the code less readable, even for someone who is used to reading code that follows this PEP.आपके मामले में जो छोटे फ़ंक्शन नाम का उपयोग कर रहे हैं।
— अकवाल

56
कंप्यूटर विज्ञान में दो कठिन समस्याएं हैं, कैश अमान्य होना, नामकरण की चीजें और ऑफ-बाय-वन त्रुटियां।
— सुर्त

जवाबों:


79

नहीं, यह संभव नहीं है।

ज्यादातर मामलों में ऐसा लंबा नाम पठनीयता और कार्य की उपयोगिता के दृष्टिकोण से अवांछनीय होगा, हालांकि परीक्षण नामों के लिए आपका उपयोग मामला काफी उचित लगता है।

अजगर का शाब्दिक नियम एक भी टोकन (इस मामले में एक पहचानकर्ता) कई पंक्तियों में विभाजित होने की अनुमति नहीं है। तार्किक रेखा निरंतरता वर्ण ( \एक पंक्ति के अंत में) एक से अधिक भौतिक रेखाओं को एक तार्किक रेखा में जोड़ सकती है, लेकिन कई रेखाओं में एक एकल टोकन शामिल नहीं हो सकता है ।


2
कि एक शर्म की बात है। मुझे अभी भी लगता है कि हालांकि किसी तरह एक जादू समाधान हो सकता है। --- मुझे इस बात का उल्लेख करना चाहिए कि मैंने अपने पोस्ट में बैकस्लैश की कोशिश की है, बस अगर किसी ने मुझे इसका उल्लेख किया है।
— बक्‍सर

6
आपका सबसे अच्छा यह है कि आप अपने वर्णनात्मक नाम का उपयोग करें क्योंकि संदेश kwarg एक self.assert * विधि में आता है। यदि परीक्षा पास होती है तो आप इसे नहीं देखेंगे। लेकिन यदि परीक्षण विफल हो जाता है तो आपकी वर्णनात्मक स्ट्रिंग परीक्षा परिणाम ऑब्जेक्ट पर उपलब्ध होगी।
— बी रेड सी

11
यह ध्यान देने योग्य है कि बिल्कुल एक स्थिति है जहां लाइन निरंतरता चरित्र का उपयोग स्वीकार्य है: लंबे withबयान with expr1 as x, \<newline> expr2 as y ...:। में सभी अन्य मामलों, कृपया, बस अभिव्यक्ति कोष्टक में लपेट: (a_very_long <newline> + expression)ठीक काम करता है, और भी बहुत कुछ पठनीय और है मजबूत तो a_very_long \<newline> + expression... बस बैकस्लैश के बाद एक भी अंतरिक्ष जोड़कर बाद टूट जाता है!
— बाकुरू

3
@ बकुरीउ - वाह! मुझे नहीं पता था कि आप withपरेंस में बयान दर्ज नहीं कर सकते ।
— Mattmc3

2
@ Mattmc3 कारण सरल है: यह एक अभिव्यक्ति नहीं है। AFAIK यह वस्तुतः एकमात्र मामला है जहाँ एक नई सीमा पर निरंतरता के लिए कोष्ठक का उपयोग करना केवल एक विकल्प नहीं है।
— बकुरीउ

52

आप एक डेकोरेटर भी लिख सकते हैं .__name__जो विधि के लिए उत्परिवर्तित करता है।

def test_name(name):
    def wrapper(f):
        f.__name__ = name
        return f
    return wrapper

तब आप लिख सकते हैं:

class ClientConnectionTest(unittest.TestCase):
    @test_name("test_that_client_event_listener_"
    "receives_connection_refused_error_without_server")
    def test_client_offline_behavior(self):
        self.given_server_is_offline()
        self.given_client_connection()
        self.when_client_connection_starts()
        self.then_client_receives_connection_refused_error()

इस तथ्य पर भरोसा करते हुए कि पायथन स्रोत-आसन्न स्ट्रिंग शाब्दिक को समेटता है।


3
यह बहुत अच्छा विचार है। यह बहुत पठनीय भी लगता है। मैं इसे अभी आज़माता हूँ और देखता हूँ कि मेरी IDE लंबे फ़ंक्शन नामों को दिखाती है या नहीं।
— byxor

2
दुर्भाग्य से डेकोरेटर PyCharm में टेस्ट रन से पहले लागू नहीं होता है, जिसका अर्थ है कि मैं अपने टेस्ट रनर से वर्णनात्मक नाम नहीं देख सकता।
— 19x

2
मुझे लगता है कि आप इसके wrapperसाथ सजना चाहते हैं @functools.wraps(f)।

2
यह सबसे अच्छा आपके-केक-और-खा-यह भी समाधान है; यह उन सभी विशेषताओं को जोड़ती है जो @BrandonIbbotson की तलाश में थीं। बहुत बुरा PyCharm अभी तक यह नहीं है।
— डैन लेन्स्की

3
इससे भी बेहतर, फ़ंक्शन के डॉकस्ट्रिंग से वर्णनात्मक नाम उत्पन्न करने के लिए डेकोरेटर को संशोधित करें।
— निक स्वीटिंग

33

इस प्रश्न के उत्तर के अनुसार: किसी विशिष्ट फ़ाइल में pep8 त्रुटि कैसे अक्षम करें? PEP-8 को लंबी लाइन के लिए निष्क्रिय करने के लिए # nopep8या # noqaअनुगामी टिप्पणी का उपयोग करें । नियमों को कब तोड़ना है, यह जानना महत्वपूर्ण है। बेशक, पायथन का ज़ेन आपको बताएगा कि "विशेष मामले नियमों को तोड़ने के लिए पर्याप्त नहीं हैं।"


5
यह वास्तव में एक शानदार विचार है, क्योंकि यह मुझे बाकी की परीक्षण फाइलों को उधार देने देता है। मैंने अभी इसका परीक्षण किया है और यह काम करता है। मुझे लंबी पद्धति के नामों के सभी लाभों को रखने के लिए भी मिलता है। --- मेरी एकमात्र चिंता यह है कि टीम # nopep8पूरे परीक्षण के दौरान टिप्पणी को देखना पसंद नहीं करेगी ;)
— byxor

8

हम विधि के बजाय कक्षा से सज्जाकार को लागू कर सकते हैं क्योंकि unittestविधियों का नाम मिलता है dir(class)।

डेकोरेटर decorate_methodकक्षा के तरीकों और func_mappingशब्दकोश के आधार पर नाम बदलने की विधि से गुजरेगा ।

इस बारे में सोचा, मेरे से @Sean Vieira, +1 से डेकोरेटर का जवाब देखने के बाद

import unittest, inspect

# dictionary map short to long function names
func_mapping = {}
func_mapping['test_client'] = ("test_that_client_event_listener_receives_"
                               "connection_refused_error_without_server")     
# continue added more funtion name mapping to the dict

def decorate_method(func_map, prefix='test_'):
    def decorate_class(cls):
        for (name, m) in inspect.getmembers(cls, inspect.ismethod):
            if name in func_map and name.startswith(prefix):
                setattr(cls, func_map.get(name), m) # set func name with new name from mapping dict
                delattr(cls, name) # delete the original short name class attribute
        return cls
    return decorate_class

@decorate_method(func_mapping)
class ClientConnectionTest(unittest.TestCase):     
    def test_client(self):
        # dummy print for testing
        print('i am test_client')
        # self.given_server_is_offline()
        # self.given_client_connection()
        # self.when_client_connection_starts()
        # self.then_client_receives_connection_refused_error()

unittestनीचे दिए गए टेस्ट रन के साथ पूर्ण वर्णनात्मक फ़ंक्शन नाम दिखाया गया है, सोचता है कि यह आपके मामले के लिए काम कर सकता है, हालांकि यह कार्यान्वयन से इतना सुंदर और पठनीय नहीं लग सकता है।

>>> unittest.main(verbosity=2)
test_that_client_event_listener_receives_connection_refused_error_without_server (__main__.ClientConnectionTest) ... i am client_test
ok

7

समस्या के संदर्भ-विशिष्ट दृष्टिकोण की तरह। आपके द्वारा प्रस्तुत किया गया परीक्षण मामला वास्तव में बहुत ही एक प्राकृतिक भाषा के प्रारूप की तरह लगता है जो कि परीक्षण के मामले के लिए आवश्यक कदम उठाने का वर्णन करता है।

यह देखें कि behaveव्यवहार चालक विकास शैली की रूपरेखा का उपयोग करने से यहां अधिक समझ में आएगा। आपका "सुविधा" कैसा लग सकता है (देखें कैसे given, when, thenप्रतिबिंबित कि आपने क्या खाया):

Feature: Connect error testing

  Scenario: Client event listener receives connection refused error without server
     Given server is offline
      when client connect starts
      then client receives connection refused error

संबंधित विषय पर हाल के उत्तर से प्रासंगिक pyspecsपैकेज , नमूना उपयोग भी है :


मैं यह उल्लेख करने की सोच रहा था कि मुझे पता था कि बीडीडी विकल्प हैं behave। हालाँकि मैं अपने प्रश्न में लोगों को बहुत अधिक विचलित नहीं करना चाहता था। यह वास्तव में एक अच्छी रूपरेखा की तरह दिखता है और मैं शायद भविष्य में इसका उपयोग करूंगा। मैंने वास्तव में अपनी टीम से पूछा कि क्या मैं इस परियोजना में इसका उपयोग कर सकता हूं, लेकिन वे "अजीब" देखने के लिए परीक्षण नहीं करना चाहते थे;) --- मैंने पहले कभी pyspecs नहीं देखा है। सलाह के लिये धन्यवाद।
— बक्सर

1
@BrandonIbbotson gotcha, मैं समझता हूं कि आप इसका उल्लेख क्यों नहीं करना चाहते थे - सही समझ में आता है। pyspecsवैसे, अपने परीक्षण कोडबेस में एकीकृत करना आसान हो सकता है - हालांकि बीडीडी करने का एक अधिक "अजगर" तरीका - इन फीचर फ़ाइलों की आवश्यकता नहीं है। धन्यवाद!
— alecxe

5

इस तरह के नामों की आवश्यकता अन्य गंधों पर संकेत दे सकती है।

class ClientConnectionTest(unittest.TestCase):
   def test_that_client_event_listener_receives_connection_refused_error_without_server(self):
       ...

ClientConnectionTestबहुत व्यापक लगता है (और एक परीक्षण योग्य इकाई की तरह नहीं है), और संभावना है कि अंदर बहुत सारे परीक्षण के साथ एक बड़ा वर्ग है जिसे फिर से बनाया जा सकता है। ऐशे ही:

class ClientEventListenerTest(unittest.TestCase):
  def receives_connection_refused_without_server(self):
      ...

"परीक्षण" नाम में उपयोगी नहीं है क्योंकि यह निहित है।

आपके द्वारा मुझे दिए गए सभी कोड के साथ, मेरी अंतिम सलाह है: अपने परीक्षण कोड को फिर से तैयार करें, फिर अपनी समस्या का पुन: परीक्षण करें (यदि यह अभी भी है)।


ईवेंट श्रोता एक इंटरफ़ेस है। इसमें तरीके ClientConnection के साथ घटित हो रहे हैं। इवेंट श्रोता का परीक्षण अपने आप ही हो चुका है। व्यक्तिगत रूप से मुझे लगता है कि क्लाइंटकेंक्शन एसआरपी को अच्छी तरह से अनुसरण करता है, लेकिन मैं पक्षपाती हो सकता हूं (और आप इसे नहीं देख सकते हैं)। --- पायथन टेस्ट नामों के साथ शुरू होना चाहिएtest या टेस्ट रनर उन्हें नहीं उठाता है।
— byxor

1
@BrandonIbbotson आह, मुझे यह अब मिल गया है, आप परीक्षण कर रहे हैं कि क्लाइंट कनेक्शन इवेंट श्रोता में कुछ ट्रिगर करता है। यह "test_that_connection_without_server_triggers_connection_refused_event" जैसे नाम के साथ अधिक स्पष्ट होगा। "परीक्षण" भाग की आवश्यकता भयानक है क्योंकि यह आपको या तो अजीब नामों या बेकार गोंद से भरे नामों के साथ जाने के लिए मजबूर करता है।
— BM

यह एक बेहतर विधि का नाम है। मैंने उन तरीकों के एक जोड़े का नाम बदला है जो आपने सुझाए हैं। हालांकि मैं शायद अभी भी 80 से अधिक तरीकों का एक बहुत कुछ करूंगा
— byxor

मैं जो देख रहा हूं उससे आप पायथन में कक्षाएं लगा सकते हैं। क्या परीक्षण धावक को संभालता है? हो सकता है कि आप क्लाइंटकॉन्फेक्शनटेस्ट के इनसाइड को उन विषयों में विभाजित कर सकते हैं जो संबंधित परीक्षण वाले नेस्टेड वर्ग हैं। इस तरह विषय की कक्षा उस नाम के भाग को ले जाती है, जिसे आपको प्रत्येक परीक्षण पर लिखने की आवश्यकता नहीं होती है।
— BM

1
हाँ लगा कि मामला हो सकता है। निश्चित नहीं है कि फिर और क्या सुझाव दिया जाए। हो सकता है कि चरित्र की सीमा को बढ़ा दें, वैसे भी, हमने खुद ही किया और अंत में महसूस किया कि यह बहुत बड़ी बात नहीं है और सभी के पास 80 से अधिक चार लाइनों का स्वागत करने के लिए जगह थी। सौभाग्य!
— BM

4

छोटे फ़ंक्शन नाम समाधान में बहुत योग्यता है। इस बारे में सोचें कि आपके वास्तविक फ़ंक्शन नाम में वास्तव में क्या आवश्यक है और पहले से ही आपूर्ति की गई है।

test_that_client_event_listener_receives_connection_refused_error_without_server(self):

निश्चित रूप से आप पहले से ही जानते हैं कि यह एक परीक्षण है जब आप इसे चलाते हैं? क्या आपको वास्तव में अंडरस्कोर का उपयोग करने की आवश्यकता है? क्या 'कि' जैसे शब्द वास्तव में समझने के लिए आवश्यक हैं? क्या ऊंट का मामला उतना ही पठनीय होगा? ऊपर के पुनर्लेखन के रूप में नीचे दिए गए पहले उदाहरण के बारे में कैसे (वर्ण गणना = 79): आम शब्दों के एक छोटे संग्रह के लिए संक्षिप्त रूप का उपयोग करने के लिए एक सम्मेलन को स्वीकार करना और भी अधिक प्रभावी है, जैसे कनेक्शन = कॉन, त्रुटि = त्रुटि। संक्षिप्ताक्षरों का उपयोग करते समय आपको संदर्भ के प्रति सचेत रहना होगा और केवल उनका उपयोग करें जब भ्रम की कोई संभावना नहीं है - नीचे दूसरा उदाहरण। यदि आप स्वीकार करते हैं कि विधि नाम में परीक्षण विषय के रूप में ग्राहक का उल्लेख करने की कोई वास्तविक आवश्यकता नहीं है क्योंकि यह जानकारी वर्ग नाम में है तो तीसरा उदाहरण उपयुक्त हो सकता है। (५४) वर्ण।

ClientEventListenerReceivesConnectionRefusedErrorWithoutServer (स्व):

ClientEventListenerReceivesConnRefusedErrWithoutServer (स्व):

EventListenerReceiveConnRefusedErrWithoutServer (स्वयं):

मैं बी राड सी के सुझाव से भी सहमत हूँ "वर्णनात्मक नाम का उपयोग करें क्योंकि स्वयं में संदेश kwarg arg होता है।" आपको केवल परीक्षण देखने के बाद असफल परीक्षणों से आउटपुट देखने में रुचि होनी चाहिए। सत्यापन कि आपके पास सभी आवश्यक परीक्षण लिखे गए हैं, विधि के नाम इतने विस्तृत होने पर निर्भर नहीं होना चाहिए।

PS शायद मैं भी 'WithoutServer' को सुपरफ्लस के रूप में अच्छी तरह से हटा दूंगा। क्या क्लाइंट ईवेंट हैंडलर को उस मामले में ईवेंट प्राप्त नहीं करना चाहिए जो किसी कारण से सर्वर से संपर्क करने योग्य नहीं है? (हालांकि tbh मुझे लगता है कि यह बेहतर होगा कि अगर वे क्लाइंट को किसी सर्वर से कनेक्ट नहीं कर सकते हैं तो यह किसी प्रकार का 'कनेक्शन अनुपलब्ध' प्राप्त करता है, कनेक्शन ने इनकार कर दिया कि सर्वर को ढूंढा जा सकता है लेकिन कनेक्शन को स्वयं मना कर सकता है।)


1
टीएल; डीआर - कृपया अपने उत्तर की लंबाई की तुलना अन्य उत्तर के साथ करें।
— MarianD

3
मैरिएनड: इतना खेद है, लेकिन उत्तर ओपी के लिए दिया गया था जो इसे पढ़ने के लिए एक मिनट के लिए परेशान हो सकते हैं और रचनात्मक उदाहरण और औचित्य के साथ नाम को छोटा करने के लिए कई रणनीतियों को संबोधित किया। यदि आप लघु संस्करण चाहते हैं ... "अनावश्यक शब्दों और विराम चिह्नों से बचें और लगातार सामान्य शब्दों को छोटा करें" - क्या यह पर्याप्त संक्षिप्त है?
— चार्मर

3
अजगर के सबसे अच्छे पुस्तकालय के साथ, प्रत्येक परीक्षण पद्धति को शुरू करना होगा testअन्यथा परीक्षण धावक इसे नहीं उठाएगा।
— byxor

1
@BrandonIbbotsontest_EventListenerReceiveConnRefusedErrWithoutServer(self):
— Hendry

1
मुझे CamelCase पसंद है, लेकिन मुझे लगता है कि यह PEP 8 के उल्लंघन का प्रतीत होता है: "फ़ंक्शन नामकरण नियमों का उपयोग करें: पठनीयता में सुधार के लिए आवश्यक के रूप में अंडरस्कोर द्वारा अलग किए गए शब्दों के साथ लोअरकेस।"
— स्कूटर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.