В Python, как Вы изменяете инстанцированный объект после перезагрузки?

Ваше использование с повышением:: взаимное исключение точно, для чего предназначается это ключевое слово. Другое использование для внутреннего результата, кэширующегося для ускорения доступа.

В основном, 'изменяемый' применяется к любому атрибуту класса, который не влияет на внешне видимое состояние объекта.

В примере кода в Вашем вопросе, изменяемом, могло бы быть несоответствующим, если значение done_ влияет на внешнее состояние, это зависит от того, что находится в...; часть.

14
задан CharlesB 25 February 2013 в 15:27
поделиться

5 ответов

Чтобы обновить все экземпляры класса, необходимо где-то отслеживать эти экземпляры - обычно через слабые ссылки (слабое значение 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:

15
ответ дан 1 December 2019 в 08:42
поделиться

Вы должны создать новый объект. Невозможно волшебным образом обновить существующие объекты.

Прочтите reload встроенную документацию - это очень понятно. Вот последний абзац:

Если модуль создает экземпляры класса, перезагрузка модуля, который определяет класс, не влияет на определения методов экземпляров - они продолжают использовать старое определение класса. То же верно и для производных классов.

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

6
ответ дан 1 December 2019 в 08:42
поделиться

Следующий код делает то, что вы хотите, но , пожалуйста, не используйте его (по крайней мере, пока вы очень уверены, что вы поступаете правильно), Я отправляю его только для объяснения .

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. Вы можете видеть это, поскольку в обоих случаях печатается один и тот же идентификатор объекта.

2
ответ дан 1 December 2019 в 08:42
поделиться

Существуют уловки, позволяющие сделать то, что вы хотите, возможным.

Кто-то уже упоминал, что у вас может быть класс, который хранит список своих экземпляров, а затем меняет класс каждого экземпляра на новый при перезагрузке.

Однако это неэффективно. Лучше всего изменить старый класс так, чтобы он стал таким же, как новый.

1
ответ дан 1 December 2019 в 08:42
поделиться

Я не уверен, что это лучший способ сделать это, или он совпадает с тем, что вы хотите сделать ... но это может работать на вас. Если вы хотите изменить поведение метода для всех объектов определенного типа ... просто используйте переменную функции. Например:


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 чего-то нового. Я попробовал этот код. Работает нормально: -).

У вас работает?

1
ответ дан 1 December 2019 в 08:42
поделиться
Другие вопросы по тегам:

Похожие вопросы: