Python’i viidete edastamine: muudetavate ja muutumatute kasutusjuhtumid

1. Väärtuse ja viite kaudu edastamise erinevus

Pythoni puhul on funktsioonidele argumentide edastamiseks kaks viisi: väärtuse järgi edastamine ja viite järgi edastamine.

  • Väärtuse järgi edastamine : Meetod, kus väärtuse koopia antakse funktsioonile argumendina; funktsiooni sees parameetri muutmine ei mõjuta algset muutujat.
  • Viite järgi edastamine : Meetod, kus muutujale antakse viide (aadress) funktsioonile, nii et funktsiooni sees tehtud muudatused kajastuvad algses muutujas.

Pythoni puhul sõltub see käitumine objekti olemusest. Pythoni “viite järgi edastamise” käitumine kehtib eelkõige muudetavate andmetüüpide puhul ja võib oluliselt mõjutada koodi käitumist, seega on oluline seda õigesti mõista.

2. Objektide omadused Pythoni keeles

Pythoni keeles käsitletakse kõiki andmeid objektidena ning nende objektide omaduste põhjal klassifitseeritakse need kas muutmatu (immutable) (ei saa muuta) või muutuv (mutable) (saab muuta). See eristus mõjutab nende käitumist, kui neid edastatakse funktsioonidele argumentidena.

  • Muutumatud objektid : objektid, mida ei saa pärast loomist muuta. Näideteks on täisarvud ( int ), ujukomaarvud ( float ), stringid ( str ), tuplid ( tuple ). Kuna neid andmetüüpe ei saa pärast loomist muuta, ei mõjuta funktsiooni sees tehtud operatsioonid kutsujaid isegi siis, kui need edastatakse viite kaudu.
  • Muutuvad objektid : objektid, mida saab pärast loomist muuta. Näideteks on loendid ( list ), sõnastikud ( dict ), hulgad ( set ). Kuna nende andmetüüpide muutused funktsiooni sees kajastuvad kutsujas, mõjutab see eriti Pythoni viite kaudu edastamise käitumist.

RUNTEQ(ランテック)|超実戦型エンジニア育成スクール

3. Kuidas Python argumente edastab

Pythoni keeles, kui edastad argumente funktsioonile, antakse objektide viiteid. Seda käitumist nimetatakse mõnikord “objekti viite järgi edastamiseks”. Järgnevalt vaatleme konkreetseid näiteid, mis illustreerivad Pythoni käitumist sõltuvalt sellest, kas objektid on muutumatud või muutuvad.

3.1 Muutumatud objektid

Kui edastad funktsioonile muutumatu objekti, loob funktsiooni sees uue väärtuse omistamine uue objekti ja ei mõjuta algset objekti.

Näide: Muutumatut täisarvu edastamine

def modify_number(num):
    num = num * 2
    print("Number inside the function:", num)

original_num = 5
modify_number(original_num)
print("Number outside the function:", original_num)

Väljund:

Number inside the function: 10
Number outside the function: 5

Selgitus

Funktsiooni modify_number sees kahekordistatakse muutuja num, kuid see ei mõjuta funktsioonist väljas olevat original_num. Kuna täisarvud on muutumatud, luuakse uue väärtuse omistamisel uus objekt ning original_num jääb muutmata.

3.2 Muutuvad objektid

Teisest küljest, kui funktsioonile edastatakse muutuva objektiga, kasutatakse selle viidet ka funktsiooni sees. Selle tulemusena kajastuvad funktsiooni sees tehtud muudatused ka algses objektis.

Näide: Muutuv loend edastamine

def add_item(my_list):
    my_list.append("Added element")
    print("List inside the function:", my_list)

original_list = ["Element 1", "Element 2"]
add_item(original_list)
print("List outside the function:", original_list)

Väljund:

List inside the function: ['Element 1', 'Element 2', 'Added element']
List outside the function: ['Element 1', 'Element 2', 'Added element']

Selgitus

Kuna loendid on muutuvad, kajastuvad add_item funktsiooni sees tehtud muudatused otse original_list-is funktsioonist väljas. Sel viisil jagatakse muutuvad objektid funktsiooni sees ja väljaspool, mistõttu funktsiooni sees tehtud muudatused mõjutavad ka kutsujaid.

4. Ettevaatused ja vastumeetmed viite kaudu edastamise puhul

Muutuvate objektide edastamine funktsioonidele Pythonis võib viia ootamatu käitumiseni. Siin on mõned meetmed, et selliseid probleeme vältida.

4.1 Kasuta objektide koopiaid

Kui soovid funktsiooni sees objekti muuta, saad vältida originaali mõjutamist, kopeerides selle enne muudatuste tegemist. Pythonis saad kasutada copy moodulit, et luua madalal tasemel koopiaid (copy.copy) või sügavaid koopiaid (copy.deepcopy).

Näide: Sügava koopia kasutamine, et vältida muutuva objekti probleeme

import copy

def add_item(my_list):
    my_list_copy = copy.deepcopy(my_list)
    my_list_copy.append("Added element")
    print("List inside the function (copy):", my_list_copy)

original_list = ["Element 1", "Element 2"]
add_item(original_list)
print("List outside the function:", original_list)

Output:

List inside the function (copy): ['Element 1', 'Element 2', 'Added element']
List outside the function: ['Element 1', 'Element 2']

Selgitus
Kasutades deepcopy, luuakse funktsiooni sees uus objekt, jättes algse loendi muutmata. See võimaldab teha sõltumatuid muudatusi nii funktsiooni sees kui ka väljaspool.

4.2 Kasuta None vaikimisi argumentide jaoks

Väldi muutuva objekti määramist funktsiooni vaikimisi argumentideks; soovitatav on kasutada vaikimisi väärtusena None ja luua funktsiooni sees uus objekt.

Näide: Turvaline viis, kuidas määrata vaikimisi argumentiks None

def add_item(my_list=None):
    if my_list is None:
        my_list = []
    my_list.append("New element")
    print("List inside the function:", my_list)
    return my_list

# When no list is passed
result = add_item()
print("Returned list:", result)

# When a list is passed
existing_list = ["Element 1", "Element 2"]
result = add_item(existing_list)
print("Returned list:", result)
print("Original list:", existing_list)

Output:

List inside the function: ['New element']
Returned list: ['New element']
List inside the function: ['Element 1', 'Element 2', 'New element']
Returned list: ['Element 1', 'Element 2', 'New element']
Original list: ['Element 1', 'Element 2', 'New element']

Selgitus
Kasutades vaikimisi argumenti None ja funktsiooni sees uue loendi loomist, saad vältida väliste loendite ootamatut muutmist. Kui vaikimisi argumentiks on None, on selge, kas luua uus loend või kasutada antud loendit.

RUNTEQ(ランテック)|超実戦型エンジニア育成スクール

5. Praktikaline näide: Kood, mis süvendab arusaamist viitamise kaudu edastamisest

Vaatame, mida oleme käsitlenud, praktilise näite abil.

Näide: Sõnastiku võtmete ja väärtuste muutmine

Sõnastikud on muutuvad objektid, seega funktsiooni sees tehtud operatsioonid mõjutavad sõnastikku väljaspool funktsiooni. Allolev näide näitab käitumist, kui muudetakse sõnastiku võtmeid ja väärtusi.

def modify_dict(my_dict):
    my_dict["new key"] = "new value"
    print("Dictionary inside the function:", my_dict)

original_dict = {"key1": "value1", "key2": "value2"}
modify_dict(original_dict)
print("Dictionary outside the function:", original_dict)

Output:

Dictionary inside the function: {'key1': 'value1', 'key2': 'value2', 'new key': 'new value'}
Dictionary outside the function: {'key1': 'value1', 'key2': 'value2', 'new key': 'new value'}

Selgitus
Kuna sõnastikud on muutuvad, kajastuvad funktsiooni sees tehtud lisamised ka original_dict-is väljaspool funktsiooni. Nagu loendid, võivad sõnastikud mõjutada kutsuvat koodi, sest need edastatakse viitena.

6. Kokkuvõte

Python’i “viitamise kaudu edastamine” käitub erinevalt sõltuvalt objekti omadustest, seega on selle mõistmine vajalik, et parandada koodi usaldusväärsust. Eriti, et vältida ootamatut käitumist, kui viiteid muutuvale objektile edastatakse, on soovitatav kasutada kopeerimist ja vaikimisi argumenti None.

Kokkuvõtte punktid

  • Erinevus väärtuse edastamise ja viite edastamise vahel : Pythoni puhul sõltub sellest, kas funktsiooni sees tehtud muudatused mõjutavad algset muutujat, objekti olemusest.
  • Muutumatud vs. muudetavad : Pythoni muutumatud objektid ei kajasta funktsiooni sees tehtud muudatusi, samas muudetavad objektid jagatakse funktsiooni sees ja väljas viite edastamise kaudu.
  • Leevendusstrateegiad : Muudetavate objektide puhul on tõhusad meetodid, nagu deepcopy kasutamine copy moodulist või vaikimisi argumentide seadistamine None‑iks, et vältida ootamatut käitumist.

Loodan, et see artikkel on süvendanud teie arusaama viite edastamisest Pythoni. Kasutage seda teadmist, et kirjutada tõhusat ja vähem veavõimalusi sisaldavat koodi.