Sziasztok.
Mark Summerfield Python3 c. remekműve előtt görnyedek és csak bámulok, hogy ezt a nyelvet miért nem a ZXSpektrumra találták ki régebben. Ezen kellett volna szocializálódnom.
Ha egy vagy több vezérlőszerkezetben semmiféle errorral nem akarom elszállítani a scriptemet, miket tehetek?
Jelenleg van egy while: -szerkezetem, amely indexhibával már nem száll el, mert beleraktam egy sort:
except IndexError:
print('indexhiba, tovabb...')
Amint ezt beraktam a kódba, azóta ha egy sorban nem találja meg monjuk a 6. oszlopot, nem száll el, nem ír ki semmi hülyeséget csak a hibaüzenetet és veszi a következő sort.
-------
A kérdésem rövid.
Van még néhány error-lehetőség, mellyel még nem szállt el a python-script, de talán elszállhat.
EOFError
ValueError
KeyError
OSError
IOError
Ezek között talán a legutolsó érdekelhet még, ha esetleg már nem tud hova írni az adathordozóra a script.
Tehát ha abszolút paranoiásan nézem a dolgokat, hányféle errorkezelést érdemes beépíteni egy mezei scriptbe, amit nem akarok leállítani semmiképp se, hiszen folyamatosan kapja a feldolgozandó sorokat?
Elég az indexhiba és az IO-hiba?
- 2321 megtekintés
Hozzászólások
Ezek szerint: https://docs.python.org/3.5/library/exceptions.html
Van egy
BaseException
osztály, ami minden beépített exception őse. Lásd.:
(a teljes fa, az öröklődésről, a doksi végén van)
try:
raise IndexError()
except BaseException:
print("elkaptam")
Ettől függetlenül ez nem ajánlott. Két oldalról megközelítve:
- az a kód, ami a tömbök, listák végét így ellenőrzi, igencsak pocsékoló. Az exception kezelés alapból egy költséges művelet. Továbbá, ha én leülnék egy ilyen kód elé, ami a tömbök végét így ellenőrzi (elkapja a túlindexelésről szóló exceptiont), elsőre valószínűleg vakargatnám a fejemet, hogy mire gondolt a költő. Az Exceptionjeid első felét (
EOFError
,
ValueError
,
KeyError
) nem illik így kezelni - ha számítassz a fájl végére, akkor ellenőrizd le. Ha nem számítassz rá, hanem tényleg hiba, akkor hagyd elszállni a programot. Sokkal jobb, ha elhal egyből, mintha napokkal később kiugrik egy bug - s aztán gondolkozhatsz, hogy melyik lenyelt exception miatt is.
- Tényleg azt akarod, hogy IO error után menjen tovább a program? Az exceptionök másik része meg olyan (
OSError
,
IOError
), amivel sokmindent nem tudsz kezdeni. Ha borul az OS, elfogyott a hely, nincs jogod oda írni, azt megintcsak nem szokás lenyelni, mert te nem tudsz vele sokmindent kezdeni.
--
blogom
- A hozzászóláshoz be kell jelentkezni
Az utolsó bekezdésed falhozvágott :)
Nem akarom hogy tovább fusson..
Amúgy sorhiba csak ritkán jelentkezik úgy, hogy nincs index.
Példa:
$GPRMC,135938.000,A,4729.7200,N,01902.3363,E,0.00,43.98,051215,,,A*5D
$GPRMC,135943.000,A,4729.7200,N,01902.3363,E,0.00,43.98,051215,,,A*51
$GNRMC,135948.000,A,4729.7200,N,01902.3363,E,0.00,43.98,051215,,,A*44
$GNGLL,4729.7200,N,01902.3363,E,13$GPRMC,135953.000,A,4729.7200,N,01902.3363,E,0.00,43.98,051215,,,A*50
$GLGSV,3,2,09,83,34,288,$GPRMC,135958.000,A,4729.7200,N,01902.3363,E,0.00,43.98,051215,,,A*5B
$GLGSV,3,2,09,83,34,288,$GPRMC,140003.000,A,4729.7200,N,01902.3363,E,0.00,43.98,051215,,,A*5E
$GPRMC,140004.000,A,4729.7200,N,01902.3363,E,0.00,43.98,051215,,,A*59
$GPVTG,43.98,T,,M,0.00,N,0.00,$GPRMC,140008.000,A,4729.7200,N,01902.3363,E,0.00,43.98,051215,,,A*55
$GPRMC,140009.000,A,4729.7200,N,01902.3363,E,0.00,43.98,051215,,,A*54
$GPRMC,140024.000,A,4729.7078,N,01902.3299,E,0.90,188.56,051215,,,A*6F
$GPRMC,140029.000,A,4729.7065,N,01902.3293,E,0.81,194.91,051215,,,A*62
$GPRMC,140030.000,A,4729.7063,N,01902.3291,E,0.80,194.51,051215,,,A*63
$GPRMC,140034.000,A,4729.7065,N,01902.3287,E,0.00,187.78,051215,,,A*67
$GPRMC,140039.000,A,4729.7065,N,01902.3287,E,0.00,187.78,051215,,,A*6A
$GPRMC,140044.000,V,,,,,0.17,257.05,051215,,,E*42
$GPRMC,140045.000,A,4729.7102,N,$GNRMC,140049.000,A,4729.7106,N,01902.3292,E,0.00,279.31,051215,,,A*7C
$GLGSV,3,1,09,67,67,029,,77,45,122,,68,36,$GNRMC,140054.000,A,4729.7106,N,01902.3292,E,0.00,279.31,051215,,,A*70
$GLGSV,3,1,09,67,67,029,,77,45,122,,68,36,$GNRMC,140059.000,A,4729.7106,N,01902.3292,E,0.00,279.31,051215,,,A*7D
$GNRMC,140100.000,A,4729.7106,N,01902.3292,E,0.00,279$GNRMC,140104.000,A,4729.7106,N,01902.3292,E,0.00,279.31,051215,,,A*74
$GNRMC,140125.000,A,4729.7133,N,01902.3378,E,0.00,76.52,051215,,,A*4C
$GNRMC,140130.000,A,4729.7133,N,01902.3378,E,0.00,76.52,051215,,,A*48
$GNRMC,140131.000,A,4729.7133,N,01902.3378,E,0.00,76.52,051215,,,A*49
$GNRMC,140135.000,A,4729.7133,N,01902.3378,E,0.00,76.52,051215,,,A*4D
$GNRMC,140140.000,A,4729.7133,N,01902.3378,E,0.00,76.52,051215,,,A*4F
$GNRMC,140145.000,A,4729.7133,N,01902.3378,E,0.00,76.52,051215,,,A*4A
$GNRMC,140150.000,A,4729.7133,N,01902.3378,E,0.00,76.52,051215,,,A*4E
$GNRMC,140155.000,A,4729.7133,N,01902.3378,E,0.00,76.52,051215,,,A*4B
$GNRMC,140200.000,A,4729.7133,N,01902.3378,E,0.00,76.52,051215,,,A*48
Vannak hosszabb sorok is, melyeknek eleje használható, de eddig a rövideknél elszállt az egész.
Különleges gond még az, hogy reguláris kifejezést szeretnék a sor elejére illeszkedésre, de a ^ jellel sehogy sem boldogulok, mert közben ott a sor elején a $ jel, ami meg a sor végére illeszkedik.
---
--- A gond akkor van, ha látszólag minden működik. ---
---
- A hozzászóláshoz be kell jelentkezni
Nem akartalak falhoz vágni, ne haragudj :-).
A dollár jelet ki kéne tudnod escapelni. (ki kéne tudnod = szerintem a Pythonos regexpben is ki lehet)
A szövegnek meg van hossza.
Vagy a felbontod, mondjuk a vesszőknél, és tömb lesz belőle, annak is van hossza.
Ha gép elé kerülök, írok példát.
--
blogom
- A hozzászóláshoz be kell jelentkezni
Eleve felbontásra szánom a sorokat, lásd itt: http://hup.hu/node/144355#comment-1935428
De előbb a sorok között egy szűrést végzek, amit bashban valahogy így fogalmaznék meg:
cat /dev/ttyAMA0 | grep "^$GNRMC" | awk 'BEGIN {FS=","}{print $5}'#etc..
---
--- A gond akkor van, ha látszólag minden működik. ---
---
- A hozzászóláshoz be kell jelentkezni
valami ilyesmi:
import re
def regexp(s):
m = re.search('^\\$GNRMC', s)
if (m is not None):
print("találat, " + s + " egyezik")
else:
print("nem találtam egyezést")
def tordeles(s):
sArray = s.split(",")
i = 0;
for sPart in sArray:
print(str(i) + ". rész: " + sPart)
s = "$GNRMC,140200.000,A,4729.7133,N,01902.3378,E,0.00,76.52,051215,,,A*48"
regexp(s);
regexp("árvíztűrő tükördúrógép")
tordeles(s);
a regexet ezek szerint escapelni kell, a speciális karaketereket \\-rel tudod.
A tördelést én így oldanám meg - s akkor nincs túlindexelés.
--
blogom
- A hozzászóláshoz be kell jelentkezni
Kösz szépen, megnézem..
---
--- A gond akkor van, ha látszólag minden működik. ---
---
- A hozzászóláshoz be kell jelentkezni
nincsmit :-D
ha van még kérdés, dobd fel nyugodtan!
--
blogom
- A hozzászóláshoz be kell jelentkezni
Működik!! :)))
def regexp(x):
m = re.search('^\\$GNRMC', x)
if (m is not None):
print('talalat, ' + x + ' egyezik')
else:
print('nem RMC')
regexp(x);
Még csiszolok rajta, aztán holnap kint hagyom egész nap és figyelem megmurál-e.
---
--- A gond akkor van, ha látszólag minden működik. ---
---
- A hozzászóláshoz be kell jelentkezni
if (m is not None):
helyett lehet:
if m:
- A hozzászóláshoz be kell jelentkezni
OT
>> cat /dev/ttyAMA0 | grep "^$GNRMC" | awk 'BEGIN {FS=","}{print $5}'#etc..
Jelzem, ez shellben is hibás, ugyanis a grep paramétere "idézőjelek" között van, amin belül a shell elvégzi a változóhelyettesítést. Azaz a shell előbb kicserélni a GNRMC nevű változó értékét ( $GNRMC ), majd ezt odaragasztja a ^ mögé, és erre a sztringre fog keresni. (Ami azért izgis, mert kb 100% eséllyel nincs ilyen nevű shell vagy környezeti változód, tehát üres sztring lesz, azaz a minta "^" - ami viszont mindig igaz.) Azaz vagy 'aposztrófok' közé kéne írni azt a paramétert (így: grep '^$GNRMC'), vagy az idézőjelen belüli $-t el kell fedni a shell elől ( "^\$GNRMC" formában ).
/OT
- A hozzászóláshoz be kell jelentkezni
Igaz.
---
--- A gond akkor van, ha látszólag minden működik. ---
---
- A hozzászóláshoz be kell jelentkezni
"reguláris kifejezést szeretnék a sor elejére illeszkedésre, de a ^ jellel sehogy sem boldogulok, mert közben ott a sor elején a $ jel, ami meg a sor végére illeszkedik."
Csak hogy tisztázzuk. RE-ben a ^ csak akkor jelent sor elejét, ha az egész kifejezésben ő van az első pozícióban. Tehát ^ab esetén igen, de a^b esetén nem. Ugyanígy, a $ csak akkor jelent sor végét, ha ő áll a minta végén. (és el se takarod). Szóval ^$a: a sor elején álló "$", amit egy "a" követ.
- A hozzászóláshoz be kell jelentkezni
>>> Szóval ^$a: a sor elején álló "$", amit egy "a" követ.
Igen, pont ezt próbáltam egy ideig, de nem ment.
Ez a kritikus sorom:
if 'GNRMC' in x: # GNRMC: glonass, GPRMC: gps
...és ha ezt írom:
if '^$GNRMC' in x: # GNRMC: glonass, GPRMC: gps
akkor semmi sem érkezik és nemtommér. :(
---
--- A gond akkor van, ha látszólag minden működik. ---
---
- A hozzászóláshoz be kell jelentkezni
nem vagyok python atyauristen, de szerintem _csak ugy_ nem lehet RE-t bedobni egy if utan. az bizony sima stringkent fog matchelni.
az re modult ajanlom figyelmedbe
- A hozzászóláshoz be kell jelentkezni
+1.
Egy másik észrevétel: a pastebin használata kicsi rendet teremthet ebben a topicban.
- A hozzászóláshoz be kell jelentkezni
+1 a pastebinre.
- A hozzászóláshoz be kell jelentkezni
Jó ronda nagy lett a kód is:
#!/usr/bin/env python
# coding: utf8
from __future__ import print_function
import serial, io, re
import pcd8544.lcd as lcd
import time, os, sys, getopt
import textwrap
# RTC orabol a datum kiszedese
from datetime import datetime
d = datetime.now()
rtctime = "{:%Y-%m-%d_%H:%M:%S}".format(d)
#rtctime = "at {:%H:%M} UTC".format(d)
print (rtctime+" fajlba iras kezdete...")
lcd.init()
if ( lcd.LED != 1 ):
sys.exit('LED pin should be GPIO1 (12)')
# Backlight PWM testing -- off -> 25% -> off
for i in range(0,1023,16):
lcd.set_brightness(i)
time.sleep(0.025)
import RPi.GPIO as GPIO
if GPIO.RPI_REVISION == 1:
ports = [0, 1, 21]
elif GPIO.RPI_REVISION == 2:
ports = [2, 3, 27]
else:
ports = ["whatever the new changes will be"]
#print "Your Pi is a Revision %s, so your ports are: %s" % (GPIO.RPI_REVISION, ports)
if not os.geteuid() == 0:
sys.exit('Script must be run as root')
addr = '/dev/ttyAMA0' # serial port
baud = 9600 # baud rate
fname = '/home/pi/gpslogger/gps-log/'+rtctime # log file rtctime szerint
fmode = 'a'
with serial.Serial(addr,9600) as pt, open(fname,fmode) as outf:
spb = io.TextIOWrapper(io.BufferedRWPair(pt,pt,1),
encoding='ascii', errors='ignore', newline='\r',line_buffering=True)
while (1):
x = spb.readline() # read one line of text from serial port
if 'GNRMC' in x: # GNRMC: glonass, GPRMC: gps
outf.write(x) # write line of text to file
outf.flush() # make sure it actually gets written out
print (x)
sorhossz = 14
balra = x.ljust(sorhossz)
kiirni = balra
print (textwrap.fill(kiirni, 14))
cucc = kiirni.split(',') # ez szeletel
print ("{[0]}".format(cucc))
try:
longitude="L: ""{[3]}".format(cucc)+"{[4]}"
print (longitude.format(cucc))
except IndexError:
print ('nincs longitude')
try:
latitude="G:""{[5]}".format(cucc)+"{[6]}"
print (latitude.format(cucc))
except IndexError:
print ('nincs latiitude')
idokiiras="{[1]}".format(cucc)
# print ('at '+idokiiras[:6]+' UTC')
print ('at '+idokiiras[:2]+':'+idokiiras[2:4]+' UTC')
try:
cog_korlat='0.3' # hogy ne ugraljon nekem a szam itt
brg="{[7]}"
if ( brg > cog_korlat ):
brg = "0"
print ('BRG:'+brg+'kn')
else:
print ('BRG:',brg.format(cucc))
except IndexError:
print ('nincs ')
try:
cog_korlat='0.3'
brg="{[7]}"
cog="{[8]}"
if ( brg > cog_korlat ):
cog = "-"
print ('COG:'+cog)
else:
print ('COG:',cog.format(cucc))
except IndexError:
print ('nincs ')
try:
datum="{[9]}"
print (datum.format(cucc))
except IndexError:
print ('nincs ')
try:
v4="{[10]}"
print (v4.format(cucc))
except IndexError:
print ('nincs ')
try:
v5="{[11]}"
print (v5.format(cucc))
except IndexError:
print ('nincs ')
print (kiirni)
lcd.text(kiirni)
time.sleep(5)
# lcd.cls()
#print ("1-----------",sorhossz)
---
--- A gond akkor van, ha látszólag minden működik. ---
---
- A hozzászóláshoz be kell jelentkezni
Ez így gányolás. Pontosan azért van struktúrált kivételkezelés, hogy ne kelljen ilyen c-szerű kódot írni; hogy ne kelljen ennyiszer ellenőrizni, hogy történt-e hiba.
Legyen a while(1) ciklusban egyetlen try/except (pl.: except Exception as ex). Ha a try lefut (nincs exception), akkor a try blokk végén, a konverziók elvégzése után kiírhatod az LCD-re az értéket. Exception esetén az except blokkban pedig eldöntheted, hogy kiírsz-e hibaüzenetet az LCD-re, vagy "lenyeled" a hibát.
szerk.: pontosítás.
- A hozzászóláshoz be kell jelentkezni
Ezen vagyok most, mivel gyakorlatilag a kísérletezések véére értem, minden működik. Szóval most jönnek a try: while: except: megy egyéb újdonságok.
Na meg a parancssori paraméterek megtervezése, mert az is szebb, mint amiket eddig műveltem más nyelvben
---
--- A gond akkor van, ha látszólag minden működik. ---
---
- A hozzászóláshoz be kell jelentkezni
"és csak bámulok, hogy ezt a nyelvet miért nem a ZXSpektrumra találták ki régebben. Ezen kellett volna szocializálódnom."
Egy hátránya azért van: futási sebesség. Ez ZX Spektrumon erőteljesen kijött volna. Miért?
ZX Spectrum: 3,54 MHz 8 bites Zilog Z80 (de jobb tempüt adott, mint az akkor menő 0,98 MHz-es C64 proci!)
Raspberry2: 900 MHz 32 bites ARM Cortex A7 proci, 4 maggal
Intel Core i3: ...
Mértem egy alap tesztet minap:
#!/usr/bin/python3
k=0;
for i in range(1000):
for j in range(1000*1000):
k+=i+1
print(k)
Hát, a Python3 értelmező néhány százszor (!!) lassabban futtatta le, mint az ezzel megegyező C-ben írt programot.
- A hozzászóláshoz be kell jelentkezni
Almát a körtéhez. Kérlek, hogy mutasd azt a C programot, amihez hasonlítod!
- A hozzászóláshoz be kell jelentkezni
64 bites architektúrán futtattam és shellből a "time" paranccsal mértem. Mérd meg légyszíves te is az időket, és kérlek írd meg.
Én is keresem, hogy netán tévedtem-e? Ezt is ellenőrizd légyszíves.
#include <stdio.h>
int main() {
int i, j;
unsigned long long k=0;
for (i=0; i<1000; i++) {
for (j=0; j<1000*1000; j++) {
k+=i+1;
asm volatile ("nop"); // "gcc -O2"-nél nélküle a ciklus kiszámításra kerül, és le se fut.
}
}
printf("%Lu\n", k);
return 0;
}
- A hozzászóláshoz be kell jelentkezni
Mielőtt tesztelnék: első blikkre azért lehet ekkora különbség, mert a Pythonban az int típus immutable (minden változtatásnál új példány jön létre). Ráadásul a range generátor függvényt használ, ami lehet, hogy nem a leggyorsabb (nem ágyaznám egymásba a két ciklust). A Python inkább a rugalmasságáról, mintsem a sebességéről híres. Van olyan szkriptnyelv, ami viszonylag gyors is: a lua, bár a szintaxisa eléggé érdekes.
- A hozzászóláshoz be kell jelentkezni
Átírhatod optimálisabbra is a Python kódot. Tényleg néhány százszor lassabb a mellékelt C-ben írt lefordítottjánál, amit kivárni ZX spektrumon "örökkévalóság" lett volna.
LUA-ban is írtam programot már. Egyébként ott is csak a luajit-tel gyors ez, a sima lua környezet szintén elvérzett, bár ez utóbbi is 3-szor gyorsabban hajtotta ezt a tesztemet végre a Python3 környezethez képest. A luajit viszont 20-szoros tempóval repesztett a sima lua értelmezőhöz képest.
- A hozzászóláshoz be kell jelentkezni
Csak egy dolgogban tudtam gyorsítani a Python szkriptet: egy függvénybe tettem a kódot. Így a változók lokálisak lettek, nem pedig a globals-ban kaptak helyet. Sok hozzáférés esetén ez számít. A map függvény használata nem gyorsított ezen konkrét esetben.
A tesztekhez egy 64-bites Windows 8-at futtató gépet használtam, 3.4.1-es, 64-bites Python interpreterrel, és 32-bites mingw GCC-vel.
Futási idők:
* C kód: ~2.1 mp
* eredeti Python kód: 213 mp (kb. 100x lassabb, mint a C kód)
* optimalizált Python kód: 161,5 mp (kb. 70x lassabb, mint a C kód)
Mellékszál:
A C kód nem ugyanazt a kimenetet adta, mint a Python szkript. Először azt hittem, hogy túlcsordult a 64-bites long, és a Python ezért át kellett álljon tetszőleges hosszúságú egész aritmetikára, és ez lassít. Ezért megnéztem, hogy a végeredmény ábrázolásához hány bitre van szükség:
import math
math.log2(500500000000)
38.864579112822256
Mivel ez kevesebb, mint az unsigned long long 64 bitje, ezért csak a formázási sztringgel van a gond, amit lecseréltem "%lu"-ra, így már a megfelelő értéket írta ki.
Módosított változat:
#!/usr/bin/python3
def szamol():
k=0
for i in range(1000):
for j in range(1000 * 1000):
k += i + 1
print(k)
szamol()
- A hozzászóláshoz be kell jelentkezni
Tanultam ismét (lokális névtér). Köszi.
Nálam megfeleződött az ideje az általad módosítottal.
Ez most 91 másodperc. A "gcc -O1" optimalizációval a C-ben írt 0,43 másodperc, az asm volatile "nop") miatt -O2 esetén is alig tér el ettől.
A -O0 esetben (optimalizáció tiltásával) pedig 2,58 másodperc.
Proci: i5-3337U CPU @ 1.80GHz laptop.
Python 3.4.3
gcc 5.2.1
- A hozzászóláshoz be kell jelentkezni
Kiegészítés: most tudtam csak lefordítani O2-vel, meg ASM betéttel. A mingw nem fogadta el az asm-et, ezt kellett __asm-re cseréljem. Így ~0,369 mp alatt fut, ami ~18%-a az eddigi futási időnek.
Proci: Xeon E3-v1230 V2 @ 3.3 GHz.
Pontosítás: a format string nem %lu, hanem %llu kell, hogy legyen.
- A hozzászóláshoz be kell jelentkezni
Ha jol ertem, a kivetelkezeles a sorok vegenek hianya miatt kell.
Nem vagyok a kivetelekezeles ellen, de itt nem lenne szebb megoldas, ha az NMEA mondatok checksum-jat nezned? Elvegre ezert van. Kiszamolni is eleg egyszeru es szepen jelzi a nalad jelentkezo hibat. Amelyik sornak nem jo a checksum-ja, azt egyszeruen eldobod. Igy elo sem fordul a kivetel, amelyet kezelni probalsz.
Raadasul jobb megoldas is, mert ahogy lattam, hogy hogyan volt problemas egy-egy sor nalad, meg az is elofordulhat, hogy a kivant helyen levo adat megvan ugyan, csak hulyeseg - szerintem erdemes lenne atgondolnod a checksum hasznalatat.
/sza2
- A hozzászóláshoz be kell jelentkezni
Ne, kerlek, hogy ezt a viselkedest addig felejtsd el, amig meg nem csontosodik. Ha exception tortenik, az azert van, mert nem figyeltel oda valamire, amire oda kellett volna figyelni. Sose nyelj be exceptiont, csak es kizarolag akkor, ha mar semmi mas modon nem tudod ezt megoldani. Ez leginkabb akkor szokott tortenni, amikor nem nalad van a bug, hanem mondjuk a frameworkben, es workaroundolsz. Minden mas esetben tessek elengedni az exceptiont, tudja meg orszag-vilag, hogy itt nagy baj van.
Ami az EOFError, ValueError, KeyError uzeneteket illeti, azokat el is lehet kerulni, a kollegak fentebb emlitettek, a rendszer szintu exception pedig azert van, hogy ertesulj arrol, hogy a scritpet futtato rendszerben gixer van.
--
Blog | @hron84
Üzemeltető macik
- A hozzászóláshoz be kell jelentkezni