পাইথন কোডের একটি লাইন কী তার বাসা বাঁধার স্তর জানতে পারে?


149

এরকম কিছু থেকে:

print(get_indentation_level())

    print(get_indentation_level())

        print(get_indentation_level())

আমি এই জাতীয় কিছু পেতে চাই:

1
2
3

এই কোডটি কি নিজেই পড়তে পারে?

আমি কেবল চাই কোডটির আরও নেস্টেড অংশগুলি থেকে আউটপুটটি আরও নীড়যুক্ত হওয়া। এই কোডটি পড়া সহজ করে তোলে, একইভাবে এটি আউটপুটটি আরও সহজভাবে পড়তে পারে।

অবশ্যই আমি এই ম্যানুয়ালি বাস্তবায়ন হতে পারে, যেমন ব্যবহার .format(), কিন্তু কি আমি মন ছিল একটি কাস্টম মুদ্রণ ফাংশন যা ছিল print(i*' ' + string)যেখানে iখাঁজ স্তর। এটি আমার টার্মিনালে পঠনযোগ্য আউটপুট করার দ্রুত উপায় হবে।

শ্রমসাধ্য ম্যানুয়াল ফর্ম্যাটিং এড়ানো যা এর থেকে আরও ভাল উপায় আছে?


70
আপনার কেন এটি প্রয়োজন তা সম্পর্কে আমি সত্যিই আগ্রহী।
হ্যারিসন

12
@ হারিসন আমি কোডটিতে কীভাবে ইন্টেন্টেড ছিল তা অনুসারে আমার কোডটির আউটপুট ইনডেন্ট করতে চেয়েছিলাম।
ফ্যাব ভন বেলিংসাউসেন

14
আসল প্রশ্নটি: আপনার এটির প্রয়োজন হবে কেন? ইন্ডেন্টেশন স্তর স্থির; আপনি যখন আপনার get_indentation_level()কোডটিতে স্ট্যাটমেন্টটি রেখেছেন তখন আপনি তা নিশ্চিততার সাথে জানেন । আপনি ঠিক পাশাপাশি print(3)বা যা কিছু সরাসরি করতে পারেন। আরও বেশি কিছুর উদ্দীপনা হতে পারে এটি হ'ল ফাংশন কল স্ট্যাকের নেস্টিংয়ের বর্তমান স্তর।
tobias_k

19
এটি কি আপনার কোডটি ডিবাগ করার উদ্দেশ্যে হয়? এটি কার্যকর মৃত্যুর প্রবাহকে লগ করার একটি দুর্দান্ত প্রতিভা উপায় বলে মনে হয় বা কোনও সাধারণ সমস্যার জন্য একটি সুপার ওভার ইঞ্জিনিয়ারড সমাধানের মতো, এবং আমি নিশ্চিত নই যে এটি কোনটি ... সম্ভবত উভয়ই!
ব্ল্যাকহক

7
@ ফ্যাভবোনবেলিংশাউসেন: মনে হচ্ছে এটি আপনার প্রত্যাশার চেয়ে অনেক কম পাঠযোগ্য হবে। আমি মনে করি আপনি depthঅন্য ফাংশনগুলিতে পাস করার সময় কোনও প্যারামিটারের সুস্পষ্টভাবে পাস করার সাথে সাথে এটি যথাযথ মান যুক্ত করে আরও ভাল পরিবেশিত হতে পারেন । আপনার কোডের বাসা বাঁধা সম্ভবত আপনার আউটপুট থেকে বেরিয়ে আসা ইন্ডেন্টেশনের সাথে পরিষ্কারভাবে মিলিত হতে পারে না।
ব্যবহারকারী 2357112 মোনিকার

উত্তর:


115

আপনি যদি ফাঁকা স্থান এবং ট্যাবগুলির চেয়ে বাসা বাঁধার স্তরের ক্ষেত্রে ইন্ডেন্টেশন চান তবে জিনিসগুলি জটিল হয়ে উঠবে। উদাহরণস্বরূপ, নিম্নলিখিত কোডে:

if True:
    print(
get_nesting_level())

কলটির get_nesting_levelলাইনে কোনও শীর্ষস্থানীয় শ্বেত স্পেস নেই সত্ত্বেও কলটি আসলে এক স্তরের গভীর নীচে বাসা বাঁধে get_nesting_level। এদিকে, নিম্নলিখিত কোডে:

print(1,
      2,
      get_nesting_level())

কলটি get_nesting_levelতার লাইনে শীর্ষস্থানীয় শ্বেতপথের উপস্থিতি সত্ত্বেও শূন্য স্তরের গভীর নীচে নিমন্ত্রিত।

নিম্নলিখিত কোডে:

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

if True:
    print(get_nesting_level())

get_nesting_levelনেতৃস্থানীয় হোয়াইটস্পেস একরকম হওয়া সত্ত্বেও দুটি কল বিভিন্ন নীড়ের স্তরে রয়েছে।

নিম্নলিখিত কোডে:

if True: print(get_nesting_level())

শূন্য স্তরের নেস্টেড কি না, এক? আনুষ্ঠানিক ব্যাকরণের দিক থেকে INDENTএবং DEDENTটোকেনগুলির ক্ষেত্রে এটি শূন্য স্তরের গভীর, তবে আপনি সম্ভবত একইভাবে অনুভব করবেন না।


আপনি যদি এটি করতে চান, আপনাকে কল এবং গণনা INDENTএবং 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

2
এই get_nesting_level()ফাংশন কলের মধ্যে যখন ডাকা হবে তখন আমি যেভাবে প্রত্যাশা করতাম তা সেভাবে কাজ করে না ― এটি সেই ফাংশনের মধ্যে নীড়ের স্তরটি ফিরিয়ে দেয়। 'গ্লোবাল' বাসা বাঁধার স্তরটি ফেরত দেওয়া কি আবার লিখতে পারে?
ফ্যাব ভন বেলিংসাউসেন

11
টুইটারে এই ফাংশনটি ইনডেন্টেশন বাসা বাঁধার স্তর দেয়। ফাংশন কল নেস্টিং স্তরটি বরং ভিন্ন হবে এবং আমার সমস্ত উদাহরণের জন্য 0 এর একটি স্তর দেবে। আপনি খাঁজ কেমন চান / নেস্টিং স্তর সংকর কল উভয় ফাংশন কল ও নিয়ন্ত্রণ প্রবাহ স্ট্রাকচার মত বাড়তি whileএবং withযে করা সম্ভব অনুভব করি, কিন্তু এটা আপনার জন্য কি জিজ্ঞাসা না, এবং প্রশ্ন পরিবর্তন এই সময়ে ভিন্ন কিছু জিজ্ঞাসা করতে একটি খারাপ ধারণা হবে।
ব্যবহারকারী 2357112

38
ঘটনাচক্রে, আমি সমস্ত লোকের সাথে একমত হয়েছি যে এটি করা সত্যিই এক অদ্ভুত কাজ। আপনি যে কোনও সমস্যা সমাধানের চেষ্টা করছেন তার সমাধানের সম্ভবত আরও অনেক ভাল উপায় আছে এবং আপনার নির্ভর করার সময় আপনার ইন্ডেন্টেশন বা ফাংশন কল স্ট্রাকচার পরিবর্তন এড়ানোর জন্য আপনাকে সমস্ত ধরণের বাজে হ্যাক ব্যবহার করতে বাধ্য করার দ্বারা এটির উপর নির্ভর করা আপনাকে পীড়িত করতে পারে likely আপনার কোড পরিবর্তন করে।
ব্যবহারকারী 2357112 মোনিকার

4
আমি অবশ্যই প্রত্যাশা করিনি যে কেউ এটির উত্তর দিয়েছে। ( linecacheস্টাফের জন্য মডিউলটি এই জাতীয় হিসাবে বিবেচনা করুন - এটি ট্রেসব্যাকগুলি মুদ্রণের জন্য ব্যবহৃত হয় এবং জিপ ফাইল এবং অন্যান্য অদ্ভুত আমদানির কৌশলগুলি থেকে আমদানি করা মডিউলগুলি পরিচালনা করতে পারে)
eভি

6
@Eevee: আমি অবশ্যই তাই অনেক মানুষ আশা ছিল না ভোট দিন এই! linecacheআই / ও ফাইলের পরিমাণ হ্রাস করার জন্য ভাল হতে পারে (এবং এটি সম্পর্কে আমাকে স্মরণ করিয়ে দেওয়ার জন্য ধন্যবাদ), তবে আমি যদি এটি অপ্টিমাইজ করা শুরু করি তবে আমরা কীভাবে একই ফাইলটিকে পুনর্বারের জন্য পুনরায় টোকেনাইজিং করব তা নিয়ে উদ্বিগ্ন হব একই কল, বা একই ফাইলের মধ্যে একাধিক কল সাইটগুলির জন্য। আমরা সেটিকেও আরও অনুকূল করতে পারি ways
ব্যবহারকারী 2357112

22

হ্যাঁ, এটি অবশ্যই সম্ভব, এখানে একটি কার্যকারী উদাহরণ:

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()

4
@ প্রন দ্বারা করা মন্তব্যের সাথে সম্পর্কিত, এটি কি ফাঁকের পরিবর্তে স্তরগুলিতে ইন্ডেন্টেশনটি ফেরত দেওয়া যেতে পারে? এটি কি সর্বদা 4 দ্বারা ভাগ করা ঠিক হবে?
ফ্যাব ফন বেলিংসাউসেন

2
না, ইনডেন্ট স্তর পেতে 4 দ্বারা ভাগ করা এই কোডটির সাথে কাজ করবে না। সর্বশেষ প্রিন্ট স্টেটমেন্টের ইনডেন্টের স্তর বাড়িয়ে যাচাই করতে পারে, শেষ মুদ্রিত মানটি কেবল বৃদ্ধি পেয়েছে।
ক্রেগ বার্গলার

10
একটি ভাল শুরু, কিন্তু সত্যিই ইমো প্রশ্নের উত্তর দেয় না। স্পেসের সংখ্যা ইন্ডেন্টেশন স্তরের মতো নয়।
wim

1
এটা অত সস্তা না. একক স্পেসের সাথে 4 টি স্পেস প্রতিস্থাপন করা কোডটির যুক্তি পরিবর্তন করতে পারে।
Wim

1
তবে এই কোডটি ওপি যা খুঁজছিল তার জন্য নির্ভুল: (ওপি মন্তব্য # 9): 'আমি কোডটিতে কীভাবে ইন্টেন্টেড ছিল তা অনুসারে আমার কোডের আউটপুট ইনডেন্ট করতে চেয়েছিলাম' ' সুতরাং তিনি এর মতো কিছু করতে পারেনprint('{Space}'*get_indentation_level(), x)
ক্রেগ বার্গলার ২

10

আপনি sys.current_frame.f_linenoলাইন নম্বর পেতে ক্রম ব্যবহার করতে পারেন । তারপরে ইন্ডেন্টেশন স্তরের সংখ্যাটি সন্ধান করতে আপনার শূন্য इंडেন্টেশন সহ আগের লাইনটি সন্ধান করতে হবে এবং তারপরে line লাইনের নম্বর থেকে বর্তমান লাইন নম্বরটি বিয়োগ করতে হবে:

import sys
current_frame = sys._getframe(0)

def get_ind_num():
    with open(__file__) as f:
        lines = f.readlines()
    current_line_no = current_frame.f_lineno
    to_current = lines[:current_line_no]
    previous_zoro_ind = len(to_current) - next(i for i, line in enumerate(to_current[::-1]) if not line[0].isspace())
    return current_line_no - previous_zoro_ind

ডেমো:

if True:
    print get_ind_num()
    if True:
        print(get_ind_num())
        if True:
            print(get_ind_num())
            if True: print(get_ind_num())
# Output
1
3
5
6

আপনি যদি পূর্বসূত্র লাইনের উপর ভিত্তি করে ইন্ডেন্টেশন স্তরের সংখ্যাটি চান তবে আপনি :এটি সামান্য পরিবর্তন দিয়ে করতে পারেন:

def get_ind_num():
    with open(__file__) as f:
        lines = f.readlines()

    current_line_no = current_frame.f_lineno
    to_current = lines[:current_line_no]
    previous_zoro_ind = len(to_current) - next(i for i, line in enumerate(to_current[::-1]) if not line[0].isspace())
    return sum(1 for line in lines[previous_zoro_ind-1:current_line_no] if line.strip().endswith(':'))

ডেমো:

if True:
    print get_ind_num()
    if True:
        print(get_ind_num())
        if True:
            print(get_ind_num())
            if True: print(get_ind_num())
# Output
1
2
3
3

এবং বিকল্প উত্তর হিসাবে এখানে ইনডেন্টেশন সংখ্যা (সাদা স্থান) পাওয়ার জন্য একটি ফাংশন:

import sys
from itertools import takewhile
current_frame = sys._getframe(0)

def get_ind_num():
    with open(__file__) as f:
        lines = f.readlines()
    return sum(1 for _ in takewhile(str.isspace, lines[current_frame.f_lineno - 1]))

প্রশ্ন ফাঁসের সংখ্যা নয়, ইনডেন্টেশন স্তরের সংখ্যার জন্য জিজ্ঞাসা করা হয়েছিল। এগুলি অগত্যা আনুপাতিক নয়।
Wim

আপনার ডেমো কোডের জন্য আউটপুট 1 - 2 - 3 - 3 হওয়া উচিত
ক্রেগ বার্গলার

@ ক্রেইগবার্গলার 1 - 2 - 3 - 3 পাওয়ার জন্য আমরা শূন্য इंडেন্টেশনের সাথে :লাইনটির মুখোমুখি না হওয়া অবধি শেষ লাইনের আগে যে রেখাগুলি শেষ হয় তার সংখ্যা গণনা করতে পারি , সম্পাদনাটি পরীক্ষা করে দেখুন!
কাসরামভিড ২

2
হুঁ ... ঠিক আছে ... এখন @ ব্যবহারকারীর 2357112 এর কিছু পরীক্ষার কেস চেষ্টা করুন;)
ক্রেগ বার্গলার

@ ক্রেইগবার্গলার এই সমাধানটি কেবল বেশিরভাগ ক্ষেত্রেই হয় এবং উত্তরটির বিষয়ে এটিও একটি সাধারণ উপায়, এটিও একটি বিস্তৃত সমাধান দেয় না। চেষ্টা করুন{3:4, \n 2:get_ind_num()}
কাসরামভিড ২

7

আপনার প্রশ্নের উত্থাপিত "বাস্তব" সমস্যার সমাধানের জন্য আপনি একটি প্রসঙ্গ ব্যবস্থাপনার প্রয়োগ করতে পারবেন যা ইনডেনশন স্তরটিকে ট্র্যাক করে এবং 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

6
>>> 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.

12
এটি স্তরে নয়, ফাঁকা জায়গায় ইন্ডেন্টেশন দেয়। প্রোগ্রামার ধারাবাহিক ইনডেন্টেশন পরিমাণ ব্যবহার না করা হলে এটি স্তরগুলিতে রূপান্তর করতে কুৎসিত হতে পারে।
26:25

4
ফাংশনটি কি অনথিভুক্ত? আমি এটি এখানে
জিঞ্জারপ্লাসপ্লাস
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.