Neues String Formatting: Bug oder Feature?

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Benutzeravatar
snafu
User
Beiträge: 5925
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Dienstag 21. September 2010, 05:05

Weiß jemand, ob dies gewolltes Verhalten ist?

Code: Alles auswählen

>>> class Ham(object):
...     def egg(self):
...         return 'spam'
... 
>>> ham = Ham()
>>> 'i love {ham.egg()}'.format(ham=ham)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Ham' object has no attribute 'egg()'
Der Attributzugriff ohne Methodenaufruf funktioniert wie erwartet:

Code: Alles auswählen

>>> 'i love {ham.egg}'.format(ham=ham)
'i love <bound method Ham.egg of <__main__.Ham object at 0xb7781bac>>'
Pekh
User
Beiträge: 482
Registriert: Donnerstag 22. Mai 2008, 09:09

Dienstag 21. September 2010, 06:18

Ich denke, es ist schlicht nicht vorgesehen, an dieser Stelle Funktionsaufrufe zu platzieren. Wenn du den Wert über einen Funktionsaufruf ermitteln willst, gehört dieser in den .format() - Teil.
Benutzeravatar
snafu
User
Beiträge: 5925
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Dienstag 21. September 2010, 08:12

Naja, wie gesagt, mit Attributen und Dict-Schlüsseln funktioniert es. Ich sehe jetzt nicht, inwiefern zum Beispiel ein `"Hello, {name.title()}"` etwas soviel anderes ausmacht, dass es da nicht rein soll/darf. Aber gut, dass ist natürlich hier nicht der Ort, an dem solche Dinge Gehör finden würden. Ich war nur etwas irritiert von der Fehlermeldung. Ganz offensichtlich trennt der Parser die Klammern nicht vom Namen.
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Dienstag 21. September 2010, 08:21

Wenn du den Wert errechnen willst nimmst du ein Property. Ansonsten ist die Überlegung wohl, dass die Strings nicht irgendwelche Beliebigen Funktionsaufrufe machen sollen, weil zu viel Programmlogik reinkommen könnte, wie bei den Django-Templates auch.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Benutzeravatar
snafu
User
Beiträge: 5925
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Dienstag 21. September 2010, 08:32

Na klar, an die Programmlogik hatte ich auch schon gedacht. Meist ist der Rückgabewert einer Funktion ja nicht unbedingt etwas, dass man in einen String setzen möchte. Trotzdem eine merkwürdige Entscheidung, wie ich finde. An anderen Stellen bevormundet einen Python ja auch nicht mit Konzepten, deren Tenor mehr oder weniger ist: "Lieber nicht, sonst machst du noch was kaputt". Ausgenommen natürlich die Speicherverwaltung, aber das ist ein ganz anderes Thema und dort ist es auch gut, so wie es ist.

Aber natürlich ist es auch denkbar, dass die Entwickler einfach nicht Funktionsaufrufe in die Planung einbezogen haben.
Benutzeravatar
mkesper
User
Beiträge: 919
Registriert: Montag 20. November 2006, 15:48
Wohnort: formerly known as mkallas
Kontaktdaten:

Dienstag 21. September 2010, 09:28

PEP 3101 hat geschrieben: Unlike some other programming languages, you cannot embed arbitrary
expressions in format strings. This is by design - the types of
expressions that you can use is deliberately limited. Only two operators
are supported: the '.' (getattr) operator, and the '[]' (getitem)
operator. The reason for allowing these operators is that they don't
normally have side effects in non-pathological code.
lunar

Dienstag 21. September 2010, 09:52

@snafu: Das ist eine nachvollziehbare, sinnvolle und begründbare Entscheidung, die nichts mit „Bevormunden“ zu tun hat. Es geht schlicht darum, welchem Zweck die Formatierung von Zeichenketten dienen soll, und wo man die Grenzen der Formatierungssprachen setzt. Python setzt diese Grenze genau an der Grenze zwischen den Daten eines Objekts (einfache Attribute, Eigenschaften und Schlüssel) und dessen Verhalten (Methoden), somit dient die Formatierung von Zeichenketten einzig und allein der Darstellung von Daten.

Ich finde das sinnvoll, denn denn die bloße Umwandlung von Daten in eine andere Repräsentation sollte keine Seiteneffekte haben. Methoden haben in der Regel Seiteneffekte zum Zweck, während Eigenschaften, Schlüssel und Attribute keine Seiteneffekte haben (sollten) [1]. Außerdem gibt es für das Verhalten von Objekten schließlich den "normalen" Quelltext, und man sieht an PHP, wo man hinkommt, wenn man die Sprache zur Zeichenkettenformatierung zur vollwertigen Programmiersprache aufbläst.

Natürlich kann man auch an anderen Stellen Grenzen ziehen, aber die Grenze zwischen Daten und Verhalten ist meines Erachtens eben die offensichtlichste. Würde man dagegen Methodenaufrufe erlauben, dann käme man logischerweise zu den Argumenten von Methoden, und würde dann bei kompletten Ausdrücken enden.

Davon abgesehen macht man imho was falsch, wenn man an dieser Stelle Methoden aufrufen möchte. Wäre die Methode so unmittelbar zur Formatierung gedacht, dann sollte sie eine Eigenschaft sein, wenn nicht, also wenn das Ziel des Aufruf eigentlich der von der Methode hervorgerufene Seiteneffekt ist, was hat die Methode dann in der Formatierung einer Zeichenkette zu suchen?

[1] Natürlich kann man theoretisch auch in einer Eigenschaft oder in __getitem__ Seiteneffekte hervorrufen, aber nicht in gutem Quelltext.
BlackJack

Dienstag 21. September 2010, 09:58

@snafu: Die Zeichenketten in die man hinein"format"ieren kann, sind ja nicht immer Konstanten im Programm, die können ja selbst schon aus Benutzereingaben entstanden sein. Und dann wäre `format()` potentiell so gefährlich wie `eval()` wenn da beliebiger Quelltext stehen dürfte und ausgeführt wird.

Solche "code injektions" gar nicht erst zu erlauben, würde ich nicht als bevormunden ansehen. Das ist einfach eine zu grosse Sicherheitslücke als dass man sie offen stehen lassen sollte.
Benutzeravatar
snafu
User
Beiträge: 5925
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Mittwoch 22. September 2010, 15:04

lunar hat geschrieben:Wäre die Methode so unmittelbar zur Formatierung gedacht, dann sollte sie eine Eigenschaft sein, wenn nicht, also wenn das Ziel des Aufruf eigentlich der von der Methode hervorgerufene Seiteneffekt ist, was hat die Methode dann in der Formatierung einer Zeichenkette zu suchen?
Es gibt imho schon einige Anwendungsbereiche, wo eine Methode nichts am Exemplar verändert, sondern lediglich etwas zurückgibt. Man denke nur an diverse PyQt-Konvertierungsmethoden oder an die schon angeschnittenen Methoden auf Zeichenketten in Python.
BlackJack hat geschrieben:Solche "code injektions" gar nicht erst zu erlauben, würde ich nicht als bevormunden ansehen. Das ist einfach eine zu grosse Sicherheitslücke als dass man sie offen stehen lassen sollte.
Naja, aber das ist es doch, was "Bevormundung" normalerweise bedeutet. Man fällt die Entscheidung für jemand anderen oder nimmt ihm generell die Entscheidungsfreiheit auf bestimmten Gebieten, weil man glaubt, dass sei das beste für ihn und würde ihn vor Gefahren schützen. Eine Warnung in der Doku hätte hier m.E. ausgereicht. Wie dem auch sei. Ich habe jetzt nicht vor, im großen Stil eine Lanze für die Implementierung von Methodenaufrufen zu brechen...
Benutzeravatar
Rebecca
User
Beiträge: 1662
Registriert: Freitag 3. Februar 2006, 12:28
Wohnort: DN, Heimat: HB
Kontaktdaten:

Mittwoch 22. September 2010, 15:12

BlackJack hat geschrieben:Und dann wäre `format()` potentiell so gefährlich wie `eval()` wenn da beliebiger Quelltext stehen dürfte und ausgeführt wird.
Snafu, damit du deine Methodenaufrufe haben koenntest, wuerde fuer uns andere format unbenutzbar...
Offizielles Python-Tutorial (Deutsche Version)

Urheberrecht, Datenschutz, Informationsfreiheit: Piratenpartei
Benutzeravatar
snafu
User
Beiträge: 5925
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Mittwoch 22. September 2010, 15:26

Potenziell gefährlich ist es auch, dass Attribute theoretisch Properties sein können, womit sich genau so viel Schaden anrichten lässt.
Benutzeravatar
Rebecca
User
Beiträge: 1662
Registriert: Freitag 3. Februar 2006, 12:28
Wohnort: DN, Heimat: HB
Kontaktdaten:

Mittwoch 22. September 2010, 15:43

Aber dann sind es nur die Getter-Methoden die aufgerufen werden. Sollte jedem klar sein dass es eine schlechte Idee ist, da wilde Sachen drin zu machen...
Offizielles Python-Tutorial (Deutsche Version)

Urheberrecht, Datenschutz, Informationsfreiheit: Piratenpartei
BlackJack

Mittwoch 22. September 2010, 16:10

@snafu: Zudem unterliegen die "getter" der Kontrolle des Programmierers. Die werden nicht vom Angreifer definiert, der die Injection versucht.

Ein gewisser Satz Regeln der das Zusammenleben ermöglicht, ist nicht das selbe wie Bevormundung. Oder findest Du es als Bevormundung, dass in den meisten Staaten/Gemeinschaften nicht einfach jeder von jedem erschossen werden darf und nicht überall Waffen und Munition herumliegen? Wenn das was Du möchtest möglich wäre, dann wäre Python noch unsicherer als ein schlecht konfigurierter Webserver mit PHP.
lunar

Samstag 25. September 2010, 19:06

@snafu: Deine Beispiele und Deine Argumentation sind nicht überzeugend, und ich glaube, dass weißt Du auch selbst.

Deine Beispiele beziehen sich auf Ausnahmen. Unveränderliche Typen sind nicht die Regel, sondern sowohl in der Standardbibliothek als auch in Drittbibliotheken Sonderfälle. Ebenso sind automatisch generierte Anbindungen an C++-Bibliotheken keine guten Beispiele für die Idiomatik und den Ausdruck der Sprache Python, zumal C++ gar keine Eigenschaften kennt und somit zwischen Daten und Verhalten gar nicht so klar trennen kann wie Python.

Deine Argumentation zieht sich folglich an Sonderfällen und Ausnahmen hoch. Sie ist gar nicht falsch, es hat ja niemand bestritten, dass man Methoden ohne Seiteneffekte ebenso implementieren kann wie Eigenschaften mit Seiteneffekten. Beides kommt in der Realität möglicherweise auch gar nicht so selten vor.

Dennoch sind und bleiben es eben Sonderfälle. Meist haben Methoden Seiteneffekte, denn andernfalls könnte man sie ja gleich in Eigenschaften oder gar triviale Attribute umwandeln. Eigenschaften mit nicht-trivialen (e.g. Caching) Seiteneffekten sind nicht einmal guter Quelltext, und können somit eigentlich gar nicht in Betracht gezogen werden.
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

Samstag 25. September 2010, 19:28

snafu hat geschrieben:
BlackJack hat geschrieben:Solche "code injektions" gar nicht erst zu erlauben, würde ich nicht als bevormunden ansehen. Das ist einfach eine zu grosse Sicherheitslücke als dass man sie offen stehen lassen sollte.
Naja, aber das ist es doch, was "Bevormundung" normalerweise bedeutet. Man fällt die Entscheidung für jemand anderen oder nimmt ihm generell die Entscheidungsfreiheit auf bestimmten Gebieten, weil man glaubt, dass sei das beste für ihn und würde ihn vor Gefahren schützen. Eine Warnung in der Doku hätte hier m.E. ausgereicht. Wie dem auch sei. Ich habe jetzt nicht vor, im großen Stil eine Lanze für die Implementierung von Methodenaufrufen zu brechen...
Ich glaube, das wurde schon genannt, aber nochmal zur Betonung: Die Implementierung von Aufrufen würde wahrscheinlich den vorhandenen Code für das Formatting verdoppeln. Denn genauso wenig wie du einen Grund siehst, keine Aufrufe zu erlauben, werden andere Leute keinen Grund sehen, diese nur ohne Argumente zu erlauben. Und Pythons Aufrufsyntax nachzuimplementieren ist durchaus aufwendig (ganz abgesehen von dem Problem, aus welchem Namespace die Argumentwerte kommen).

Was dann für Aufrufe gilt, gilt genauso für beliebige Expressions. Und so weiter, bis wir gleich eval() verwenden könnten.

Und da find ich die Beschränkung, so wie sie jetzt ist, noch am sinnvollsten.
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
Antworten