This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: __class__ assignment error message confusing
Type: behavior Stage: resolved
Components: Interpreter Core Versions: Python 3.11
process
Status: closed Resolution: out of date
Dependencies: Superseder:
Assigned To: Nosy List: Trundle, aroberge, benjamin.peterson, eric.araujo, flox, iritkatriel, jonash, stutzbach, terry.reedy
Priority: normal Keywords: patch

Created on 2008-12-08 21:25 by terry.reedy, last changed 2022-04-11 14:56 by admin. This issue is now closed.

Files
File name Uploaded Description Edit
4600.diff jonash, 2011-02-27 18:00
Messages (6)
msg77343 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2008-12-08 21:25
ob.__class__ = ob2
gives some confusing TypeError messages.

>>> c.__class__ = 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __class__ must be set to new-style class, not 'int' object

Problem: 'new-style' is obsolete in 3.0. It is also too inclusive...

>>> c.__class__ = object
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __class__ assignment: only for heap types

object *is* 'new-style'.  I presume 'heap type' means 'class defined by
class statement'.  If so, let us say so, since beginning programmers may
not know what a 'heap type' is.  If the above is incorrect, then this
experienced programmer also does not know what it means in Python
context ;-).

Proposal: when someone tries to set __class__ to an inappropriate
object, give similar error message for instances and heap classes.

TypeError: __class__ must be set to a class defined by a class
statement, not 'xxx' [object].

where 'object', without the brackets, is added for non-classes, as it is
today.

>>> c.__class__ = object
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __class__ assignment: only for heap types

C, the class of c, *is* a heap type.  The different problem, the target
being an instance of heap class, should get a different message.  'Heap'
is still possibly confusing. Proposal:

TypeError: __class__ assignment: only for instances of classes defined
by class statements.
msg77381 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2008-12-09 00:59
Related issue that applies to recent 2.x.  Language/data model/Objects,
values, and types says 'An object’s type is also unchangeable.'.  This
should be changed or deleted.
msg129643 - (view) Author: Jonas H. (jonash) * Date: 2011-02-27 18:00
Here comes a patch, changing the behaviour to:

./python -q
>>> class C:
...   pass
... 
>>> (1).__class__ = 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __class__ must be set to a class defined by a class statement, not 'int' object
>>> (1).__class__ = object
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: class__ must be set to a class defined by a class statement, not 'object'
>>> (1).__class__ = C
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __class__ assignment: only for instances of classes defined by class statements
msg129646 - (view) Author: Benjamin Peterson (benjamin.peterson) * (Python committer) Date: 2011-02-27 18:25
This is not really accurate:

>>> class x(int): pass
... 
>>> class y(object): pass
... 
>>> x().__class__ = y
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __class__ assignment: 'x' object layout differs from 'y'
>>> y().__class__ = x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __class__ assignment: 'y' object layout differs from 'x'
msg396989 - (view) Author: Irit Katriel (iritkatriel) * (Python committer) Date: 2021-07-05 13:35
The error messages are different now:

>>> class C: pass
...
>>> c = C()
>>> c.__class__ = 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __class__ must be set to a class, not 'int' object
>>> c.__class__ = object
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __class__ assignment only supported for mutable types or ModuleType subclasses
>>>
msg397017 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2021-07-05 19:15
I neglected to mention above what c is.  I Irit guessed right as 

>>> class C: pass
... 
>>> c = C()

is what I (also) usually do for examples and testing.

Removing "new-style" elsewhere solved the issue with the error message for "ob.__class__ = non_class_object".  The new error message for "ob.__class__ = someclass" replaces 'heap' with 'mutable'.  But it can still be confusing as the qualification in

__class__ assignment only supported for mutable types or ModuleType subclasses

applies to both type(ob) and someclass and the same error is given if either does not qualify.  The use of the plural 'types' allows but does not mandate this interpretation.  Also, "mutable types" means that the types are mutable, not their instances.  Although 'list' is sometimes referred to as a 'mutable type' because its instances are, 'list' itself is not mutable and does not qualify here.

I am closing this issue, which is about the error message, because the new message is accurate when understood.  I cannot think of any better one-line message.  Explaining the background needed to understand should be done elsewhere.  

Andre, I nosied you in case the above would help you improve Friendly's explanation of this error.  I was a bit confused myself until I did more experiments.

Note: Even when type(ob) and someclass both 'qualify', the assignment will fail if instances are 'incompatible'.  Let M be a subclass of types.ModuleType.

c.__class__ = M  # fails with

TypeError: __class__ assignment: 'M' object layout differs from 'C'

The difference is obvious by looking as dir(c) and dir(M('somename')).
History
Date User Action Args
2022-04-11 14:56:42adminsetgithub: 48850
2021-07-05 19:15:08terry.reedysetnosy: + aroberge
title: __class__ assignment: new-style? heap? == confusing -> __class__ assignment error message confusing
messages: + msg397017

versions: + Python 3.11, - Python 3.3
2021-07-05 17:46:03terry.reedysetstatus: open -> closed
resolution: out of date
stage: resolved
2021-07-05 13:35:46iritkatrielsetnosy: + iritkatriel
messages: + msg396989
2012-04-17 17:12:08floxsetnosy: + flox
2011-05-23 11:32:59eric.araujosetassignee: docs@python ->

nosy: - docs@python
2011-05-23 11:32:37eric.araujosetnosy: + eric.araujo

versions: + Python 3.3, - Python 3.0
2011-02-27 18:25:42benjamin.petersonsetnosy: + benjamin.peterson
messages: + msg129646
2011-02-27 18:00:31jonashsetfiles: + 4600.diff

nosy: + jonash
messages: + msg129643

keywords: + patch
2011-02-27 16:14:25Trundlesetnosy: + Trundle
2011-02-27 16:04:58stutzbachsetnosy: + stutzbach
2010-08-01 06:40:22georg.brandlsetassignee: docs@python

nosy: + docs@python
2008-12-09 00:59:47terry.reedysetmessages: + msg77381
2008-12-08 21:25:22terry.reedycreate