Что Ruby является аналогом к Метаклассам Python?

Python имеет идею метаклассов, которые, если я понимаю правильно, позволяют Вам изменять объект класса во время конструкции. Вы не изменяете класс, но вместо этого объект, который должен быть создан затем инициализированный.

Python (по крайней мере, с 3,0 я верю), также имеет идею декораторов класса. Снова, если я понимаю правильно, декораторы класса позволяют изменение определения класса в данный момент, оно объявляется.

Теперь я полагаю, что существует эквивалентная функция или функции декоратору класса в Ruby, но я в настоящее время не знаю о чем-то эквивалентном метаклассам. Я уверен, что можно легко накачать какой-либо объект Ruby через некоторые функции и сделать то, что Вы будете к нему, но существует ли функция на языке, который настраивает, это как метаклассы делает?

Таким образом, снова Ruby имеет что-то подобным метаклассам Python?

Редактирование я был выключен на метаклассах для Python. Метакласс и декоратор класса делают очень похожие вещи, это появляется. Они оба изменяют класс, когда он определяется, но различными способами. Надо надеяться, гуру Python войдет и объяснит лучше на этих функциях в Python.

Но класс или родитель класса могут реализовать a __new__(cls[,..]) функция, которая действительно настраивает конструкцию объекта, прежде чем это будет инициализировано с __init__(self[,..]).

Редактирование, которое Этот вопрос главным образом для обсуждения и приобретения знаний о том, как эти два языка выдерживают сравнение в этих функциях. Я знаком с Python, но не Ruby и был любопытен. Надо надеяться, кто-либо еще, у кого есть тот же вопрос об этих двух языках, найдет это сообщение полезным и поучительным.

10
задан weronika 30 April 2012 в 11:26
поделиться

2 ответа

В Ruby нет метаклассов. В Ruby есть некоторые конструкции, которые некоторые люди иногда ошибочно называют метаклассами, но это не так (что является источником бесконечной путаницы).

Однако есть много способов добиться в Ruby тех же результатов, что и с метаклассами. Но не сообщая нам, что именно вы хотите сделать, невозможно сказать, что это за механизмы.

Вкратце:

  • Ruby не имеет метаклассов
  • Ruby не имеет ни одной конструкции, соответствующей метаклассам Python
  • Все, что Python может делать с метаклассами, также может быть выполнено в Ruby
  • Но не существует единственной конструкции , вы будете использовать разные конструкции в зависимости от того, что именно вы хотите сделать
  • Любая из этих конструкций, вероятно, также имеет другие функции, которые не соответствуют метаклассам (хотя они, вероятно, соответствуют чему-то else в Python)
  • Хотя вы можете делать в Ruby все, что вы можете делать с метаклассами в Python, это может быть не всегда просто
  • Хотя часто будет более Rubyish решение что элегантный
  • И последнее, но не менее важное: хотя вы можете делать в Ruby все, что вы можете делать с метаклассами в Python, это не обязательно должно быть Ruby Way

Итак, что точно метаклассы? Ну, это классы классов. Итак, давайте сделаем шаг назад: что такое классы ?

Классы…

  • - это фабрики для объектов
  • определяют поведение объектов
  • определяют на метафизическом уровне, что это означает быть экземпляром класса

Например, класс Array создает объекты массива, определяет поведение массивов и определяет, что означает «массивность».

Вернемся к метаклассам.

Метаклассы…

  • - это фабрики для классов
  • определяют поведение классов
  • определяют на метафизическом уровне, что значит быть классом

В Ruby эти три обязанности разделены на три разных места :

  • класс Class создает классы и определяет немного поведения
  • собственный класс отдельного класса определяет немного поведения класса
  • концепция «классности» является встроен в интерпретатор, который также реализует основную часть поведения (например, вы не можете наследовать от Class , чтобы создать новый тип класса, который ищет методы по-другому, или что-то в этом роде - алгоритм поиска метода встроен в интерпретатор)

Итак, эти три вещи вместе играют роль метаклассов, но ни один из них не является метаклассом (каждый реализует лишь небольшую часть того, что делает метакласс), ни сумма этих метаклассов (потому что они много больше чем это).

К сожалению, некоторые люди называют собственные классы классов метаклассами. (До недавнего времени я был одной из тех заблудших душ, пока наконец не увидел свет.) Другие люди называют все собственными классами метаклассами. (К сожалению, один из этих людей является автором одного из самых популярных руководств по метапрограммированию Ruby и объектной модели Ruby.) Некоторые популярные библиотеки добавляют метод метакласса к Object , который возвращает значение собственный класс объекта (например, ActiveSupport, Facets, metaid). Некоторые люди называют все виртуальными классами (т.е.eigenclasses и include classes) метаклассы. Некоторые называют Class метаклассом. Даже в самом исходном коде Ruby слово «метакласс» используется для обозначения вещей, которые не являются метаклассами.

23
ответ дан 3 December 2019 в 14:18
поделиться

Ваш обновленный вопрос теперь выглядит иначе. Если я вас правильно понял, вы хотите подключиться к распределению и инициализации объектов, что не имеет абсолютно ничего общего с метаклассами. (Но вы по-прежнему не пишете, что вы действительно хотите делать, так что я все равно могу отключиться.)

В некоторых объектно-ориентированных языках объекты создаются конструкторами. Однако в Ruby нет конструкторов. Конструкторы - это всего лишь фабричные методы (с дурацкими ограничениями); нет причин использовать их на хорошо разработанном языке, если вместо этого вы можете просто использовать (более мощный) фабричный метод.

Создание объекта в Ruby работает следующим образом: построение объекта делится на две фазы: размещение и инициализация . Распределение выполняется общедоступным методом класса allocate , который определяется как метод экземпляра класса Class и обычно никогда не переопределяется. (На самом деле, я не думаю, что вы на самом деле можете переопределить его.) Он просто выделяет пространство памяти для объекта и устанавливает несколько указателей, однако объект на данный момент не может использоваться.

Здесь на помощь приходит инициализатор: это метод экземпляра с именем initialize , который устанавливает внутреннее состояние объекта и переводит его в согласованное, полностью определенное состояние, которое может использоваться другими объектами.

Итак, чтобы полностью создать новый объект, вам нужно сделать следующее:

x = X.allocate
x.initialize

[Примечание: программисты Objective-C могут это понять.]

Однако, поскольку слишком легко забыть вызвать initialize , и, как правило, объект должен быть полностью допустимым после построения, существует удобный фабричный метод под названием Class # new , который делает все, что работает за вас, и выглядит примерно так:

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

    return obj
  end
end
{ {1}}

[Примечание: на самом деле initialize является закрытым, поэтому необходимо использовать отражение для обхода таких ограничений доступа: obj.send (: initialize, * args, & block ) ]

Это, кстати, причина, по которой для создания объекта вы вызываете метод открытого класса Foo.new , но вы реализуете метод частного экземпляра Foo # initialize , что, кажется, сбивает с толку многих новичков.

Однако ничего из этого никоим образом не встроено в язык.Тот факт, что основной фабричный метод для любого класса обычно называется new , является просто соглашением (и иногда мне хотелось бы, чтобы он был другим, потому что он похож на конструкторы в Java, но полностью ] другой). В других языках у конструктора должно быть определенное имя. В Java он должен иметь то же имя, что и класс, что означает, что а) может быть только один конструктор и б) анонимные классы не могут иметь конструкторов, потому что у них нет имен. В Python фабричный метод должен называться __ new __ , что опять же означает, что может быть только один. (И в Java, и в Python вы, конечно, можете иметь разные фабричные методы, но их вызов выглядит иначе, чем вызов по умолчанию, тогда как в Ruby (и в Smalltalk, откуда возник этот шаблон) он выглядит точно так же.)

В Ruby , может быть сколько угодно фабричных методов с любым именем, а фабричный метод может иметь много разных имен. (Для классов коллекций, например, фабричный метод часто имеет псевдоним [], что позволяет писать List [1, 2, 3] вместо List.new (1, 2) , 3) , который больше похож на массив, что подчеркивает коллекционную природу списков.)

Вкратце:

  • стандартизированный заводской метод - Foo.new , но это может быть что угодно
  • Foo.new вызывает allocate для выделения памяти для пустого объекта foo
  • Foo.new затем вызывает foo.initialize , т.е.метод экземпляра Foo # initialize
  • все три из них являются такими же методами, как и любые другие, которые вы можете отменить, переопределить, переопределить, обернуть, использовать псевдоним и еще много чего
  • , кроме allocate , которому необходимо выделить память внутри среды выполнения Ruby, чего нельзя сделать в Ruby

В Python, __ new __ примерно соответствует как new , так и allocate в Ruby, а __ init __ точно соответствует initialize в Ruby. Основное отличие состоит в том, что в Ruby new вызывает initialize , тогда как в Python среда выполнения автоматически вызывает __ init __ после __ new __ .

Например, вот класс, который позволяет создавать максимум 2 экземпляра:

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!
12
ответ дан 3 December 2019 в 14:18
поделиться