LINUX.ORG.RU

[python]Определить новый метод в импортированном модуле.

 


0

0

Итак, есть модуль pysvn, в нём есть класс Client и его метод log(), который позволяет извечь некоторую информацию о коммите. Я хочу определить метод Client.author(), который будет возвращать строку-имя пользователя. Если просто написать

class Client:
    def author(self, repository_url, revision):
        return self.log(repository_url, revision_start=revision, revision_end=revision)[0]['author']
# Запрашиваем информацию по ревизии revision из репозитария по ссылке, получаем в ответ список с единственным элементом-словарём, поле 'author' в котором содержит имя автора. 

То при попытке использования этого метода client.author(myRepoURL, myRevision) получим

AttributeError: author

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

Как в python'е добавить к классу из загружаемого модуля метод?

★★★★★
Ответ на: комментарий от Sphinx

Классы закрыты.

>from pysvn import Client as _Client

>class Client(_Client):

> # insert your code here


То есть классы не являются открытыми как, например, в Ruby? Интересно.

Спасибо, Sphinx.

Camel ★★★★★
() автор топика

В питоне не силен, но быть может:

def client_author(self, repository_url, revision):
  return self.log(repository_url, revision_start=revision,  revision_end=revision)[0]['author']

Client.author = client_author

dizza ★★★★★
()
Ответ на: комментарий от dizza

Нет, так менять словарь типа нельзя.

Если очень хочется, можно переопределить стандартный метакласс, чтобы
он добавлял нужный метод к импортируемому классу Client.

Но имхо лучше и чище в данном случае просто сделать новый тип.

Sphinx ★★☆☆
()
Ответ на: Классы закрыты. от Camel

>То есть классы не являются открытыми как, например, в Ruby? Интересно.

Самое забавное, что термин "monkeypatching" пошел таки из питона, точнее из зопы. Я так и не удосужился найти и посмотреть, как и что они там делали. Может кто подкинет ссылку?

volh ★★
()
Ответ на: Классы закрыты. от Camel

Не знаю, как там в этом вашем руби, но в python тебе ничего не мешает проманкипатчить класс, как например у dizza.

anonymous4
()
Ответ на: комментарий от volh

> Самое забавное, что термин "monkeypatching" пошел таки из питона, точнее из зопы.

Не зря её так назвали :)

const86 ★★★★★
()
Ответ на: Классы закрыты. от Camel

> То есть классы не являются открытыми как, например, в Ruby?

Открыты для манкипатчинга, кроме встроенных типов в CPython, где они закрыты для увеличения быстродействия.

dccp
()
Ответ на: комментарий от Sphinx

> Нет, так менять словарь типа нельзя.

Можно. Но лучше этого никогда не делать, а использовать наследование.

dccp
()
Ответ на: комментарий от dccp

> Нет, так менять словарь типа нельзя.

> Можно. Но лучше этого никогда не делать, а использовать наследование.

Почему? Уместен ли вообще Питон, если не пользоваться его динамическими фишками? Вот недавно спорил с коллегами по поводу замыканий. Они меня убеждали, что замыкания - зло, и надо их везде заменять на объекты. Так ведь если ограничиваться рамками pure OOP и всяких паттернов, то быстрее и надежнее будет сразу на C++ писать. Без динамических качеств тот же Питон вообще не интересен. Он и так то весьма убог для динамического языка :/

Hjorn
()
Ответ на: комментарий от Hjorn

Так замыкания вовсе не являются динамической фишкой. В трижды насквозь статичном OCaml они тоже есть.

Zenom ★★★
()
Ответ на: комментарий от Hjorn

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

isden ★★★★★
()
Ответ на: комментарий от isden

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

профиты есть. сам я являюсь неизлечимым СИшником, но от «замыканий» в жабаскрипте и перле кипятком писал. очень годная фича, часто помогает не только сократить код скрипта, но и сделать его более читаемым.

на правах ЗЫ/ЖЖ: в руби замыкания не понравились, хотя сам язык очень интересный. в питоне вроде неплохо сделано, но сам язык не понравился (нет, не отступами).

arsi ★★★★★
()
Ответ на: комментарий от isden

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

Простой пример: в браузере надо установить текст в заголовке таба из элемента title HTML-документа. Для этого надо дождаться загрузки документа. Мы можем зарегистрировать callback, который будет вызван, когда документ будет загружен. Регистрируем в качестве этого callback-а замыкание, у которого виджет, описывающий заголовок таба является свободной переменной. Профит в том, что не надо этот виджет выпячивать наружу. И код получается более кратким.

Zenom ★★★
()
Ответ на: комментарий от Hjorn

> Без динамических качеств тот же Питон вообще не интересен. Он и так то весьма убог для динамического языка :/

Афигеть. Хоть я и ненавижу все динамические языки оптом, в чем "убожество Питона как динамического языка"?

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

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

Hjorn
()
Ответ на: комментарий от Hjorn

> Почему?

Горький опыт разработчиков Zope показал, что манкипатчинг надо избегать любой ценой. Но вы, конечно, можете использовать. А те кто поумнее будут учиться на чужих ошибках.

dccp
()
Ответ на: комментарий от dccp

Зачем тогда эта фича присутствует в языке? Гвидо не уследил? Неужели раздувать иерархии на каждый чих - это лучше?

Hjorn
()
Ответ на: комментарий от Hjorn

> Неужели раздувать иерархии на каждый чих - это лучше?

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

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

dccp
()
Ответ на: комментарий от dccp

> стандартный, общепринятый, надежный, реюзабельный

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

> но как только появятся серьезные проекты

Серьёзные проекты на Питоне? Нонсенс. Хотя сейчас это модно, знаю.

Hjorn
()
Ответ на: комментарий от tailgunner

> Афигеть. Хоть я и ненавижу все динамические языки оптом, в чем "убожество Питона как динамического языка"?

Питон не знаю, поэтому спрашиваю "на вскидку":

1. он позволяет программно создать новую локальную переменную текущего блока?

2. он позволяет обратиться или создать новую локальную переменную из того блока, откуда была вызвана наша функция/метод?

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от www_linux_org_ru

п.2 не ясен вышел

2. он позволяет обратиться к локальной переменной того блока, откуда была вызвана наша функция/метод?

3. он позволяет создать новую локальную переменную в том блоке, откуда была вызвана наша функция/метод?

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от tailgunner

Еще:

4. он позволяет создать анонимную локальную переменную в том блоке, из которого была вызвана наша функция/метод?

5. он позволяет создавать переменные с *динамической* областью видимости?

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от Hjorn

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

Hjorn
()
Ответ на: комментарий от Hjorn

Есть тамо встроеннии функции locals() и globals() которые тебе возвращают контекст текущиго фрейма и глобальнии контекст ето словари туда можно читать и писать (правдо с оговорками особенно locals().

Та на самом деле то они не нужни томо че есть еще есть exec. То exec он умеет че любое кот выполнять в тикущем контексти можешь сделать exec 'a = 1' и вот тибе локальное переменное. То можешь сделать exec 'global asdf; asdf=1' и вот тебе глобальное перименное. То в питоне 3 есть еще nonlocal е-то как раз вышестоящий scope вот и делаи с ни м че хочиш.

ce_tamotko_za_uzori
()
Ответ на: комментарий от ce_tamotko_za_uzori

Ну да, про locals() забыл. В общем получается, что в Питоне можно динамически работать только с глобальным и текущим контекстами. Ну и косвенно с тем, что в замыкании связано.

Hjorn
()
Ответ на: комментарий от isden

> а зачем они вообще нужны, эти ваши замыкания?

Сэкономить на паре параметров при вызове функции. Актуально, имхо, только если весь код состоит из маленьких хитрожопых функций.

LamerOk ★★★★★
()
Ответ на: комментарий от LamerOk

>> а зачем они вообще нужны, эти ваши замыкания?

> Сэкономить на паре параметров при вызове функции. Актуально, имхо, только если весь код состоит из маленьких хитрожопых функций.

Вовсе нет. Вот в libcurl замыкания юзаются, или в posix threads, только там приходится писать f(......, void g(void*), void* g_parameter) вместо строгой типизации.

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от Hjorn

> Нет, это вам не тикль...

и не перл.

perl -e 'sub f(){print "<$a>";} f(); local $a=1; f(); '

выхлоп: <><1>, а при наличии -W ругнется, что в первом вызове $a не определена.

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от ce_tamotko_za_uzori

в locals() писать ниче нельзя -- http://docs.python.org/library/functions.html#locals

насчет exec() -- хотелось бы потверждения, что он может добавлять локальные переменные, т.к. его описаловка (там же) дает повод сомневаться в этом.

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от www_linux_org_ru

1. он позволяет программно создать новую локальную переменную текущего блока?

Да. exec

2. он позволяет обратиться к локальной переменной того блока, откуда была вызвана наша функция/метод?

Да. inspect.currentframe().f_back.f_locals

3. он позволяет создать новую локальную переменную в том блоке, откуда была вызвана наша функция/метод?

Да. exec in f_locals

4. он позволяет создать анонимную локальную переменную в том блоке, из которого была вызвана наша функция/метод?

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

5. он позволяет создавать переменные с *динамической* областью видимости?

Явным образом нет. Но можно использовать 2 и 3.

>>> import inspect
>>> def func():
...     try:
...         print inspect.currentframe().f_back.f_locals['a']
...     except KeyError:
...         print "'a' is not defined"
...
>>> func()
'a' is not defined
>>> a = 1
>>> func()
1

Поскольку есть доступ к фреймам, объекту code и возможность изменять байткод, то можно даже эмулировать блоки из ruby.

dccp
()
Ответ на: комментарий от www_linux_org_ru

насчет exec() — хотелось бы потверждения

>>> def a():
...  b()
...  print var
...
>>> def b():
...  exec 'var=1' in inspect.currentframe().f_back.f_locals, inspect.currentframe().f_back.f_globals
...
>>> a()
1

Надеюсь все это никогда, никогда, никогда не будет использоваться в питон-сообществе.

dccp
()
Ответ на: комментарий от dccp

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

dccp
()
Ответ на: комментарий от dccp

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

dccp
()
Ответ на: комментарий от dccp

> Надеюсь все это никогда, никогда, никогда не будет использоваться в питон-сообществе.

а паттерн-матчинг ты как сделаешь без добавления локальных переменных, а? только некрасиво.

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от dccp

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

Синтаксис полностью выдуман, но вероятно будет понятен:

match my_list
  case 1:a:_   do print(a)
  case 2:b:c:_ do print(b,c)
  default      do print("error")
end
www_linux_org_ru ★★★★★
()
Ответ на: комментарий от Hjorn

> Никогда не видел этого в чужом коде.

Это тонкий намек, что это никто не использует. И вам не следует.

dccp
()
Ответ на: комментарий от dccp
...         print inspect.currentframe().f_back.f_locals['a']

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

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от www_linux_org_ru

> а паттерн-матчинг ты как сделаешь без добавления локальных переменных, а

Да, создание DSL это слабейшая сторона питона из-за строгого и неизменяемого синтаксиса.

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

Но я нигде не видел, чтобы кто-то хотел такого же странного как вы.

dccp
()
Ответ на: комментарий от www_linux_org_ru

Это не решение задачи на питоне. Это попытка сделать из питона какой-то другой язык и решить задачу на нем.

Если вам не решить вашу задачу без динамическая видимости переменных и паттерн матчинга - питон не ваш выбор.

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

dccp
()
Ответ на: комментарий от dccp

Да, создание DSL это слабейшая сторона питона из-за строгого и неизменяемого синтаксиса.

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

perl -e 'sub f(){print "<$a>";} f(); { local $a=1; f(); } f(); '

<><1><>
www_linux_org_ru ★★★★★
()
Ответ на: комментарий от dccp

> Если вам не решить вашу задачу без динамическая видимости переменных и паттерн матчинга - питон не ваш выбор.

Я, често говоря, тут задачу не решаю и потроллить пришел насчет того, что не все в питоне есть, что должно быть в динамическом языке :-) про exec() & locals() было интересно, спасибо.

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от www_linux_org_ru

Оказалось, что есть довольно многое, только никто не пользуется :-/ У меня на работе питонщики даже на лямбды косо смотрят.

Hjorn
()
Ответ на: комментарий от Hjorn

> Оказалось, что есть довольно многое, только никто не пользуется :-/ У меня на работе питонщики даже на лямбды косо смотрят.

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

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от Hjorn

> Оказалось, что есть довольно многое, только никто не пользуется

Что тут удивительного-то? Люди, обычно, решают реальные задачи наиболее безопасным, простым и поддерживаемым способом. Упоение "довольно многим" проходит с опытом.

> У меня на работе питонщики даже на лямбды косо смотрят.

И правильно делают. Лямбды в питоне практически бесполезны, с очень узкой спецификой применения. Даже и не припомню когда я их в последний раз использовал. Всегда лучше обойтись list comprehensions, модулем operator или именованной функцией.

dccp
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.