[megoldva] Python változó láthatósága

Elég basic téma, tudom, de mégis belefutottam.

Ez a kis python program hogyhogy nem írja ki az alábbi hibaüzenetet?

local variable 'a' referenced before assignment

Van ennek valami méretkorlátja? Ha ugyanez a szitu egy nagyobb programban kerül elő, nemcsak warning jön, hanem lehal a futás a fenti hibaüzenettel, ha nem írom ki explicite a függvényben, hogy global a.

a=2

def perform_strategy():
    print('a:', a)
    return

for x in range(0, 2):
    perform_strategy()

Hozzászólások

Szerkesztve: 2020. 02. 15., szo – 12:22

Ha módosítani akarod az értékét a funkción belül, akkor kell a global. Ha csak olvasod, akkor nem.

a=2

def perform_strategy():
    print('a:', a)
    a += 1
    return

for x in range(0, 2):
    perform_strategy()

UnboundLocalError: local variable 'a' referenced before assignment

Ha módosítani akarod az értékét a funkción belül, akkor kell a global. Ha csak olvasod, akkor nem.

Ha módosítani kell, akkor így csinálnám (de lehet, hogy félreértem mi a cél):


def perform_strategy(a):
    print('a:', a)
    a += 1
    return a

y = 0
for x in range(0, 2):
    y = perform_strategy(x)

Mert ott van definiálva a főprogramban az "a" változó. Ezt átveszi a függvény. Viszont ha megváltoztatod a függvényből az értékét, az nem megy vissza a főprogramba. Kivéve

def perform_strategy():
   global a
   a=5

esetben.
Látszik, hogy a Python nem egy szigorú nyelv. Ellenpéldaként próbáld meg ugyanezt Rust-ban. A globális változóra már eleve kiakad, legalábbis ha nem konstansként definiálod.

Szerintem is egy nyelvi hiba, de némileg megnyugtató, hogy lehetne sokkal rosszabb is:

function process() {
    a = "hello"
}
process()
console.log(a)

> hello

Napi feladvány:

function process() {
    ret = 0
    for (i=0;i<5;i++) {
        ret += 1
    }
    return ret
}
for (i=0;i<10;i++) result = process()
console.log(result)

Anélkül, hogy elindítanád: mennyi lesz a result értéke?

Ó ez még csak a kezdet Python esetén. Amit jobban utálok: írsz egy összetett programot. Fut már fél napja és teljesül egy addig nem teljesült feltétel, ami alapján beugrik egy addig nem használt kódrészbe. Itt egy szintaktikai hiba miatt ekkor, fél nap után fog elszállni a Python kód. Egyébként a Python kétségtelen előnye a vele való könnyű kezdés, aranyos nyelv.
Ellenpéldaként Rust esetén fordításkor küzdesz meg, nem futás közben. Igen szigorú nyelv, miközben a Python adatszerkezeteit teljes mértékben ismeri.
 

Szintaktikai hiba szerintem mindig kiderül a py fájl betöltésekor, de pl. a topicindító hiba valóban nem derül ki meghívás nélkül, pedig kiderülhetne.

Flake8 használata ajánlott:

$ python3 -m flake8 --select F test.py
test.py:5:5: F823 local variable 'a' defined in enclosing scope on line 1 referenced before assignment
test.py:5:5: F841 local variable 'a' is assigned to but never used   

Nem tudom mire gondolsz. Ha nincs benne a global akkor jo, hogy a lokalis valtozot bizgeralja. Mondjuk csinalok egy fuggvenyt:

def func1()
   a = 3
   print(a)

Akkor az jo, hogy ez a fuggveny attol fuggetlenul mukodik, hogy a scriptemben amugy van-e "a" vagy sem (es persze nem valtoztatja meg a globalis "a" erteket ha veletlenul van olyan). Ha viszont igy irom:

def func1()
   print(a)

akkor nyilvan a kulso "a"-t akarom hasznalni, mert nincs a fuggvenyben definialva. (Mas kerdes, hogy miert nem adom at parameterkent, de lehet erre is okom.)

Szerkesztve: 2020. 02. 15., szo – 18:28

A FAQ-ból:

"In Python, variables that are only referenced inside a function are implicitly global. If a variable is assigned a value anywhere within the function’s body, it’s assumed to be a local unless explicitly declared as global."

Ha sok globális változót használ az ember, és csak annyira beszédes neveket alkalmaz, mint "a","b" stb., akkor érdemes egy külön névteret készíteni számukra:

class GV:

   a,b=10,20

def perform_strategy():
    print('a:', GV.a)
    return
 

Bonyolultabb programok esetében azért jobb külön namespace objectet alkalmazni, mert lehet többet csinálni belőle. Ez előnyös tesztelhetőség szempontjából vagy ha párhuzamosítani akarod az alkalmazást, de debugolni is egyszerűbb.

Persze a normális változónevekre a namespace objectek esetében is szükséged lesz, de server_connections helyett jobb a server.connections

A parhuzamosithatosag a GIL mellett azert eleg gyenge erv. De akkor mar namespace objectek helyett lehet rendesen OO-ban irni meg modulositani, es akkor ki is fog nezni valahogy a kodod. Persze tisztesseges objektumbol is lehet tobbet csinalni.

Nyulfarknyi scriptekre meg teljesen jok a fuggvenyek + globalis valtozok is.

A strange game. The only winning move is not to play. How about a nice game of chess?

"Nyulfarknyi scriptekre meg teljesen jok a fuggvenyek + globalis valtozok is."

Igen, én is így csinálom. De az OP ezt írta: "Ha ugyanez a szitu egy nagyobb programban kerül elő..."

Más. Párhuzamosítani meg lehet a multiprocessing modullal, ahol "tényleg" párhuzamosan futhatnak a példányok.

Ismerem a multiprocessing-et, azzal meg az volt a bajom, hogy a threaddel ellentetben teljesen kulon program, es nem latja a masik valtozoit.

Adott egy kutyu, 30kHz mintaveteli frekivel 768 csatornan vesz mindenfele biologiai jeleket (foleg neuronok elektromos aktivitasat). A bejovo jelalakokat egymastol fuggetlenul lehet feldolgozni (persze esszel), szoval kiszerveztem oket a sokmagos gep miatt kulon processekbe, megfelelo kommunikacioval a fonok es a feldolgozo processek kozott. Ha nincs GIL, akkor threadekkel sokkal egyszerubben (plusz hatekonyabban) fel tudom dolgozni azt a rengeteg adatot, mert elerek minden valtozot egy processen belul.

(ezen a teruleten Pythonban van minden szoval adott volt, de ez mar masnak a problemaja)

A strange game. The only winning move is not to play. How about a nice game of chess?

Kb. 400 Mbit/s lett a vege, mert 16 bites A/D volt a chipekben, plusz jott mas info is rajta (idobelyegek, melyik csatorna melyik, stb). Gigabites ethernetet hasznaltunk hozza a PC fele, es vegulis mukodott, de mar az elejetol fogva nagyon szamolgattam, hogy mi fogja ezt birni.. szoval jogos kerdes.

A strange game. The only winning move is not to play. How about a nice game of chess?

Python3 esetén a NumPy sokat segít a feldolgozás tempójában, továbbá bizonyos esetekben a Numba. Bár utóbbival már szívtam meg.
Ha nem elég, akkor C-ben vagy Rust-ban írt feldolgozó betét és nem kell multiprocessing az adott feladathoz. A Python egyik baja, hogy maga a nyelv rohadt lassan fut.
FFT tesztem alapján ugyanaz a nyersen az adott nyelven megírt algoritmus (háttérfüggvények hívása nélkül):

Rust: 0.17435 mp
PyPy3: 0.72238 mp
Python3 natívan: 12.895 mp
--------------------------------
Rust 74-szer gyorsabb aritmetikára a natív Python3-nál, a PyPy3-at is 4 .. 4,5-szeresen túlszárnyalja a Rust tempója.
Ha nem elég (esetemben a digitalizált rádiófreki feldolgozásnál), akkor C-vel még nyerek picit (-Ofast).

Mint látható, a Python3-nál sokkal gyorsabb a PyPy3  JIT. Legutóbb a kiértékelésnél ez sem volt elég, így a Python kódot tükörben átírtam Rust-ra, mivel szerencsére itt a dictionary, list, tuple, set mind megvan.

Igen, tele volt a kod numpy (meg ahova kellett scipy) hivasokkal. Anelkul teljesen eselytelen lett volna.

Ettol fuggetlenul van olyan algoritmus a teruleten, amit pythonban irtak, szoval emiatt adott volt a nyelv. Ha keves lett volna, C betetek fele mentem volna en is. (vagy kiadni kulso programnak)

Rustot nem ismerem, es amikor kozel a hatarido, nem all neki az ember uj nyelvnek.

A strange game. The only winning move is not to play. How about a nice game of chess?