2010-04-04 10 views

Odpowiedz

71

W duchu Pythona z "prosić o przebaczenie, a nie uprawnień", oto jeden sposób:

try: 
    b = a[4] 
except IndexError: 
    b = 'sss' 
+14

w jakikolwiek prosty sposób? – zjm1126

+2

Jeśli chcesz jednoelementowy, umieść go w małej funkcji pomocnika. –

+7

@zjm: to * jest * prostym sposobem –

3
try: 
    b = a[4] 
except IndexError: 
    b = 'sss' 

Czystsze sposób (działa tylko jeśli używasz dict):

b = a.get(4,"sss") # exact same thing as above 

Oto kolejny sposób może chcesz (znów tylko dla dicts):

b = a.setdefault(4,"sss") # if a[4] exists, returns that, otherwise sets a[4] to "sss" and returns "sss" 
+0

Powinieneś zdefiniować wyjątek dla 'except:'. Na przykład twój wyjątek jest również wyzwalany, gdy zmienna "a" nie jest zdefiniowana. – zoli2k

+0

@Goose: puste 'z wyjątkiem' jest złe. O wiele lepiej jest powiedzieć "z wyjątkiem IndexError" –

+0

@shakov, @Eli Bendersky: masz rację. Naprawiony. –

0

Używając try/catch?

try: 
    b=a[4] 
except IndexError: 
    b='sss' 
50

W non-Python duchu "prosić o pozwolenie, nie przebaczenia", oto inny sposób:

b = a[4] if len(a) > 4 else 'sss' 
+1

używał go, dobrze, aby potwierdzić niezawodność. Staram się unikać próbowania (i łapania) jak najwięcej. –

6

Można również zdefiniować trochę funkcję pomocniczą dla tych przypadkach:

def default(x, e, y): 
    try: 
     return x() 
    except e: 
     return y 

Zwraca wartość zwracaną przez funkcję x, chyba że podniosła wyjątek typu e; w takim przypadku zwraca wartość y. Zastosowanie:

b = default(lambda: a[4], IndexError, 'sss') 

Edit: Robić to złapać tylko jeden określony typ wyjątku.

Sugestie dotyczące ulepszeń są nadal mile widziane!

+2

@Thomas: IMHO jest nieelegancki, a chwytający "wyjątkiem" jest niepokojący –

+1

Istnieje dyskusja na liście dyskusyjnej na temat takiej konstrukcji: http://mail.python.org/pipermail/python-dev/2009- August/091039.html – Thomas

+0

Stara odpowiedź, ale wciąż. Python jest jednym z niewielu języków, w których wyjątki są postrzegane jako dobre. Jest często używany do kontroli przepływu, gdy tworzy czytelność. – Etse

1

Jestem za pytaniem o pozwolenie (tj. Nie podoba mi się metoda try ... except). Jednak kod dostaje wiele czystsze, gdy jest zamknięty w sposób:

def get_at(array, index, default): 
    if index < 0: index += len(array) 
    if index < 0: raise IndexError('list index out of range') 
    return array[index] if index < len(a) else default 

b = get_at(a, 4, 'sss') 
+2

'mylist [-1]' powinien po prostu uzyskać ostatni element, ale twoje "pytanie o pozwolenie" 'get_at' code _doesn't_ zachowuje się w ten sposób. To pokazuje, że jednym z wielu powodów "prośby o pozwolenie" jest po prostu błędna filozofia: to, co sprawdzasz, może nie pasować do tego, co zrobiłby system. Oznacza to, że nie tylko systematycznie starasz się powielać pracę, którą system wykonuje dla ciebie, ale możesz łatwo uzyskać dodatkową, powieloną pracę. "prośba o przebaczenie" jest ** dużo ** lepsza. –

+0

@Alex: dobry połów, nie myślałem o tym. Pythonowa płatna lista komponentów sprawia, że ​​jest to nieco bardziej skomplikowane ... * jednak *, nie zgadzam się z twoją ekstrapolacją z tego specjalnego przypadku, że "prośba o przebaczenie" w ogóle jest dobra. Jestem oczywiście stronniczy, ponieważ jestem wielkim zwolennikiem pisania statycznego. Ale w każdym razie to po prostu zły wniosek. Lepszym wnioskiem byłoby to, że moja analiza wymagań była niewystarczająca (* i * być może, że nie ma dobrego sposobu na uzyskanie wewnętrznego zachowania w sposób modyfikowalny bez powielania kodu lub wyzwalania błędów, co wskazuje na zły interfejs API). –

+0

Możesz uciec, jeśli zrobisz 'def get_at (array, index, default): try: return array [index] z wyjątkiem IndexError: return default' – voyager

0

Ponieważ jest to top google hit, to chyba warto również wspomnieć, że pakiet standard „zbiory” ma „defaultdict”, który zapewnia bardziej elastyczne rozwiązanie tego problemu.

Można zrobić schludne rzeczy, na przykład:

twodee = collections.defaultdict(dict) 
twodee["the horizontal"]["the vertical"] = "we control" 

czytaj więcej: http://docs.python.org/2/library/collections.html

11

Można stworzyć własną listę klasy:

class MyList(list): 
    def get(self, index, default=None): 
     return self[index] if len(self) > index else default 

można go używać tak :

>>> l = MyList(['a', 'b', 'c']) 
>>> l.get(1) 
'b' 
>>> l.get(9, 'no') 
'no' 
1

Na wspólnej przypadku, gdy chcesz pierwszego elementu, można to zrobić

next(iter([1, 2, 3]), None) 

Używam tego do „otwierania” listę, ewentualnie po jego filtrowania.

next((x for x in [1, 3, 5] if x % 2 == 0), None) 

lub

cur.execute("SELECT field FROM table") 
next(cur.fetchone(), None) 
15

W duchu Pythona piękne jest lepsza niż brzydkie

metody Kod golfowego, wykorzystując kawałek i rozpakowaniu

b=a[4:4+1] or 'sss' 

ładniejszy niż funkcja otoki lub próbuj złapać IMHO, ale zastraszając dla początkujących. Osobiście uważam krotka rozpakowaniu być sposób bardziej seksownego niż listy [#]

używając krojenie bez rozpakowywania:

b,=a[4:5] or ['sss'] 

lub, jeśli trzeba to robić często, i nie przeszkadza tworzenia słownika

d = dict(enumerate(a)) 
b=d.get(4,'sss') 
+1

Twój pierwszy przykład nie działa, jeśli lista jest dłuższa niż 5 elementów. I idąc z 'a [4: 5]' nie jest już miłe ... –

+0

'używanie łączenia bez rozpakowywania' jest tym, co działa dla mnie, ponieważ w przeciwnym razie zwracany element był listą wielkości 1, a nie skalarem. –

+0

Dlaczego pierwsza odpowiedź zawiera dodatkowe przecinki? Odtwarzanie w interpreterze python: 'b, = a [4:] lub 'sss',' jest takie samo jak 'b = a [4:] lub 'sss'' –

9

inny sposób:

b = (a[4:]+['sss'])[0] 
+0

OK, więc podoba mi się brak gadatliwości. Czy możesz wyjaśnić trochę składnię? – froggythefrog

+0

'a [4:]' tworzy listę elementów, od (włącznie) z indeksu 4. Powoduje to pustą listę. '[1, 2, 3] [999:] == []' Tak działa operacja krojenia. Jeśli 'a' to' ['123', '2', 4, 5, 6] ', to zwróci [5, 6]. Następnie dodaje element "sss", tworząc nową listę, która w tym przypadku jest "['sss']". Ostatni krok '[0]' po prostu bierze pierwszy element, zwracając '' sss'', ale zwróciłby 'a [4]' jeśli był taki element' –

+0

w ciekawy sposób, aby to osiągnąć. trochę po nieczytelnej stronie. – Alex

0

Jeśli szukasz zarządzalny sposób na uzyskanie wartości domyślnych na operatora indeksu znalazłem następujące przydatne:

Jeśli zastąpisz operator.getitem z modułu operatora, aby dodać opcjonalny parametr domyślny, zachowujesz identyczne zachowanie z oryginałem, zachowując kompatybilność wsteczną.

def getitem(iterable, index, default=None): 
    import operator 
    try: 
    return operator.getitem(iterable, index) 
    except IndexError: 
    return default 
0

Jeśli szukasz szybkiego hackowania w celu skrócenia długości kodu, możesz spróbować.

a=['123','2',4] 
a.append('sss') #Default value 
n=5 #Index you want to access 
max_index=len(a)-1 
b=a[min(max_index, n)] 
print(b) 

Ale ta sztuczka jest przydatna tylko gdy nie chcesz dalszej modyfikacji do listy