Нежелательная реликвия экземпляра питателя питона - PullRequest
2 голосов
/ 17 января 2010

Вопрос: Как убить экземпляр или гарантировать, что я создаю новый экземпляр универсального фидпарсера python?


Информация:

Я сейчас работаю над программой, которая загружает и каталогизирует большое количество блогов. Это хорошо сработало, за исключением неудачной ошибки. Мой код настроен так, чтобы брать список URL блогов и запускать их через цикл for. при каждом запуске он выбирает URL и отправляет его в отдельный класс, который управляет загрузкой, извлечением и сохранением данных в файл.

Первый URL работает просто отлично. Он загружает весь блог и сохраняет его в файл. Но во втором блоге, который он загружает, будут также все данные из первого, я совершенно не знаю, почему.


Фрагменты кода:

class BlogHarvester:
  def __init__(self,folder):
    f = open(folder,'r')
    stop = folder[len(folder)-1]
    while stop != '/':
        folder = folder[0:len(folder)-1]
        stop = folder[len(folder)-1]
    blogs = []
    for line in f:
        blogs.append(line)

    for herf in blogs:
        blog = BlogParser(herf)
        sPath = ""
        uid = newguid()##returns random hash.
        sPath = uid
        sPath = sPath + " - " + blog.posts[0].author[1:5] + ".blog"
        print sPath
        blog.storeAsFile(sPath)

class BlogParser:
  def __init__(self, blogherf='null', path='null', posts = []):
    self.blogherf = blogherf

    self.blog = feedparser.parse(blogherf)
    self.path = path
    self.posts = posts
    if blogherf != 'null':
        self.makeList()
    elif path != 'null':
        self.loadFromFile()

class BlogPeices:
  def __init__(self,title,author,post,date,publisher,rights,comments):
    self.author = author
    self.title = title
    self.post = post
    self.date = date
    self.publisher = publisher
    self.rights = rights
    self.comments = comments

Я включил фрагменты, которые, как мне показалось, было бы полезно. Извините, если есть какие-то запутанные артефакты. Эта программа была болью в заднице.

Ответы [ 2 ]

1 голос
/ 17 января 2010

Проблема posts=[].Аргументы по умолчанию вычисляются во время компиляции, а не во время выполнения, поэтому мутации в объекте остаются в течение всего времени жизни класса.Вместо этого используйте posts=None и проверьте:

if posts is None:
  self.posts = []
0 голосов
/ 17 января 2010

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

С http://docs.python.org/reference/compound_stmts.html#function-definitions

Значения параметров по умолчанию оцениваются когда определение функции казнены. Это означает, что Выражение вычисляется один раз, когда функция определена, и что это то же «предварительно вычисленное» значение используется для каждый звонок. Это особенно важно понимать, когда по умолчанию Параметр является изменяемым объектом, таким как список или словарь: если функция изменяет объект (например, добавление элемента в список), значение по умолчанию фактически изменено. Это вообще не то что было предназначена. Способ обойти это использовать Ни один по умолчанию, и явно проверить это в теле функция.

Но это вызывает некоторую ошибку, вы изменяете ссылку ... Так что вы можете изменять список, который потребитель класса, который не должен был быть изменен:

Например:

class A:
  def foo(self, x = [] ):
    x.append(1)
    self.x = x

a = A()
a.foo()
print a.x
# prints: [1]
a.foo()
print a.x
# prints: [1,1]   # !!!! Consumer would expect this to be [1]
y = [1,2,3]
a.foo(y)
print a.x
# prints: [1, 2, 3, 1]
print y
# prints: [1, 2, 3, 1]  #  !!!! My list was modified

Если вместо этого вы скопируете его: (См. http://docs.python.org/library/copy.html)

import copy
class A:
  def foo(self, x = [] ):
    x = copy.copy(x)
    x.append(1)
    self.x = x

a = A()
a.foo()
print a.x
# prints: [1]
a.foo()
print a.x
# prints: [1]   # !!! Much better =)
y = [1,2,3]
a.foo(y)
print a.x
# prints: [1, 2, 3, 1]
print y
# prints: [1, 2, 3]  #  !!!! My list is how I made it
...