• Using __new__

    From Jonathan Gossage@3:633/280.2 to All on Sun Feb 18 09:35:21 2024
    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

    --- MBSE BBS v1.0.8.4 (Linux-x86_64)
    * Origin: ---:- FTN<->UseNet Gate -:--- (3:633/280.2@fidonet)
  • From Stefan Ram@3:633/280.2 to All on Sun Feb 18 09:51:29 2024
    Jonathan Gossage <jgossage@gmail.com> writes:
    I am attempting to use the __new__ method in the following code:
    class SingletonExample(object):

    Above, you specify that the superclass is "object".

    super().__new__(cls, **kwargs)

    Now, since you know the superclass to be "object",
    why can't you just write "super().__new__( cls )"?

    --- MBSE BBS v1.0.8.4 (Linux-x86_64)
    * Origin: Stefan Ram (3:633/280.2@fidonet)
  • From MRAB@3:633/280.2 to All on Sun Feb 18 10:08:57 2024
    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.

    --- MBSE BBS v1.0.8.4 (Linux-x86_64)
    * Origin: ---:- FTN<->UseNet Gate -:--- (3:633/280.2@fidonet)
  • From dn@3:633/280.2 to All on Sun Feb 18 10:31:39 2024
    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

    --- MBSE BBS v1.0.8.4 (Linux-x86_64)
    * Origin: DWM (3:633/280.2@fidonet)
  • From dn@3:633/280.2 to All on Sun Feb 18 11:05:54 2024
    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


    --- MBSE BBS v1.0.8.4 (Linux-x86_64)
    * Origin: DWM (3:633/280.2@fidonet)
  • From dn@3:633/280.2 to All on Sun Feb 18 13:24:09 2024
    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


    --- MBSE BBS v1.0.8.4 (Linux-x86_64)
    * Origin: DWM (3:633/280.2@fidonet)
  • From Mats Wichmann@3:633/280.2 to All on Mon Feb 19 02:52:12 2024
    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.



    --- MBSE BBS v1.0.8.4 (Linux-x86_64)
    * Origin: ---:- FTN<->UseNet Gate -:--- (3:633/280.2@fidonet)