Я столкнулся с аналогичной проблемой, связанной с сигналами, и нашел то, что я считаю лучшим решением.
Я определенно предпочитаю использовать аргумент sender
для connect
для проверки внутри обработчика, если это возможно.
Проблема, как вы говорите, заключается в объекте id()
: две строки (даже не просто строки Юникода!) С одинаковым содержимым могут иметь разные идентификаторы объектов.Решением является встроенная функция intern()
, которая вводит данную строку во внутреннюю таблицу идентификаторов python (это очень похоже на Symbol
в ruby).
Если вы используете sender=intern(sender_string)
на send()
и connect()
, все должно работать как положено.
Два важных предостережения:
intern()
работает только на str
, а не unicode
- вам придется иметь дело с кодировкой обратно до str
, и вы должны выполнить одинаковое кодирование для send()
и connect()
. - Внутренняя запись Python вашей интернированной строки может быть отброшена сборщиком мусора, когда он сбрасывает ссылку на вашу интернированную строку, поэтому вам нужно убедиться, что вы храните ее.
ХорошийСпособ решения обеих проблем заключается в том, что вы, вероятно, интересуетесь только сигналами из нескольких предварительно определенных строк, поэтому просто вставьте их в константу конфигурации, уже интернированную.
Например:
user_did_something = Signal(providing_args=["data"])
class User(models.Model):
identifier = models.CharField(max_length=32)
def send_signal(self):
user_did_something.send(sender=intern(self.example_field.encode('utf8')), data=self)
ADMIN_USER = intern('admin')
BIG_ADMIN_USER = intern(u'größer admin'.encode('utf8'))
user_did_something.connect(admin_behavior, sender=ADMIN_USER)
user_did_something.connect(big_admin_behavior, sender=BIG_ADMIN_USER)
BIG_ADMIN_USER
будет распечатываться на тарабарщину, если не декодируется обратно в строку unicode
, но я подозреваю, что большинство таких идентификаторов будет ascii.