[Python-Dev] PEP 567 pre v3 (original) (raw)

Yury Selivanov yselivanov.ml at gmail.com
Thu Jan 11 01:23:43 EST 2018


On Thu, Jan 11, 2018 at 4:44 AM, Nathaniel Smith <njs at pobox.com> wrote: [..]

It may have gotten lost in that email, but my actual favorite approach is that we make the signatures:

ContextVar(name, , initialvalue) # or even (, name, initialvalue) ContextVar.get() ContextVar.set(value) so that when you create a ContextVar you always state the initial value, whatever makes sense in a particular case. (Obviously None will be a very popular choice, but this way it won't be implicit, and no-one will be surprised to see it returned from get().)

Alright, you've shown that most of the time when we use threading.local in the standard library we subclass it in order to provide a default value (and avoid AttributeError being thrown). This is a solid argument in favour of keeping the 'default' parameter for the ContextVar constructor. Let's keep it.

However I still don't like the idea of making defaults mandatory. I have at least one exemplary use case (I can come up with more of such examples, btw) which shows that it's not always desired to have a None default: getting the current request object in a web application. With the current PEP 567 semantics:

request_var: ContextVar[Request] = ContextVar('current_request')

and later:

request : Request = request_var.get()

'request_var.get()' will throw a LookupError, which will indicate that something went wrong in the framework layer. The user should never see this error, and they can just rely on the fact that the current request is always available (cannot be None).

With mandatory defaults, the type of 'request' variable will be 'Optional[Request]', and the user will be forced to add an 'if' statement to guard against None values. Otherwise the user risks having occasional AttributeErrors that don't really explain what actually happened. I would prefer them to see a LookupError('cannot lookup current_request context variable') instead.

I think that when you have an int stored in a context variable it would usually make sense to give it a 0 default (or some other number). However, for a complex object (like current request object) there is no sensible default value sometimes. Forcing the user to set it to None feels like a badly designed API that forces the user to work around it.

Therefore I'm still in favour of keeping the current PEP 567 behaviour. It feels very consistent with how variable lookups and threading.local objects work in Python now.

Yury



More information about the Python-Dev mailing list