Каковы некоторые (конкретные) примеры использования для метаклассов?

Примечание: Преобразование в строковое преобразование

Это происходит просто, если вы пытаетесь рассматривать массив как строку:

$arr = array('foo', 'bar');

echo $arr;  // Notice: Array to string conversion
$str = 'Something, ' . $arr;  // Notice: Array to string conversion

Массив не может быть просто echo 'd или конкатенируется с строкой, потому что результат не определен. PHP будет использовать строку «Array» вместо массива и вызвать уведомление, чтобы указать, что это, вероятно, не то, что было предназначено, и что вы должны проверять свой код здесь. Вероятно, вы захотите что-то вроде этого:

echo $arr[0];  // displays foo
$str = 'Something ' . join(', ', $arr); //displays Something, foo, bar

Или зациклируйте массив:

foreach($arr as $key => $value) {
    echo "array $key = $value";
    // displays first: array 0 = foo
    // displays next:  array 1 = bar
}

Если это уведомление появляется где-то, чего вы не ожидаете, это означает переменную, которую вы мысль - это строка, на самом деле это массив. Это означает, что у вас есть ошибка в коде, которая делает эту переменную массивом вместо ожидаемой строки.

103
задан martineau 29 June 2018 в 21:18
поделиться

9 ответов

У меня есть класс, который обрабатывает неинтерактивное графическое изображение как frontend к Matplotlib. Однако при случае каждый хочет сделать интерактивное графическое изображение. Только с парой функций я нашел, что смог увеличить количество числа, вызов тянут вручную, и т.д., но я должен был сделать их прежде и после каждого вызова графического изображения. Таким образом для создания и интерактивной обертки графического изображения и внеэкранной обертки графического изображения я нашел, что было более эффективно сделать это через метаклассы, обернув соответствующие методы, чем сделать что-то как:

class PlottingInteractive:
    add_slice = wrap_pylab_newplot(add_slice)

Этот метод не не отстает от изменений API и так далее, но тот, который выполняет итерации по атрибутам класса в __init__ прежде, чем сбросить атрибуты класса, более эффективен и совершенствует вещи:

class _Interactify(type):
    def __init__(cls, name, bases, d):
        super(_Interactify, cls).__init__(name, bases, d)
        for base in bases:
            for attrname in dir(base):
                if attrname in d: continue # If overridden, don't reset
                attr = getattr(cls, attrname)
                if type(attr) == types.MethodType:
                    if attrname.startswith("add_"):
                        setattr(cls, attrname, wrap_pylab_newplot(attr))
                    elif attrname.startswith("set_"):
                        setattr(cls, attrname, wrap_pylab_show(attr))

, Конечно, могли бы быть лучшие способы сделать это, но я нашел, что это эффективно. Конечно, это могло также быть сделано в __new__ или __init__, но это было решением, я нашел самое простое.

23
ответ дан Ali Afshar 24 November 2019 в 04:18
поделиться

Путем я использовал метаклассы, должен был предоставить некоторые атрибуты классам. Возьмите, например:

class NameClass(type):
    def __init__(cls, *args, **kwargs):
       type.__init__(cls, *args, **kwargs)
       cls.name = cls.__name__

поместит имя атрибут на каждом классе, которому установят метакласс для указания на NameClass.

3
ответ дан hyperboreean 24 November 2019 в 04:18
поделиться

Метаклассы не заменяют программирование! Они - просто прием, который может автоматизировать или сделать более изящным некоторые задачи. Хороший пример этого библиотека Pygments подсветки синтаксиса. Это имеет класс, названный RegexLexer, который позволяет пользователю определить ряд lexing правила как регулярные выражения на классе. Метакласс используется для превращения определений в полезный синтаксический анализатор.

Они похожи на соль; это просто в использовании слишком много.

3
ответ дан Benjamin Peterson 24 November 2019 в 04:18
поделиться

Я думал то же самое только вчера, и достичь единой точки зрения. Сложности в коде, вызванном попытками сделать его большим количеством описания обычно, делают кодовую базу тяжелее, чтобы поддержать, тяжелее читать и меньше pythonic, по-моему. Это также обычно требует большого количества copy.copy () луг (чтобы поддержать наследование и скопировать от класса до экземпляра) и означает, что необходимо посмотреть во многих местах для наблюдения то, что продолжается (всегда смотрящий от метакласса), который идет вразрез с мелкой частицей Python также. Я выбирал через formencode и код sqlalchemy, чтобы видеть, стоил ли такой декларативный стиль того и ясно нет. Такой стиль нужно оставить дескрипторам (таким как свойство и методы) и неизменные данные. Ruby имеет лучшую поддержку таких декларативных стилей, и я рад, что базовый язык Python не спускается по тому маршруту.

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

class test(baseclass_with_metaclass):
    method_maker_value = "hello"

мог иметь метакласс, который генерировал метод в том классе со специальными свойствами на основе "привет" (скажите метод, который добавил "привет" до конца строки). Для пригодности для обслуживания могло быть хорошо удостовериться, что Вы не должны были писать метод в каждом подклассе, Вы делаете вместо этого все, что необходимо определить, method_maker_value.

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

5
ответ дан David Raznick 24 November 2019 в 04:18
поделиться

Единственное время я использовал метаклассы в Python, было при записи обертки для API Flickr.

Моя цель состояла в том, чтобы очистить сайт API flickr и динамично генерировать полную иерархию классов для разрешения доступа API с помощью объектов Python:

# Both the photo type and the flickr.photos.search API method 
# are generated at "run-time"
for photo in flickr.photos.search(text=balloons):
    print photo.description

Так в том примере, потому что я генерировал весь API Flickr Python от веб-сайта, я действительно не знаю определения классов во времени выполнения. Способность динамично генерировать типы была очень полезна.

5
ответ дан Triptych 24 November 2019 в 04:18
поделиться

Метаклассы могут быть удобными для конструкции Предметно-ориентированных языков в Python. Конкретными примерами является Django, декларативный синтаксис SQLObject схем базы данных.

А основной пример от Метакласс консерватора А Ian Bicking:

метаклассы, которые я использовал, должны были, прежде всего, поддерживать своего рода декларативный стиль программирования. Например, рассмотрите схему проверки:

class Registration(schema.Schema):
    first_name = validators.String(notEmpty=True)
    last_name = validators.String(notEmpty=True)
    mi = validators.MaxLength(1)
    class Numbers(foreach.ForEach):
        class Number(schema.Schema):
            type = validators.OneOf(['home', 'work'])
            phone_number = validators.PhoneNumber()

Некоторые другие методы: Ингредиенты для Создания DSL в Python (PDF).

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

number_validator = [
    v.OneOf('type', ['home', 'work']),
    v.PhoneNumber('phone_number'),
]

validators = [
    v.String('first_name', notEmpty=True),
    v.String('last_name', notEmpty=True),
    v.MaxLength('mi', 1),
    v.ForEach([number_validator,])
]

Это не прекрасно, но уже существует почти нулевое волшебство, никакая потребность в метаклассах и улучшенная однородность.

6
ответ дан Tripp Lilley 24 November 2019 в 04:18
поделиться

Давайте запустимся с классической кавычки Tim Peter:

Метаклассы являются более глубоким волшебством, чем 99% пользователей должны когда-либо волноваться о. Если Вы задаетесь вопросом, нужны ли Вам они, Вы не делаете (люди, которым на самом деле нужны они, знают с уверенностью, что они нуждаются в них и не нуждаются в объяснении о почему). Tim Peters (c.l.p отправляют 22.12.2002)

Однако я (периодически) натыкался на истинное использование метаклассов. Тот, который приходит на ум, находится в Django, где все Ваши модели наследовались моделям. Модель. модели. Модель, в свою очередь, делает некоторое серьезное волшебство обернуть Ваши модели DB с совершенством Django ORM. То волшебство происходит посредством метаклассов. Это создает весь способ классов исключений, классы менеджера, и т.д. и т.д.

Видят django/db/models/base.py, класс ModelBase () в течение начала истории.

17
ответ дан Peter Rowell 24 November 2019 в 04:18
поделиться

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

  • подклассы Отслеживания, обычно для регистрации обработчиков. Это удобно при использовании сменной установки стиля, где Вы хотите зарегистрировать обработчик для конкретной вещи просто путем разделения на подклассы и установки нескольких атрибутов класса. например, предположите запись обработчика для различных музыкальных форматов где каждый класс реализует соответствующие методы (игра / получают теги и т.д.) для ее типа. Добавление обработчика для нового типа становится:

    class Mp3File(MusicFile):
        extensions = ['.mp3']  # Register this type as a handler for mp3 files
        ...
        # Implementation of mp3 methods go here
    

    метакласс тогда поддерживает словарь {'.mp3' : MP3File, ... } и т.д. и создает объект соответствующего типа, когда Вы запрашиваете обработчик через функцию фабрики.

  • Изменяющееся поведение. Можно хотеть присоединить особое значение к определенным атрибутам, приводящим к измененному поведению, когда они присутствуют. Например, можно хотеть искать методы с именем _get_foo и _set_foo и прозрачно преобразовать их в свойства. Как реальный пример, вот рецепт, который я записал для предоставления большего количества подобных C определений структуры. Метакласс используется, чтобы преобразовать заявленные объекты в строку формата структуры, обрабатывая наследование и т.д., и произвести класс, способный к контакту с ним.

    Для других реальных примеров, смотрите на различный ORMs, как sqlalchemy's ORM или sqlobject. Снова, цель состоит в том, чтобы интерпретировать определения (здесь определения столбца SQL) с конкретным значением.

35
ответ дан S.Lott 24 November 2019 в 04:18
поделиться

Вы никогда абсолютно потребность для использования метакласса, так как можно всегда создавать класс, который делает то, что Вы хотите использовать наследование или агрегирование класса, который Вы хотите изменить.

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

существует превосходное статья DeveloperWorks о метаклассификации в Python, который мог бы помочь. Статья Wikipedia также довольно хороша.

4
ответ дан Charlie Martin 24 November 2019 в 04:18
поделиться
Другие вопросы по тегам:

Похожие вопросы: