Найти - Пользователи
Полная версия: Вызвать статические методы некоторых классов при запуске
Начало » Python для новичков » Вызвать статические методы некоторых классов при запуске
1 2 3
Soteric
Чтобы подписать класс, нужно вызвать его метод. Как вызвать метод класса, если заранее неизвестно имя класса?

Daevaorn, не совсем уловил. Даже если я заведу такой класс и унаследую от него всех подписчиков, то как это поможет мне вызвать методы подписки? Мне вообще сначала показалось, что это довольно типовая задача и ее решение должно быть довольно тривиальным, если не очевидным. Что-то видимо не так я делаю.
dimabest
Soteric
Чтобы подписать класс, нужно вызвать его метод. Как вызвать метод класса, если заранее неизвестно имя класса?
Тоесть какие классы должны реагировать на событие ты знаешь, но имя неизвестно? :)

Ок, сделай подписку иначе. Пускай класс Publisher, который публикует событие делегирует подписку Subscriber-ам.

# coding: utf8


class Publisher(object):

subscribers = []

@classmethod
def notify(cls):
for subscriber in cls.subscribers:
subscriber.woohoo()


class Subscriber(object):

@classmethod
def attach(cls, publisher):
publisher.subscribers.append(cls)

class Subscriber_Dima(Subscriber):

@classmethod
def woohoo(cls):
print 'Dima!'


class Subscriber_Ira(Subscriber):

@classmethod
def woohoo(cls):
print 'Ira!'

Subscriber_Ira.attach(Publisher)
Subscriber_Dima.attach(Publisher)
Publisher.notify()
Soteric
Нет, не совсем. Про классы ничего неизвестно. То есть

Subscriber_Ira.attach(Publisher)
Subscriber_Dima.attach(Publisher)

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

Да, на самом деле я знаю что это за класс, какое у него имя и в каком модуле он расположен. Я могу при запуске приложения прямо в main ветке вызвать его метод и осуществить подписку. Но при каких-либо изменениях я должен буду постоянно редактировать main. Этого хотелось бы избежать. Т.е. если диалоговое окно я решу убрать, то я просто удалю класс этого диалога, не трогая основной код. И точно также если я хочу добавить новый диалог, то я добавлю новый класс. То есть отключение и подключение отдельных компонентов программы не должно затрагивать код. Должен быть механизм, который пробежит по всем классам проекта при запуске и скажет всем запустить метод с некоторым предопределенным именем (Initialize в моем случае).

Но я смотрю, что в питоне такое понятие как проект или сборка отсутствует. Здесь каждый модуль сам в себе и нет никакого механизма, который бы следил за всей программой в целом.
Isem
В питоне есть такая возможность, как интроспекция. Другими словами, во время выполнения программы можно узнать, какие модули загружены, какие классы находятся в этих модулях, какие методы есть у этих классов и есть ли метод, который отвечает за регистрацию класса и вызвать его. Можно действовать так. А еще можно после описания класса вызывать некоторую функцию (или метод некоторого класса), которая регистрирует данный класс. Можно написать декоратор класса, который регистрирует этот класс и тогда перед каждым классом, который нужно зарегистрировать, достаточно написать, например, @register_event. Можно еще что-нибудь придумать.

Soteric
Но я смотрю, что в питоне такое понятие как проект или сборка отсутствует. Здесь каждый модуль сам в себе и нет никакого механизма, который бы следил за всей программой в целом.
Ни кто не запрещает написание собственного модуля, который будет отвечать за сборку проекта.
Андрей Светлов
Soteric, Daevaorn внятно написал: используйте метаклассы - и будет вам счастье.
Незачем изобретать велосипед - он и так прекрасно работает.
pasaranax
А че-то типа этого проканает?
class C1(object):
@classmethod
def initialize(cls):
print "C1 initialized"

class C2(object):
@classmethod
def initialize(cls):
print "C2 initialized"

for c in locals().values():
if hasattr(c, 'initialize'):
c.initialize()
Soteric
Все усугубляется тем, что даже модуль с этим классом нигде не импортируется :( Получается, что этот файл вообще лежит себе отдельно и программа даже не знает ее это или не ее. В locals и globals такой класс не попадет и интроспекцией воспользоваться здесь нельзя.

Про мета-классы совсем не понял. Я почитал документацию. Мета-классы позволяют создавать классы налету, добавлять в них методы, поля и т.д. Все это хорошо, напоминает рефлексию в C#, но как может помочь непонятно. Можно пример?

В итоге все что известно: класс находится в одном из пакетов/модулей по каталогу “ниже” главного файла; у класса есть метод initialize(). Я пишу на Jython, может быть со стороны явы это как-то можно решить.
doza_and
Можно предложить такое решение - сканируете директории и импортиуруете все подряд внутрь сканирующей функции то что при импорте отзовется импортируете по настоящему …

Это явно не питоновский стиль гурзить все подряд. Мне кажется надо смотреть в сторону пакетов с их __init__.py где можно проделать всю нужную работу.

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

import inspect
class Tx(object):
print "hello! I am class ",inspect.getframeinfo(inspect.currentframe()).function
hello I am class Tx
Андрей Светлов
Тут, батенька, вы несколько загнули. Нельзя из class code block получить доступ к этому самому классу - его попросту еще не существует.

Поэтому:

1. Декоратор для класса.
@deco
class A(object):
pass
Просто и сердито.

2. Метакласс
class Meta(object):
def __init__(cls, name, bases, dct):
type.__init__(cls, name, bases, dct)
# А вот здесь уже имеем полностью созданный класс, для которого был указан наш метакласс.

class Base(object):
__metaclass__ = Meta

class A(Base):
pass
Метакласс не забудешь - если был прописан, хоть и в базовом классе - вызовется.
Зато декоратор нагляднее. И понимают его быстрее - магии меньше.

3. Просто пишем в коде.
class A(object):
pass

register(A)
Самый тупой и некрасивый метод.

Теперь об инициализации. Код прийдется импортировать, явно или неявно. Лучше всего, конечно, в __init__.py

Soteric, раз уж вы хотите использовать для сравнения C#…

В нем все равно указывается, какие файлы попадут в assembly. И какие assembly будут подгружены. Импорт пакета ничем не отличается - указываем имя пакета, а дальше пакет сам инициализирует себя как ему нужно.

В декораторы, кстати, похожи на атрибуты в .Net. Только в отличие от атрибутов декоратор может сделать что угодно с функцией - а не только зарегистрироваться для дальнейшего использования. Так оно погибче будет.
doza_and
Я с вами Андрей согласен что в тот момент когда я произвожу действия класс еще не создан, но всеже я привел рабочий код, как вы можете легко проверить. Я исходил из того что человеку нужен ведь не сам класс а информация о том что он существует и предназначен для решения данной задачи. А для этого класс не нужен. Достаточно его имени. Это и показано в приведенном коде.

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

Я бы свой способ не рекомендовал по другой причине - потенциальной возможности возникновения исключительной ситуации при создании класса, класс зарегистрируется а фактически не создастся
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB