Я плохо знаком с Python и работал через примеры в CH Swaroop "Байт Python". Я вижу некоторое поведение с __del__
метод, который является озадачивающим меня.
В основном, если я запускаю следующий скрипт (в Python 2.6.2)
class Person4:
'''Represents a person'''
population = 0
def __init__(self, name):
'''Initialize the person's data'''
self.name = name
print 'Initializing %s'% self.name
#When the person is created they increase the population
Person4.population += 1
def __del__(self):
'''I am dying'''
print '%s says bye' % self.name
Person4.population -= 1
if Person4.population == 0:
print 'I am the last one'
else:
print 'There are still %d left' % Person4.population
swaroop = Person4('Swaroop')
kaleem = Person4('Kalem')
с помощью консоли Python (или Spyder интерактивная консоль) я вижу следующее:
execfile (u'C:\1_eric\Python\test1.py')
Инициализация Swaroop
Инициализация Kalemexecfile (u'C:\1_eric\Python\test1.py')
Инициализация Swaroop
Swaroop заявляет до свидания
Я - последний
Инициализация Kalem
Kalem заявляет до свидания
Я - последний
Почему __del__
метод сразу называют после __init__
на втором выполнении?
Я предполагаю, что, так как те же имена экземпляра ('swaroop' и 'kaleem') используются, что он выпускает исходный экземпляр и собирает "мусор" он. Но, это, кажется, играет опустошение с текущим количеством населения.
Что продолжается здесь?
Что хороший путь состоит в том, чтобы избежать этого вида беспорядка?
Избегайте использования __del__
? Проверить на существующие имена экземпляра прежде, чем снова использовать их?...
Спасибо, Eric
Общий совет: не используйте __ del __ на Python. Это может нарушить сбор мусора несколькими способами, например, в случае круглых ссылок между объектами.
В вашем примере есть различные проблемы, связанные с использованием функции execfile() - что не является лучшей практикой - и переопределением глобальных переменных. Кстати, если вам действительно нужно создать псевдо-деструктор (т.е. код, который вызывается всякий раз, когда объект собирает мусор), напишите так называемую функцию "финализатор" (это некорректный деструктор) и вызовите ее, используя обратный вызов weakref.ref. Конечно, это не должно быть методом instance, и помните, что лямбда на самом деле создает закрытие, поэтому убедитесь, что в обратном вызове не будет утечки ссылок на себя! Если вам нужны данные из уничтоженного экземпляра, используйте подход с аргументами по умолчанию, просто убедитесь, что никогда не ссылается на "Я" внутри лямбды, иначе это не сработает. Вывод
from weakref import ref
from time import sleep
class Person4:
'''Represents a person'''
population = 0
def __init__(self, name):
'''Initialize the person's data'''
self.name = name
print 'Initializing %s'% self.name
#When the person is created they increase the population
Person4.population += 1
self._wr = ref(self, lambda wr, name=self.name: Person4_finalizer(name))
def Person4_finalizer(name):
'''I am dying'''
print '%s says bye' % name
Person4.population -= 1
if Person4.population == 0:
print 'I am the last one'
else:
print 'There are still %d left' % Person4.population
p1 = Person4("one")
p2 = Person4("two")
p3 = Person4("three")
del p2
del p3
sleep(5)
(сон там, чтобы помочь увидеть, что происходит):
Initializing one
Initializing two
Initializing three
two says bye
There are still 2 left
three says bye
There are still 1 left
one says bye
I am the last one
Здесь происходит несколько вещей. Когда ваш класс Person4
создается, он инициализирует свою переменную класса Population
значением 0. С интерактивной консоли вы, кажется, запускаете файл «test1.py» несколько раз. При втором запуске класс Person4
объявляется снова, что делает его технически отличным от первого (даже несмотря на то, что у него такое же имя). Это означает, что у него есть свой собственный независимый счетчик населения
.
Теперь swaroop
и kaleem
- это глобальные переменные, общие для обоих ваших экземпляры «test1.py». Python внутренне использует подсчет ссылок для большей части своей автоматической сборки мусора, поэтому исходный экземпляр первого класса Person4
не освобождается до второго присвоения swaroop
. Присвоение swaroop
уменьшает счетчик ссылок для первого экземпляра, вызывая вызов __ del __
, поскольку счетчик ссылок теперь равен нулю. Но поскольку вы ссылаетесь на Person4
по имени внутри __ del __ ()
, когда предыдущий экземпляр исчезает, он уменьшает новый Person4. счет населения
вместо старого счетчика населения Person4
Надеюсь, это имело смысл. Я понимаю, почему это может сбить с толку тех, кто изучает Python. Использование вами переменных класса одновременно с переопределением класса Person4
с помощью execfile ()
еще больше сбивает с толку. Как бы то ни было, я написал много кода Python и не думаю, что мне когда-либо понадобилось использовать специальный метод __ del __
.