Seite 1 von 1
Bottle: Navigation erstellen
Verfasst: Mittwoch 6. Februar 2013, 19:28
von friedduck
Hallo,
ich bin grade dabei mich in Bottle einzuarbeiten, klappt soweit ganz gut nur eine Sache begreife ich nicht, wie kriegt man eine
Liste der routes, die mann erstellt hat?
Um z.B ein Navigationsmenu zu erstellen.
Mein Weg sieht so aus:
Code: Alles auswählen
from bottle import Bottle, route, run, template
app = Bottle()
@app.route('/')
def index():
return 'Bla'
@app.route('/test')
def test():
return 'Bla'
for route in app.routes:
print 'http://localhost%s' % route.__dict__['rule']
Ausgabe:
Gibt es evtl. einen eleganteren, anderen Weg?
Re: Bottle: Navigation erstellen
Verfasst: Mittwoch 6. Februar 2013, 22:05
von Sirius3
Hallo friedduck,
zwischen Decorator und Funktion sollte keine Leerzeile sein, weil dann ja die enge Verknüpfung der beiden nicht mehr so deutlich ist.
Wie kommst Du auf "route.__dict__['rule']"? Auf Attribute einer Instanz greift man normalerweise direkt mit dem .-Operator zu: "route.rule".
Eleganter – also noch einfacher – kann denn der Zugriff doch eigentlich gar nicht mehr sein.
Re: Bottle: Navigation erstellen
Verfasst: Mittwoch 6. Februar 2013, 22:39
von friedduck
Sirius3 hat geschrieben:
Wie kommst Du auf "route.__dict__['rule']"?
Diese Schleife ist "schuld"

:
Ausgabe:
Code: Alles auswählen
['__call__', '__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_context', '_make_callback', 'all_plugins', 'app', 'call', 'callback', 'config', 'method', 'name', 'plugins', 'prepare', 'reset', 'rule', 'skiplist']
Nein, im Ernst, ich bin noch recht neu in Python und manche Sachen interpretiere ich einfach falsch. Jetzt wo ich die Ausgabe sehe und dank deiner Erklärung, würde ich sagen, dass in dem Object? ein dict vorhanden ist, indem auch das attribut rule vorkommt.
Sirius3 hat geschrieben:
Auf Attribute einer Instanz greift man normalerweise direkt mit dem .-Operator zu: "route.rule".
Eleganter – also noch einfacher – kann denn der Zugriff doch eigentlich gar nicht mehr sein.
Schon wieder was gelernt, meine Lösung sah mir gleich zu kryptisch aus, deswegen habe ich hier im Forum nachgefragt.
Re: Bottle: Navigation erstellen
Verfasst: Montag 11. Februar 2013, 09:46
von friedduck
Falls irgendjemand mal das gleiche Problem hat, das ist mein Lösungsweg:
Code: Alles auswählen
import bottle
app = bottle.Bottle()
@app.route('/')
def index():
return 'Bla'
@app.route('/test')
def test():
pass
@app.route('/<name>')
def test1(name):
pass
def menu():
unwanted = set('<>:')
navurl = list()
for url in app.routes:
if not any( (char in unwanted) for char in url.rule):
navurl.append(url.rule)
return navurl
for url in menu():
print (url)
Ausgabe:
Es werden nur statische Routes berücksichtigt.
Re: Bottle: Navigation erstellen
Verfasst: Montag 11. Februar 2013, 10:14
von Sirius3
@friedduck: oder man schreibt
Code: Alles auswählen
def menu():
unwanted = set('<>:')
return (url.rule for url in app.routes if unwanted.isdisjoint(url.rule))
for url in menu():
print (url)
Re: Bottle: Navigation erstellen
Verfasst: Montag 11. Februar 2013, 19:19
von friedduck
sehr kompakte Schreibweise und tut was es soll
Aus der Python Doku:
Code: Alles auswählen
isdisjoint(other)
Return True if the set has no elements in common with other. Sets are disjoint if and only if their intersection is the empty set.
Re: Bottle: Navigation erstellen
Verfasst: Montag 11. Februar 2013, 19:32
von friedduck
Ich habs noch etwas abgeändert:
Code: Alles auswählen
def navigation():
host = '127.0.0.0'
port = '8080'
unwanted = set('<>:')
return list(('http://%s:%s%s' % (host, port, url.rule) for url in app.routes if unwanted.isdisjoint(url.rule)))
Ausgabe:
Code: Alles auswählen
['http://localhost:8080/', 'http://localhost:8080/new']
Ich glaub mehr rausholen kann man nicht...
Re: Bottle: Navigation erstellen
Verfasst: Montag 11. Februar 2013, 22:05
von Sirius3
Wie hast Du die Umwandlung '127.0.0.1' -> 'localhost' geschafft
Noch besser wäre es, den die Umgebungsvariablen des Web-Servers zu verwenden, um
Host und Port zu erfahren.
PS: Statt list((...)) besser [...]
Re: Bottle: Navigation erstellen
Verfasst: Montag 11. Februar 2013, 22:18
von friedduck
Sirius3 hat geschrieben:Wie hast Du die Umwandlung '127.0.0.1' -> 'localhost' geschafft
Das ist eine nicht näher kommentierte Python 5 funktion
Statt list((...)) besser [...]
Was du alles weißt..
Warum ist es besser?
Noch besser wäre es, den die Umgebungsvariablen des Web-Servers zu verwenden, um
Host und Port zu erfahren.
Geht das auch bei Bottle? Die IP und den Port gibst du ihm ja beim start mit.
Re: Bottle: Navigation erstellen
Verfasst: Montag 11. Februar 2013, 22:49
von Sirius3
friedduck hat geschrieben:Geht das auch bei Bottle? Die IP und den Port gibst du ihm ja beim start mit.
Solange Du den integrierten Webserver benutzt, hast Du noch einigermaßen Einfluß auf Hostname und Port.
Normalerweise läuft bottle aber mit WSGI auf einem richtigen Server, möglicherweise noch mit
virtuellen Hosts, load balancing, proxys usw.
Deshalb liefert jeder Request weitere Daten mit, so dass man weiß, welche URL der Benutzer tatsächlich
aufgerufen hat, sonst verweisen Deine Menülinks irgendwann mal auf falsche Seiten.
Schau mal nach request.url, bzw. request.urlparts.
Re: Bottle: Navigation erstellen
Verfasst: Dienstag 12. Februar 2013, 22:00
von friedduck
macht Sinn, werde ich machen.
Aber warum soll man [], anstelle von list() nehmen?
Re: Bottle: Navigation erstellen
Verfasst: Dienstag 12. Februar 2013, 22:45
von /me
friedduck hat geschrieben:Aber warum soll man [], anstelle von list() nehmen?
Geschmackssache.
Man kann aber mit
dis mal einen Blick auf den von CPython erzeugten Bytecode werfen.
Code: Alles auswählen
def list_1(data):
foo = list()
def list_2(data):
foo = []
Aus diesem Codefragment wird im Disassembler folgendes:
Code: Alles auswählen
12 0 LOAD_GLOBAL 0 (list)
3 CALL_FUNCTION 0
6 STORE_FAST 1 (foo)
9 LOAD_CONST 0 (None)
12 RETURN_VALUE
15 0 BUILD_LIST 0
3 STORE_FAST 1 (foo)
6 LOAD_CONST 0 (None)
9 RETURN_VALUE
Man könnte jetzt vermuten, dass die zweite Variante schneller ist. Allerdings weiß man es nicht ohne gemessen zu haben und die reale Laufzeit ist wohl ohnehin eher unkritisch.
Re: Bottle: Navigation erstellen
Verfasst: Dienstag 12. Februar 2013, 23:08
von friedduck
Danke für die ausführliche Antwort, ist wohl wirklich geschmacksache.
Aber der 2 Beispiel suggeriert eine rasantere Ausführung

Ich etscheide mich für die 2te Variante

Re: Bottle: Navigation erstellen
Verfasst: Mittwoch 13. Februar 2013, 01:04
von BlackJack
Das Beispiel passt hier nicht, denn es ging ja nicht um ``[]`` vs. ``list()`` um eine leere Liste zu erstellen sondern um list comprehension vs. `list()`-Aufruf mit einem Generatorausdruck als Argument. Letzteres ist einfach umständlicher weil bei einer list comprehension direkt eine Liste erstellt wird, während bei einem Generatorausdruck halt erst einmal ein Generator erstellt wird, und daraus dann erst die Liste aufgebaut wird. Ein Zwischenergebnis mehr.
Re: Bottle: Navigation erstellen
Verfasst: Mittwoch 13. Februar 2013, 08:51
von friedduck
Also ich kann nur aus der sicht eines Noobs sprechen und sagen, dass dieser Code für mich am verständlichsten und sehr gut nachvollziehbar ist:
Code: Alles auswählen
def menu():
unwanted = set('<>:')
navurl = list()
for url in app.routes:
if not any( (char in unwanted) for char in url.rule):
navurl.append(url.rule)
return navurl
for url in menu():
print (url)
Dieser Code ist schwer für mich zu lesen und danach zu Verarbeiten, da ein generator objekt zurückgegeben wird, aber er ist sehr kompakt und ich denke das soll mein
Ziel werden. Man kanns ja kommentieren

:
Code: Alles auswählen
def menu():
unwanted = set('<>:')
return (url.rule for url in app.routes if unwanted.isdisjoint(url.rule))
for url in menu():
print (url)
Das wichtigste vergessen, in dem Zusammenhang:
Daraus folgend ist list() besser für einen Anfänger zu lesen als nur [].