Frage

Python hat die Idee von Metaklassen, dass, wenn ich das richtig verstehe, erlauben Sie zu ändern ein Objekt einer Klasse ist im moment der Bau.Sie sind sich nicht ändern der Klasse, sondern das Objekt, das erstellt werden soll, dann initialisiert.

Python (zumindest als 3,0 glaube ich) hat auch die Idee Klasse Dekorateure.Wieder, wenn ich das richtig verstehe, Klasse decorators erlauben die änderung der definition der Klasse, im moment ist es erklärt wird.

Nun ich glaube, es ist eine gleichwertige Funktion oder die Funktionen der Klasse Dekorateur in Ruby, aber ich bin mir momentan nicht bewusst etwas gleichwertiges zu Metaklassen.Ich bin sicher, Sie können leicht Pumpe jedes Ruby-Objekt über einige Funktionen und tun, was Sie werden, um es, aber es ist ein feature in der Sprache, der Sätze, wie Metaklassen tun?

Also nochmal, Tut Ruby haben etwas ähnliches für Python-Metaklassen?

Bearbeiten Ich war auf der Metaklassen Python.Eine Metaklasse und ein Klasse decorator tun sehr ähnliche Dinge, es scheint.Sie beide die Klasse ändern, wenn es definiert ist, aber in unterschiedlicher Weise.Hoffentlich ein Python-guru kommen Sie und erklären, besser auf diese Funktionen in Python.

Aber eine Klasse oder die Eltern von eine Klasse implementieren kann, eine __new__(cls[,..]) - Funktion, die Anpassung der Bau des Objekts, bevor es initialisiert wird mit __init__(self[,..]).

Bearbeiten Diese Frage ist vor allem für die Diskussion und das lernen darüber, wie die beiden Sprachen zu vergleichen, in diese Funktionen.Ich bin vertraut mit Python, aber nicht Rubin und wurde neugierig.Hoffentlich jemand, die hat die gleiche Frage über die beiden Sprachen finden diesen Beitrag hilfreich und aufschlussreich.

War es hilfreich?

Lösung

Ruby hat keine Metaklasse. Es gibt einige Konstrukte in Ruby, die manche Menschen manchmal fälschlicherweise Metaklasse nennen, aber sie sind nicht (was eine Quelle von ist endlos Verwirrtheit).

Es gibt jedoch viele Möglichkeiten, die gleichen Ergebnisse in Ruby zu erzielen, die Sie mit Metaklasse machen würden. Aber ohne uns zu sagen, was genau Sie tun möchten, ist nicht abzusehen, was diese Mechanismen sein könnten.

Zusamenfassend:

  • Ruby hat keine Metaklasse
  • Ruby hat kein Konstrukt, das Pythons Metaklasse entspricht
  • Alles, was Python mit Metaklassen machen kann, kann auch in Ruby erfolgen
  • Aber es gibt keinen Single Konstrukten verwenden Sie unterschiedliche Konstrukte, je nachdem, was genau Sie tun möchten
  • Jedes dieser Konstrukte hat wahrscheinlich auch andere Merkmale, die nicht Metacklasse entsprechen (obwohl sie wahrscheinlich etwas entsprechen anders in Python)
  • Während Sie alles in Ruby tun können, was Sie mit Metaklasse in Python machen können, ist es möglicherweise nicht unbedingt unkompliziert
  • Obwohl es oft eine reibungsvollere Lösung gibt, die ist elegant
  • Last but not least: Während Sie in Python alles in Ruby tun können, was Sie mit Metaklasse machen können, ist dies möglicherweise nicht unbedingt der Ruby -Weg

Na und sind Metaklasse genau? Nun, es sind Klassen von Klassen. Machen wir also einen Schritt zurück: Was sind Klassen exakt?

Klassen …

  • sind Fabriken für Objekte
  • Definieren Sie das Verhalten von Objekten
  • Definieren Sie auf metaphysischer Ebene, was es bedeutet, eine Instanz der Klasse zu sein

Zum Beispiel die Array Die Klasse erzeugt Array-Objekte, definiert das Verhalten von Arrays und definiert, was "Array-Ness" bedeutet.

Zurück zu Metaklasse.

Metaklasse…

  • sind Fabriken für Klassen
  • Definieren Sie das Verhalten von Klassen
  • Definieren Sie auf metaphysischer Ebene, was es bedeutet, eine Klasse zu sein

In Ruby werden diese drei Verantwortlichkeiten an drei verschiedenen Orten aufgeteilt:

  • das Class Die Klasse erstellt Klassen und definiert ein wenig des Verhaltens
  • Die Eigenklasse der einzelnen Klasse definiert ein wenig Verhalten der Klasse
  • Das Konzept der "Klasse" ist fest in den Dolmetscher fest verdrahtet, was auch den Großteil des Verhaltens implementiert (z. B. können Sie nicht erben Class Um eine neue Art von Klasse zu erstellen, die die Methoden anders nachsieht, oder so ähnlich - der Methode -Lookup -Algorithmus wird in den Dolmetscher fest verdrahtet)

Diese drei Dinge zusammen spielen also die Rolle der Metaklasse, aber weder eines davon ist eine Metaklas (jeder implementiert nur einen kleinen Teil dessen, was eine Metaklasse tut), noch das ist die Summe von denen die Metaklas (weil sie viel mehr tun).

Leider nennen manche Leute Eigenklassen von Klassenmetaklassen. (Bis vor kurzem war ich einer dieser fehlgeleiteten Seelen, bis ich endlich das Licht sah.) Andere Leute rufen an alle Eigenhilfe von Metaklasse. (Leider ist einer dieser Personen der Autor eines der beliebtesten Tutorials für Ruby -Metaprogrammierung und das Ruby -Objektmodell.) Einige beliebte Bibliotheken fügen eine hinzu metaclass Methode an Object Das gibt die Eigenschaft des Objekts zurück (z. B. Activesupport, Facetten, Metaid). Einige Leute rufen an alle Virtuelle Klassen (dh Eigenclasses und inklusive Klassen) Metaklasse. Einige Leute rufen an Class die Metaklas. Selbst innerhalb des Ruby -Quellcodes selbst wird das Wort "Metaclass" verwendet, um sich auf Dinge zu beziehen, die keine Metaklasse sind.

Andere Tipps

Ihre aktualisierte Frage sieht heute ganz anders.Wenn ich Sie richtig verstehe, wollen Sie hook Objekt-Zuweisung und Initialisierung, das hat absolut überhaupt nichts zu tun mit Metaklassen.(Aber Sie noch schreiben Sie nicht, was es ist, dass Sie wirklich wollen, zu tun, so könnte ich immer noch off.)

In einigen objektorientierten Programmiersprachen, Objekte erstellt werden Konstruktoren.Aber Ruby hat nicht Konstruktoren.Konstruktoren sind nur factory-Methoden (dumm mit Einschränkungen);es gibt keinen Grund zu haben, Sie in einem gut gestalteten Sprache, wenn Sie können, verwenden Sie einfach eine (starke) factory-Methode statt.

Objekt-Konstruktion in Ruby funktioniert wie folgt:Objekt-Konstruktion ist in zwei Phasen aufgeteilt, Zuordnung und Initialisierung.Die Zuteilung erfolgt durch eine öffentliche Methode der Klasse aufgerufen allocate, die definiert ist als eine Instanz-Methode der Klasse Class und ist in der Regel nie überschrieben.(In der Tat, ich glaube nicht, dass Sie tatsächlich können außer Kraft setzen.) Es ist einfach reserviert den Speicher für das Objekt und legt ein paar Hinweise, aber das Objekt ist nicht wirklich brauchbar an dieser Stelle.

Das ist, wo der Initialisierung kommt in:es ist eine Instanzmethode aufgerufen initialize,, das festlegt, das Objekt seiner internen Zustand und bringt es in eine konsistente, voll definierten Zustand, die können verwendet werden durch andere Objekte.

So, um Sie vollständig zu erstellen Sie ein neues Objekt, was Sie tun müssen, ist dies:

x = X.allocate
x.initialize

[Hinweis:Objective-C-Programmierer können dies erkennen.]

Jedoch, weil es ist zu einfach, zu vergessen, zu nennen initialize und als eine Allgemeine Regel, die ein Objekt sollte in vollem Umfang in Kraft nach dem Bau, es ist eine convenience-Fabrik-Methode genannt Class#new, die nicht alle, die für Sie arbeiten und sieht so etwas wie dieses:

class Class
  def new(*args, &block)
    obj = allocate
    obj.initialize(*args, &block)

    return obj
  end
end

[Hinweis:eigentlich initialize ist Sie privat, so die reflektion verwendet werden, um die Umgehung von Zugriffsbeschränkungen, wie diese: obj.send(:initialize, *args, &block)]

Das, übrigens, ist der Grund, warum die Konstruktion eines Objekts, das Sie call eine öffentliche Methode der Klasse Foo.new aber Sie Umsetzung eine private Instanz-Methode Foo#initialize, scheint Reise eine Menge Neulinge.

Jedoch, none dieses ist in keiner Weise gebacken in der Sprache.Die Tatsache, dass die primäre factory-Methode für jede Klasse ist in der Regel genannt new ist nur eine Konvention (und manchmal habe ich wünschte, es wäre anders, denn es sieht ähnlich aus wie Konstruktoren in Java, jedoch ist komplett anders ist).In anderen Sprachen, der Konstruktor muss einen bestimmten Namen haben.In Java, es müssen die selben Namen wie die Klasse, was bedeutet, dass a) es kann nur einen Konstruktor und b) anonyme Klassen können keine Konstruktoren, da Sie nicht über Namen.In Python, die factory-Methode aufgerufen werden muss __new__, was wiederum bedeutet, es kann nur einen geben.(In Java und Python, können Sie natürlich verschiedene factory-Methoden, sondern ruft Sie sieht anders aus als das aufrufen der Standard, während in Ruby (und Smalltalk, Woher dieses Muster stammt) sieht es genauso.)

In Ruby kann es so viele factory-Methoden, wie Sie möchten, mit jedem Namen, den Sie möchten, und eine factory-Methode können viele verschiedene Namen.(Sammlung für Klassen, zum Beispiel die factory-Methode wird Häufig als alias für [],, die ermöglicht Sie zu schreiben List[1, 2, 3] statt List.new(1, 2, 3) die endet auf der Suche wie ein array, so betonen die Kollektion-ish Art von Listen.)

In kurz:

  • die standardisierte Fabrik-Methode Foo.new, aber es kann alles sein
  • Foo.new Aufrufe allocate reservieren von Speicher für ein leeres Objekt foo
  • Foo.new dann ruft foo.initialize, d.h.die Foo#initialize Instanz-Methode
  • alle drei sind diejenigen Methoden wie jede andere, die Sie löschen, neu zu definieren, überschreiben, wrap, alias und so weiter
  • naja, außer allocate die Speicher im inneren der Ruby-Laufzeit, die können Sie eigentlich nicht aus Ruby

In Python, __new__ entspricht in etwa beide new und allocate in Ruby, und __init__ genau entspricht initialize in Ruby.Der Hauptunterschied ist, dass in Ruby new Aufrufe initialize in der Erwägung, dass in Python, die Laufzeit automatisch Anrufe __init__ nach __new__.

Zum Beispiel, hier ist eine Klasse, die nur erlaubt, maximal 2 Instanzen erstellt:

class Foo
  def self.new(*args, &block)
    @instances ||= 0
    raise 'Too many instances!' if @instances >= 2

    obj = allocate
    obj.send(:initialize, *args, &block)

    @instances += 1

    return obj
  end

  attr_reader :name

  def initialize(name)
    @name = name
  end
end

one = Foo.new('#1')
two = Foo.new('#2')
puts two.name         # => #2
three = Foo.new('#3') # => RuntimeError: Too many instances!
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top