Mailing List Archive

Using __new__
I am attempting to use the __new__ method in the following code:
class SingletonExample(object):

_instance = None

def __new__(cls, **kwargs):
if cls._instance is None:
cls._instance = super().__new__(cls, **kwargs)
return cls._instance

def __init__(self, **kwargs) -> None:
our_attributes = ('h', 'x')
if kwargs is not None:
for k, v in kwargs.items():
if k in our_attributes:
setattr(self, k, v)

a = SingletonExample(h=1)

and I get the following result:

(PRV) jonathan@jfgdev:/PR$ python -m Library.Testing.test2
Traceback (most recent call last):
File "<frozen runpy>", line 198, in _run_module_as_main
File "<frozen runpy>", line 88, in _run_code
File "/mnt/ProgrammingRenaissance/Library/Testing/test2.py", line 16, in
<module>
a = SingletonExample(h=1)
^^^^^^^^^^^^^^^^^^^^^
File "/mnt/ProgrammingRenaissance/Library/Testing/test2.py", line 6, in
__new__
cls._instance = super().__new__(cls, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: object.__new__() takes exactly one argument (the type to
instantiate)

I am quite puzzled as it looks as if this code will not work if the
super-class is 'object'. Any suggestions on how to proceed?

--
Jonathan Gossage
--
https://mail.python.org/mailman/listinfo/python-list
Re: Using __new__ [ In reply to ]
On 2024-02-17 22:35, Jonathan Gossage via Python-list wrote:
> I am attempting to use the __new__ method in the following code:
> class SingletonExample(object):
>
> _instance = None
>
> def __new__(cls, **kwargs):
> if cls._instance is None:
> cls._instance = super().__new__(cls, **kwargs)
> return cls._instance
>
> def __init__(self, **kwargs) -> None:
> our_attributes = ('h', 'x')
> if kwargs is not None:
> for k, v in kwargs.items():
> if k in our_attributes:
> setattr(self, k, v)
>
> a = SingletonExample(h=1)
>
> and I get the following result:
>
> (PRV) jonathan@jfgdev:/PR$ python -m Library.Testing.test2
> Traceback (most recent call last):
> File "<frozen runpy>", line 198, in _run_module_as_main
> File "<frozen runpy>", line 88, in _run_code
> File "/mnt/ProgrammingRenaissance/Library/Testing/test2.py", line 16, in
> <module>
> a = SingletonExample(h=1)
> ^^^^^^^^^^^^^^^^^^^^^
> File "/mnt/ProgrammingRenaissance/Library/Testing/test2.py", line 6, in
> __new__
> cls._instance = super().__new__(cls, **kwargs)
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> TypeError: object.__new__() takes exactly one argument (the type to
> instantiate)
>
> I am quite puzzled as it looks as if this code will not work if the
> super-class is 'object'. Any suggestions on how to proceed?
>
Don't pass kwargs to object.__new__ because it doesn't expect it.

Incidentally, kwargs will never be None, and there's no point in giving
a return type for __init__ because it can only ever return None.
--
https://mail.python.org/mailman/listinfo/python-list
Re: Using __new__ [ In reply to ]
On 18/02/24 11:35, Jonathan Gossage via Python-list wrote:
> I am attempting to use the __new__ method in the following code:
> class SingletonExample(object):
>
> _instance = None
>
> def __new__(cls, **kwargs):
> if cls._instance is None:
> cls._instance = super().__new__(cls, **kwargs)
> return cls._instance
>
> def __init__(self, **kwargs) -> None:
> our_attributes = ('h', 'x')
> if kwargs is not None:
> for k, v in kwargs.items():
> if k in our_attributes:
> setattr(self, k, v)
>
> a = SingletonExample(h=1)
>
> and I get the following result:
>
> (PRV) jonathan@jfgdev:/PR$ python -m Library.Testing.test2
> Traceback (most recent call last):
> File "<frozen runpy>", line 198, in _run_module_as_main
> File "<frozen runpy>", line 88, in _run_code
> File "/mnt/ProgrammingRenaissance/Library/Testing/test2.py", line 16, in
> <module>
> a = SingletonExample(h=1)
> ^^^^^^^^^^^^^^^^^^^^^
> File "/mnt/ProgrammingRenaissance/Library/Testing/test2.py", line 6, in
> __new__
> cls._instance = super().__new__(cls, **kwargs)
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> TypeError: object.__new__() takes exactly one argument (the type to
> instantiate)
>
> I am quite puzzled as it looks as if this code will not work if the
> super-class is 'object'. Any suggestions on how to proceed?

Don't be puzzled. Read the error-message.

Change the super-call to: cls._instance = super().__new__(cls)
and happiness will follow...


That said, mystifications - not sure if this meets the/your definition*
of "singleton", because:

- it can be aliased, eg
a = SingletonExample(h=1)
b = SingletonExample(x=2)

- when it is, the effect is an accumulation of attributes and values
a = SingletonExample(h=1)
b = SingletonExample(h=2)
print( a.__dict__, b.__dict__, )

- it can be re-created with a different value, eg
a = SingletonExample(h=1)
a = SingletonExample(h=2)

- and can be 'regenerated':
a = SingletonExample(h=1)
a = SingletonExample(x=2)

- all failures are silent


* noting "Nowadays, the Singleton pattern has become so popular that
people may call something a singleton even if it solves just one of the
listed problems." (https://refactoring.guru/design-patterns/singleton)


YMMV!

--
Regards,
=dn
--
https://mail.python.org/mailman/listinfo/python-list
Re: Using __new__ [ In reply to ]
On 18/02/24 12:48, Jonathan Gossage wrote:
> The problem that I am facing is that when the superclass is not
> 'object', the __init__ method may well need arguments. I do not know how
> to determine if the superclass is 'object'. For what it is worth, any
> attempt to use this with different arguments should return the initial
> singleton and ignore further attempts to create a second instance.
1 "object"
don't understand. Perhaps give us a broader description of the problem?
Remember also ABCs (Abstract Base Classes).

2 arguments
yes, must accommodate arguments in __new__() if some/same are needed in
__init__() However, when using the default "object", the super() does
not need, use, or want, any arguments to be passed.

3 singleton
don't think that is happening!


PS please reply to the list - there may be others who can learn from, or
contribute to, this conversation!

--
Regards,
=dn

--
https://mail.python.org/mailman/listinfo/python-list
Re: Using __new__ [ In reply to ]
On 18/02/24 13:21, Jonathan Gossage wrote:
> The problem is that if you are dealing with a library class, you may
> have times when the superclass is 'object' while at other times, with a
> different inheritance hierarchy, the superclass may need arguments. My
> thought is that the object class __new__ method should not choke on
> arguments, just ignore them.

All true.

So, what you're looking for is one mechanism to rule them all?

Not going to happen: for exactly the reasons you've stated. If you
really want to get right 'down into the weeds' with a __new__()
constructor, then you're well into customisation-territory.

I think it would be 'going nuts' but...
If it 'absolutely, positively, ...' then perhaps introspect the
super-class and modify the call based-upon whether it is 'something' or
"object"?
(in similar fashion to the singleton's if-statement attempting to make
sure it is unique)

- perhaps someone knows a better/proper way to do this?

Suggested research: custom classes, ABCs, and meta-classes...

See also recent improvements to Python which have made it easier for
sub-classes (and Descriptors - __set_name__() ) to identify
who/how/where to 'phone home', in case (also) applicable...


> When I talk about 'object', I am talking about the ultimate base class
> of any inheritance hierarchy.  have seen the class named 'object' called
> that.

Correct.

The earlier comment was that

class S( object ):

is 'tradition', and synonymous with:

class S:

(not disputing the concept of "object" as the base class)


Not correct.

Please see last paragraph from previous message:


> On Sat, Feb 17, 2024 at 7:06?PM dn via Python-list
> <python-list@python.org <mailto:python-list@python.org>> wrote:
...

> PS please reply to the list - there may be others who can learn
> from, or
> contribute to, this conversation!
...

--
Regards,
=dn

--
https://mail.python.org/mailman/listinfo/python-list
Re: Using __new__ [ In reply to ]
On 2/17/24 19:24, dn via Python-list wrote:
> On 18/02/24 13:21, Jonathan Gossage wrote:

> - perhaps someone knows a better/proper way to do this?
>
> Suggested research: custom classes, ABCs, and meta-classes...

Cure the old "what do you want to accomplish" question. If it's to
channel access to a resource to a single place, many folks seem to
advocate just putting that code in a module, and not trying to use a
class for that - Python already treats modules as a form of singleton
(if you squint a bit). It's not Java, after all, everything doesn't
_have_ to be a class.

I'd also second the idea of looking at metaclasses for an
implementation. Most simpler class-based singleton approaches turn out
not to be thread-safe... you can get closer to solving that with a
metaclass with a lock taken in the dunder-call method.


--
https://mail.python.org/mailman/listinfo/python-list