Python с заявлениями - PullRequest
       30

Python с заявлениями

3 голосов
/ 19 августа 2011

Я экспериментирую с операторами Python with и обнаружил, что в следующем листинге кода мой метод __init__ вызывается дважды, а метод __exit__ вызывается один раз. Это, вероятно, означает, что произойдет утечка ресурсов, если этот код сделает что-нибудь полезное.

class MyResource:
    def __enter__(self):
        print 'Entering MyResource'
        return MyResource()

    def __exit__(self, exc_type, exc_value, traceback):
        print 'Cleaning up MyResource'

    def __init__(self):
        print 'Constructing MyResource'

    def some_function(self):
        print 'Some function'

def main():
    with MyResource() as r:
        r.some_function()

if __name__=='__main__':
    main()

Это вывод программы:

Constructing MyResource
Entering MyResource
Constructing MyResource
Some function
Cleaning up MyResource

Я предполагаю, что это потому, что я делаю что-то не так в операторе with, фактически вызывая конструктор вручную. Как мне исправить это?

Ответы [ 4 ]

19 голосов
/ 19 августа 2011

Вы не должны возвращать новый экземпляр из __enter__.Вместо этого верните self (экземпляр, для которого вызывается __enter__. Вот почему __init__() вызывается дважды - вы вызываете его дважды, один раз в операторе with, один раз в __enter__(). Вот правильная версия:

def __enter__(self):
    print 'Entering MyResource'
    return self
6 голосов
/ 19 августа 2011

Причина, по которой __init__ вызывается дважды, заключается в том, что вы вызываете его дважды:

Один раз, когда вы инициируете объект MyResource в операторе with, и еще раз, когда оператор with вызывает __enter__, который, в свою очередь, создает и возвращает другой экземпляр MyResource

Ваш метод __enter__ должен вернуть self.

3 голосов
/ 19 августа 2011

Я предполагаю, что вы не return MyResource(), а return self, поскольку self является экземпляром уже созданного класса.

2 голосов
/ 19 августа 2011

Измените код на:

def __enter__(self):
    print 'Entering MyResource'
    return self

Метод __enter__ предназначен для инициализации, а не для создания экземпляра, он уже существует (самостоятельно).

...