Почему слияние системных классов Python с пользовательскими классами менее желательно, чем подключение механизма импорта?

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

Я прочитал некоторые ресурсы, а именно ответ @Omnifarious на этот вопрос python-importing-from-builtin-library-when -модуль-с-имя-существует

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

Я реализовал механизм импорта, но мы решили, что это не то направление, в котором нам хотелось бы двигаться, поскольку оно слишком сильно зависит от среды. Решение объединить классы в гибрид, а не полагаться на механизмы импорта, кажется лучшим подходом в моем случае.

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

Вот фрагмент кода, в котором вставка должна перехватить сообщение сокета перед его отправкой:

class vector_clock:

  def __init__(self):
   """
   Initiate the clock with the object
   """
   self.clock = [0,0]

  def sendMessage(self):
   """
   Send Message to the server
   """
   self.msg = "This is the test message to that will be interposed on"
   self.vector_clock.increment(0) # We are clock position 0

   # Some extraneous formatting details removed for brevity….
   # connectAndSend needs interpositioning to include the vector clock

   self.client.connectAndSend(totalMsg);
   self.client.s.close()

person jspacek    schedule 20.05.2014    source источник
comment
Пожалуйста, подчеркните, в чем вопрос. Я думаю, вы получили отрицательный голос, потому что неясно, о чем вы спрашиваете.   -  person kapa    schedule 21.05.2014
comment
@kapa Большое спасибо за ваше предложение! Я отредактирую, чтобы было понятнее.   -  person jspacek    schedule 21.05.2014
comment
Заголовок звучит так, будто ты троллишь, а не цитируешь :/   -  person    schedule 21.05.2014
comment
@Will - О нет, правда?! Я использую формулировку из исходного ответа, которую Всевышний назвал своим решением. Я обновлю его, чтобы сделать его менее провокационным, так как непонятно, почему я упомянул его таким образом.   -  person jspacek    schedule 21.05.2014
comment
Теперь намного лучше, и первоначальная проблема также решена: вы можете комментировать везде :).   -  person kapa    schedule 21.05.2014
comment
Взглянули ли вы на сокет с обезьяньим исправлением, как gevent (gevent.org/intro .html#monkey-patching)? Я не уверен, что это то, что вы имеете в виду под слиянием или нет, но люди из gevent довольно успешно используют этот подход в проекте, используемом многими людьми.   -  person dano    schedule 22.05.2014
comment
@kapa Да, теперь я могу комментировать! Так будет намного лучше, спасибо за вашу помощь :)   -  person jspacek    schedule 22.05.2014
comment
@dano Это очень интересная статья. Я слышал о динамических функциях, но только в той мере, в какой я учился на курсах переводчика! Хотя я и не знал, что их называют обезьяньими исправлениями. Я также нашел эту ссылку blog.codinghorror.com/monkeypatching-for-humans. Обычно это не считается хорошей практикой, потому что ее очень сложно отлаживать, но я не понимаю, почему это было бы проблемой, если бы я использовал ее только для добавления к сообщению. Я посмотрю на это - спасибо, что обратили мое внимание на этот вариант!   -  person jspacek    schedule 22.05.2014


Ответы (1)


Насколько я понимаю ваш пост, вы хотите изменить существующую библиотеку сокетов, чтобы внедрить в нее свои собственные функции.

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

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

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

Если вы полностью понимаете это и все еще думаете, что ваше решение является хорошим, я говорю: «Дерзайте». Однако рассматривали ли вы какие-либо альтернативы?

Если вам просто нужно внедрить эту функциональность для определенного набора библиотек, которые вы используете, я бы предложил сделать что-то вроде исправления: https://docs.python.org/3/library/unittest.mock.html#unittest.mock.patch

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

PS. Я не думаю, что ваша ситуация требует подключения механизма импорта.

person Brendan F    schedule 24.05.2014
comment
Мой файл init.py в моей векторной библиотеке меток времени вызывает статическую функцию с patcher = mock.patch('__main__.socket.socket', SVSocket.SVSocket). Одна сложная проблема заключалась в том, чтобы остановить патч, чтобы я мог создать простую переменную socket.socket внутри класса декоратора SVSocket. Для этого я использовал mock.patch.stopall(). Работа продолжается, но полный код здесь, если он кому-то пригодится bitbucket.org /bestchai/shivector/src/default/python - person jspacek; 20.07.2014
comment
mock.patch.stopall() есть проблема bugs.python.org/issue21239. Исправленная версия mock.py включена в ссылку, которую я с большим успехом использовал для версий Python ‹ 3.5. - person jspacek; 12.08.2014