Альтернативным решением для использования weakref
является динамическое связывание функции с экземпляром только тогда, когда она вызывается путем переопределения __getattr__
или __getattribute__
в классе для возврата func.__get__(self, type(self))
вместо просто func
для функций привязан к экземпляру. Так ведут себя функции, определенные в классе. К сожалению (для некоторых случаев использования) python не выполняет ту же логику для функций, связанных с самим экземпляром, но вы можете изменить его, чтобы сделать это. У меня были похожие проблемы с дескрипторами, привязанными к экземплярам. Производительность здесь, вероятно, не так хороша, как при использовании weakref
, но это опция, которая будет работать прозрачно для любой динамически назначаемой функции с использованием только встроенных функций Python.
Если вы обнаружите, что делаете это часто, вам может потребоваться собственный метакласс, который выполняет динамическое связывание функций уровня экземпляра.
Другой альтернативой является добавление функции непосредственно в класс, который затем будет правильно выполнять привязку при вызове. Для многих случаев использования это будет связано с некоторыми головными болями, а именно с правильным пространством имен функций, чтобы они не сталкивались. Для этого можно использовать идентификатор экземпляра, так как идентификатор в cPython не гарантированно уникален в течение всей жизни программы, вам нужно немного подумать, чтобы убедиться, что он работает для вашего варианта использования ... в В частности, вам, вероятно, нужно убедиться, что вы удалили функцию класса, когда объект выходит из области видимости, и, таким образом, его адрес id / memory снова доступен. __del__
идеально подходит для этого :). В качестве альтернативы, вы можете очистить все методы, пространства имен для экземпляра при создании объекта (в __init__
или __new__
).
Другая альтернатива (вместо того, чтобы связываться с магическими методами python) - явно добавить метод для вызова ваших динамически связанных функций. Это имеет обратную сторону: ваши пользователи не могут вызывать вашу функцию, используя обычный синтаксис Python:
class MyClass(object):
def dynamic_func(self, func_name):
return getattr(self, func_name).__get__(self, type(self))
def call_dynamic_func(self, func_name, *args, **kwargs):
return getattr(self, func_name).__get__(self, type(self))(*args, **kwargs)
"""
Alternate without using descriptor functionality:
def call_dynamic_func(self, func_name, *args, **kwargs):
return getattr(self, func_name)(self, *args, **kwargs)
"""
Просто чтобы завершить эту запись, я покажу также ваш вариант weakref
:
import weakref
inst = MyClass()
def func(self):
print 'My func'
# You could also use the types modules, but the descriptor method is cleaner IMO
inst.func = func.__get__(weakref.ref(inst), type(inst))