Форум сайта python.su
20
Чтобы подписать класс, нужно вызвать его метод. Как вызвать метод класса, если заранее неизвестно имя класса?
Daevaorn, не совсем уловил. Даже если я заведу такой класс и унаследую от него всех подписчиков, то как это поможет мне вызвать методы подписки? Мне вообще сначала показалось, что это довольно типовая задача и ее решение должно быть довольно тривиальным, если не очевидным. Что-то видимо не так я делаю.
Отредактировано (Ноя. 5, 2010 23:56:08)
Офлайн
0
SotericТоесть какие классы должны реагировать на событие ты знаешь, но имя неизвестно? :)
Чтобы подписать класс, нужно вызвать его метод. Как вызвать метод класса, если заранее неизвестно имя класса?
# 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()
Офлайн
20
Нет, не совсем. Про классы ничего неизвестно. То есть
Subscriber_Ira.attach(Publisher)
Subscriber_Dima.attach(Publisher)
если бы я знал выделенное, то мог бы при старте приложения вызвать их методы Initialize() и подписаться на события. Собственно из-за чего вопрос. Есть интерфейс приложения. По нажатию кнопки генерируется некоторое событие. На это событие должны реагировать другие части интерфейса. Если они уже созданы, то все просто: при создании компонента я делаю подписку. Но если компонент еще не создан, например диалоговое окно которое должно быть создано только по событию, то к его классу обращений еще не было, не вызывалось ни одного его метода, т.е. вообще никак к этому классу никто не обращался, и соответственно некуда добавить подписку на событие. Чтобы класс себя подписал надо вызвать какой-то метод этого класса.
Да, на самом деле я знаю что это за класс, какое у него имя и в каком модуле он расположен. Я могу при запуске приложения прямо в main ветке вызвать его метод и осуществить подписку. Но при каких-либо изменениях я должен буду постоянно редактировать main. Этого хотелось бы избежать. Т.е. если диалоговое окно я решу убрать, то я просто удалю класс этого диалога, не трогая основной код. И точно также если я хочу добавить новый диалог, то я добавлю новый класс. То есть отключение и подключение отдельных компонентов программы не должно затрагивать код. Должен быть механизм, который пробежит по всем классам проекта при запуске и скажет всем запустить метод с некоторым предопределенным именем (Initialize в моем случае).
Но я смотрю, что в питоне такое понятие как проект или сборка отсутствует. Здесь каждый модуль сам в себе и нет никакого механизма, который бы следил за всей программой в целом.
Офлайн
7
В питоне есть такая возможность, как интроспекция. Другими словами, во время выполнения программы можно узнать, какие модули загружены, какие классы находятся в этих модулях, какие методы есть у этих классов и есть ли метод, который отвечает за регистрацию класса и вызвать его. Можно действовать так. А еще можно после описания класса вызывать некоторую функцию (или метод некоторого класса), которая регистрирует данный класс. Можно написать декоратор класса, который регистрирует этот класс и тогда перед каждым классом, который нужно зарегистрировать, достаточно написать, например, @register_event. Можно еще что-нибудь придумать.
SotericНи кто не запрещает написание собственного модуля, который будет отвечать за сборку проекта.
Но я смотрю, что в питоне такое понятие как проект или сборка отсутствует. Здесь каждый модуль сам в себе и нет никакого механизма, который бы следил за всей программой в целом.
Отредактировано (Ноя. 6, 2010 03:11:19)
Офлайн
14
Soteric, Daevaorn внятно написал: используйте метаклассы - и будет вам счастье.
Незачем изобретать велосипед - он и так прекрасно работает.
Офлайн
0
А че-то типа этого проканает?
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()
Офлайн
20
Все усугубляется тем, что даже модуль с этим классом нигде не импортируется :( Получается, что этот файл вообще лежит себе отдельно и программа даже не знает ее это или не ее. В locals и globals такой класс не попадет и интроспекцией воспользоваться здесь нельзя.
Про мета-классы совсем не понял. Я почитал документацию. Мета-классы позволяют создавать классы налету, добавлять в них методы, поля и т.д. Все это хорошо, напоминает рефлексию в C#, но как может помочь непонятно. Можно пример?
В итоге все что известно: класс находится в одном из пакетов/модулей по каталогу “ниже” главного файла; у класса есть метод initialize(). Я пишу на Jython, может быть со стороны явы это как-то можно решить.
Офлайн
253
Можно предложить такое решение - сканируете директории и импортиуруете все подряд внутрь сканирующей функции то что при импорте отзовется импортируете по настоящему …
Это явно не питоновский стиль гурзить все подряд. Мне кажется надо смотреть в сторону пакетов с их __init__.py где можно проделать всю нужную работу.
Приведенные примеры поразили сложностью. В в документации ясно сказано, код класса исполняется в тот момент когда класс первый раз встречен интерпретатором. Те вы можете делать все что только вам взбредет в голову в теле класса
import inspect
class Tx(object):
print "hello! I am class ",inspect.getframeinfo(inspect.currentframe()).function
Отредактировано (Ноя. 6, 2010 20:32:15)
Офлайн
14
Тут, батенька, вы несколько загнули. Нельзя из class code block получить доступ к этому самому классу - его попросту еще не существует.
Поэтому:
1. Декоратор для класса.
@deco
class A(object):
pass
class Meta(object):
def __init__(cls, name, bases, dct):
type.__init__(cls, name, bases, dct)
# А вот здесь уже имеем полностью созданный класс, для которого был указан наш метакласс.
class Base(object):
__metaclass__ = Meta
class A(Base):
pass
class A(object):
pass
register(A)
Офлайн
253
Я с вами Андрей согласен что в тот момент когда я произвожу действия класс еще не создан, но всеже я привел рабочий код, как вы можете легко проверить. Я исходил из того что человеку нужен ведь не сам класс а информация о том что он существует и предназначен для решения данной задачи. А для этого класс не нужен. Достаточно его имени. Это и показано в приведенном коде.
Этим примером я хотел подчеркнуть что в отличии от компилируемых языков - классы питона исполняемый код.
Я бы свой способ не рекомендовал по другой причине - потенциальной возможности возникновения исключительной ситуации при создании класса, класс зарегистрируется а фактически не создастся
Отредактировано (Ноя. 8, 2010 19:24:56)
Офлайн