|
BillMaier
Supporter
Anmeldungsdatum: 4. Dezember 2008
Beiträge: 6497
|
Hallo, ich möchte gerne mit python3 eine Liste aus einem yml generieren. Bin allerdings völliger Anfänger und stehe etwas auf dem Schlauch. Hier die yml: version: '3.4'
services:
service1:
image: xzy
ports:
- "1053:1053/tcp"
volumes:
- /source1:/destination1
- /source2:/destination2
service2:
volumes:
- /source3:/destination3
- ...Die Liste soll enthalten: - source1
- source2
- source3 Bisher gemacht: | >>> import yaml
>>> stream = open('test.yml', 'r')
>>> data = yaml.load(stream)
>>> services=data["services"]
>>> for a,b in services.items():
... b["volumes"]
...
['/source3:/destination3']
['/source1:/destination1', '/source2:/destination2']
|
wie packe ich die Ergebnisse der Schleife in eine Variable? Brauche ich dazu eine extra Funktion? geht das einfacher?
Danke für alle geduldigen Tipps 😉
|
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11278
|
Meinst du sowas?
| >>> import yaml
>>> with open('test.yml') as f:
... data = yaml.safe_load(f)
...
>>> source_list = [value["volumes"] for value in data["services"].values()]
>>> source_list
[['/source1:/destination1', '/source2:/destination2'], ['/source3:/destination3', '...']]
|
Oder willst du die verschachtelten Listen noch platt machen?
|
|
BillMaier
Supporter
(Themenstarter)
Anmeldungsdatum: 4. Dezember 2008
Beiträge: 6497
|
So, bin durch: 1
2
3
4
5
6
7
8
9
10
11
12 | #!/usr/bin/env python3
import yaml
stream = open('test.yml', 'r')
data = yaml.load(stream)
services=data["services"]
volume_list = []
for a,b in services.items():
volume_pairs=(b["volumes"])
for volume_pair in volume_pairs:
source,dest=volume_pair.split(":")
print(source)
|
Verbesserungen? //edited: Danke, seahawk1986, da hat sich wohl was überschnitten.
|
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11278
|
Wenn man will geht es noch kürzer (und File-Deskriptoren würde ich immer schließen, wenn sie nicht mehr benötigt werden):
| #!/usr/bin/env python3
import itertools
import yaml
with open('test.yml') as f:
data = yaml.safe_load(f)
for entry in itertools.chain(*(service["volumes"] for service in data["services"].values()):
print(entry.split(':')[0])
|
Ach ja: yaml.safe_load() sollte man zumindest immer dann nutzen, wenn die yaml-Datei nicht aus einer vertrauenswürdigen Quelle stammt, sonst öffnest du Tür und Tor für unfreiwillige Code-Ausführung - vgl. https://pyyaml.org/wiki/PyYAMLDocumentation Warning: It is not safe to call yaml.load with any data received from an untrusted source! yaml.load is as powerful as pickle.load and so may call any Python function. Check the yaml.safe_load function though.
|
|
BillMaier
Supporter
(Themenstarter)
Anmeldungsdatum: 4. Dezember 2008
Beiträge: 6497
|
Ok, vielen Dank. Kürzer war nicht unbedingt gewollt - eher "einfacher" im Sinne für einen Anfänger. Kürzer ist meist schlechter lesbar für Neulinge 😉
|
|
noisefloor
Anmeldungsdatum: 6. Juni 2006
Beiträge: 29567
|
Hallo,
Kürzer war nicht unbedingt gewollt - eher "einfacher" im Sinne für einen Anfänger.
Man muss zwar nicht unbedingt die List Comprehensions verwenden, aber stilistisch sollte es schon sauber programmiert sein. Dazu gehört u.a. geöffnete Dateien zu schließen. Bzw. viel besser ist, direkt den Context Manager über das with Statement zu nutzen. | for a,b in services.items():
|
ist in so fern schlecht, als das a) a und b nichtssagende Variablennamen sind - Variablennamen sollen aber aussagekräftig sein - und b) verwendest du a nirgends. Wenn du den Schlüssel nicht brauchst, wäre das von seahawk1986 gezeigte | for value in services.values()
|
besser. Wir machen dich noch zum Python-Guru, keine Sorge 😉 Gruß, noisefloor
|
|
Neral
Anmeldungsdatum: 3. Oktober 2007
Beiträge: 230
|
Man kann die Lösung von seahawk1986 noch ein wenig lesbarer gestalten, wenn man chain und das Sternchen-Argument zu chain.from_iterable zusammenfasst:
| for entry in chain.from_iterable(
service["volumes"] for service in data["services"].values()
):
...
|
Ansonsten würde ich mich noisefloor anschließen: Auch als Anfänger sollte man sauber programmieren (lernen). Außerdem sollte man (spätestens wenn man ein wenig fortgeschrittener ist), die wichtigen Teile der Standardbibliothek kennen. Vieles wird mit ein wenig Übung nicht nur kürzer, sondern auch einfacher lesbar. Wobei man sich in diesem Fall darüber streiten kann, ob chain.from_iterable wirklich besser ist als zwei verschachtelte for-Schleifen... 😉
|
|
BillMaier
Supporter
(Themenstarter)
Anmeldungsdatum: 4. Dezember 2008
Beiträge: 6497
|
noisefloor schrieb: Man muss zwar nicht unbedingt die List Comprehensions verwenden, aber stilistisch sollte es schon sauber programmiert sein.
Deshalb frag ich ja hier. Mir ging es eben nicht um "möglichst wenig code", sondern schlicht und sauber.
Dazu gehört u.a. geöffnete Dateien zu schließen. Bzw. viel besser ist, direkt den Context Manager über das with Statement zu nutzen.
Also
with open('test.yml') as f:
muss dann nicht geschlossen werden?
| for a,b in services.items():
|
ist in so fern schlecht, als das a) a und b nichtssagende Variablennamen sind
überzeugt.
| for value in services.values()
|
gefällt mir auch besser. Kannte ich bisher nicht.
Wir machen dich noch zum Python-Guru, keine Sorge 😉
Alles klar, hab noch ein paar Jährchen bis zur Rente... 😀 Viele Grüße Euch und danke! //edited: Ps: Python-Strukturen (dicts etc) kenne ich hauptsächlich von Ansible her, das macht es manchmal einfacher und manchmal schwieriger - weil ähnlich aber nicht gleich...
|
|
BillMaier
Supporter
(Themenstarter)
Anmeldungsdatum: 4. Dezember 2008
Beiträge: 6497
|
Neral schrieb: Außerdem sollte man (spätestens wenn man ein wenig fortgeschrittener ist), die wichtigen Teile der Standardbibliothek kennen.
Kannst du mir da einen guten Link empfehlen, der mich nicht gleich erschlägt?
|
|
Neral
Anmeldungsdatum: 3. Oktober 2007
Beiträge: 230
|
@BillMaier: Einen Link speziell für die wichtigen Teile der Standardbibliothek hätte ich jetzt nicht (was wichtig ist, hängt auch vom Einsatzzweck ab), aber das offizielle Tutorial bietet einen guten Einstieg. Die Standardbibliothek ist in der Dokumentation dokumentiert. Vielleicht hilft es, einfach mal den Index zu überfliegen und sich die Module genauer anzugucken, die zu deinem Einsatzzweck passen. Das könnte dich dann allerdings erschlagen. 😉 Ansonsten ist es schwer, da was konkretes zu sagen, ohne deinen Einsatzzweck und Kenntnisstand zu kennen. Das with-Statement benutzt Context-Manager: Wenn der with-Block verlassen wird, wird die __exit__-Methode des Context-Managers aufgerufen. Bei Dateiobjekten wird damit die Datei geschlossen. PEP 8 ist sicherlich auch einen Blick wert. Und import this.
|
|
noisefloor
Anmeldungsdatum: 6. Juni 2006
Beiträge: 29567
|
Hallo, @BillMaier: sehr lesenswert ist auch: Python Module of the Week 🇬🇧. Da werden nur Module aus der Standardbibliothek praktisch erklärt. Die Artikel kann man in beliebiger Reihenfolge lesen bzw. alles weg lassen, was nicht von Interesse ist. Gruß, noisefloor
|
|
BillMaier
Supporter
(Themenstarter)
Anmeldungsdatum: 4. Dezember 2008
Beiträge: 6497
|
Moin, jetzt hatte ich zum ersten Mal den Fall, dass der Key "volumes" nicht vor kam. Meine Lösung: 1
2
3
4
5
6
7
8
9
10
11
12
13
14 | def get_volumes(file):
with open(file) as f:
data = yaml.safe_load(f)
services=data["services"]
source_list=[]
for value in services.values():
try:
volume_pairs=(value['volumes'])
for volume_pair in volume_pairs:
source=volume_pair.split(":")[0]
source_list.append(source)
except:
pass
return source_list
|
Gebt mir saures...
|
|
Marc_BlackJack_Rintsch
Ehemalige
Anmeldungsdatum: 16. Juni 2006
Beiträge: 4735
|
@BillMaier: Aber gerne doch: Du verschluckst da nicht nur den Fall das 'volumes' nicht vorkommt, sondern auch alle anderen Ausnahmen die zwischen try und except auftreten können. Inklusive Fehler an die Du nicht gedacht hast. Und das sind im Grunde fast alle Fehler, denn wenn man dran gedacht hätte, wären sie in der Regel nicht im Code. 😉 Niemals ein nacktes except:, sondern immer nur die Ausnahmen behandeln die man auch tatsächlich erwartet und bei denen das was im except-Block steht, auch eine sinnvolle Behandlung ist. Dabei den except-Block möglichst klein halten, denn je mehr Code darin enthalten ist, um so grösser ist die Chance das eine Ausnahme nicht nur an der einen Stelle auftreten kann an die man gerade gedacht hat, sondern auch an anderer Stelle, inklusive irgendwo in Code der aufgerufen wird. Und da ist die Behandlung, in diesem Falle nichts tun, vielleicht nicht mehr sinnvoll. Vor allem bekommt man so etwas dann gar nicht mit. In diesem Fall würde ich gar keine Ausnahme verwenden, sondern dafür sorgen das man auf jeden Fall einen gültigen, passenden Wert bekommt, auch wenn 'volumes' nicht vorkommt:
| def get_volumes(filename):
with open(filename) as yaml_file:
data = yaml.safe_load(yaml_file)
services = data['services']
source_list = []
for value in services.values():
volume_pairs = value.get('volumes', [])
for volume_pair in volume_pairs:
source = volume_pair.split(':')[0]
source_list.append(source)
return source_list
|
Edit: Etwas kompakter ausgedrückt:
| def get_volumes(filename):
with open(filename) as yaml_file:
data = yaml.safe_load(yaml_file)
source_list = list()
for value in data['services'].values():
volume_pairs = value.get('volumes', [])
source_list.extend(pair.split(':', 1)[0] for pair in volume_pairs)
return source_list
|
Allerdings sollte man auch an das hier denken:
| In [8]: 'kein doppelpunkt'.split(':')[0]
Out[8]: 'kein doppelpunkt'
|
Falls es wichtig ist diesen Fall zu berücksichtigen, sollte man das tun. ☺
|
|
BillMaier
Supporter
(Themenstarter)
Anmeldungsdatum: 4. Dezember 2008
Beiträge: 6497
|
Soweit so logisch. Aber: woher kommt dieser Ausdruck? Marc_BlackJack_Rintsch schrieb: | volume_pairs = value.get('volumes', [])
|
also das get? Kann ich das "immer" verwenden statt dem bisher vorgeschlagenen: | for value in services.values()
|
}}}
Allerdings sollte man auch an das hier denken:
| In [8]: 'kein doppelpunkt'.split(':')[0]
Out[8]: 'kein doppelpunkt'
|
Falls es wichtig ist diesen Fall zu berücksichtigen, sollte man das tun. ☺
Ist hier nicht wichtig. Wenn da kein Doppelpunkt existiert ist die Syntax des zu prüfenden Files sowieso kaputt. Welcher Fehler da kommt ist recht egal...
|
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11278
|
Schau dir mal die Dokumentation zum Typ dict an: https://docs.python.org/3/library/stdtypes.html#dict - da sind die ganzen Methoden beschrieben, um auf die Keys und Values zuzugreifen.
|