Context manager with class methods

G

Gavin Panella

Hi,

On Python 2.6 and 3.1 the following code works fine:

class Foo(object):

@classmethod
def __enter__(cls):
print("__enter__")

@classmethod
def __exit__(cls, exc_type, exc_value, traceback):
print("__exit__")

with Foo: pass

However, in 2.7 and 3.2 I get:

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: __exit__

Is this a regression or a deliberate change? Off the top of my head I
can't think that this pattern is particularly useful, but it seems
like something that ought to work.

Gavin.
 
T

Thomas Rachel

Am 22.09.2011 12:21 schrieb Gavin Panella:
Hi,

On Python 2.6 and 3.1 the following code works fine:

class Foo(object):

@classmethod
def __enter__(cls):
print("__enter__")

@classmethod
def __exit__(cls, exc_type, exc_value, traceback):
print("__exit__")

with Foo: pass

However, in 2.7 and 3.2 I get:

Traceback (most recent call last):
File "<stdin>", line 1, in<module>
AttributeError: __exit__

Same here.

But

with Foo(): pass

works, and that is more important and more logical.


Thomas
 
M

Mel

Gavin said:
Hi,

On Python 2.6 and 3.1 the following code works fine:

class Foo(object):

@classmethod
def __enter__(cls):
print("__enter__")

@classmethod
def __exit__(cls, exc_type, exc_value, traceback):
print("__exit__")

with Foo: pass

However, in 2.7 and 3.2 I get:

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: __exit__

Is this a regression or a deliberate change? Off the top of my head I
can't think that this pattern is particularly useful, but it seems
like something that ought to work.

This seems to work:



class MetaWith (type):
@classmethod
def __enter__(cls):
print("__enter__")

@classmethod
def __exit__(cls, exc_type, exc_value, traceback):
print("__exit__")

class With (object):
__metaclass__ = MetaWith

with With:
pass



Mel.
 
M

Mel

Mel said:
This seems to work:



class MetaWith (type):
@classmethod
def __enter__(cls):
print("__enter__")

@classmethod
def __exit__(cls, exc_type, exc_value, traceback):
print("__exit__")

class With (object):
__metaclass__ = MetaWith

with With:
pass

It seems to work equally well without the `@classmethod`s

Mel.
 
T

Terry Reedy

On Python 2.6 and 3.1 the following code works fine:
class Foo(object):
@classmethod
def __enter__(cls):
print("__enter__")
@classmethod
def __exit__(cls, exc_type, exc_value, traceback):
print("__exit__")

with Foo: pass

This could be regarded as a bug, see below.
However, in 2.7 and 3.2 I get:

Traceback (most recent call last):
File "<stdin>", line 1, in<module>
AttributeError: __exit__

type(Foo) == type and type has no such attribute.

Unless otherwise specified, 'method' typically means 'instance method'.
In particular, the '__xxx__' special methods are (all?) (intended to be)
instance methods, which is to say, functions that are attributes of an
object's class. So it is normal to look for special methods on the class
(and superclasses) of an object rather than starting with the object
itself. For instance, when executing 'a+b', the interpreter never looks
for __add__ as an attribute of a itself (in a.__dict__)
but starts the search looking for with type(a).__add__
Is this a regression or a deliberate change? Off the top of my head I
can't think that this pattern is particularly useful, but it seems
like something that ought to work.

I suspect there was a deliberate change to correct an anomaly, though
this might have been done as part of some other change. As Thomas noted,
*instances* of Foo work and as Mei noted, making Foo an instance of a
(meta)class with the needed methods also works.
 
G

Gregory Ewing

Terry said:
it is normal to look for special methods on the class (and superclasses)
of an object rather than starting with the object itself.
I suspect there was a deliberate change to correct an anomaly, though
this might have been done as part of some other change.

It's a necessary consequence of the fact that new-style classes
are also instances. Without it, there would be an ambiguity as
to whether a special method defined the behaviour of instances
of a class or of the class object itself.

It also increases efficiency, because for those special methods
that correspond to C-level type slots, you only have to look
in the type slot to find an implementation of the method,
rather than having to look in the instance dict first.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,470
Messages
2,571,807
Members
48,797
Latest member
PeterSimpson
Top