Steven D'Aprano wrote:
When you call a new-style class, the __new__ method is called with the
user-supplied arguments, followed by the __init__ method with the same
arguments.
I would like to modify the arguments after the __new__ method is called
but before the __init__ method, somewhat like this:
>>>class Spam(object):
... def __new__(cls, *args):
... print "__new__", args
... x = object.__new__(cls)
... args = ['spam spam spam']
... return x
... def __init__(self, *args):
... print "__init__", args # hope to get 'spam spam spam'
... return None
but naturally it doesn't work:
>>>s = Spam('spam and eggs', 'tomato', 'beans are off')
__new__ ('spam and eggs', 'tomato', 'beans are off')
__init__ ('spam and eggs', 'tomato', 'beans are off')
Is there any way to do this, or am I all outta luck?
You can really only achieve this by writing a metaclass. When a new
object is created, what's first called is the __call__ method of the
type object. This basically looks like::
def __call__(cls, *args, **kwargs):
obj = cls.__new__(cls, *args, **kwargs)
obj.__init__(*args, **kwargs)
return obj
Hopefully that explains the behavior you're seeing. If you want
different behavior than this, you can change __call__ by defining your
own metaclass with a different __call__ method, for example::
>>class SpamMeta(type):
... def __call__(cls, *args, **kwargs):
... obj = cls.__new__(cls)
... obj.__init__('spam spam spam')
... return obj
...
>>class Spam(object):
... __metaclass__ = SpamMeta
... def __new__(cls, *args):
... print '__new__', args
... return object.__new__(cls)
... def __init__(self, *args):
... print '__init__', args
...
>>Spam()
__new__ ()
__init__ ('spam spam spam',)
<__main__.Spam object at 0x00E756F0>
Hope that helps,
STeVe