Renaming datetime.datetime to datetime.DateTime

That’s precisely BECAUSE large changes aren’t done. Major breaking changes would have the exact same problem again. It’s a completely rational response to the fact that the 2 to 3 transition was a major problem, not to be repeated.

It’s also a recognition that, if there are two ways of doing things that remain valid in parallel, the correct and reasonable thing to do is to stick to the old one until you are forced to change. Which basically makes deprecation periods largely arbitrary and mythical when it comes to major breaking changes. (They are significantly LESS mythical when it comes to changes that are easy to span, or where the proposed new way of doing things already worked on older versions of Python. For example, the generator_stop change, while it did meet with notable resistance, did at least have the benefit that correct code for modern Python runs just fine on all Python versions, so the problem of transitioning was far less.)

Let me give you an example of where PEP 8 naming was introduced, and some idea of how long a deprecation period it takes before the old one can be safely removed.

>>> import threading
>>> threading.currentThread() is threading.current_thread()
<stdin>:1: DeprecationWarning: currentThread() is deprecated, use current_thread() instead
True

Python 2.6 introduced an alias current_thread (and a bunch of others) in 2008. Python 3.13 still has the old names, in 2023. We’re fifteen years in. I think it MIGHT be safe to remove currentThread now, but it’s definitely safer to just issue the warning and leave it there.

If datetime.datetime is renamed to datetime.DateTime, expect to still see code in the wild using datetime.datetime for at least ten, probably fifteen, potentially twenty years. And if the alias gets removed, it will be breaking otherwise-valid code.

If datetime.datetime is renamed to datetime.DateTime , expect to still see code in the wild using datetime.datetime for at least ten, probably fifteen, potentially twenty years.

Yea, that’s true. But I believe Python will still be widely used in 100 years. The future is long. We need to keep that in mind too. It’s worth while to do things even if the fruits of our work are not realized until long after we are dead.

3 Likes

Quick question! Which of these are functions (correctly named in lowercase) and which are types (should™ be capitalized)?

any, bool, classmethod, enumerate, filter, hash, iter, max, open, property, range, super, vars, zip,
heapq.heapify, dataclasses.dataclass, zlib.compress, operator.add, operator.call, operator.itemgetter,
hashlib.sha256, hashlib.blake2b, hashlib.md5, subprocess.run, urllib.request.urlopen, itertools.chain,
itertools.tee, collections.defaultdict, collections.namedtuple

Followup question: Would it be a breaking change if any one of these were to become a type instead of a function, but keep its existing name? Hint: That has happened in the past.

3 Likes

Luckily, all names match PEP8 already:

In particular: do not break backwards compatibility just to comply with this PEP!

This is like one of the first things in the PEP, before any style suggestions are mentioned.

13 Likes

A good read: PEP 8: A Foolish Consistency is the Hobgoblin of Little Minds :slight_smile:

Seriously, Python has for a very long time used the convention that builtin types have lower case constructors and classes use CamelCase names. This originated from the times where we had two different object kinds: types and classes. And I guess that the datetime objects use the lower case because at the time they were implemented as types, not classes.

Today, there is only one object kind: what used to be called types in the early days.

I don’t think it makes sense to change any of these names in the light of overall consistency. The module is consistent in itself. That’s enough.

Some things like class methods were used a bit too much in the design (they were new at the time), IMO, making calls very long to write, so adding a few shortcuts would help with the UX, but whether to write datetime or DateTime doesn’t really make much difference.

7 Likes

Whether or not other builtins should be changed or not can be a discussion for another time :blush: FWIW I think datetime’s class and module clash is a legitimate design problem, which is not just about the case of classes and functions.

4 Likes

I don’t know if that’s a “quick question”, but defaultdict and deque being lowercase annoys me.

My point is that it’s very very hard to know which ones are classes and which are functions - and, even more importantly, it is irrelevant to most code. It’s NOT a quick question, in fact. The “classes should have a capital letter” argument becomes a lot weaker when we don’t care whether they’re classes or functions.

Specific example: property is a class. Would it be an improvement to write this:

class Spam:
    @Property
    def ham(self): return "ham"

or do we not care? In what situations does it actually make a difference?

And yes, there is some inconsistency between defaultdict and UserDict. But there’s already inconsistency between dict and UserDict anyway, so there isn’t a lot to justify a rename. Maybe Deque might have been better, but it’s also not that big a deal.

2 Likes

Decorators and builtins are usually lowercase though. defaultdict is inconsistent with not only UserDict, but also OrderedDict in the same package. It’s a non-built-in container, and those are almost always camelcase.

The datetime class is confusing because it has the same name as its package, which is a further argument for repairing it at the cost of a few years of churn.

3 Likes

Also, I find the case inconsistency between datetime.datetime and zoneinfo.ZoneInfo kind of funny as well.

4 Likes

There is at least one feature request on the old bugtracker requesting that DateTime etc. be added as aliases (not replacements) for datetime etc. I think this is a great idea.

Personally I have been writing from datetime import datetime as date as Date, Datetime, timezone as Timezone for a couple of years now and been very happy with the improvement in readability. I’ve been doing the same with from collections import defaultdict as Defaultdict. Personally I don’t think it needs the “double capitalization”, but DateTime might look nicer than Datetime alongside the other names in the standard library.

5 Likes

Capitalization should reflect intended usage in my opinion, not specifically the underlying type. defaultdict and deque are both classes and more importantly those names are meant to be used as classes, so Defaultdict and Deque make sense to me. Whereas property is not really intended to be used as a class that you instantiate with () in regular code, so it should remain lower-cased.

I’m OK with list, tuple, etc. remaining lower-cased because you don’t have to import them, and they are so ubiquitous that changing them would substantially change the look and feel of Python overall. But I think these imported names are comparatively uncommon, and if nothing else it helps to visually distinguish the kinds of things that you’re importing in a block of import ... statements.

5 Likes

socket.socket is also kind of odd. I guess in hindsight it should have been socket.Socket … regardless my opinion is that we shouldn’t change it at this point.

If we want to alias to current-standard that’s fine, but i think deprecating or removing the old versions causes needless toil.

3 Likes

Even PHP tries to be consistant within their codebase. I feel like this kind of things only reflects the reality of Python, everyone is scare to change things.

2 Likes

That’s not accurate. Python changes all the time, to get bugs fixed and new things added. But each change is considered carefully to see if it breaks compatibility, fits with the rest of the language, is easy to teach, really improves something, etc. So each proposal has the burden of demonstrating the benefits it brings and consider its costs.

9 Likes

That’s news to me.

3 Likes

I personally use dt as the variable name for datetime instances, so updating the recommendation may cause confusion for readers of my code in the future. I suggest finding out how prevalent my naming scheme is before updating the docs.

I like the idea of aliasing the date-time classes to have capitalised naming without deprecating/removing anything. It might be a while before I could use those aliases, but it would be worth it.

4 Likes

A soft way to deprecate things would be to have linters like Ruff nudge users towards the capitalized versions. Ruff also can rewrite the code for you, which mitigates toil.

Despite also finding this naming inconsistency a bit odd, I have to agree about the tremendous impact it would have on the ecosystem, even with a very long-term migration plan.
It’s quite understandable everyone is apprehensive as the ecosystem recently ended a traumatic decade-long migration period.

If I’m not mistaken, most features added to the language after PEP-8 (and the Python 3 release) already follow established conventions. As long as conventions continue to be followed for new code, I see little reason to introduce possible redundancy into modules and cause confusion in the future solely to rename heavily used functionality.

There are modules with even more glaring inconsistencies - such as logging and unittest whose methods use camelCase - which became “facts of life”.

4 Likes

What has been done to PHP is pretty much the same as Python: ideas are discussed, pros, cons and consequences are raised and detailed, and possibly proposals are put together to be considered.

There has been a lot of effort and investment over the last 10+ years to further shape PHP and organize the addition and removal of features. Still, many historic API contracts were kept without changes. You still find the soup of name casing conventions, abbreviations and names borrowed from C in PHP stdlib and namespaces, but new additions follow the new established standards.