Генераторлық түсініктер және түсінікті тізімдер

Генератордың өрнектерін қашан пайдалану керек және Python жүйесінде тізім әдістерін пайдалану керек пе?

 # Generator expression (x*2 for x in range(256)) # List comprehension [x*2 for x in range(256)] 
357
06 сент. Оқу жиынтығы 06 қыркүйек. 2008-09-06 23:07 '08 at 23:07 2008-09-06 23:07
@ 9 жауап

Джонның жауабы жақсы (бірнеше рет сұрыптағыңыз келгенде тізімдерді түсіну жақсы). Сонымен қатар, тізім әдістерінің кез келгенін қолданғыңыз келсе, тізімді пайдалануыңыз керек. Мысалы, келесі код жұмыс істемейді:

 def gen(): return (something for something in get_some_stuff()) print gen()[:2] # generators don't support indexing or slicing print [5,6] + gen() # generators can't be added to lists 

Негізінен генераторлық өрнек пайдаланыңыз, егер сіз жасайтын болсаңыз, бір рет қайталаңыз. Егер жасалған нәтижелерді сақтағыңыз келсе және пайдаланғыңыз келсе, онда сіз тізіммен жақсырақ боласыз.

Себебі өнімділікті басқа біреуді таңдаудың ең көп тараған себебі болып табылады, менің кеңесім бұл туралы алаңдамау және біреуін таңдау; егер сіздің бағдарламаңыз тым баяу екенін анықтасаңыз, содан кейін ғана сіздің кодты орнату туралы қайтып келуіңіз керек.

244
06 сент. Бұл сұраққа жауап Eli Courtwright 06 қыркүйек . 2008-09-06 23:54 '08 at 23:54 pm 2008-09-06 23:54

Генератордың өрнегін өзгерту немесе тізімді түсіну солай жасайды. Дегенмен, тізімді түсіну алдымен жадыдағы бүкіл тізімді жасайды, ал генератор өрнегі элементтерді ұшақта жасайды, сондықтан оны оны өте үлкен (сонымен қатар шексіз!) Тізбектерде пайдалануға болады.

border=0
158
Жауап - dF. 06 Қыр 2008-09-06 23:11 '08 at 11:11 pm 2008-09-06 23:11

Нәтиже бірнеше рет қайталануы немесе жылдамдық өте маңызды болған кезде тізімді пайдаланыңыз. Ауқым үлкен немесе шексіз болған генераторлық өрнектерді пайдаланыңыз.

87
06 сент. жауап John Millikin қыркүйек 06 2008-09-06 23:10 '08 at 11:10 pm 2008-09-06 23:10

Маңыздысы, тізімді түсіну жаңа тізім жасайды. Генератор биттерді пайдаланған кезде бастапқы материалды сүзгіден өткізетін итереалды нысанды жасайды.

Сізге «үлкен .txt файлы» деп аталатын 2TB журнал файлы бар екенін және барлық жолдардың мазмұны мен ұзындығын «ENTRY» сөзінен бастау керек екенін елестетіңіз.

Мәселен, Сіз тізімді түсіну арқылы бастайсыз:

 logfile = open("hugefile.txt","r") entry_lines = [(line,len(line)) for line in logfile if line.startswith("ENTRY")] 

Бұл бүкіл файлды бұзады, әр жолды өңдейді және массивіңіздегі тиісті жолдарды сақтайды. Демек, бұл массивінде 2 Тбайт мазмұн болуы мүмкін. Бұл ЖЖҚ көп және сіздің мақсаттарыңыз үшін практикалық емес.

Оның орнына, біздің мазмұнымызға «сүзгі» қолдану үшін генераторды пайдалануға болады. Нәтижені қайталауды бастағанға дейін ешқандай деректер оқылмайды.

 logfile = open("hugefile.txt","r") entry_lines = ((line,len(line)) for line in logfile if line.startswith("ENTRY")) 

Біздің файлымыздың бірде-бір жолы әлі оқылмады. Шын мәнінде, біздің нәтижемізді одан әрі сүзгісі келетіндігін айтайық:

 long_entries = ((line,length) for (line,length) in entry_lines if length > 80) 

Дегенмен ештеңе оқылмады, бірақ қазір біз екі генераторды көрсеттік, олар біздің деректерге сәйкес біздің қалауымыз бойынша әрекет етеді.

Сүзілген сызықтарды басқа файлға бөлейік:

 outfile = open("filtered.txt","a") for entry,length in long_entries: outfile.write(entry) 

Енді кіріс файлы оқылады. Біздің цикл үшін қосымша жолдарды сұрау жалғасуда, long_entries генераторы long_entries генератордан жолдарды талап етеді, тек 80 таңбадан ұзынырақ қайтарады. Ал, өз кезегінде, entry_lines генераторы entry_lines жолдарды (көрсетілгендей сүзгіленген) сұрайды, ол өз кезегінде файлды оқиды.

Осылайша, толығымен толтырылған тізімде сіздің шығу функцияңыздағы деректерді «орнына келтірудің» орнына, сіз шығыс функциясын қажет болған кезде деректерді «шығарып алу» әдісімен қамтамасыз етесіз. Біздің жағдайда бұл әлдеқайда тиімді, бірақ соншалықты икемді емес. Генераторлар - бір жол, бір өту; біз оқыған журнал файлынан деректер дереу жойылады, сондықтан алдыңғы жолға оралай алмаймыз. Екінші жағынан, біз онымен жасаған кезде деректерді сақтау туралы алаңдамауымыз керек емес.

52
04 апр. жауап берді tylerl 04 Apr. 2014-04-04 12:14 '14 at 12:14 2014-04-04 12:14

Генераторлық өрнектің артықшылығы - ол аз еске түсіруді пайдаланады, себебі ол бүкіл тізімді бірден жасамайды. Генератордың өрнектері тізімді делдал болғанда жақсы пайдаланылады, мысалы, нәтижелерді қорытындылау немесе нәтижелерден дикті жасау.

Мысалы:

 sum(x*2 for x in xrange(256)) dict( ((k, some_func(k) for k in some_list_of_keys) ) 

Тізім толығымен жасалмаған артықшылығы болып табылады және сондықтан аз еске пайдаланылады (және тезірек болуы тиіс)

Алайда, сіз қалаған соңғы өнім тізім болған кезде тізімдерді пайдалануыңыз керек. Сіз генератор өрнектерін пайдаланып mememory-ді сақтамайсыз, себебі жасалған тізімді қажет етесіз. Сондай-ақ, тізімдегі функциялардың кез-келгенін пайдалануға мүмкіндік аласыз, мысалы, сұрыпталған немесе жойылған.

Мысалы:

 reversed( [x*2 for x in xrange(256)] ) 
44
10 окт. Chuck 10 қазанда берген жауап . 2008-10-10 04:42 '08 at 4:42 2008-10-10 04:42

Айнымалы нысаннан генераторды жасаған кезде (мысалы, тізім) генератор генераторды құру кезінде емес, генераторды пайдалану кезінде тізімнің күйі бойынша бағаланады:

 >>> mylist = ["a", "b", "c"] >>> gen = (elem + "1" for elem in mylist) >>> mylist.clear() >>> for x in gen: print (x) # nothing 

Егер тізіміңіз өзгертілетін болса (немесе осы тізімдегі өзгертілген нысан) болса, бірақ генераторды жасау кезінде сізге қажет жағдай болса, тізімнің түсінігін қолданыңыз.

10
13 марта '16 в 1:21 2016-03-13 01:21 13 наурызда сағат 16: 00-де 1: 20-да 2016-03-13 01:21

Мен Hadoop Mincemeat модулін қолданамын. Менің ойымша, бұл - жақсы үлгі.

 import mincemeat def mapfn(k,v): for w in v: yield 'sum',w #yield 'count',1 def reducefn(k,v): r1=sum(v) r2=len(v) print r2 m=r1/r2 std=0 for i in range(r2): std+=pow(abs(v[i]-m),2) res=pow((std/r2),0.5) return r1,r2,res 

Мұнда генератор мәтіндік файлдан сандарды алады (15 ГБ-қа дейін) және осы сандарға қарапайым математика қолданып, Hadoop қысқартуларын қолданады. Мен кірістілік функциясын пайдаланбасам, бірақ тізімнің орнына түсінген болсам, соманы және орташа мәндерді (кеңістіктің күрделілігін еске сала алмай) есептеуге көп уақыт кетеді.

Хадооп генератордың барлық артықшылықтарын пайдаланудың тамаша мысалы болып табылады.

5
04 янв. Жауап Murphy 04 jan беріледі. 2016-01-04 23:31 '16 сағат 11 : 31- те 2016-01-04 23:31

Кейде сіз оның iTertools функциясынан кете аласыз, бірдей генератор үшін бірнеше итераторды қайтарады, олар өз бетімен қолданылуы мүмкін.

3
10 сент. Жауап Джейкоб Ригби 10 қыркүйек. 2008-09-10 03:58 '08 3:58 pm 2008-09-10 03:58
 def infinite(): i = 0 while(True): yield i i += 1 for i in infinite(): print(i) 

Қазір бұл тізіммен көріңіз!

0
24 янв. жауап 24 қаңтар күні жарияланады 2019-01-24 11:42 '19 at 11:42 2019-01-24 11:42

туралы сауалдарға қатысты басқа сұрақтар немесе Сұрақ қою