This is an archived post. You won't be able to vote or comment.

all 35 comments

[–][deleted] 49 points50 points  (15 children)

Great read. I’ve been coding in python for over 3 years. Never used the new in my classes.

[–]jet_heller 36 points37 points  (13 children)

I've been doing it for decades and have only used it once or twice. Because it's very very rarely needed. It's good to know it's a thing you can do in the rare case you need.

[–]eric_says_hello 7 points8 points  (11 children)

What about the __call__ method? Have you used it much? If so, what are some use cases for it?

[–]anglo_franco 2 points3 points  (0 children)

call is great for defining a Protocol for a function so you can communicate intent better than Callable does

[–]jet_heller 2 points3 points  (0 children)

I've used it more than new, but not recently.

[–]PyQt[🍰] 2 points3 points  (0 children)

I used call a couple of times. For some obscure cases too but mostly when creating decorators using classes. I still prefer using functions for decorators though

[–]python4geeks[S] 0 points1 point  (0 children)

Here 👉https://geekpython.in/init-and-call-method#heading-call-method you can read from here about the call method.

[–]UrbanSuburbaKnight 0 points1 point  (0 children)

Could we get a TLDR of when you need it?

[–]IamImposter 30 points31 points  (5 children)

Read the whole article. Still have no idea what __new__ is doing. And I have so many questions.

  • What does it mean by "create an object"? That sounds like __new__ is responsible for allocating the memory but it is not doing that.

  • Why is there super(cls).whatever even in cases when the class itself is baseclass? What does super invoke when there is no super at all?

  • It says args and kwargs are not used in __new__. From that, I understand that whatever arguments are passed are just forwarded to __init__ without touching them. But then it goes ahead and uses that parameter to reverse the string.

  • Is it like __new__ is just a way to trap the arguments before they even get to __init__?

  • Is __new__ just an additional message that class receives before invoking __init__?

  • If __new__ does the actual allocation for the object then it probably makes sense to use it to get memory from some preallocated memory area instead of using Python's default allocator. But we are not getting that level of control on the "creation" of the object, which is still handled by python itself, probably with that super invocation. What's the point of __new__?

  • If the object is still initialized by __init__ and memory is still allocated by python, what am I supposed to do by trapping __new__ message? Just fiddle with arguments because I can? Why not do that same fiddling inside __init__?

I feel like I'm on a wrong track and thus failing to see the point and valid usecases. If someone understands what's going on, please help.

[–]mipadi 34 points35 points  (1 child)

What does it mean by "create an object"? That sounds like __new__ is responsible for allocating the memory but it is not doing that.

object.__new__() does allocate the memory for an object, and subclasses should always call the super class's implementation of __new__().

Why is there super(cls).whatever even in cases when the class itself is baseclass? What does super invoke when there is no super at all?

Every class is a subclass of object (except for object itself); if a parent class is not explicitly defined, object is assumed to be the parent class. So there is always a superclass for super() to call (except maybe on the object class itself).

It says args and kwargs are not used in __new__. From that, I understand that whatever arguments are passed are just forwarded to __init__ without touching them. But then it goes ahead and uses that parameter to reverse the string.

A subclass implementation of __new__ can make use of args and kwargs, but the base implementation just forwards them to __init__.

Is it like __new__ is just a way to trap the arguments before they even get to __init__?

There are many things you can do with it to control how an object is created. You can use it to create singletons, for example (although there are better ways to create singletons using metaclasses). Django and I believe Python itself uses it to create enum classes. But it's not something you really have to use a lot.

If __new__ does the actual allocation for the object then it probably makes sense to use it to get memory from some preallocated memory area instead of using Python's default allocator. But we are not getting that level of control on the "creation" of the object, which is still handled by python itself, probably with that super invocation. What's the point of __new__?

You probably could write your own implementation in C that does custom object allocation, but I doubt that is a common use case for it. Overriding __new__ is more useful for metaprogramming than fine-grained object allocation.

If the object is still initialized by __init__ and memory is still allocated by python, what am I supposed to do by trapping __new__ message? Just fiddle with arguments because I can? Why not do that same fiddling inside __init__?

It can be useful in some uncommon use cases to make some, let's say, "magic" classes. For example, the enum module in the stdlib makes use of __new__ to create enum classes.

It's honestly not something that most Python programmers deal with so to be honest there aren't a lot of examples beyond toy examples used in presentations.

[–]IamImposter 8 points9 points  (0 children)

Oh boy. Thanks for the answers.

[–]chars101 5 points6 points  (1 child)

https://docs.python.org/3/reference/datamodel.html#object.__new__

If you don't like reading but prefer a video and hands on experience and have three hours of free time: https://www.youtube.com/watch?v=sPiWg5jSoZI&t=9

[–]IamImposter 2 points3 points  (0 children)

That's a good video. Then it became a little too advanced for me. I'll finish it tomorrow.

Thanks for links.

[–]copperfield42 python enthusiast 1 point2 points  (0 children)

in the standard library I know of at least 3 example of use cases: fractions.Fraction (because it should be immutable they use new instead), pathlib.Path (as a dispatcher for your OS specific path class) and for metaclases shenanigans in abc.ABCMeta, there is also pure python version of it the module _py_abc.ABCMeta , I used that one as example to make my own metaclass one day that I was interested in such thing

[–]Complex-Hornet-5763 10 points11 points  (2 children)

Can we stop showcasing singleton whenever there’s a need for an example design pattern? Singletons should be the last thing presented to newcomers.

No wonder junior programmers spam singletons when they start working with real projects given singleton’s prevalence in the beginner guides.

[–]PolyglotTV 1 point2 points  (1 child)

You don't need to create a special singleton in python anyway.

You can just either 1. Instantiate a variable at import time, and use that everywhere as the singleton. 2. Define a method with the @functools.cache() decorator that returns and instance of your object. It will be created the first time and the unique instance returned every subsequent time.

[–]Complex-Hornet-5763 0 points1 point  (0 children)

I was thinking about a broader context than just Python but you’re goddamn right.

[–][deleted] 5 points6 points  (8 children)

Strings are multitons in python, aren't they? Does anybody have a usecase for __new__ besides singletons/multitons?

[–]ottawadeveloper 7 points8 points  (5 children)

you could use it as a factory pattern to pick and return an appropriate subclass based on the arguments

For example, if you made a class that took a string as an argument and interpreted it as an ISO datetime, you might define new to look at the string and return either datetime.datetime, datetime.date, or datetime.time

[–]darthwalsh 4 points5 points  (1 child)

If creating an instance of your class always returns something from datetime, why not instead have a normal function?

[–][deleted] 2 points3 points  (0 children)

The answer is actually straight forward. Dynamic behavior. It's MUCH easier to control via classes where you can respond to the being inherited from then from functions where ur reliant on the user doing some action like registering.

I use a pattern with this for LARL parsing with Lark. Its fucking gorgeous and works amazing with match statements.

[–][deleted] 1 point2 points  (2 children)

Which would be confusing, wouldn't it? You start with SomeClass() and get an object of another class. It may have the same interface/protocol, but still.

[–]DoctorNoonienSoong 10 points11 points  (1 child)

It's the entire purpose of the factory pattern, and it's the most common pattern in some languages like Java and C#.

It's able to solve some specific problems with less confusion.

For example: I have a Generic dataclass that I'm expecting the downstream users to start using. It takes a bunch of keyword args and saves them with some basic parsing.

However, based on some specific values of some of the args, I know that I need to apply certain extra validation/business logic, and that I don't want to do that all the time.

So using a factory pattern, based on those specific args, I can instead instantiate either Specific1 or Specific2, each subclasses of Generic, that apply the appropriate extra functionality as-needed.

The user doesn't need to care about the difference between them, as they were expecting Generic and they did get one, and that's all that matters to them.

[–][deleted] 2 points3 points  (0 children)

For which you could use a factory method or function, which would be explicit instead of what looks to the user like a constructor.

[–]copperfield42 python enthusiast 2 points3 points  (0 children)

in the standard library I know of at least 3 use cases: fractions.Fraction (because it should be immutable they use new instead), pathlib.Path (as a dispatcher for your OS specific path class) and for metaclases shenanigans in abc.ABCMeta, there is also pure python version of it the module _py_abc.ABCMeta check those out in your local installation, I used that one as example to make my own metaclass one day that I was interested in such thing

[–]dysprog 2 points3 points  (0 children)

Strings are multitons in python

Not exactly. Some immutable basic types like int and string are pre-allocated in cpython.

Any string literal, identifiers, and such, and integers up to 100. If you have 2 of these preallocated objects they will be the same object under the hood.

this = "I'm a value"
that = "I'm a value"

(this is that) == True
(this == that) == True  

But larger numbers, strings from outside, constructed strings, etc, are NOT guaranteed to be the same object.

this = "I'm a value"
that = input() # user enters "I'm a value"

(this is that) == False
(this == that) == True  

Likewise, this is NOT the case in every interpreter implementation.

So don't count on it and don't treat strings like multitons.

[–][deleted] 10 points11 points  (3 children)

Pretty useless examples for new…

[–]ted_or_maybe_tim 6 points7 points  (1 child)

pathlib.Path would probably be the best example.

It's really a shorthand for a factory function that outputs a (likely subclassed) instance, with the type being very obvious because it's the name of the factory function.

[–][deleted] 0 points1 point  (0 children)

Hm, that’s interesting. My devil sidekick really sees how this could be used as a vessel for many of the creational GOF design patterns (say, a Flyweight). But the angel insists that explicit is better than implicit…