Bir Python kod satırı bir əlavə yuvasının səviyyəsini bilir?

Bu kimi bir şeydən:

 print(get_indentation_level()) print(get_indentation_level()) print(get_indentation_level()) 

Mən bu kimi bir şey əldə edərdim:

 1 2 3 

Kod bu şəkildə özünü oxuya bilərmi?

İstədiyim hər şey kodun daha çox iç içə hissələrindən daha çox iç içə olması üçün çıxmaqdır. Kodun oxunmasını asanlaşdıran kimi oxumağı asanlaşdırır.

Əlbəttə ki, mən bunu el ilə həyata keçirə bilərəm, məsələn .format() , amma xüsusi bir print funksiyası nəzərdə tuturdu ki, mən print(i*' ' + string) , burada i indent səviyyəsidir. Mənim terminimə oxunaqlı bir nəticə vermək üçün bu sürətli bir yol olacaq.

Əlbəttə ki, bu əlamətdar əl ilə formatlaşmanın qarşısını almaq üçün daha yaxşı bir yol varmı?

146
26 авг. Fab von Bellingshausen tərəfindən təyin olunan 26 av. 2016-08-26 21:07 '16 at 21:07 2016-08-26 21:07
@ 5 cavab

İstədiyiniz yerləri boşluq və nişanlar deyil, yuva səviyyələri baxımından istəyirsinizsə, hər şey mürəkkəbləşir. Məsələn, aşağıdakı kodda:

 if True: print( get_nesting_level()) 

get_nesting_level çağırışı həqiqətən get_nesting_level aparıcı yer olmasa da, bir səviyyədə içəri get_nesting_level . Bu vaxt, aşağıdakı kodda:

 print(1, 2, get_nesting_level()) 

get_nesting_level çağırışı, simli boşluqların olmasına baxmayaraq, iç içə sıfırlar dərinliyinə malikdir.

Aşağıdakı kodda:

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

iki get_nesting_level , aparıcı yerlər eyni olsa da, müxtəlif yuvalama səviyyələrindədir.

Aşağıdakı kodda:

 if True: print(get_nesting_level()) 

Bu iç içə sıfır səviyyələri mi yoxsa bir mi? INDENTDEDENT formal qrammatika baxımından sıfır səviyyədədir, ancaq eyni hiss edə bilməzsiniz.


Bunu etmək istəyirsinizsə, bütün faylları INDENTDEDENT ayələrini çağırmaq və hesablamaq nöqtəsinə tokenize etmək lazımdır. tokenize modul belə bir funksiya üçün çox faydalı olardı:

 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 
113
26 авг. 26 avqustda user2357112 tərəfindən verilmiş cavab . 2016-08-26 21:41 '16 at 21:41 2016-08-26 21:41

Bəli, mütləq mümkündür, burada bir nümunədir:

border=0
 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() 
21
26 авг. cavab BPL 26 aug verilir . 2016-08-26 21:23 '16 'da 21:23 2016-08-26 21:23' də

Satır nömrəsini almaq üçün sys.current_frame.f_lineno istifadə edə bilərsiniz. Sonra indent səviyyələrinin sayını tapmaq üçün sıfır indent ilə əvvəlki xətt tapmaq və sonra bu xətt nömrəsindən mövcud xəttin nömrəsini çıxartmaq lazımdır, indentlərin sayını alacaqsınız:

 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 

Demo:

 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 

Çıxış səviyyəsinin sayı ilə əvvəlcədən təyin olunan xətlərə əsaslanmaq istəsəniz, bunu sadəcə kiçik bir dəyişikliklə edə bilərsiniz:

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

Demo:

 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 

Burada alternativ bir cavab olaraq, indent sayı (boşluq) almaq funksiyası:

 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])) 
9
26 авг. Kasramdv 26 avqustda cavab verdi . 2016-08-26 21:21 '16 saat 09:21 'da 2016-08-26 21:21

Sualınıza gətirib çıxaracaq "real" problemi həll etmək üçün, indentasiya səviyyəsini izləyən və çıxış indent səviyyələrinə uyğun olan kodu blok strukturu ilə birləşdirən kontekst meneceri tətbiq edə bilərsiniz. Beləliklə, kodu indent hələ çox çox bağlamadan çıxış indentini əks etdirir. Kodunuzu fərqli funksiyalara yenidən təşkil edə bilərsiniz və kodun strukturuna əsaslanan digər indentslər çıxışla çıxdıqda çıxışa daxil olmaya bilər.

 #!/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() 

Nəticə:

 0 1 Hallo 2 3 and back one level 2 
6
28 авг. Cavab BlackJack 28 aug tərəfindən verilir . 2016-08-28 16:46 '16 saat 16:46 'da 2016-08-28 16:46
 >>> 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. 
6
26 авг. Craig Burgler tərəfindən verilmiş cavabı 26 Avqust. 2016-08-26 21:18 '16 at 21:18 2016-08-26 21:18