Nano Hash - криптовалюты, майнинг, программирование

Оборачиваем все возможные вызовы методов класса в блок try/except

Я пытаюсь обернуть все методы существующего класса (не моего создания) в пакет try/except. Это может быть любой класс, но я буду использовать здесь класс pandas.DataFrame в качестве практического примера.

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

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

Этот пост был весьма полезен (особенно @martineau Python-3 ответ), но у меня возникли проблемы с его адаптацией. Ниже я ожидал, что второй вызов (обернутого) метода info() выдаст вывод на печать, но, к сожалению, этого не происходит.

#!/usr/bin/env python3

import functools, types, pandas

def method_wrapper(method):
    @functools.wraps(method)
    def wrapper(*args, **kwargs): #Note: args[0] points to 'self'.
        try:
            print('Calling: {}.{}()... '.format(args[0].__class__.__name__,
                                                method.__name__))
            return method(*args, **kwargs)
        except Exception:
            print('Exception: %r' % sys.exc_info()) # Something trivial.
            #<Actual code would append that exception info to a list>.
    return wrapper


class MetaClass(type):
    def __new__(mcs, class_name, base_classes, classDict):
        newClassDict = {}
        for attributeName, attribute in classDict.items():
            if type(attribute) == types.FunctionType: # Replace it with a
                attribute = method_wrapper(attribute) # decorated version.
            newClassDict[attributeName] = attribute
        return type.__new__(mcs, class_name, base_classes, newClassDict)

class WrappedDataFrame2(MetaClass('WrappedDataFrame',
                                  (pandas.DataFrame, object,), {}),
                                  metaclass=type):
    pass

print('Unwrapped pandas.DataFrame().info():')
pandas.DataFrame().info()

print('\n\nWrapped pandas.DataFrame().info():')
WrappedDataFrame2().info()
print()

Это выводит:

Unwrapped pandas.DataFrame().info():
<class 'pandas.core.frame.DataFrame'>
Index: 0 entries
Empty DataFrame

Wrapped pandas.DataFrame().info():   <-- Missing print statement after this line.
<class '__main__.WrappedDataFrame2'>
Index: 0 entries
Empty WrappedDataFrame2

В итоге,...

>>> unwrapped_object.someMethod(...)
# Should be mirrored by ...

>>> wrapping_object.someMethod(...)
# Including signature, docstring, etc. (i.e. all attributes); except that it
# executes inside a try/except suite (so I can catch exceptions generically).

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

Ответы:


1

давно не виделись. ;-) На самом деле прошло так много времени, что вам уже все равно, но если вам (или другим) интересно...

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

mockpandas.py:

""" Fake pandas module. """

class DataFrame:
    def info(self):
        print('pandas.DataFrame.info() called')
        raise RuntimeError('Exception raised')

Ниже приведен код, который, кажется, делает то, что вам нужно, реализуя предложение @Blckknght по итерации через MRO, но игнорирует ограничения, отмеченные в его ответе, которые могут возникнуть в результате этого). Это не очень красиво, но, как я уже сказал, похоже, что это работает, по крайней мере, с созданной мной фиктивной библиотекой pandas.

import functools
import mockpandas as pandas  # mock the library
import sys
import traceback
import types

def method_wrapper(method):
    @functools.wraps(method)
    def wrapper(*args, **kwargs): # Note: args[0] points to 'self'.
        try:
            print('Calling: {}.{}()... '.format(args[0].__class__.__name__,
                                                method.__name__))
            return method(*args, **kwargs)
        except Exception:
            print('An exception occurred in the wrapped method {}.{}()'.format(
                    args[0].__class__.__name__, method.__name__))
            traceback.print_exc(file=sys.stdout)
            # (Actual code would append that exception info to a list)

    return wrapper

class MetaClass(type):
    def __new__(meta, class_name, base_classes, classDict):
        """ See if any of the base classes were created by with_metaclass() function. """
        marker = None
        for base in base_classes:
            if hasattr(base, '_marker'):
                marker = getattr(base, '_marker')  # remember class name of temp base class
                break  # quit looking

        if class_name == marker:  # temporary base class being created by with_metaclass()?
            return  type.__new__(meta, class_name, base_classes, classDict)

        # Temporarily create an unmodified version of class so it's MRO can be used below.
        TempClass = type.__new__(meta, 'TempClass', base_classes, classDict)

        newClassDict = {}
        for cls in TempClass.mro():
            for attributeName, attribute in cls.__dict__.items():
                if isinstance(attribute, types.FunctionType):
                    # Convert it to a decorated version.
                    attribute = method_wrapper(attribute)
                    newClassDict[attributeName] = attribute

        return type.__new__(meta, class_name, base_classes, newClassDict)

def with_metaclass(meta, classname, bases):
    """ Create a class with the supplied bases and metaclass, that has been tagged with a
        special '_marker' attribute.
    """
    return type.__new__(meta, classname, bases, {'_marker': classname})

class WrappedDataFrame2(
        with_metaclass(MetaClass, 'WrappedDataFrame', (pandas.DataFrame, object))):
    pass

print('Unwrapped pandas.DataFrame().info():')
try:
    pandas.DataFrame().info()
except RuntimeError:
    print('  RuntimeError exception was raised as expected')

print('\n\nWrapped pandas.DataFrame().info():')
WrappedDataFrame2().info()

Вывод:

Unwrapped pandas.DataFrame().info():
pandas.DataFrame.info() called
  RuntimeError exception was raised as expected


Wrapped pandas.DataFrame().info():
Calling: WrappedDataFrame2.info()...
pandas.DataFrame.info() called
An exception occurred in the wrapped method WrappedDataFrame2.info()
Traceback (most recent call last):
  File "test.py", line 16, in wrapper
    return method(*args, **kwargs)
  File "mockpandas.py", line 9, in info
    raise RuntimeError('Exception raised')
RuntimeError: Exception raised

Как показано выше, method_wrapper() декорированная версия используется методами обернутого класса.

29.07.2017

2

Ваш метакласс применяет декоратор только к методам, определенным в классах, которые являются его экземплярами. Он не украшает унаследованные методы, так как их нет в classDict.

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

20.04.2016
  • Является ли исправление обезьяны напрямую pd.DataFrame одним из решений? 20.04.2016
  • Исправление обезьяны может быть вариантом. Я также написал автору Pandas, чтобы получить его мнение (вне StackOverflow). Может быть, у него есть какие-то мысли, и я с радостью поделюсь ими, когда свяжусь с ним. Стараюсь пока не уходить слишком далеко от проторенной дорожки. знак равно 20.04.2016
  • Спасибо за отзыв @Blckknght. Будет обдумывать ваш ответ больше. 20.04.2016
  • Привет @Blckknght. Спасибо за интересный ответ о подходе MRO. Что касается действительной проблемы, которую вы упомянули («множество уровней наследования»), вы имеете в виду в результате возможного подкласса MetaClass и/или «WrappedDataFrame2» в будущем? Или какой-то другой побочный эффект? (Кстати, «MetaClass» здесь предназначен для одноразового/эксклюзивного частного использования). Спасибо. 21.04.2016
  • Новые материалы

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

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

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

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..