Pull to refresh
124
0
Михаил Стадник @Mikhus

Software Engineer

Send message
Спасибо, работаю над исправлением
UPD: исправлено
Спасибо, интересно, возьму себе «на карандаш»… Как минимум в планах были knob-buttons, arc-gauges. Подобные чарты тоже выглядят интересно
Опишите подробнее, что имеете ввиду, все что попадает под категорию «gauges» готов рассматривать как потенциальную идею для расширения библиотеки…
Это естественно. Там анимация просто для примера через setInterval, поэтому много раз нажали — много таймеров запустили :) Здесь цель была просто показать что анимация есть и работает…
Функцию реализовать можно, но для чего? Приборы призваны отображать значения которые вы им даете. Зачем вам их копировать (если вы их и так знаете)? :)

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

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

Например, пользователи обратились и просят добавить возможность анимировать не стрелку, а циферблат, т.к. они делают компас на приборной панели и это для них критично. И сделать это они ну никак не могут без изменения библиотеки. С другой стороны, раньше с библиотекой поставлялся цифровой шрифт, но пользователи жаловались, что это не вмещается в концепцию минималистичности кода, поэтому его теперь нет, но есть возможность прикручивать любой шрифт по желанию сбоку. Поэтому у меня вопрос — а нужно ли реализовывать копирование в самих приборах? Не теоретически «это бвыло бы круто», а практически — «действительно ли это нужно»?

Ведь можно приделать стотыщпиццот функций, в том числе функию нанесения ответного ядерного удара Марса по Венере, но зачем?
Прошу прощения, но, как вы сказали, как бы "«canvas» уже намекает на это" — это все-таки динамически создаваемая растровая графика (bitmap) а не текст. Возможно вы хотели бы SVG, но
это таки canvas gauges. :)
Поскольку zabbix имеет веб-интерфейс, не думаю, что это невозможно :)
Э… как бы… совсем о другом будет, не?
Продолжу…

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

Кстати, если кто-то может ткнуть меня мордой в то, как обойти парсинг исходников в такой ситуации — я буду просто благодарен и наконец-то стану спать спокойно.

Усложняем модель.

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

Вот тут и поможет моя библиотека. Она позволяет получить get_real_function(). Но это будет доступно только если оба декоратора «зарегистрированы» перед определением класса. При этом декоратор, который используется сверху, переопределяем, подсовывая нативному реальную функцию. И все работает. И овцы целы, и волки сыты. Кстати можно переопределить таким способом оба и тогда можно вообще забить на порядок их следования при написании кода классов.

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

Я специально не хотел описывать этот кейс (он очень специфичный), а подать статью немного в другом ракурсе, как бы «вот библиотека, вот это она умеет». Но не фартануло… :)
Смотрите мой комент выше
Дорогой КО, зачем вы мне это пишете?
Я говорю именно о том, что подобный подход мне не нравится в Python.

Ваш пример:

>>> def m():
...     pass
... 
>>> def m(self):
...     pass
... 
>>> class A(object):
...     f = m
... 
>>> class B(object):
...     f = m
... 
>>> A.f.im_class
<class '__main__.A'>
>>> B.f.im_class
<class '__main__.B'>
>>> m.im_class
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'function' object has no attribute 'im_class'


Теперь объявляем класс с таким задекорированым методом:

>>> def d( fn):
...     print fn.im_class
...     def w(*a, **k):
...             return fn(*a, **k)
...     return w
... 
>>> class X(object):
...     @d
...     def f(self):
...             pass
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in X
  File "<stdin>", line 2, in d
AttributeError: 'function' object has no attribute 'im_class'


Все вы даже определить класс не можете! Чтобы это все таки работало — будете парсить код. Я не вижу другого решения. Вы видите?

И еще раз — я не пишу библиотеку «для парсинга исходников». Я просто использую библиотеку, у которой это внутри.
Вообще-то, если по-честному, я немного лукавлю, говоря, что библиотеки написаны не очень хорошо. Просто сам Python, на мой взгляд устроен не совсем хорошо. Сам факт того, что при декорировании, метод переданый в декоратор становиться unbound функцией и зарефлектить, к какому классу принадлежит данный метод, не представляется возможным без таких вещей, как f.__code__.co_filename, f.__code__.co_firstlineno, и с последующим парсингом исходника с целью найти какому классу принадлежит данный метод. Если же декораторов было несколько, то вы вообще теряете связь с самим исходным методом! Вам опять может стать непонятным для чего это нужно, но ведь, в целом, рефлексии позволяют создавать некоторые абстракции, что может быть полезным при проектировании некоторых библиотек общего назначения. Все было бы гораздо проще, если бы на уровне языка рефлексии, да и реализация декораторов, были бы немного продуманнее.
Я имею на это сказать. Почему по вашему он не ожидает, что он не задекорирован? Как он об этом знает? Вед декоратор только знает о функции, которую он декорирует. Я вед именно эту задачу и решаю — позволить себе знать не только вниз но и вверх. Если он об этом знает, значит он использует мою библиотеку? :)
> И проще написать еще одну, лишь бы не исправлять эти? :)
Ну вам уже не придется так напрягаться — можете воспользоваться моей :)

> Просто исправьте их и судя по вашему рассказу не будет вообще никаких проблем ни с чем.
Да и так нет проблем ни с чем
Правы. Вас это смущает? В конце концов я не агитирую использовать данную библиотеку именно в таком контексте. Можно на это, в конце-концов, посмотреть под другим углом. К примеру, вы ищете решение такой задачи — узнать какие методы в заданном классе задекорированы заданным декоратором. Данная библиотека позволяет задачу решить без парсинга исходного кода. Сам язык такого инструментария не дает. Это что, что-то совершенно бесполезное?
Виноват, засыпаю. конечно же будет работать и так
Я считаю не заранее, а по факту.
Вот жеж вы зануды.
Хорошо, пусть будет такой пример. Начнем с того, что есть сторонняя библиотека «один» поставляющая некий «мега-функционал», который «включается» декоратором «one». Есть вторая, такая же важначя и нужная и поставляет декоратор «two».

Есть некий наш класс:

class MyClass(object):

    def my_method(self):
        pass


Если вы применяете декораторы из двух библиотек по одному на ваших методах — все работает. Так работает:

class MyClass(object):

    @one
    def my_method(self):
        pass


и так работает:

class MyClass(object):

    @two
    def my_method(self):
        pass


А так не работает:

class MyClass(object):

    @one
    @two
    def my_method(self):
        pass


и так не работает:

class MyClass(object):

    @two
    @one
    def my_method(self):
        pass


Не работает потому, что сами библиотеки внутри возможно написаны не очень хорошо (такое бывает?) и каждая из них делает нечно, для чего ожидает что переданный в ее декоратор метод — это метод класса, патается каким-то образом отрефлектить этот метод, и что-то там сделать — не важно. Поэтому в таком варианте не работает по той причине что верхний декоратор декорирует уже задекорированый метод, а не исходный. В качестве решения я и воспользовался таким подходом — регистрирую оба декоратора в реестре и один из них переопределяю, передавая реальную функцию, когда она не доступна. Остальной функционал по рефлексии получился в качестве дополнительного инструментария, что иногда полезно, как минимум в дебаге. Сторонние же библиотеки остались нетронутыми, и не будет проблем с их обновлением. Может это и не очень правильно, как вы говорите, но зато удобно.
Может быть оно и не самое хорошее но наиболее удобное, так как позволяет не править сторонюю библиотеку и иметь впоследствии проблемы с ее обновлением. К сожалению описание деталей тянет на отдельную статью… Ваше право считать так как вы считаете.
Вот я ожидал этого вопроса и даже начал описывать кейс, но потом передумал. Вы готовы поверить на слово, что на то были объективные причины?
1
23 ...

Information

Rating
Does not participate
Location
Киев, Киевская обл., Украина
Date of birth
Registered
Activity