Vinnaren i pepparkakshustävlingen!
  • 1
  • 2
2022-11-21, 12:43
  #13
Moderator
Pontiac-Garages avatar
Citat:
Ursprungligen postat av Hatespawn
Har precis fått upp ögonen för programmering och programmerat lite python på senaste tiden.
Mitt första projekt är att göra en suppersimpelt kodlås med 4 knappar kopplade till GPIO på raspberry pi.

Jag har en variabel som jag sätter vid uppstart av filen:
fail1 = False

funktionen failed_one() skall ändra fail1 till fail1 = True, detta är i sin tur villkoren för att nästa misslyckade kod ska generera fail2 = True.

Problemet är att efter att den kört failed_one() så är fail1 = False fortfarande.

Vad är det jag missförstår här?


Kod:
#import libraries
import RPi.GPIO as GPIO
import time

#GPIO Basic initialization
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)

#LCD
from lcd_api import LcdApi
from i2c_lcd import I2cLcd
 
I2C_ADDR = 0x27
I2C_NUM_ROWS = 4
I2C_NUM_COLS = 20

lcd = I2cLcd(1, I2C_ADDR, I2C_NUM_ROWS, I2C_NUM_COLS)


led1 = 21
led2 = 20
led3 = 16
led4 = 12
button1 = 26
button2 = 19
button3 = 13
button4 = 6

#Initialize your pin
GPIO.setup(led1,GPIO.OUT)
GPIO.setup(led2,GPIO.OUT)
GPIO.setup(led3,GPIO.OUT)
GPIO.setup(led4,GPIO.OUT)
GPIO.setup(26, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(19, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(13, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(6, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)


digit0=False
digit1=False
digit2=False
digit3=False
digit4=False
button1=False
button2=False
button3=False
button4=False
fail1=False
print("debug1")
fail2=False
GPIO.output(led1,0)
GPIO.output(led2,0)
GPIO.output(led3,0)
GPIO.output(led4,0)

code=dict([(26,0),(19,0),(13,0),(6,0)])
print(code)

validcode=[26,19,13,6]

lcd.clear()
lcd.move_to(0,0)
lcd.putstr("Enter Code")

clickedbuttons=[]

def correct():
    GPIO.output(led1,1)
    GPIO.output(led2,0)
    GPIO.output(led3,0)
    GPIO.output(led4,0)
    fail1 = False
    print("debug2")
    fail2 = False
    clickedbuttons.clear()
    lcd.clear()
    lcd.move_to(0,0)
    lcd.putstr("Correct")
    print("Correct")
    time.sleep(5)
    GPIO.output(led1,0)
    lcd.clear()
    lcd.move_to(0,0)
    lcd.putstr("Enter Code")

def failed_one():
    print("incorrect1")
    lcd.clear()
    lcd.move_to(0,0)
    lcd.putstr("Fail 1/3")
    GPIO.output(led2,1)
    clickedbuttons.clear()
    fail1 = True
    print(fail1)
    
def failed_two():
    print("incorrect2")
    lcd.clear()
    lcd.move_to(0,0)
    lcd.putstr("Fail 2/3")
    GPIO.output(led3,1)
    clickedbuttons.clear()
    fail2 = True
    
def failed_three():
    print("incorrect3")
    lcd.clear()
    lcd.move_to(0,0)
    lcd.putstr("Fail 3/3")
    lcd.move_to(1,0)
    lcd.putstr("5 min timeout")
    GPIO.output(led4,1)
    clickedbuttons.clear()
    time.sleep(10)
    fail1 = False
    print("debug3")
    fail2 = False



#FIRST ATTEMPT
while True:
    print(fail1)
    for key in code:
        if GPIO.input(key) and code[key] == 0:
            clickedbuttons.append(key)
            code.update({key:1})
            time.sleep(0.2)
        elif code[key] == 1 and GPIO.input(key) == 0:
            code.update({key:0})
    if len(clickedbuttons) == 4:
        print(clickedbuttons)
        if validcode == clickedbuttons:
            correct()
        else:
            if fail1 == False and fail2 == False:
                failed_one()
            elif fail1 == True and fail2 == False:
                failed_two()
            elif fail1 == True and fail2 == True:
                failed_three()

Som du säkert har märkt kör Python-funktioner pass by value som automatik, och inte pass by reference. Pass by reference (dvs. en automatisk uppdatering av variabeln genom funktionen) kan du åstadkomma genom global, som tidigare nämnts:

Kod:
# En funktion som uppdaterar variabeln x
def foo():
    global x
    x += 1

# Uppdatera x automatiskt
x = 10
foo()
print(x) # Nu är x = 11

Som nämnts är det dock ingen bra idé att ha en hel del globals som lösning, så om du vill uppdatera en variabel genom funktionen så kör hellre på en vanlig return (dvs. pass by value) som du sedan skriver över ursprungsvariabeln med.
Citera
2022-11-24, 17:20
  #14
Medlem
JohannesSnajdares avatar
Objekt skickas "by reference" så du kan ju alltid kapsla in värdet i en klass.
Eller varför inte en funktion, det är ju ändå python

Kod:
def foo():
    foo.x += 1

foo.x = 10
foo()
print(foo.x)
Citera
2022-12-04, 01:00
  #15
Medlem
Citat:
Ursprungligen postat av JohannesSnajdare
Objekt skickas "by reference" så du kan ju alltid kapsla in värdet i en klass.
Eller varför inte en funktion, det är ju ändå python

Kod:
def foo():
    foo.x += 1

foo.x = 10
foo()
print(foo.x)

Den här är rejält skogsfarlig och hålla på med. Det för att man aldrig använder attribut på funktioner på det där sättet.

Ska man hålla på med en massa ändringar av globala variabler får man göra en funktion som ändrar variabeln i global space

Kod:
 fail = False

def check_fail (fail):
        if not fail:
             return True
       return False

fail = check_fail(fail)
>>> fail
True
>>>
Citera
2022-12-04, 09:43
  #16
Medlem
Enterprises avatar
Citat:
Ursprungligen postat av Methos

Ska man hålla på med en massa ändringar av globala variabler får man göra en funktion som ändrar variabeln i global space

Kod:
 fail = False

def check_fail (fail):
        if not fail:
             return True
       return False

fail = check_fail(fail)
>>> fail
True
>>>
Vet inte om jag missförstår dig, men din funktion här ändrar ju egentligen ingenting, utan returnerar bara ett värde som du "assignar" till den globala variabeln fail.
Citera
2022-12-04, 09:46
  #17
Medlem
Citat:
Ursprungligen postat av Enterprise
Vet inte om jag missförstår dig, men din funktion här ändrar ju egentligen ingenting, utan returnerar bara ett värde som du "assignar" till den globala variabeln fail.

I det här fallet ja. Men i hans fall kan man lägga in att koden kollar om det är rätt kombination och sedan ändrar variabeln.
Citera
2022-12-04, 10:04
  #18
Moderator
vhes avatar
Citat:
Ursprungligen postat av Methos
Den här är rejält skogsfarlig och hålla på med. Det för att man aldrig använder attribut på funktioner på det där sättet.

Har använt attribut i funktioner för att äga en cache som används av funktionen. Även om jag föredrar mutable inparametrar. Huvudanledningen till att använda det tidigare är väl att vissa linters blir sura på mutable inparametrar.

Kod:
def foo(par, cache={}):
  try:
    return cache[par]
  except KeyError:
    cache[par] = heavy_calculation(par)
    return cache[par]

alt.
Kod:
def foo(par):
  try:
    return foo.cache[par]
  except KeyError:
    foo.cache[par] = heavy_calculation(par)
    return foo.cache[par]
foo.cache = {}

...typ. Ja, jag känner till functools.lru_cache och vänner, men ibland kan det vara något intermediärt värde som skall cachas eller annan orsak till att man inte vill använda dem.

Var inte så dogmatisk :-)
Citera
  • 1
  • 2

Stöd Flashback

Flashback finansieras genom donationer från våra medlemmar och besökare. Det är med hjälp av dig vi kan fortsätta erbjuda en fri samhällsdebatt. Tack för ditt stöd!

Stöd Flashback