Typ des kompilierten Regex-Objekts in Python

73

Was ist der Typ des kompilierten regulären Ausdrucks in Python?

Insbesondere möchte ich bewerten

isinstance(re.compile(''), ???)

um wahr zu sein, zu Zwecken der Selbstbeobachtung.

Eine Lösung, die ich hatte, war, eine globale Konstante zu haben REGEX_TYPE = type(re.compile('')), aber sie scheint nicht sehr elegant zu sein.

BEARBEITEN: Der Grund, warum ich dies tun möchte, ist, dass ich eine Liste von Zeichenfolgen und kompilierten Regex-Objekten habe. Ich möchte eine Zeichenfolge mit der Liste "abgleichen"

  • Versuchen Sie für jede Zeichenfolge in der Liste, die Zeichenfolgengleichheit zu überprüfen.
  • Überprüfen Sie für jeden regulären Ausdruck in der Liste, ob die Zeichenfolge mit dem angegebenen Muster übereinstimmt.

und der Code, den ich mir ausgedacht habe, war:

for allowed in alloweds:
    if isinstance(allowed, basestring) and allowed == input:
        ignored = False
        break
    elif isinstance(allowed, REGEX_TYPE) and allowed.match(input):
        ignored = False
        break
Jeeyoung Kim
quelle
3
Bei Python dreht sich alles um das Eingeben von Kanälen. Dies ist eine Verletzung von Pythons Geist.
Pwnna
3
Dies ist möglicherweise der beste Weg, wenn Sie den Typ wirklich überprüfen müssen. Soweit ich mich erinnere, gibt es nur re._pattern_typedas, was aus einem bestimmten Grund wahrscheinlich mit einem Unterstrich beginnt.
ad.match (Eingabe) ??? Meinst du erlaubt.match (Eingabe)?
John Machin
3
@ultimatebuster: oder vielleicht duck taping:)
John Machin
Ich liebe das an SO: Jedes Mal, wenn ich eine Frage habe, egal wie spezifisch oder dunkel, gibt es eine SO-Antwort darauf. Ich könnte genauso gut SO anstelle von Google suchen.
Bgw

Antworten:

39

Wenn der Typ von etwas nicht genau angegeben ist, ist es nichts Falsches, typewenn Sie das integrierte Programm verwenden, um die Antwort zur Laufzeit zu ermitteln:

>>> import re
>>> retype = type(re.compile('hello, world'))
>>> isinstance(re.compile('goodbye'), retype)
True
>>> isinstance(12, retype)
False
>>> 

Das Erkennen des Typs zur Laufzeit schützt Sie vor dem Zugriff auf private Attribute und vor zukünftigen Änderungen des Rückgabetyps. Es ist nichts Unelegantes an der Verwendung typehier, obwohl es etwas Unelegantes sein kann, den Typ überhaupt kennen zu wollen.

Jean-Paul Calderone
quelle
12
Die Verwendung des durch diesen Ansatz erkannten Typs ist nicht immer richtig. Eine Implementierung verwendet möglicherweise einen oder mehrere Typen, um eine bestimmte Funktion zu unterstützen. Bei regulären Ausdrücken unwahrscheinlich, aber einige Fabriken geben möglicherweise jetzt einen Typ und später viele Typen zurück. Aber das ist nur eine andere Form, die Erwartungen an die Unterstützung bei der Eingabe von Enten zu brechen, indem Typen überprüft werden.
Rosh Oxymoron
1
Wie unterscheidet sich das von jedem anderen Typ? Alles, was Sie in Python aufrufen, gibt möglicherweise etwas anderes zurück. Das ist der Grund, warum es vielleicht etwas Unelegantes ist, den Typ überhaupt kennen zu wollen .
Jean-Paul Calderone
4
@Rosh: Dies ist eine pragmatische Antwort auf den Punkt der OP-Frage. Jean-Paul hat gesagt, dass es am Ende keine gute Praxis ist, aber als direkte Antwort ist es eine gute. ++
Eli Bendersky
Dies beantwortet nicht die Frage
Xaxxon
62

Python 3.5 hat das typingModul eingeführt. Darin enthalten ist typing.Pattern, a _TypeAlias.

Ab Python 3.6 können Sie einfach Folgendes tun:

from typing import Pattern

my_re = re.compile('foo')
assert isinstance(my_re, Pattern)

In Version 3.5 gab es einen Fehler , bei dem Sie Folgendes tun mussten:

assert issubclass(type(my_re), Pattern)

Was laut Dokumentation und Testsuite nicht garantiert funktioniert.

fliegende Schafe
quelle
2
Dieser Fehler scheint laut dem verknüpften Problem am 27.09.2016 behoben zu sein.
Michael Barton
6
Ich musste verwenden, from typing import Patternum darauf zuzugreifen Pattern.
Rotareti
@ Rotareti danke, typing.rewurde in 3.6 entfernt, denke ich
fliegende Schafe
21

Es ist möglich, einen kompilierten regulären Ausdruck mit 're._pattern_type' zu vergleichen.

import re
pattern = r'aa'
compiled_re = re.compile(pattern)
print isinstance(compiled_re, re._pattern_type)

>>True

Gibt True, zumindest in Version 2.7

Alemol
quelle
Dies ist der ideale Weg, um damit umzugehen, vielen Dank!
Jamie Ivanov
16

Haftungsausschluss: Dies ist keine direkte Antwort auf Ihre spezifischen Anforderungen, sondern eine Alternative, die als alternativer Ansatz nützlich sein kann


Sie können sich an die Ideale der Ententypisierung halten und hasattrbestimmen, ob das Objekt bestimmte Eigenschaften aufweist, die Sie verwenden möchten. Zum Beispiel könnten Sie etwas tun wie:

if hasattr(possibly_a_re_object, "match"): # Treat it like it's an re object
    possibly_a_re_object.match(thing_to_match_against)
else:
    # alternative handler
bgw
quelle
Tipphinweise sind jetzt eine Sache :)
Cedric H.
10

Vorbeugung ist besser als Heilung. Erstellen Sie überhaupt keine so heterogene Liste. Verfügen Sie über eine Reihe zulässiger Zeichenfolgen und eine Liste kompilierter Regex-Objekte. Dadurch sollte Ihr Prüfcode besser aussehen und schneller ausgeführt werden:

if input in allowed_strings:
    ignored = False
else:
    for allowed in allowed_regexed_objects:
        if allowed.match(input):
            ignored = False
            break

Wenn Sie die Erstellung einer solchen Liste nicht vermeiden können, prüfen Sie, ob Sie die Möglichkeit haben, sie einmal zu untersuchen und die beiden Ersatzobjekte zu erstellen.

John Machin
quelle
Dies ist wahrscheinlich die vernünftigste Antwort.
Jeeyoung Kim
1
Die for-Schleife könnte vereinfacht werden ignored = not any(allowed.match(input) for allowed in allowed_regexed_objects)).
Sven Marnach
2
Diese Antwort ist konstruktiv, was gut ist, aber sie beantwortet nicht die ursprüngliche Frage.
Tyler
7

Zur Veranschaulichung des Polymorphismus besteht eine alternative Lösung darin, Wrapper-Klassen zu erstellen, die eine gemeinsame Methode implementieren.

class Stringish (str):
    def matches (self, input):
        return self == input

class Regexish (re):
    def matches (self, input):
        return self.match(input)

Jetzt kann Ihr Code eine Liste allowedsmit Objekten durchlaufen, die eine dieser beiden Klassen vollständig transparent instanziieren:

for allowed in alloweds:
    if allowed.matches(input):
        ignored = False
        break

Beachten Sie auch, wie einige Codeduplikationen verschwinden (obwohl Ihr ursprünglicher Code möglicherweise überarbeitet wurde, um dies separat zu beheben).

Tripleee
quelle
Ich mag diese Antwort aus irgendeinem Grund wirklich sehr. Dies zeigt wirklich, wie man die Ententypisierung nutzt, um sowohl Pythonalität als auch Abstraktion (DRY) aufrechtzuerhalten. (Ich hatte auch einen ähnlichen Bedarf an einer generischen Textsuche, bei der das Suchprädikat entweder eine Liste der übereinstimmenden Zeichenfolgen oder eine Regex sein könnte.) Ich kann sich ändern , strum basestringda in Py2, beide unicodeund strerben von basestring.
Cowbert
Funktioniert leider nicht in Py27, reist ein klassenloses Modul, das nicht einfach mit einem Klassenvererbungsmodell erweitert werden kann.
Cowbert
1
Sie können arbeiten , um , dass sie nicht haben , von zu vererben re; Die Hauptsache ist, eine gleichnamige Methode mit zwei verschiedenen Implementierungen zu haben.
Tripleee
Ja für die Regexish, erben von object, dann rufen Sie einfach rean __init__, um ein reObjekt nach Komposition zu erstellen (da Sie, wie Sie sagen, nur implementieren müssen matchesodersearch
Cowbert
3

Zu Ihrer Information, ein Beispiel für einen solchen Code befindet sich in BeautifulSoup: http://www.crummy.com/software/BeautifulSoup und verwendet die 'hasattr'-Technik. Im Sinne des "alternativen Ansatzes" können Sie Ihre Zeichenfolgensuche auch in einem regulären Ausdruck kapseln, indem Sie Folgendes tun: regexp = re.compile (re.escape (your_string)), daher nur eine Liste regulärer Ausdrücke.

Erkunden
quelle
1

In 3.7 können Sie verwenden re.Pattern:

import re
rr = re.compile("pattern")
isinstance(rr, re.Pattern)
>> True
DominiCane
quelle
0

Dies ist eine andere nicht die Antwort auf die Frage, aber es löst die Problemantwort . Sofern your_string keine Sonderzeichen für reguläre Ausdrücke enthält,

if re.match(your_string,target_string):

hat den gleichen Effekt wie

if your_string == target_string:

Gehen Sie also einen Schritt zurück und verwenden Sie nicht kompilierte Muster für reguläre Ausdrücke in Ihrer Liste der zulässigen. Dies ist zweifellos langsamer als die Verwendung kompilierter regulärer Ausdrücke, funktioniert jedoch nur gelegentlich mit unerwarteten Ergebnissen, und zwar nur dann, wenn Sie Benutzern erlauben, die zulässigen Elemente anzugeben

Griswolf
quelle
-10
>>> import re
>>> regex = re.compile('foo')
>>> regex
<_sre.SRE_Pattern object at 0x10035d960>

Nun - _sre ist eine C-Erweiterung, die den Mustervergleich durchführt. Sie können in der _sre C-Quelle nachsehen.

Warum kümmert es dich?

Oder du versuchst so etwas (aus welchem ​​Grund auch immer - es ist mir egal):

>>> regex1 = re.compile('bar')
>>> regex2 = re.compile('foo')
>>> type(regex1) == type(regex2)
True
Andreas Jung
quelle
Das _sreModul hat hier kein solches Attribut.
Rosh Oxymoron
1
@AndreasJung "Kein solches Attribut" bedeutet, dass from _sre import SRE_Patterndies nicht funktioniert. Die Abstimmungen sind wahrscheinlich 1. aufgrund Ihrer Einstellung: "Es ist mir egal" - was? Und 2. weil du die Frage nicht wirklich beantwortet hast.
fliegende Schafe