Kazi za mpangilio wa juu wa Python. Ulimwengu wa Python: utendaji kwa njia ndogo - Advanced Python - Hexlet. Hufanya kazi kama vitu

2010-11-17 09:47

Ramani, zip, na kazi za lambda (zinazoitwa "kazi za hali ya juu" au "kazi za daraja la kwanza," kwa njia, hukuruhusu kufanya upotoshaji wa data anuwai kwa urahisi, ambayo inahitaji kuandika nambari zaidi katika "kawaida. ” mtindo wa kiutaratibu. Kila kitu kilichoandikwa hapa chini kinahusu programu inayoitwa kazi, tafuta maelezo.

Hufanya kazi ramani, zip na lambda katika mifano.

Kazi rahisi ni orodha a = na orodha b = ya urefu sawa na unahitaji kuunganisha kwa jozi. Ni rahisi kama ganda la pears - kwa kutumia kazi zip :

a = [ 1 , 2 ] b = [ 3 , 4 ] chapisha zip (a , b ) [(1 , 3 ), (2 , 4 )]

au katika sehemu tatu:

a = [1, 2] b = [3, 4] c = [5, 6] chapisha zip (a, b, c) [(1, 3, 5), (2, 4, 6)]

au kwa ujumla zaidi

list = [a, b, c] chapisha zip (* orodha) [(1, 3, 5), (2, 4, 6)]

Nyota * kabla ya orodha inaonekana kuashiria kuwa orodha ya hoja inapitishwa, i.e. Kuigiza ni sawa na kupitisha a, b, c i.e. Inawezekana hata chapisha zip(*) matokeo hayatabadilika.

def f (x): rudisha x * x nums = [1, 2, 3] kwa nambari katika nambari: chapa f (idadi)

Noob mwenye uzoefu zaidi ambaye amesoma ufahamu wa orodha:

def f (x): rudisha x * x chapisha [ f (idadi) kwa nambari katika nambari ]

Msanidi programu atafanya iwe rahisi:

def f (x): rudisha x * x ramani ya kuchapisha (f, nambari)

Na mdukuzi wa ujuzi wa kweli atafanya kama ifuatavyo (mradi, kwa kweli, kwamba kazi inaweza kuandikwa kama lambda; kazi haitakuwa rahisi kila wakati kuandikwa kama lambda):

chapisha ramani (lambda x : x * x , nums )

Kuingia kwa mwisho ni mfano wa mbinu inayofaa zaidi. Ukweli ni kwamba wakati mtu anaandika msimbo kama ushairi, kwa msukumo (ambao kwa maneno mengine unaweza kuitwa "katika mshtuko wa porini"), kasi ya uandishi ni muhimu sana (hapa ndipo mizizi ya upendo wa heshima. ya watengenezaji wengi wa wahariri wa maandishi rahisi vim, emacs, sublimetext grow) , na nguvu ya Python ni saizi ya nambari inayotengenezwa - ni ngumu sana. Kuandika mstari mmoja kwa kawaida ni haraka kuliko 7, na msimbo mfupi ni rahisi kusoma, lakini kuandika msimbo kama huo kunahitaji ujuzi fulani. Upande mwingine wa sarafu ni kwamba wakati mwingine katika "frenzy hii ya mwitu" mlolongo mzima wa vitendo ngumu huandikwa kwa mstari mmoja, kiasi kwamba ni vigumu sana kuelewa kinachotokea huko na nini kinatokea mwishoni.

Kutoka kwa mfano ni wazi kwamba ramani inatumika kwa orodha na kurudisha matokeo, tena katika mfumo wa orodha. Unaweza kupitisha orodha kadhaa, kisha kazi (ambayo ni parameta ya kwanza) lazima ichukue hoja kadhaa (kulingana na idadi ya orodha zilizopitishwa ramani).

def f (x, y): rudisha x * y a = [1, 3, 4] b = [3, 4, 5] ramani ya kuchapisha (f, a, b) [3, 12, 20]

Baridi, sawa?

Hata hivyo, ikiwa orodha ni za urefu tofauti, i.e. Moja ni fupi kuliko nyingine, basi itawekwa na Hakuna maadili kwa urefu unaohitajika. Ikiwa imeondolewa kwenye orodha b thamani ya mwisho - mfano hautafanya kazi, kwa sababu Katika kazi f, jaribio litafanywa kuzidisha nambari na Hakuna, na Python hairuhusu hii, ambayo, kwa njia, inaitofautisha vyema kutoka kwa php, ambayo ingeendelea kufanya kazi katika hali kama hiyo. Kwa hivyo, ikiwa chaguo la kukokotoa f ni kubwa vya kutosha, itakuwa ni wazo nzuri kuangalia maadili yanayopitishwa. Kwa mfano;

Ikiwa kazi inabadilishwa na Hakuna, basi ramani inafanya kazi sawa na zip, lakini ikiwa orodha zilizopitishwa ni za urefu tofauti, matokeo yataandikwa Hakuna - ambayo, kwa njia, inafaa sana katika baadhi ya matukio.

a = [ 1 , 3 , 4 ] b = [ 3 , 4 ] chapisha ramani (Hakuna , a , b ) [(1 , 3 ), (3 , 4 ), (4 , Hakuna )]

Sasa kuhusu lambda hufanya kazi kwenye python. Zinatumika wakati unahitaji kufafanua kazi bila kutumia def func_name(): ..., kwa sababu mara nyingi (kama katika mifano iliyopita) kazi ni ndogo sana kwamba hakuna maana katika kuifafanua kando (mistari ya ziada ya msimbo huharibika usomaji. ) Kwa hivyo, kazi inaweza kufafanuliwa "mahali" f = lambda x: x*x kana kwamba inatuambia - inakubali x, inarudisha x*x

Kwa hivyo, kwa kutumia zana za kawaida za Python, unaweza kuandika vitendo ngumu kabisa kwenye mstari mmoja. Kwa mfano kazi:

def f (x , y ): ikiwa (y == Hakuna ): y = 1 kurudi x * y

inaweza kuwakilishwa kama:

lambda x , y : x * (y ikiwa y sio Hakuna mwingine 1)

Sasa itakuwa nzuri kupitisha orodha zilizopangwa kwa urefu - len(a) > (b) - rahisi kama ganda la pears - wacha tutumie kazi hiyo. imepangwa :

imepangwa ([ a , b ], ufunguo = lambda x : len ( x ), kinyume = Kweli )

kipengele cha kukokotoa kimepangwa inachukua orodha ya maadili ( = [,]) na kupanga kwa ufunguo- ambayo imetolewa na kazi ya len(x) - ambayo inarudisha urefu wa orodha, tunaipanga kwa mpangilio wa kushuka (reverse=True)

Mwishowe, operesheni nzima imeandikwa kama hii:

ramani (lambda x , y : x * (y ikiwa y sio Hakuna mwingine 1 ), * imepangwa ([ a , b ], ufunguo = lambda x : len (x ), kinyume = Kweli ))

orodha a na b inaweza kuwa na urefu tofauti na kupitishwa kwa mpangilio wowote. Misemo ya Lambda ni muhimu kwa kufafanua vipengele visivyo ngumu sana ambavyo hupitishwa kwa vitendaji vingine.

3.2.3 Ufahamu wa Kamusi

Sema tunayo kamusi ambayo funguo zake ni herufi na maadili ambayo ramani ya idadi ya mara herufi inaonekana katika maandishi fulani. Kamusi kwa sasa inatofautisha kati ya herufi kubwa na ndogo.

Tunahitaji kamusi ambamo matukio ya herufi kubwa na ndogo yanaunganishwa:

dct = ( "a" : 10 , "b" : 34 , "A" : 7 , "Z" : 3 )

frequency = ( k . chini () : dct . pata ( k . chini () , 0 ) + dct . pata ( k . juu () , 0 )

kwa k in dct . funguo())

masafa ya kuchapisha #("a": 17, "z": 3, "b": 34)

Python inasaidia uundaji wa vitendaji visivyojulikana (yaani vitendaji ambavyo havifungamani na jina) wakati wa utekelezaji, kwa kutumia muundo unaoitwa "lambda". Hii si sawa kabisa na lambda katika lugha tendaji za programu, lakini ni dhana yenye nguvu sana ambayo imeunganishwa vyema kwenye Python na mara nyingi hutumiwa pamoja na dhana za utendaji kazi kama filter() , map() na reduce() .

Vitendaji visivyojulikana kwa namna ya usemi vinaweza kuundwa kwa kutumia lambda
kauli:

args ni orodha ya hoja iliyotenganishwa kwa koma, na usemi ni usemi unaohusisha hoja hizo. Sehemu hii ya nambari inaonyesha tofauti kati ya ufafanuzi wa kawaida wa kazi na kazi ya lambda:

def kazi (x) :

kurudi x *x

kazi ya kuchapisha(2) #4

#-----------------------#

kazi = lambda x : x * x

kazi ya kuchapisha(2) #4

Kama unavyoona, zote mbili function() hufanya sawa na zinaweza kutumika kwa njia sawa. Kumbuka kuwa ufafanuzi wa lambda haujumuishi taarifa ya "kurudi" - huwa na usemi ambao hurejeshwa. Pia kumbuka kuwa unaweza kuweka ufafanuzi wa lambda mahali popote kazi inavyotarajiwa, na sio lazima uikabidhi kwa kutofautisha hata kidogo.

Vipande vya msimbo vifuatavyo vinaonyesha matumizi ya vitendaji vya lambda.

def increment (n) :

rudisha lambda x : x + n

nyongeza ya uchapishaji(2) # kwa 0x022B9530>

nyongeza ya uchapishaji (2) (20) #22

Nambari iliyo hapo juu inafafanua nyongeza ya chaguo la kukokotoa ambayo huunda kitendakazi kisichojulikana kwenye nzi na kuirejesha. Chaguo za kukokotoa zilizorejeshwa huongeza hoja yake kwa thamani ambayo ilibainishwa wakati iliundwa.

Sasa unaweza kuunda kazi nyingi tofauti za nyongeza na kuzikabidhi kwa vigeu, kisha uzitumie bila ya kila mmoja. Kama taarifa ya mwisho inavyoonyesha, si lazima hata ukabidhi utendakazi popote - unaweza kuitumia mara moja na kuisahau wakati haihitajiki tena.

Q3. Lambda ni nzuri kwa nini?
Jibu.
Jibu ni:

  • Hatuhitaji lambda, tunaweza kuishi vizuri bila hiyo. Lakini...
  • kuna hali fulani ambapo ni rahisi - hurahisisha kuandika msimbo, na msimbo ulioandikwa kuwa safi zaidi.

Q4. Ni hali gani?

Kweli, hali ambazo tunahitaji kazi rahisi ya mara moja: kazi ambayo itatumika mara moja tu.

Kwa kawaida, chaguo za kukokotoa huundwa kwa mojawapo ya madhumuni mawili: (a) kupunguza urudiaji wa msimbo, au (b) kurekebisha msimbo.

  • Ikiwa programu yako ina vijisehemu vinavyorudiwa vya msimbo katika sehemu mbalimbali, basi unaweza kuweka nakala moja ya msimbo huo kwenye chaguo la kukokotoa, upe chaguo la kukokotoa jina, kisha - kwa kutumia jina la chaguo la kukokotoa - liite kutoka sehemu mbalimbali kwenye msimbo wako.
  • Ikiwa una sehemu ya msimbo ambayo hufanya operesheni moja iliyofafanuliwa vizuri - lakini ni ndefu sana na inasumbua mtiririko unaoweza kusomeka wa programu yako - basi unaweza kutoa msimbo huo mrefu wa gnarly na kuiweka kwenye utendaji yenyewe.

Lakini tuseme unahitaji kuunda kitendakazi ambacho kitatumika mara moja tu - kinachoitwa kutoka kimoja tu weka katika maombi yako. Naam, kwanza kabisa, huna haja ya kutoa kazi jina. Inaweza kuwa "isiyojulikana". Na unaweza kufafanua tu mahali unapotaka kuitumia. Hapo ndipo lambda inafaa.

Kwa kawaida, lambda hutumiwa katika muktadha wa operesheni nyingine, kama vile kupanga au kupunguza data:

majina = [ "David Beazley" , "Brian Jones" , "Raymond Hettinger" , "Ned Batchelder" ]

chapisha kimepangwa (majina , ufunguo = jina lambda : jina . mgawanyiko () [- 1 ] . chini ())

# ["Ned Batchelder", "David Beazley", "Raymond Hettinger", "Brian Jones"]

Ingawa lambda hukuruhusu kufafanua kazi rahisi, matumizi yake yamezuiliwa sana. Katika
haswa, usemi mmoja tu unaweza kubainishwa, matokeo yake ni kurudi
thamani. Hii ina maana kwamba hakuna vipengele vingine vya lugha, ikiwa ni pamoja na kauli nyingi, masharti, marudio na ushughulikiaji wa kipekee, vinaweza kujumuishwa.
Unaweza kuandika kwa furaha nambari nyingi za Python bila kutumia lambda. Hata hivyo,
mara kwa mara utakutana nayo katika programu ambapo mtu anaandika vidogo vingi
kazi zinazotathmini misemo mbalimbali, au katika programu zinazohitaji watumiaji kutoa
kazi za kurudi nyuma.

Umefafanua chaguo la kukokotoa lisilojulikana kwa kutumia lambda, lakini pia unahitaji kunasa faili ya
maadili ya vigezo fulani wakati wa ufafanuzi.

>>> x = 10

>>> a = lambda y : x + y

>>> x = 20

>>> b = lambda y : x + y

Sasa jiulize swali. Je, maadili ya a(10) na b(10) ni yapi? Ikiwa unafikiri
matokeo yanaweza kuwa 20 na 30, utakuwa umekosea:

Shida hapa ni kwamba thamani ya x inayotumika katika usemi wa lambda ni tofauti ya bure
ambayo hufungwa wakati wa kukimbia, sio wakati wa ufafanuzi. Kwa hivyo, thamani ya x kwenye lambda
misemo ni chochote thamani ya utofauti wa x hutokea wakati wa utekelezaji.
Kwa mfano:

Ikiwa unataka chaguo la kukokotoa lisilojulikana kukamata thamani katika hatua ya ufafanuzi na
ihifadhi, jumuisha dhamana kama dhamana chaguo-msingi, kama hii:

Tatizo linaloshughulikiwa hapa ni jambo ambalo huwa linajitokeza kwa kificho kwamba
inajaribu kuwa wajanja kidogo tu na matumizi ya vitendaji vya lambda. Kwa mfano,
kuunda orodha ya misemo ya lambda kwa kutumia ufahamu wa orodha au katika kitanzi cha aina fulani na kutarajia vitendaji vya lambda kukumbuka utofautishaji wa marudio wakati wa ufafanuzi. Kwa mfano:

>>> funcs = [ lambda x : x + n kwa n katika masafa (5 )]

  • Tafsiri

Wakati wa kuzungumza juu ya programu ya kazi, mara nyingi watu huanza kutupa kundi la sifa za "kazi". Data isiyoweza kubadilika, vitendaji vya daraja la kwanza, na uboreshaji wa kujirudia mkia. Hizi ni sifa za lugha zinazokusaidia kuandika programu zinazofanya kazi. Wanataja uchoraji wa ramani, kuchuja, na kutumia vitendaji vya hali ya juu. Hizi ni mbinu za programu zinazotumiwa kuandika msimbo wa kazi. Wanataja ulinganifu, tathmini ya uvivu, na uamuzi. Hizi ni faida za programu za kazi.

Alama. Nambari ya kazi inatofautishwa na mali moja: kutokuwepo madhara. Haitegemei data nje ya chaguo za kukokotoa za sasa, na haibadilishi data nje ya chaguo za kukokotoa. "Sifa" zingine zote zinaweza kupatikana kutoka kwa hili.

Kitendaji kisichofanya kazi:

A = 0 def increment1(): kimataifa a += 1

Kipengele cha Utendaji:

Def increment2(a): rudisha + 1

Badala ya kurudia kupitia orodha, tumia ramani na upunguze

Ramani

Inakubali chaguo za kukokotoa na seti ya data. Huunda mkusanyiko mpya, hutekeleza chaguo la kukokotoa kwenye kila nafasi ya data, na kuongeza thamani ya kurejesha kwenye mkusanyiko mpya. Hurejesha mkusanyiko mpya.

Ramani rahisi ambayo inachukua orodha ya majina na kurudisha orodha ya urefu:

Name_lengths = ramani(len, ["Masha", "Petya", "Vasya"]) chapisha jina_lengths # =>

Ramani hii inaweka mraba kila kipengele:

Mraba = ramani(lambda x: x * x, ) chapisha miraba # =>

Haikubali chaguo la kukokotoa lililopewa jina, lakini huchukua isiyojulikana iliyofafanuliwa kupitia lambda. Vigezo vya Lambda vinafafanuliwa upande wa kushoto wa koloni. Mwili wa kazi uko upande wa kulia. Matokeo yanarejeshwa kwa ukamilifu.

Msimbo usiofanya kazi katika mfano ufuatao unachukua orodha ya majina na badala yake majina ya utani ya nasibu.

Leta majina nasibu = ["Masha", "Petya", "Vasya"] code_names = ["Shpuntik", "Vintik", "Funtik"] kwa i in range(len(majina)): names[i] = nasibu. chaguo(code_names) chapisha majina # => ["Shpuntik", "Vintik", "Shpuntik"]

Kanuni ya kanuni inaweza kuwapa mawakala tofauti wa siri majina ya utani sawa. Hebu tumaini hili halitasababisha matatizo wakati wa misheni ya siri.

Wacha tuandike tena hii kwa kutumia ramani:

Leta majina nasibu = ["Masha", "Petya", "Vasya"] secret_names = ramani(lambda x: random.choice(["Shpuntik", "Vintik", "Funtik"]), majina)

Zoezi 1. Jaribu kuandika tena msimbo ufuatao kwa kutumia ramani. Inachukua orodha ya majina halisi na kuchukua nafasi yao kwa majina ya utani kwa kutumia njia ya kuaminika zaidi.

Majina = ["Masha", "Petya", "Vasya"] kwa i in range(len(majina)): names[i] = hash(majina[i]) chapisha majina # =>

Uamuzi wangu:

majina = ["Masha", "Petya", "Vasya"] secret_names = ramani(heshi, majina)

Punguza

Kupunguza huchukua kazi na seti ya vitu. Hurejesha thamani iliyopatikana kwa kuchanganya vipengee vyote.

Mfano wa kupunguza rahisi. Hurejesha jumla ya vitu vyote katika seti:

Jumla = punguza(lambda a, x: a + x, ) chapisha jumla # => 10

X ndicho kipengee cha sasa, na ni betri. Hii ndio dhamana inayorejeshwa kwa kutekeleza lambda katika hatua iliyotangulia. reduce() inarudia kupitia thamani zote, na huendesha lambda kwa kila moja kwa thamani za sasa a na x, na hurejesha matokeo katika a kwa marudio yanayofuata.

Ni nini thamani ya a katika marudio ya kwanza? Ni sawa na kipengele cha kwanza cha mkusanyiko, na reduce() huanza kufanya kazi kutoka kwa kipengele cha pili. Hiyo ni, x ya kwanza itakuwa sawa na kipengee cha pili cha seti.

Mfano ufuatao huhesabu ni mara ngapi neno "nahodha" linaonekana katika orodha ya mifuatano:

Sentensi = ["Kapteni Jack Sparrow", "nahodha wa bahari", "mashua yako tayari, nahodha"] cap_count = 0 kwa sentensi katika sentensi: cap_count += sentence.count("captain") print cap_count # => 3

Nambari sawa kwa kutumia kupunguza:

Sentensi = ["nahodha jack sparrow", "nahodha wa bahari", "mashua yako iko tayari, nahodha"] cap_count = punguza(lambda a, x: a + x.count("nahodha"), sentensi, 0)

Thamani ya awali a inatoka wapi hapa? Haiwezi kuhesabiwa kutoka kwa idadi ya marudio katika mstari wa kwanza. Kwa hivyo, imepewa kama hoja ya tatu kwa kupunguza() kazi.

Kwa nini ramani ni bora na kupunguza?

Kwanza, kawaida hulingana kwenye mstari mmoja.

Pili, sehemu muhimu za kurudia-mkusanyiko, uendeshaji, na thamani ya kurudi-siku zote ziko mahali pamoja, ramani na kupunguza.

Tatu, msimbo katika kitanzi unaweza kubadilisha thamani ya vigezo vilivyoainishwa hapo awali, au kuathiri msimbo baada yake. Kwa makubaliano, ramani na kupunguza ni kazi.

Nne, ramani na kupunguza ni shughuli za kimsingi. Badala ya kusoma loops mstari kwa mstari, ni rahisi kwa msomaji kutambua ramani na kupunguza kujengwa katika algoriti changamano.

Tano, wana marafiki wengi wanaoruhusu tabia muhimu, iliyorekebishwa kidogo ya vipengele hivi. Kwa mfano, chujio, yote, yoyote na pata.

Zoezi 2: Andika upya msimbo ufuatao kwa kutumia ramani, punguza na chujio. Kichujio kinakubali chaguo za kukokotoa na mkusanyiko. Hurejesha mkusanyiko wa vitu hivyo ambavyo chaguo la kukokotoa hurejesha Kweli.

People = [("jina": "Masha", "height": 160), ("height": "Sasha", "height": 80), ("jina": "Pasha")] height_total = 0 height_count = 0 kwa mtu katika watu: ikiwa "urefu" ana kwa ana: urefu_jumla += mtu["urefu"] urefu_hesabu += 1 ikiwa urefu_hesabu > 0: wastani_urefu = urefu_jumla / urefu_hesabu chapa urefu_wastani # => 120

Uamuzi wangu:

people = [("jina": "Masha", "height": 160), ("height": "Sasha", "height": 80), ("jina": "Pasha")] urefu = ramani(lambda x: x["urefu"], kichujio(lambda x: "urefu" katika x, watu)) ikiwa len(urefu) > 0: kutoka kwa uingizaji wa opereta ongeza wastani_height = punguza(ongeza, urefu) / len(urefu)

Andika kwa kutangaza, sio lazima.

Mpango unaofuata unaiga mbio za magari matatu. Kwa kila wakati wa wakati, gari linasonga mbele au la. Kila wakati programu inaonyesha umbali unaosafirishwa na magari. Baada ya vipindi vitano mbio huisha.

Mifano ya pato:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Maandishi ya programu:

Kutoka kwa muda wa kuleta nasibu = nafasi_za_gari 5 = wakati: # muda wa kupungua -= kuchapisha 1 "" kwa i katika masafa(len(nafasi_ya_gari)): # sogeza gari ikiwa nasibu() > 0.3: nafasi_ya_gari[i] += 1 # chora chapa ya gari "-" * nafasi_ya_gari[i]

Kanuni ni muhimu. Toleo la utendaji lingekuwa la kutangaza - lingeelezea kile kinachohitajika kufanywa, sio jinsi inapaswa kufanywa.

Kutumia vipengele

Utangazaji unaweza kupatikana kwa kuingiza nambari kwenye vitendaji:

Kutoka kwa kuagiza bila mpangilio def move_cars(): kwa i, _ katika hesabu(nafasi_za_gari): ikiwa nasibu() > 0.3: nafasi_ya_gari[i] += 1 def draw_car(car_position): chapisha "-" * car_position def run_step_of_race(): wakati wa dunia nzima -= 1 move_cars() def draw(): chapisha "" kwa car_position in car_positions: draw_car(car_position) time = 5 car_positions = while time: run_step_of_race() draw()

Ili kuelewa programu, msomaji anaangalia kitanzi kikuu. "Ikiwa kuna wakati uliobaki, tutapitia hatua moja ya kinyang'anyiro na kuonyesha matokeo. Hebu tuangalie saa tena." Ikiwa msomaji anahitaji kuelewa jinsi hatua ya mbio inavyofanya kazi, wanaweza kusoma msimbo tofauti.

Hakuna maoni yanayohitajika, nambari inajielezea yenyewe.

Kuvunja msimbo kuwa vitendakazi hufanya msimbo kusomeka zaidi. Mbinu hii hutumia kazi, lakini tu kama subroutines. Wanafunga msimbo, lakini usiifanye ifanye kazi. Kazi huathiri msimbo unaozizunguka na kubadilisha vigeu vya kimataifa badala ya kurudisha thamani. Ikiwa msomaji atakutana na tofauti, atahitaji kupata ilitoka wapi.

Hapa toleo la kazi programu hii:

Kutoka kwa uagizaji nasibu def move_cars(car_positions): rudisha ramani(lambda x: x + 1 ikiwa nasibu() > 0.3 else x, car_positions) def output_car(car_position): rudisha "-" *car_position def run_step_of_race(state): return ( "muda": hali["wakati"] - 1, "nafasi_za_gari": hoja_gari(jimbo["nafasi_za_gari"])) def draw(jimbo): chapisha "" chapisha "\n".jiunge(ramani(uto_gari, jimbo[ "gari_nafasi"])) def mbio(jimbo): sare(jimbo) ikiwa hali["wakati"]: mbio(kukimbia_hatua_ya_race(jimbo)) mbio(("muda": 5, "nafasi_za_gari": ))

Nambari sasa imegawanywa katika vitendaji vya kazi. Kuna ishara tatu za hii. Ya kwanza ni kwamba hakuna vigezo vilivyoshirikiwa. wakati na nafasi_za gari hupitishwa moja kwa moja kwenye mbio (). Pili, kazi huchukua vigezo. Tatu, vigeuzo havibadilishi vitendakazi vya ndani; maadili yote yanarejeshwa. Kila wakati run_step_of_race() inapofanya hatua inayofuata, inarudishwa hadi inayofuata.

Hapa kuna kazi mbili zero() na moja():

Def sufuri: ikiwa s == "0": rudisha s def moja: ikiwa s == "1": rudisha s

Zero() inachukua kamba s. Ikiwa herufi ya kwanza ni 0, basi inarudisha safu iliyobaki. Ikiwa sivyo, basi Hakuna. one() hufanya vivyo hivyo ikiwa mhusika wa kwanza ni 1.

Wacha tufikirie kanuni_sequence() kazi. Inachukua kamba na orodha ya kazi za sheria, zinazojumuisha kazi sifuri na moja. Inaita sheria ya kwanza, kupita kwa kamba. Ikiwa Hakuna itarejeshwa, basi chukua thamani iliyorejeshwa na kuita sheria inayofuata. Nakadhalika. Ikiwa Hakuna itarejeshwa, rule_sequence() itasimama na kurudisha Hakuna. Vinginevyo - maana ya kanuni ya mwisho.

Mifano ya data ya pembejeo na pato:

Print rule_sequence("0101", ) # => 1 print rule_sequence("0101", ) # => Hakuna

Toleo la lazima la rule_sequence():

Def rule_sequence(s, sheria): kwa sheria katika kanuni: s = sheria(s) if s == None: break return s

Zoezi 3. Msimbo huu hutumia kitanzi. Iandike upya kwa kutangaza kwa kutumia urejeshaji.

Uamuzi wangu:

def rule_sequence(s, sheria): ikiwa s == Hakuna au si sheria: return s else: return rule_sequence(kanuni), sheria)

Tumia mabomba

Sasa hebu tuandike upya aina nyingine ya kitanzi kwa kutumia mbinu inayoitwa bomba.

Kitanzi kinachofuata hurekebisha kamusi zilizo na jina, nchi asilia isiyo sahihi na hadhi ya baadhi ya vikundi.

Bendi = [("name": "sunset rubdown", "country": "UK", "active": False), ("name": "women", "country": "Germany", "active": Si kweli ), ("name": "a silver mt. zion", "country": "Spain", "active": True)] def format_bands(bendi): kwa bendi katika bendi: bendi["country"] = "Kanada " bendi["jina"] = bendi["jina"].replace(".", "") bendi["name"] = bendi["jina"].title() format_bands(bendi) chapisha bendi # => [("name": "Sunset Rubdown", "active": False, "country": "Canada"), # ("name": "Wanawake", "active": False, "country": "Canada" ) , # ("name": "A Silver Mt Zion", "active": True, "country": "Canada")]

Jina la chaguo la kukokotoa "umbizo" ni la jumla sana. Kwa ujumla, kanuni husababisha wasiwasi fulani. Mambo matatu tofauti hutokea katika mzunguko mmoja. Thamani ya ufunguo wa "nchi" inabadilishwa kuwa "Kanada". Dots huondolewa na herufi ya kwanza ya jina inabadilishwa kuwa kubwa. Ni ngumu kuelewa ni nini nambari inapaswa kufanya, na ni ngumu kusema ikiwa inafanya hivyo. Ni vigumu kutumia, kupima na kusawazisha.

Linganisha:

Chapisha bomba_kila(bendi, )

Ni rahisi. Vitendo vya usaidizi vinaonekana kufanya kazi kwa sababu vimefungwa pamoja. Matokeo ya uliopita ni pembejeo ya ijayo. Ni rahisi kuzijaribu, kuzitumia tena, kuhalalisha na kusawazisha.

Pipeline_each() hurudia kupitia vikundi moja baada ya nyingine na kuvipitisha kwa vitendaji vya ugeuzaji kama vile set_canada_as_country(). Baada ya kutumia kitendakazi kwa vikundi vyote, pipeline_each() hufanya orodha yao na kuipitisha kwa inayofuata.

Hebu tuangalie kazi za uongofu.

Def assoc(_d, key, value): kutoka kwa nakala leta deepcopy d = deepcopy(_d) d = value return d def set_canada_as_country(bendi): return assoc(bendi, "country", "Canada") def strip_punctuation_from_name(bendi): return assoc(bendi, "jina", bendi["jina"].replace(".", "")) def capitalize_names(bendi): return assoc(bendi, "jina", bendi["jina"].title( ))

Kila mmoja huhusisha ufunguo wa kikundi na thamani mpya. Hii ni ngumu kufanya bila kubadilisha data asili, kwa hivyo tunatatua hii na assoc(). Inatumia deepcopy() kuunda nakala ya kamusi iliyopitishwa. Kila chaguo la kukokotoa hubadilisha nakala na kurudisha nakala hiyo.

Kila kitu kinaonekana kuwa sawa. Data asili inalindwa dhidi ya mabadiliko. Lakini kuna nafasi mbili zinazowezekana katika msimbo wa mabadiliko ya data. Katika strip_punctuation_from_name() jina bila dots huundwa kwa kupiga simu replace() na jina asili. capitalize_names() huunda jina na herufi kubwa ya kwanza kulingana na kichwa() na jina la asili. Ikiwa nafasi na wakati hazifanyi kazi, basi strip_punctuation_from_name() na capitalize_names() hazifanyi kazi.

Kwa bahati nzuri, wao ni kazi. Katika Python, kamba hazibadiliki. Vipengele hivi hufanya kazi na nakala za mifuatano. Uff, asante Mungu.

Tofauti hii kati ya masharti na kamusi (asili yao inayoweza kubadilika) katika Python inaonyesha faida za lugha kama Clojure. Huko, mpangaji programu sio lazima afikirie ikiwa atabadilisha data. Haitabadilika.

Zoezi 4. Jaribu kutengeneza pipeline_kila kitendakazi. Fikiria juu ya mlolongo wa shughuli. Vikundi viko katika safu, hupitishwa moja baada ya nyingine hadi kitendakazi cha kwanza cha ubadilishaji. Kisha safu inayotokana hupitishwa kipande kimoja kwa kazi ya pili, na kadhalika.

Uamuzi wangu:

def pipeline_each(data, fns): rudisha punguza(lambda a, x: ramani(x, a), fns, data)

Vitendaji vyote vitatu vya mageuzi husababisha kubadilisha uga mahususi kwa kikundi. call() inaweza kutumika kuunda kifupi kwa hili. Inakubali chaguo za kukokotoa na ufunguo ambao itatumiwa.

Set_canada_as_country = call(lambda x: "Canada", "country") strip_punctuation_from_name = call(lambda x: x.replace(".", ""), "name") capitalize_names = call(str.title, "jina") chapisha bomba_kila(bendi, )

Au, kujinyima usomaji:

Chapisha bomba_kila(bendi, )

Nambari ya simu ():

Def assoc(_d, key, value): kutoka kwa nakala leta deepcopy d = deepcopy(_d) d = value return d def call(fn, key): def apply_fn(rekodi): return assoc(rekodi, key, fn(rekodi. get(key))) rudisha apply_fn

Nini kinaendelea hapa?

Moja. wito ni kazi ya utaratibu wa juu, kwa sababu huchukua chaguo jingine la kukokotoa kama hoja na kurudisha chaguo la kukokotoa.

Mbili. apply_fn() ni sawa na kazi za ubadilishaji. Inapata kiingilio (kikundi). Inatafuta rekodi ya thamani. Inapiga simu kwa fn. Hukabidhi matokeo kwa nakala ya rekodi na kuirejesha.

Tatu. simu yenyewe haifanyi chochote. apply_fn() hufanya kazi yote. Katika pipeline_each() mfano, mfano mmoja wa apply_fn() huweka "nchi" kuwa "Kanada". Nyingine ina herufi kubwa ya kwanza.

Nne. Wakati wa kutekeleza mfano wa apply_fn(), fn na utendakazi muhimu hazitapatikana katika wigo. Hizi sio hoja za kuomba_fn() au anuwai za ndani. Lakini kutakuwa na upatikanaji wao. Chaguo za kukokotoa zinapofafanuliwa, huhifadhi marejeleo ya vigeu vinavyofunga—vile ambavyo vilibainishwa nje ya chaguo za kukokotoa na kutumika ndani. Chaguo la kukokotoa linapoendeshwa, vigeu hutafutwa kati ya zile za kawaida, kisha kati ya hoja, na kisha kati ya marejeleo ya kufungwa. Huko utapata fn na ufunguo.

Tano. Hakuna kutajwa kwa vikundi kwenye simu. Hii ni kwa sababu simu inaweza kutumika kuunda mabomba yoyote, bila kujali yaliyomo. Programu inayofanya kazi, haswa, huunda maktaba kazi za jumla, yanafaa kwa ajili ya nyimbo na kutumia tena.

Umefanya vizuri. Kufungwa, utendaji wa mpangilio wa juu na upeo - yote katika aya chache. Unaweza pia kunywa chai na biskuti.

Bado uchakataji mmoja zaidi wa data ya kikundi. Ondoa kila kitu isipokuwa jina na nchi. extract_name_and_country() kazi:

Def extract_name_and_country(bendi): plucked_band = () plucked_band["name"] = bendi["jina"] plucked_band["nchi"] = bendi["nchi"] rudisha plucked_band chapa bomba_kila(bendi, ) # => [(" name": "Sunset Rubdown", "country": "Canada"), # ("name": "Women", "country": "Canada"), # ("name": "A Silver Mt Zion", " nchi": "Kanada")]

Extract_name_and_country() inaweza kuandikwa kwa njia ya kawaida inayoitwa pluck(). Ingetumika kama hii:

Chapisha bomba_kila(bendi, )])

Zoezi 5. pluck inakubali orodha ya vitufe ili kutoa kutoka kwa rekodi. Jaribu kuiandika. Hii itakuwa kazi ya utaratibu wa juu.

Sio bure kwamba lugha ya Python ni maarufu kati ya watengenezaji wa programu za Google na wahariri wa Hacker kwa wakati mmoja :). Lugha hii yenye nguvu kweli hukuruhusu kuandika msimbo kufuatia dhana kadhaa, na leo tutajaribu kujua ni tofauti gani kati yao na ni ipi bora kufuata.

Mawazo gani?! Hebu tuweke nambari!

Unapohitaji kuandika kitu, jambo la mwisho ambalo labda una wasiwasi kuhusu ni dhana gani ya programu ya kuchagua. Badala yake, unaweza kuchagua lugha inayofaa zaidi, au anza mara moja kuweka misimbo katika unayopenda, unayopendelea na iliyothibitishwa kwa miaka mingi. Ni kweli, wacha wanaitikadi wafikirie juu ya itikadi, kazi yetu ni kupanga :). Na bado, wakati wa kupanga, lazima ufuate aina fulani ya dhana. Hebu tuangalie mfano. Wacha tujaribu kuandika kitu rahisi ... vizuri, kwa mfano, wacha tuhesabu eneo la duara.

Unaweza kuiandika kama hii:

Eneo la duara (chaguo la kwanza)

eneo_mbili_la_mduara(mara mbili) (
rudisha M_PI*pow(r,2);
}
int kuu() (
mara mbili r = 5;
koti<< "Площадь: "<< area_of_circle(r)<< endl;
}

Au unaweza kufanya hivi:

Eneo la duara (chaguo la pili)

mzunguko wa darasa (
mara mbili r;
umma:
Mduara(mara mbili r) (hii->r = r;)
eneo mbili() ( rudisha M_PI*pow(this->r,2); )
utupu print_eneo() (
koti<< "Площадь: "<< this->eneo ()<< endl;
}
};
int main() ((Mduara mpya(5))->chapisho_eneo();)

Inaweza kufanywa kwa njia tofauti ... lakini haijalishi unajaribu sana, nambari hiyo itakuwa ya lazima (kama ilivyo katika kesi ya kwanza) au iliyoelekezwa kwa kitu (kama ilivyo kwa pili).
Hii sio kwa sababu ya ukosefu wa mawazo, lakini kwa sababu C ++ imeundwa kwa dhana hizi.

Na bora (au mbaya zaidi, kulingana na unyoofu wa mikono yako) ambayo unaweza kufanya nayo ni kuchanganya dhana kadhaa.

Vigezo

Kama unavyoweza kukisia, unaweza kuandika kwa lugha moja kufuata dhana kadhaa, wakati mwingine hata kadhaa mara moja. Wacha tuangalie wawakilishi wao wakuu, kwa sababu bila ufahamu huu hautaweza kujiona kuwa mtangazaji wa kitaalam, na uwezekano mkubwa utalazimika kusahau kufanya kazi katika timu.

Upangaji wa lazima

"Kwanza tunafanya hivi, halafu hivi, halafu hivi"

Lugha: Karibu zote

Mfano unaoeleweka kabisa kwa programu yoyote: "Mtu hutoa maagizo kwa mashine."
Kila mtu huanza kujifunza/kuelewa upangaji programu kutoka kwa dhana ya lazima.

Upangaji wa kazi

"Tunahesabu usemi na kutumia matokeo kwa kitu kingine."

Lugha: Haskell, Erlang, F#

Mtazamo usioeleweka kabisa kwa mpanga programu anayeanza. Hatuelezei mlolongo wa hali (kama katika dhana ya lazima), lakini mlolongo wa vitendo.

Upangaji unaolenga kitu

"Tunabadilishana ujumbe kati ya vitu, kuiga mwingiliano katika ulimwengu wa kweli."

Lugha: Karibu zote

Pamoja na ujio wake, dhana yenye mwelekeo wa kitu imeingia kwa uthabiti katika maisha yetu.
Takriban michakato yote ya kisasa ya biashara imejengwa kwenye OOP.

Upangaji wa mantiki

"Tunajibu swali kwa kutafuta suluhu."

Lugha: Prolog

Upangaji wa mantiki ni jambo maalum, lakini wakati huo huo, la kuvutia na la angavu.
Mfano rahisi utatosha:

(weka kanuni)
mchawi(X)<= burns(X) and female(X).
kuchoma (X)<= wooden(X).
mbao (X)<= floats(X).
inaelea (X)<= sameweight(duck, X).
(weka uchunguzi)
mwanamke (msichana).
uzani sawa (bata, msichana).
(Uliza Swali)
? mchawi (msichana).

Ingawa kila mpangaji programu kwa ufafanuzi anafahamu upangaji wa lazima na unaolenga kitu, ni nadra sana kukutana na upangaji programu katika umbo lake safi.

Upangaji wa utendaji kazi unalinganishwa na upangaji wa lazima.

Upangaji wa lazima unahusisha mlolongo wa mabadiliko kwa hali ya programu, na vigezo hutumiwa kuhifadhi hali hii.

Programu ya kazi, kinyume chake, inahusisha mlolongo wa vitendo kwenye data. Hii ni sawa na hisabati - tunaandika formula f(x) kwenye ubao kwa muda mrefu, na kisha kubadilisha x na kupata matokeo.

Na jambo zima la utayarishaji wa programu ni kwamba hapa fomula ni zana ambayo tunatumia kwa X.

Chatu mwenye nyuso mbili

Hakuna nadharia bora kuliko mazoezi, kwa hivyo wacha tuandike kitu tayari. Bora zaidi, iandike kwa Python :).
Wacha tuhesabu jumla ya miraba ya vipengee vya safu ya "data" kwa lazima na kiutendaji:

Chatu Muhimu

data = [...]
jumla = 0
kwa kipengele katika:
jumla += kipengele ** 2
Chapisha jumla

Python inayofanya kazi

data = [...]
sq = lambda x: x**2
jumla = lambda x,y: x+y
chapisha kupunguza(jumla, ramani(sq, data))

Mifano zote mbili ziko kwenye Python, ingawa sikuijumuisha kwenye orodha ya lugha zinazofanya kazi. Hii sio bahati mbaya, kwani lugha inayofanya kazi kikamilifu ni kitu maalum na kisichotumika sana. Lugha ya kazi ya kwanza ilikuwa Lisp, lakini hata haikufanya kazi kabisa (ya kutatanisha, sivyo?). Lugha zinazofanya kazi kikamilifu hutumika kwa kila aina ya matumizi ya kisayansi na bado hazijatumika sana.

Lakini ikiwa "kazi" zenyewe hazijaenea, mawazo fulani yamehamia kutoka kwao hadi kwa kuandika (na si tu) lugha za programu.
Ilibadilika kuwa sio lazima kabisa kuandika nambari inayofanya kazi kikamilifu, inatosha kupamba nambari ya lazima na vitu vya kufanya kazi.

Python katika hatua

Inabadilika kuwa dhana za FP zinatekelezwa katika Python zaidi ya kifahari. Hebu tuangalie kwa karibu zaidi.

?-hesabu

Lambda calculus ni dhana ya hisabati ambayo ina maana kwamba kazi zinaweza kuchukua kama hoja na kurejesha utendaji mwingine.
Kazi kama hizo huitwa kazi za maagizo ya juu. ?-calculus inategemea shughuli mbili: utumiaji na uondoaji.
Tayari nimetoa mfano wa programu katika tangazo lililopita. Ramani na kipengele cha kupunguza ni vitendakazi sawa vya mpangilio wa juu ambavyo "hutumika", au hutumika, chaguo za kukokotoa zinazopitishwa kama hoja kwa kila kipengele cha orodha (kwa ramani) au kila jozi ya mfululizo ya vipengele vya orodha (kwa kupunguza).

Kuhusu uondoaji, ni kinyume chake: kazi huunda vitendaji vipya kulingana na hoja zao.

Uondoaji wa Lambda

def add(n):
rudisha lambda x: x + n

ongeza =

Hapa tumeunda orodha ya kazi, ambayo kila mmoja huongeza nambari fulani kwa hoja.
Mfano huu mdogo pia una ufafanuzi kadhaa wa kuvutia zaidi wa programu ya kufanya kazi - kufungwa na kuchezea.

Kufungwa ni ufafanuzi wa chaguo la kukokotoa ambalo linategemea hali ya ndani ya chaguo la kukokotoa lingine. Katika mfano wetu hii ni lambda x. Kwa mbinu hii, tunafanya kitu sawa na kutumia vigeu vya kimataifa, katika kiwango cha ndani pekee.

Kubeba ni badiliko la chaguo la kukokotoa ambalo huchukua jozi ya hoja hadi kitendakazi ambacho huchukua hoja zake moja baada ya nyingine. Hivi ndivyo tulifanya katika mfano, tu tuliishia na safu ya kazi kama hizo.

Kwa njia hii tunaweza kuandika msimbo ambao haufanyi kazi tu na vigezo, lakini pia na kazi, ambayo inatupa "digrii za uhuru" chache zaidi.

Kazi safi na mkusanyaji mvivu

Vitendaji muhimu vinaweza kubadilisha vigeu vya nje (kitandawazi), ambayo ina maana kwamba chaguo za kukokotoa zinaweza kurejesha thamani tofauti kwa thamani sawa za hoja katika hatua tofauti za utekelezaji wa programu.

Taarifa hii haifai kabisa kwa dhana ya utendaji. Hapa, vipengele vya kukokotoa hutazamwa kama vya hisabati, kutegemea tu hoja na kazi zingine, ndiyo maana zinaitwa "kazi safi."

Kama tulivyokwishagundua, katika dhana ya utendakazi unaweza kudhibiti vitendaji unavyotaka. Lakini tunapata manufaa zaidi tunapoandika "kazi safi". Kazi safi ni kazi bila madhara, ambayo inamaanisha kuwa haitegemei mazingira yake na haibadili hali yake.

Kutumia vitendaji safi hutupatia faida kadhaa:

  • Kwanza, ikiwa kazi hazitegemei anuwai za mazingira, basi tunapunguza idadi ya makosa yanayohusiana na maadili yasiyotakikana ya anuwai hizi. Pamoja na idadi ya hitilafu, pia tunapunguza muda unaochukua kutatua programu, na ni rahisi zaidi kutatua kazi kama hizo.
  • Pili, ikiwa kazi ni huru, basi mkusanyaji ana nafasi ya kuzurura. Ikiwa kipengele cha kukokotoa kinategemea tu hoja, basi kinaweza kutathminiwa mara moja tu. Wakati ujao unaweza kutumia thamani iliyoakibishwa. Pia, ikiwa kazi hazitegemei kila mmoja, zinaweza kubadilishwa na hata kusawazishwa kiotomatiki.

Ili kuongeza utendaji, FP pia hutumia tathmini ya uvivu. Mfano wa kuvutia:

urefu wa kuchapisha ()

Kwa nadharia, tunapaswa kupata mgawanyiko kwa kosa la sifuri kwenye pato. Lakini mkusanyaji wa Python mvivu hatahesabu maadili ya kila kipengele cha orodha, kwani haikuulizwa kufanya hivyo. Unahitaji urefu wa orodha - tafadhali!
Kanuni hizo hizo hutumika kwa miundo mingine ya lugha.

Matokeo yake, si tu programu, lakini pia mkusanyaji hupokea "digrii za uhuru" kadhaa.

Orodhesha misemo na kauli zenye masharti

Ili maisha (na programu) haionekani kama asali kwako, watengenezaji wa Python walikuja na syntax maalum ya "utamu", ambayo mabepari huita "sukari ya kisintaksia".
Inakuwezesha kuondokana na kauli za masharti na matanzi ... vizuri, ikiwa sio kujiondoa, basi hakika uwapunguze kwa kiwango cha chini.

Kimsingi, tayari umeiona katika mfano uliopita - inaongeza = . Hapa tunaunda na kuanzisha orodha mara moja na maadili ya kazi. Rahisi, sawa?
Pia kuna kitu kama na na au waendeshaji, ambayo hukuruhusu kufanya bila miundo ngumu kama if-elif-else.

Kwa hivyo, kwa kutumia zana ya zana ya Python, unaweza kugeuza kipengee kizito cha msimbo kuwa kitendakazi kizuri.

Msimbo wa lazima

L=
kwa x katika xrange(10):
ikiwa x % 2 == 0:
ikiwa x**2>=50:
Nyongeza (x)
kwingine:
L.ongeza(-x)
chapisha L

Msimbo wa kazi

chapa

Matokeo

Kama unavyoelewa tayari, sio lazima kufuata kabisa dhana ya kufanya kazi; inatosha kuitumia kwa ustadi pamoja na ile ya lazima ili kurahisisha maisha yako. Walakini, niliendelea kuzungumza juu ya dhana ya lazima ... na sikusema chochote kuhusu OOP na FP.

Kweli, OOP ni, kwa kweli, nyongeza kwa dhana ya lazima, na ikiwa umehama kutoka IP hadi OOP, basi hatua inayofuata inapaswa kuwa kutumia FP katika OOP. Kwa kumalizia, nitasema maneno machache kuhusu kiwango cha uondoaji. Kwa hiyo, ni ya juu zaidi, ni bora zaidi, na ni mchanganyiko wa OOP na FP ambayo inatupa kiwango hiki.

CD

Kwenye diski niliweka usambazaji mpya wa Python kwa watumiaji wa Windows. Watu wa Linux hawahitaji msaada :).

WWW

Rasilimali zingine nzuri kwa wale wanaotaka kujifunza zaidi:

HABARI

Ikiwa hupendi Python, usijali - unaweza kutumia kwa ufanisi mawazo ya programu ya kazi katika lugha nyingine za kiwango cha juu.

Kuna dhana kadhaa katika programu, kwa mfano, OOP, kazi, muhimu, mantiki, na nyingi zao. Tutazungumzia kuhusu programu ya kazi.

Masharti ya upangaji kamili wa utendaji katika Python ni: kazi za mpangilio wa juu, zana za usindikaji wa orodha zilizotengenezwa, urejeshaji, na uwezo wa kupanga hesabu za uvivu.

Leo tutafahamiana na mambo rahisi, na miundo tata itakuwa katika masomo mengine.

Nadharia katika nadharia

Kama ilivyo kwa OOP na upangaji kazi, tunajaribu kuzuia ufafanuzi. Bado, ni vigumu kutoa ufafanuzi wazi, kwa hiyo hakutakuwa na ufafanuzi wazi hapa. Hata hivyo! Wacha tuangazie matakwa ya lugha inayofanya kazi:

  • Kazi za Agizo la Juu
  • Kazi safi
  • Data isiyoweza kubadilika

Hii sio orodha kamili, lakini hata hii inatosha kuifanya "nzuri". Ikiwa msomaji anataka zaidi, hapa kuna orodha iliyopanuliwa:

  • Kazi za Agizo la Juu
  • Kazi safi
  • Data isiyoweza kubadilika
  • Kufungwa
  • Uvivu
  • Kurudi kwa mkia
  • Aina za data za aljebra
  • Kulinganisha muundo

Wacha tuzingatie hatua kwa hatua vidokezo hivi vyote na jinsi ya kuzitumia kwenye Python.

Na leo, kwa ufupi, ni nini kwenye orodha ya kwanza.

Kazi safi

Vitendaji safi havitoi athari zinazoonekana, rudisha matokeo. Hazibadilishi vigezo vya kimataifa, hazitume au kuchapisha chochote popote, hazigusa vitu, na kadhalika. Wanakubali data, kuhesabu kitu, kwa kuzingatia hoja tu, na kurudisha data mpya.

  • Rahisi kusoma na kuelewa msimbo
  • Rahisi kujaribu (hakuna haja ya kuunda "masharti")
  • Inaaminika zaidi kwa sababu hawategemei "hali ya hewa" na hali ya mazingira, tu kwa hoja
  • Inaweza kuendeshwa kwa sambamba, matokeo yanaweza kuhifadhiwa

Data isiyoweza kubadilika

Miundo ya data isiyoweza kubadilika ni mikusanyiko ambayo haiwezi kubadilishwa. Karibu kama nambari. Nambari ipo tu, haiwezi kubadilishwa. Vivyo hivyo, safu isiyoweza kubadilika ni njia ambayo iliundwa na itakuwa hivyo kila wakati. Ikiwa unahitaji kuongeza kipengee, itabidi uunde safu mpya.

Faida za miundo isiyoweza kubadilika:

  • Shiriki marejeleo kwa usalama kati ya mazungumzo
  • Rahisi kupima
  • Rahisi kufuatilia mzunguko wa maisha (inalingana na mtiririko wa data)

Kazi za Agizo la Juu

Chaguo la kukokotoa ambalo huchukua fomula nyingine ya kukokotoa kama hoja na/au kurejesha chaguo za kukokotoa nyingine huitwa kazi ya utaratibu wa juu:

Def f(x): rudisha x + 3 def g(kazi, x): kurejesha kazi(x) * function(x) print(g(f, 7))

Baada ya kuzingatia nadharia, wacha tuanze kuendelea na mazoezi, kutoka rahisi hadi ngumu.

Orodha ya majumuisho au jenereta ya orodha

Hebu tuangalie muundo wa lugha moja ambao utasaidia kupunguza idadi ya mistari ya msimbo. Sio kawaida kuamua kiwango cha programu ya Python kwa kutumia muundo huu.

Msimbo wa sampuli:

Kwa x katika xrange(5, 10): ikiwa x % 2 == 0: x =* 2 vingine: x += 1

Mzunguko wenye hali kama hii sio kawaida. Sasa hebu tujaribu kugeuza mistari hii 5 kuwa moja:

>>>

Sio mbaya, mistari 5 au 1. Zaidi ya hayo, ufafanuzi umeongezeka na kanuni hiyo ni rahisi kuelewa - maoni moja yanaweza kuongezwa ikiwa tu.

Kwa ujumla, muundo huu ni kama ifuatavyo:

Inafaa kuelewa kuwa ikiwa nambari haisomeki kabisa, basi ni bora kuachana na muundo kama huo.

Vitendaji visivyojulikana au lambda

Tunaendelea kupunguza kiasi cha msimbo.

Def calc(x, y): rudisha x**2 + y**2

Kazi ni fupi, lakini angalau mistari 2 ilipotea. Je, inawezekana kufupisha kazi hizo ndogo? Au labda usiiumbie kama vitendaji? Baada ya yote, hutaki kila wakati kuunda kazi zisizohitajika katika moduli. Na ikiwa kazi inachukua mstari mmoja, basi hata zaidi. Kwa hivyo, katika lugha za programu kuna kazi zisizojulikana ambazo hazina jina.

Kazi zisizojulikana katika Python zinatekelezwa kwa kutumia calculus lambda na zinaonekana kama misemo ya lambda:

>>> lambda x, y: x**2 + y**2 kwa 0x7fb6e34ce5f0>

Kwa programu, hizi ni kazi sawa na unaweza pia kufanya kazi nazo.

Ili kufikia vitendaji visivyojulikana mara kadhaa, tunavipa kigezo na kuzitumia kwa manufaa yetu.

>>> (lambda x, y: x**2 + y**2)(1, 4) 17 >>> >>> func = lambda x, y: x**2 + y**2 >>> kazi(1, 4) 17

Kazi za Lambda zinaweza kufanya kama hoja. Hata kwa lambdas zingine:

Multiplier = lambda n: lambda k: n*k

Kutumia lambda

Tulijifunza jinsi ya kuunda kazi bila jina, lakini sasa tutajua wapi kuzitumia. Maktaba ya kawaida hutoa kazi kadhaa ambazo zinaweza kuchukua kazi kama hoja - map(), filter(), reduce(), apply().

ramani ()

Map() kazi huchakata mlolongo mmoja au zaidi kwa kutumia chaguo la kukokotoa.

>>> list1 = >>> list2 = [-1, 1, -5, 4, 6] >>> orodha(ramani(lambda x, y: x*y, list1, list2)) [-7, 2, -15, 40, 72]

Tayari tumefahamiana na jenereta ya orodha, wacha tuitumie ikiwa urefu wa orodha ni sawa):

>>> [-7, 2, -15, 40, 72]

Kwa hivyo, inaonekana kuwa kutumia inclusions za orodha ni fupi, lakini lambdas ni rahisi zaidi. Twende mbele zaidi.

chujio ()

Kichungi () kazi hukuruhusu kuchuja maadili ya mlolongo. Orodha inayotokana ina thamani zile tu ambazo thamani ya chaguo la kukokotoa ya kipengele ni kweli:

>>> nambari = >>> orodha(chujio(lambda x: x< 5, numbers)) # В результат попадают только те элементы x, для которых x < 5 истинно

Jambo lile lile na misemo ya orodha:

>>> nambari = >>>

kupunguza ()

Kupanga mahesabu ya mnyororo katika orodha, unaweza kutumia kitendakazi cha reduce(). Kwa mfano, bidhaa ya vitu vya orodha inaweza kuhesabiwa kama hii (Python 2):

>>> nambari = >>> punguza(lambda res, x: res*x, nambari, 1) 720

Mahesabu hufanyika kwa mpangilio ufuatao:

((((1*2)*3)*4)*5)*6

Mlolongo wa simu umeunganishwa kwa kutumia matokeo ya kati (res). Ikiwa orodha haina tupu, paramu ya tatu inatumiwa tu (katika kesi ya bidhaa ya sababu sifuri, hii ni 1):

>>> punguza(lambda res, x: res*x, , 1) 1

Bila shaka matokeo ya kati si lazima idadi. Hii inaweza kuwa aina nyingine yoyote ya data, ikiwa ni pamoja na orodha. Mfano ufuatao unaonyesha kinyume cha orodha:

>>> punguza(lambda res, x: [x]+res, , )

Python ina vitendaji vilivyojumuishwa kwa shughuli za kawaida:

>>> nambari = >>> jumla (nambari) 15 >>> orodha(iliyobadilishwa(nambari))

Python 3 haina kitendaji kilichojengwa ndani ya reduce(), lakini inaweza kupatikana kwenye moduli ya functools.

kuomba()

Kazi ya kutumia kazi nyingine kwa hoja za nafasi na zilizopewa jina zilizopewa orodha na kamusi mtawalia (Python 2):

>>> def f(x, y, z, a=None, b=None): ... chapa x, y, z, a, b ... >>> apply(f, , ("a": 4, "b": 5)) 1 2 3 4 5

Kwenye Python 3, unapaswa kutumia syntax maalum badala ya apply() kazi:

>>> def f(x, y, z, a=None, b=None): ... chapisha(x, y, z, a, b) ... >>> f(*, **(" a": 4, "b": 5)) 1 2 3 4 5

Hebu tumalize ukaguzi kwa kutumia kipengele hiki cha kukokotoa. maktaba ya kawaida na wacha tuendelee kwenye mbinu ya mwisho ya utendaji kwa leo.

Kufungwa

Kazi zilizofafanuliwa ndani ya vitendaji vingine ni kufungwa. Kwa nini hii ni muhimu? Hebu tuangalie mfano wa kueleza:

Msimbo (wa kubuni):

Uchakataji wa kipengee (kipengele, kichungi, ukubwa_wa_data): vichujio = Kichujio(saizi_yote_ya_data, aina_ya_chujio). get_all() kwa vichujio katika vichujio: kipengele = chujio. kichujio (kipengele) def main(): data = DataStorage().get_all_data() kwa ajili ya x katika data: usindikaji(x, "yote", len(data))

Unachoweza kugundua katika msimbo: katika msimbo huu kuna vigezo ambavyo kimsingi vinaishi kwa kudumu (yaani, sawa), lakini wakati huo huo tunapakia au kuanzisha mara kadhaa. Kwa hivyo, tunaelewa kuwa uanzishaji wa kutofautisha huchukua sehemu kubwa ya muda katika mchakato huu; hutokea kwamba hata kupakia vigeu kwenye wigo hupunguza utendakazi. Ili kupunguza kufungwa kwa matumizi ya juu.

Kufungwa huanzisha vigeu mara moja, ambavyo vinaweza kutumika bila ya juu.

Hebu tujifunze jinsi ya kuunda kufungwa:

Def multiplier(n): "multiplier(n) hurejesha kitendakazi kinachozidisha kwa n" def mul(k): rudisha n*k rudisha mul # athari sawa inaweza kupatikana kwa # multiplier = lambda n: lambda k: n* k mul2 = kizidishi (2) # mul2 - kitendakazi kinachozidisha kwa 2, kwa mfano, mul2(5) == 10

Hitimisho

Katika somo tulipitia dhana za kimsingi za FP, na pia tukakusanya orodha ya mifumo ambayo itajadiliwa katika masomo yafuatayo. Tulizungumza juu ya njia za kupunguza idadi ya nambari, kama vile ujumuishaji wa orodha (jenereta ya orodha), kazi za lamda na utumiaji wao, na mwishowe kulikuwa na maneno machache kuhusu kufungwa na ni nini.