python - क्या पायथन कोड की एक पंक्ति इसके इंडेंटेशन नेस्टिंग स्तर को जान सकती है?




reflection metaprogramming (4)

कुछ इस तरह से:

print(get_indentation_level())

    print(get_indentation_level())

        print(get_indentation_level())

मैं कुछ इस तरह से प्राप्त करना चाहूंगा:

1
2
3

क्या कोड को इस तरह से पढ़ा जा सकता है?

मैं चाहता हूं कि कोड के अधिक नेस्टेड भागों से आउटपुट अधिक नेस्टेड हो। इसी तरह से यह कोड को पढ़ना आसान बनाता है, यह आउटपुट को पढ़ने में आसान बनाता है।

बेशक, मैं इसे मैन्युअल रूप से लागू कर सकता हूं, उदाहरण के लिए .format() का उपयोग कर सकता हूं, लेकिन मेरे मन में जो था वह एक कस्टम प्रिंट फ़ंक्शन था जो print(i*' ' + string) करेगा print(i*' ' + string) जहां i इंडेंटेशन स्तर है। यह मेरे टर्मिनल पर पठनीय आउटपुट बनाने का एक त्वरित तरीका होगा।

क्या ऐसा करने का एक बेहतर तरीका है जो श्रमसाध्य मैनुअल प्रारूपण से बचा जाता है?


आपके प्रश्न का नेतृत्व करने वाली "वास्तविक" समस्या को हल करने के लिए आप एक संदर्भप्रबंधक को कार्यान्वित कर सकते हैं जो इंडक्शन स्तर पर नज़र रखता है और कोड में ब्लॉक संरचना के with आउटपुट के इंडेंटेशन स्तरों के अनुरूप होता है। इस तरह कोड इंडेंटेशन अभी भी दोनों को बहुत अधिक युग्मन के बिना आउटपुट इंडेंटेशन को दर्शाता है। कोड को अलग-अलग कार्यों में रिफ्लेक्टर करना और आउटपुट इंडेंटेशन में गड़बड़ी नहीं करने के लिए कोड संरचना के आधार पर अन्य इंडेंटेशन करना अभी भी संभव है।

#!/usr/bin/env python
# coding: utf8
from __future__ import absolute_import, division, print_function


class IndentedPrinter(object):

    def __init__(self, level=0, indent_with='  '):
        self.level = level
        self.indent_with = indent_with

    def __enter__(self):
        self.level += 1
        return self

    def __exit__(self, *_args):
        self.level -= 1

    def print(self, arg='', *args, **kwargs):
        print(self.indent_with * self.level + str(arg), *args, **kwargs)


def main():
    indented = IndentedPrinter()
    indented.print(indented.level)
    with indented:
        indented.print(indented.level)
        with indented:
            indented.print('Hallo', indented.level)
            with indented:
                indented.print(indented.level)
            indented.print('and back one level', indented.level)


if __name__ == '__main__':
    main()

आउटपुट:

0
  1
    Hallo 2
      3
    and back one level 2

यदि आप रिक्त स्थान और टैब के बजाय नेस्टिंग स्तर के संदर्भ में इंडेंटेशन चाहते हैं, तो चीजें मुश्किल हो जाती हैं। उदाहरण के लिए, निम्नलिखित कोड में:

if True:
    print(
get_nesting_level())

get_nesting_level लिए कॉल वास्तव में एक स्तर गहरा है, इस तथ्य के बावजूद कि get_nesting_level कॉल की लाइन पर कोई प्रमुख get_nesting_level । इस बीच, निम्नलिखित कोड में:

print(1,
      2,
      get_nesting_level())

get_nesting_level लिए कॉल शून्य स्तर गहरा है, बावजूद इसके लाइन पर प्रमुख get_nesting_level की उपस्थिति है।

निम्नलिखित कोड में:

if True:
  if True:
    print(get_nesting_level())

if True:
    print(get_nesting_level())

get_nesting_level लिए दो कॉल अलग-अलग घोंसले के स्तर पर हैं, इस तथ्य के बावजूद कि प्रमुख get_nesting_level समान है।

निम्नलिखित कोड में:

if True: print(get_nesting_level())

क्या यह शून्य स्तर, या एक है? औपचारिक व्याकरण में INDENT और DEDENT टोकन के संदर्भ में, यह शून्य स्तर गहरा है, लेकिन आप उसी तरह महसूस नहीं कर सकते हैं।

यदि आप ऐसा करना चाहते हैं, तो आपको कॉल के बिंदु तक पूरी फ़ाइल को टोकन INDENT और DEDENT और DEDENT टोकन को DEDENT । इस तरह के एक समारोह के लिए tokenize मॉड्यूल बहुत उपयोगी होगा:

import inspect
import tokenize

def get_nesting_level():
    caller_frame = inspect.currentframe().f_back
    filename, caller_lineno, _, _, _ = inspect.getframeinfo(caller_frame)
    with open(filename) as f:
        indentation_level = 0
        for token_record in tokenize.generate_tokens(f.readline):
            token_type, _, (token_lineno, _), _, _ = token_record
            if token_lineno > caller_lineno:
                break
            elif token_type == tokenize.INDENT:
                indentation_level += 1
            elif token_type == tokenize.DEDENT:
                indentation_level -= 1
        return indentation_level

हाँ, यह निश्चित रूप से संभव है, यहाँ एक कार्य उदाहरण है:

import inspect

def get_indentation_level():
    callerframerecord = inspect.stack()[1]
    frame = callerframerecord[0]
    info = inspect.getframeinfo(frame)
    cc = info.code_context[0]
    return len(cc) - len(cc.lstrip())

if 1:
    print get_indentation_level()
    if 1:
        print get_indentation_level()
        if 1:
            print get_indentation_level()

>>> import inspect
>>> help(inspect.indentsize)
Help on function indentsize in module inspect:

indentsize(line)
    Return the indent size, in spaces, at the start of a line of text.





tokenize