Kann ich integrierten Python-Typen benutzerdefinierte Methoden / Attribute hinzufügen?


76

Angenommen, ich möchte dem Diktattyp helloWorld()von Python eine Methode hinzufügen . Darf ich das machen?

JavaScript verfügt über ein Prototypobjekt, das sich so verhält. Vielleicht ist es schlechtes Design und ich sollte das diktierte Objekt in Unterklassen unterteilen, aber dann funktioniert es nur in den Unterklassen und ich möchte, dass es in allen zukünftigen Wörterbüchern funktioniert.

So würde es in JavaScript ablaufen:

String.prototype.hello = function() {
    alert("Hello, " + this + "!");
}
"Jed".hello() //alerts "Hello, Jed!"

Hier ist ein nützlicher Link mit weiteren Beispielen: http://www.javascriptkit.com/javatutors/proto3.shtml


1
Sie können dies auch in Ruby tun, indem Sie die Klasse einfach erneut öffnen, dh: class String; def new_method () ...; end; Ich bin mir ziemlich sicher, dass Python auch so etwas hat.
Abdullah Jibaly

@Abdullah Ich glaube, Sie beziehen sich auf das Patchen von Affen, das meistens verpönt ist.
Rafe Kettler

Ja genau. In Rails ist alles erledigt.
Abdullah Jibaly

Dies ist spezifisch für, numpy.ndarrayaber wenn jemand hierher gekommen ist, um dies zu versuchen, und beim Versuch, einer Instanz eine Methode hinzuzufügen, ein Fehler aufgetreten numpy.ndarrayist, werfen Sie einen Blick auf die numpy.ndarray.viewMethode.
Mondaugen

Antworten:


79

Sie können die Methode nicht direkt zum Originaltyp hinzufügen. Sie können den Typ jedoch in eine Unterklasse unterteilen und ihn dann im integrierten / globalen Namespace ersetzen, wodurch der größte Teil des gewünschten Effekts erzielt wird. Leider sind Objekte, die mit Literal-Syntax erstellt wurden, weiterhin vom Vanille-Typ und verfügen nicht über Ihre neuen Methoden / Attribute.

So sieht es aus

# Built-in namespace
import __builtin__

# Extended subclass
class mystr(str):
    def first_last(self):
        if self:
            return self[0] + self[-1]
        else:
            return ''

# Substitute the original str with the subclass on the built-in namespace    
__builtin__.str = mystr

print str(1234).first_last()
print str(0).first_last()
print str('').first_last()
print '0'.first_last()

output = """
14
00

Traceback (most recent call last):
  File "strp.py", line 16, in <module>
    print '0'.first_last()
AttributeError: 'str' object has no attribute 'first_last'
"""

Ich denke, ich muss nur die bevorzugte Methode der Unterklasse verwenden. Vielleicht werde ich es lieben.
jedmao

26
Hinweis: Das __builtin__Modul wurde builtinsin Python3 umbenannt.
Changokun

Nun, ich bin auf ein Problem in Python 2 gestoßen. Danach kann ich nicht mehr nach dem Typ suchen> type ('') == str <gibt nur> false <. Wenn ich ("") tippe, bekomme ich <type 'str'>, aber irgendwie funktioniert der Vergleich nicht mehr. Vor dem Ausführen der 'line builtin .str = mystr' funktioniert die Prüfung auf Typ.
Nadu

@ Nadu wie OP sagte, "Objekte, die durch wörtliche Syntax erstellt wurden, werden weiterhin vom Vanille-Typ sein"
Alex Hall

@ Nadu. Normalerweise sollten Sie == nicht verwenden, wenn Sie nach Typen suchen. Verwenden Sie stattdessen isinstance ("", str), die True zurückgibt, wenn der erste Wert eine Instanz der zweiten oder eine Unterklasse der zweiten ist.
Chris Cogdon

6

Habe gerade die Forbbidenfrucht probiert!

Hier ist der Code, sehr einfach!

from forbiddenfruit import curse


def list_size(self):
    return len(self)

def string_hello(self):
    print("Hello, {}".format(self))

if __name__ == "__main__":
    curse(list, "size", list_size)
    a = [1, 2, 3]
    print(a.size())
    curse(str, "hello", string_hello)
    "Jesse".hello()

6
Forbiddenfruit ist nicht nur eine schlechte Idee, sondern auch schlecht implementiert und führt sehr leicht zu Segfaults und Speicherbeschädigungen.
user2357112 unterstützt Monica

ich mag das. ich werde benützen.
Vitaly Fadeev

@ user2357112supportsMonica Haben Sie Links, über die ich ausführlicher über verbotene Früchte lesen kann?
DarthVlader

2
class MyString:
    def __init__(self, string):
        self.string = string
    def bigger_string(self):
        print(' '.join(self.string))

mystring = MyString("this is the string")
mystring.bigger_string()

Ausgabe

t h i s   i s   t h e   s t r i n g

Datenklasse in Python 3.7

from dataclasses import dataclass

@dataclass
class St:

    text : str

    def bigger(self) -> None:
        self.text = list(self.text)
        print(" ".join(self.text))

mys = St("Hello")
mys.bigger()

Ausgabe

H e l l o

2

HINWEIS : Diese Qualitätssicherung ist als Duplikat zu dieser gekennzeichnet , aber IMO fordert sie etwas anderes an. Ich kann dort nicht antworten, also antworte ich hier.


Insbesondere wollte ich von strbenutzerdefinierten Attributen erben und diese hinzufügen. Bestehende Antworten (insbesondere diejenigen, die sagen, dass Sie nicht können ) haben es nicht ganz gelöst, aber das hat bei mir funktioniert:

class TaggedString(str):
    """
    A ``str`` with a ``.tags`` set and ``.kwtags`` dict of tags.
    Usage example::
      ts = TaggedString("hello world!", "greeting", "cliche",
                        what_am_i="h4cker")
      (ts.upper(), ts.tags, ts.kwtags)
    """

    def __new__(cls, *args, **kwargs):
        return super().__new__(cls, args[0])

    def __init__(self, s, *tags, **kwtags):
        super().__init__()
        self.tags = set(tags)
        self.kwtags = kwtags

Hoffentlich hilft das jemandem! Prost,
Andres


1

Ja, aber Sie müssen eine neue Klasse desselben Typs definieren und sie sollte von diesem Typ erben.

Zum Beispiel:

class list(list):
    def __init__(self,*args):
        super().__init__(args)
    def map(self,function):
        return [function(i) for i in self]

a = list(1,2,3,4,5)
Def double(i): return i*2

print(a.map(double))

0

Ja, indem Sie diese Typen unterordnen. Siehe Vereinheitlichen von Typen und Klassen in Python .

Nein, das bedeutet nicht, dass tatsächliche Diktate diesen Typ haben, denn das wäre verwirrend. Die Unterklasse eines integrierten Typs ist die bevorzugte Methode zum Hinzufügen von Funktionen.


11
Das wäre verwirrend und sehr, sehr nützlich.
Evgeni Sergeev

1
@Veky Ich möchte any_dictionary_instance.len()oder .size(), zusätzlich zu den verfügbaren any_dictionary_instance.__len__()und len(any_dictionary_instance)das nennt es. Größe ist semantisch eine Eigenschaft von Containern, daher ist es bequemer zu schreiben, wenn Sie sagen, z. B. "von 0 bis zur Größe des Objekts iterieren" ... oops, das kann ich nicht ausdrücken, die Sprache zwingt mich, es als "iterieren von 0" neu zu formulieren auf die Größe des Objekts ". Aus nichts Besserem als historischen Gründen versammle ich mich.
Evgeni Sergeev

1
@nehemiah und du weißt was Evgeni meinte ... wie genau? Ich habe seine Worte gelesen. Hast du seinen Kommentar oben gelesen? Er beklagte ausdrücklich die Tatsache, dass er beim Zugriff auf die Größe keinen sächsischen Genitiv verwenden kann. Übrigens ja, es ist sein Code, bis jemand anderes ihn pflegen kann. Und er kann natürlich die Laufzeitumgebung nach Belieben ändern und neu kompilieren. :-P
Veky

1
@ Nehemia und was ist das Problem damit? Sie stimmen zu, dass str ein anderer Typ als MyStr ist, oder?
Veky

4
Ich hoffe es wird nicht geben (obwohl jetzt, da Guido zurückgetreten ist, alles möglich ist: - /). Der springende Punkt beim Kennen von Python-Typen ist das Wissen, über welche Methoden sie verfügen. Wenn jemand zufällige Funktionen hinzufügen könnte str, dann wissen Sie einfach nicht, um welchen Typ es sich 'abc'handelt. Das ist natürlich inakzeptabel. Und ja, JS hat große Probleme damit: Zeugen motools Array.flatten Fiasko.
Veky

-3

Unterklassen sind der richtige Weg in Python. Polyglot-Programmierer lernen, das richtige Werkzeug für die richtige Situation zu verwenden - im Rahmen der Vernunft. Etwas so kunstvoll konstruiertes wie Rails (ein DSL mit Ruby) ist in einer Sprache mit starrerer Syntax wie Python schmerzlich schwer zu implementieren. Die Leute vergleichen oft die beiden und sagen, wie ähnlich sie sind. Der Vergleich ist etwas unfair. Python scheint auf seine eigene Weise. totochto.


Ich sehe keinen Punkt in der Unterklassen-String-Klasse. Dem OP ist klar, was er will.
Nehem
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.