Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #18692 > unrolled thread

Using an OrderedDict for __dict__ in Python 3 using __prepare__

Started bySteven D'Aprano <steve+comp.lang.python@pearwood.info>
First post2012-01-09 02:21 +0000
Last post2012-01-09 03:46 +0100
Articles 2 — 2 participants

Back to article view | Back to comp.lang.python


Contents

  Using an OrderedDict for __dict__ in Python 3 using __prepare__ Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2012-01-09 02:21 +0000
    Re: Using an OrderedDict for __dict__ in Python 3 using __prepare__ Christian Heimes <lists@cheimes.de> - 2012-01-09 03:46 +0100

#18692 — Using an OrderedDict for __dict__ in Python 3 using __prepare__

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2012-01-09 02:21 +0000
SubjectUsing an OrderedDict for __dict__ in Python 3 using __prepare__
Message-ID<4f0a4f2a$0$11120$c3e8da3@news.astraweb.com>
I'm using Python 3.1 and trying to create a class using an OrderedDict as 
its __dict__, but it isn't working as I expect.

See http://www.python.org/dev/peps/pep-3115/ for further details.

Here is my code:


from collections import OrderedDict

# The metaclass
class OrderedClass(type):
	# The prepare function
	@classmethod
	def __prepare__(metacls, name, bases): # No keywords in this case
		print('calling metaclass __prepare__')
		return OrderedDict()
	# The metaclass invocation
	def __new__(cls, name, bases, classdict):
		print('calling metaclass __new__')
		for x in cls, name, bases, classdict, type(classdict):
			print(' ', x)
		return type.__new__(cls, name, bases, classdict)

class MyClass(metaclass=OrderedClass):
	spam = 'Cardinal Biggles'
	ham = 'Ethel the Aardvark'
	def method1(self):
		pass
	def method2(self):
		pass

list(MyClass.__dict__.keys())


and the results I get:

calling metaclass __prepare__
calling metaclass __new__
  <class '__main__.OrderedClass'>
  MyClass
  ()
  OrderedDict([('__module__', '__main__'), ('spam', 'Cardinal Biggles'), 
('ham', 'Ethel the Aardvark'), ('method1', <function method1 at 
0xb71a972c>), ('method2', <function method2 at 0xb71a96ac>)])
  <class 'collections.OrderedDict'>

['__module__', 'method2', 'ham', 'spam', 'method1', '__dict__', 
'__weakref__', '__doc__']


I expected that the output of MyClass.__dict__.keys would match the input 
OrderedDict (ignoring the entries added later, like __module__ and 
__doc__).

And I'm completely flummoxed by the existence of 
MyClass.__dict__['__dict__'].


What am I doing wrong?



-- 
Steven

[toc] | [next] | [standalone]


#18695

FromChristian Heimes <lists@cheimes.de>
Date2012-01-09 03:46 +0100
Message-ID<mailman.4539.1326077197.27778.python-list@python.org>
In reply to#18692
Am 09.01.2012 03:21, schrieb Steven D'Aprano:
> What am I doing wrong?

You aren't doing anything wrong. It's just not possible to have
something different than a dict as a type's __dict__. It's a deliberate
limitation and required optimization. The __prepare__ hook allows to you
have a dict subclass as intermediate dict, but in the end it always
comes down to a dict.

The code in Objects/typeobject.c:type_new() copies the dict:

    /* Initialize tp_dict from passed-in dict */
    type->tp_dict = dict = PyDict_Copy(dict);

PyDict_Copy() takes an instance of a PyDict_Type subclass and always
returns a PyDictObject.

However you can use the __prepare__ hook to *remember* the order of
insertion, see
http://docs.python.org/py3k/reference/datamodel.html#customizing-class-creation

Christian

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web