2009-09-03 3 views
5

Ich habe eine Funktion, die ein String-artiges Argument verwendet.Wie testet man in Python, ob ein stringähnliches Objekt veränderbar ist?

Ich möchte entscheiden, ob ich das Argument sicher speichern und sicher sein kann, dass es sich nicht ändert. Also würde ich gerne testen, ob es veränderbar ist, z. B. das Ergebnis einer buffer() aus einer array.array() oder nicht.

Derzeit verwende ich:

type(s) == str 

Gibt es einen besseren Weg, es zu tun?

(das Argument Kopieren ist zu teuer, deshalb habe ich es vermeiden wollen)

+3

ich Sie Ihre Frage Titel umformulieren würde empfehlen. Per Definition sind Strings ('str'-Instanzen) in Python ** niemals ** änderbar. String-ähnliche Objekte können jedoch sein. –

+1

Dies beantwortet Ihre Frage nicht, daher poste ich sie als Kommentar: Sie sollten isinstance (s, basestring) anstelle des Typs type verwenden, damit Sie abgeleitete Klassen und Unicode nicht verbieten. Verwenden Sie in Python 3 isinstance (s, str). –

+0

Was machst du, wenn das Argument veränderbar ist? – bstpierre

Antwort

4

Wenn es nur eine Heuristik für Ihre Zwischenspeicherung ist, verwenden Sie einfach, was auch immer funktioniert. isinstance (x, str), zum Beispiel, fast genau wie jetzt. (Given wollen Sie entscheiden, ob oder nicht cachen, einen Falsch-Lagertest bedeutet nur eine Cache-Miss, Sie nichts falsch gemacht.)


(Anmerkung: Es stellt sich heraus, dass Puffer Objekte hashable sind , obwohl ihre String-Darstellung unter den Füßen kann sich ändern;. die Hash-Diskussion unten interessant ist, ist aber nicht die reine Lösung beabsichtigt wurde, zu sein)

jedoch gut umgesetzt Klassen sollten Instanzen hashable zu sein, wenn sie sind unveränderlich und nicht, wenn sie veränderbar sind. Ein allgemeiner Test wäre, Ihr Objekt zu hacken und auf Erfolg zu prüfen.

>>> hash({}) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: dict objects are unhashable 

Dies wird falsche positive Ergebnisse geben, bin ich sicher, aber veränderbare Objekte, die hashable sind, sind streng genommen eine Unterbrechung der Schnittstelle; Ich würde Python-Bibliothek Typen erwarten, dass diese Schnittstelle zu gehorchen, ein Test einer kleinen Probe gibt die richtigen Antworten:

hashabe: str (Immutable), buffer (Warning, immutable slice of (possibly) mutable object!) 
unhashable: list, array.array 
+0

Wenn Sie die Ausnahme vermeiden möchten, könnten Sie dies auch tun: wenn '__hash__' in dir (obj) und obj .__ hash__: # do sachen –

+0

Ja, es scheint, es gibt nicht wirklich eine bessere Möglichkeit, das zu tun. Zum Spaß habe ich timed isinstance() vs type() und isinstance() ist langsamer, wenn es false zurückgibt. Ist es, weil es versucht/außer intern? – tonfa

+0

@ kaizer.se: Puffer ist veränderbar (wenn Sie einen Puffer aus einem array.array erstellen) – tonfa

3

Verwenden Sie einfach duck typing - denken Sie daran, es ist „Einfachere um Vergebung zu bitten als um Erlaubnis“. Versuchen Sie, das stringähnliche Objekt zu mutieren, und seien Sie darauf vorbereitet, eine Ausnahme abzufangen, wenn Sie dies nicht können.

+3

Und erkennen, dass dies nicht wasserdicht ist; Jemand kann immer ein Objekt übergeben, das wie eine Zeichenfolge aussieht, aber über eine Methode verfügt, die seinen Wert effektiv ändert. Ein stringähnliches Objekt könnte z. B. eine force_upper() -Methode haben, die die Zeichenfolge selbst nicht ändert, sondern Getter dazu veranlasst, Großbuchstaben zurückzugeben. Wenn Sie wichtige Invarianten haben, die davon abhängen, ob Sie etwas Veränderliches erhalten, sollten Sie dies dokumentieren - da es den meisten APIs egal ist. –

+0

Das stimmt, aber das OP möchte sicherstellen, dass das Argument * nicht * geändert wird. – bstpierre

+0

Die Idee ist nett (und pythonisch), aber es ist schwierig zu testen, ob die Mutation funktioniert, während die Zeichenkette gleichzeitig "unmodifiziert" bleibt ('a [0] = a [0]' + Sonderfall für leere Zeichenkette). Und btw, try/exception ist langsamer als eine if-Anweisung, wenn Sie eine Exception auslösen, die ausgelöst werden soll. – tonfa

5

Es wäre besser,

isinstance(s, basestring) 

Es ist für zu Strings Unicode arbeitet zu verwenden.

+0

Ich brauche es nicht für Unicode zu arbeiten, es ist wirklich für Bytes (ich arbeite an einem VCS). – tonfa

+0

Es hat auch den Vorteil, für Klassen zu arbeiten, die für 'str' abgeleitet sind. –

+0

Dies ist keine Antwort, sondern Bemerkung, daher sollte es als Kommentar gepostet werden. –

3

würde ich konvertiere es nur zu einem unveränderlichen string:

>>> s1 = "possibly mutable" 
>>> 
>>> s2 = str(s1) 
>>> s1 is s2 
True 

Bei s1 ist unveränderlich das gleiche Objekt zurück gegeben wird, in keinem Overhead-Speicher führt. Wenn es veränderbar ist, wird eine Kopie erstellt.

+0

funktioniert nicht so gut funktionieren, wenn s1 keine tatsächliche str: >>> s1 = u "Foo" >>> s2 = str (s1) >>> s2 s1 Falsch – bstpierre

+0

Es ist nicht Arbeit, eine Kopie ist hier zu teuer. – tonfa

+2

Können Sie näher erläutern, warum "eine Kopie hier zu teuer ist"? Dies ist der natürliche pythonische Weg, um dein Problem zu lösen: Wenn du eine unveränderliche Zeichenkette an str() übergibst, tut es nichts, schnell; Wenn Sie etwas veränderlich übergeben, erhalten Sie eine sichere unveränderliche Schnur zurück. Es macht die minimale Arbeit, die benötigt wird, um Unveränderlichkeit sicherzustellen. Ich versuche mir vorzustellen, wann das zu teuer wäre, und ich sehe es noch nicht. – steveha

Verwandte Themen