Ваше использование с повышением:: взаимное исключение точно, для чего предназначается это ключевое слово. Другое использование для внутреннего результата, кэширующегося для ускорения доступа.
В основном, 'изменяемый' применяется к любому атрибуту класса, который не влияет на внешне видимое состояние объекта.
В примере кода в Вашем вопросе, изменяемом, могло бы быть несоответствующим, если значение done_ влияет на внешнее состояние, это зависит от того, что находится в...; часть.
Чтобы обновить все экземпляры класса, необходимо где-то отслеживать эти экземпляры - обычно через слабые ссылки (слабое значение dict - самый удобный и общий), чтобы функция «отслеживания» не мешала ненужным экземплярам уйти, конечно!
Обычно вы хотите сохранить такой контейнер в объекте класса, но в этом случае, поскольку вы будете перезагружать модуль, получить старый объект класса нетривиально; проще работать на уровне модуля.
Итак, предположим, что «обновляемый модуль» должен определять в своем начале слабое значение dict (и вспомогательный «следующий ключ для использования» int) с, скажем, обычными именами:
import weakref
class _List(list): pass # a weakly-referenceable sequence
_objs = weakref.WeakValueDictionary()
_nextkey = 0
def _register(obj):
_objs[_nextkey] = List((obj, type(obj).__name__))
_nextkey += 1
Каждый класс в модуле должен иметь, обычно в __ init __
, вызов _register (self)
для регистрации новых экземпляров.
Теперь «функция перезагрузки» может получить список всех экземпляров всех классов в этом модуле, получив копию _objs
, прежде чем она перезагрузит модуль .
Если все, что нужно, - это изменить код , тогда жизнь довольно проста:
def reload_all(amodule):
objs = getattr(amodule, '_objs', None)
reload(amodule)
if not objs: return # not an upgraable-module, or no objects
newobjs = getattr(amodule, '_objs', None)
for obj, classname in objs.values():
newclass = getattr(amodule, classname)
obj.__class__ = newclass
if newobjs: newobjs._register(obj)
Увы, обычно хочется дать новому классу возможность обновить объект старого класса. себе более мелко, например, подходящим методом класса. Это тоже не так сложно:
def reload_all(amodule):
objs = getattr(amodule, '_objs', None)
reload(amodule)
if not objs: return # not an upgraable-module, or no objects
newobjs = getattr(amodule, '_objs', None)
for obj, classname in objs:
newclass = getattr(amodule, classname)
upgrade = getattr(newclass, '_upgrade', None)
if upgrade:
upgrade(obj)
else:
obj.__class__ = newclass
if newobjs: newobjs._register(obj)
Например, скажем, новая версия класса Zap переименовала атрибут с foo в bar. Это может быть код нового Zap:
Вы должны создать новый объект. Невозможно волшебным образом обновить существующие объекты.
Прочтите reload
встроенную документацию - это очень понятно. Вот последний абзац:
Если модуль создает экземпляры класса, перезагрузка модуля, который определяет класс, не влияет на определения методов экземпляров - они продолжают использовать старое определение класса. То же верно и для производных классов.
В документации есть и другие предостережения, поэтому вам действительно следует ее прочитать и рассмотреть альтернативы.
Следующий код делает то, что вы хотите, но , пожалуйста, не используйте его (по крайней мере, пока вы очень уверены, что вы поступаете правильно), Я отправляю его только для объяснения .
mymodule.py:
class ClassChange():
@classmethod
def run(cls,instance):
print 'one',id(instance)
myexperiment.py:
import mymodule
myObject = mymodule.ClassChange()
mymodule.ClassChange.run(myObject)
# change mymodule.py here
reload(mymodule)
mymodule.ClassChange.run(myObject)
Когда в своем коде вы создаете экземпляр myObject
, вы получаете экземпляр ClassChange
. У этого экземпляра есть метод экземпляра с именем run
. Объект сохраняет этот метод экземпляра (по причине, объясненной nosklo) даже при перезагрузке, потому что перезагрузка перезагружает только класс ClassChange
.
В мой код выше, run
- это метод класса . Методы класса всегда привязаны к классу и работают с ним, а не с экземпляром (поэтому их первый аргумент обычно называется cls
, а не self
). Венн ClassChange
перезагружается, как и этот метод класса.
Вы можете видеть, что я также передаю экземпляр в качестве аргумента для работы с правильным (таким же) экземпляром ClassChange. Вы можете видеть это, поскольку в обоих случаях печатается один и тот же идентификатор объекта.
Как видите, я также передаю экземпляр в качестве аргумента для работы с правильным (таким же) экземпляром ClassChange. Вы можете видеть это, поскольку в обоих случаях печатается один и тот же идентификатор объекта.
Как видите, я также передаю экземпляр в качестве аргумента для работы с правильным (таким же) экземпляром ClassChange. Вы можете видеть это, поскольку в обоих случаях печатается один и тот же идентификатор объекта.
Существуют уловки, позволяющие сделать то, что вы хотите, возможным.
Кто-то уже упоминал, что у вас может быть класс, который хранит список своих экземпляров, а затем меняет класс каждого экземпляра на новый при перезагрузке.
Однако это неэффективно. Лучше всего изменить старый класс так, чтобы он стал таким же, как новый.
Я не уверен, что это лучший способ сделать это, или он совпадает с тем, что вы хотите сделать ... но это может работать на вас. Если вы хотите изменить поведение метода для всех объектов определенного типа ... просто используйте переменную функции. Например:
def default_behavior(the_object):
print "one"
def some_other_behavior(the_object):
print "two"
class Foo(object):
# Class variable: a function that has the behavior
# (Takes an instance of a Foo as argument)
behavior = default_behavior
def __init__(self):
print "Foo initialized"
def method_that_changes_behavior(self):
Foo.behavior(self)
if __name__ == "__main__":
foo = Foo()
foo.method_that_changes_behavior() # prints "one"
Foo.behavior = some_other_behavior
foo.method_that_changes_behavior() # prints "two"
# OUTPUT
# Foo initialized
# one
# two
Теперь у вас может быть класс, отвечающий за перезагрузку модулей, и после перезагрузки установка для Foo.behavior
чего-то нового. Я попробовал этот код. Работает нормально: -).
У вас работает?