Settings: lists or tuples?

731 views
Skip to first unread message

Aymeric Augustin

unread,
Dec 17, 2014, 3:49:10 PM12/17/14
to django-d...@googlegroups.com
Hello,

I’m about to introduce a new setting that is a sequence of things, TEMPLATES, and I have to decide whether it will be a tuple of a list.

Unfortunately Django is very inconsistent in the type of settings. In global_settings.py:

- 22 settings are tuples
- 10 are empty, 12 aren't
- 12 are referred to as “lists” in code comments, 1 as “tuple”
- 6 settings are lists
- all of them are empty

Even the tutorial is inconsistent. The first two settings described are:

- INSTALLED_APPS: example is a tuple
- TEMPLATE_DIRS: example is a list

It would be nice to standardize on tuples or lists — at least for new code if it’s undesirable to change the existing code.

This is purely a matter of consistency and aesthetics. Using a tuple or a list never makes any difference in the code.

While lists are less common than tuples currently, I prefer them for two reasons:

1) All these settings are sequences of similar things. Such values are best represented with lists, unless they have to be immutable, in which case a tuple can be used. (tuples are both “namedtuples without names” and “immutable lists” in Python.)

2) Lists aren’t prone to the “missing comma in single-item tuple” problem which bites beginners and experienced pythonistas alike. Django even has code to defend against this mistake for a handful of settings. Search for “tuple_settings” in the source.

Surprisingly, it seems that there isn’t a backwards compatibility problem with changing the type to lists, as the following pattern still works:

# myproject/settings.py
from django.conf.global_settings import FILE_UPLOAD_HANDLERS
FILE_UPLOAD_HANDLERS += ('myproject.uploadhandler.FooBarUploadHandler',)

Proof:

>>> foo = ['abc']
>>> foo += ('def',)
>>> foo
['abc', ‘def’]

I can’t think of another circumstance it which the type of the default value will make a difference.

So… can we normalize the code and satisfy my OCD? Or should I just stop caring and move on? ;-)

--
Aymeric.



Carl Meyer

unread,
Dec 17, 2014, 3:54:59 PM12/17/14
to django-d...@googlegroups.com
On 12/17/2014 01:48 PM, Aymeric Augustin wrote:
> I’m about to introduce a new setting that is a sequence of things, TEMPLATES, and I have to decide whether it will be a tuple of a list.
>
> Unfortunately Django is very inconsistent in the type of settings. In global_settings.py:
>
> - 22 settings are tuples
> - 10 are empty, 12 aren't
> - 12 are referred to as “lists” in code comments, 1 as “tuple”
> - 6 settings are lists
> - all of them are empty
>
> Even the tutorial is inconsistent. The first two settings described are:
>
> - INSTALLED_APPS: example is a tuple
> - TEMPLATE_DIRS: example is a list
>
> It would be nice to standardize on tuples or lists — at least for new code if it’s undesirable to change the existing code.
>
> This is purely a matter of consistency and aesthetics. Using a tuple or a list never makes any difference in the code.
>
> While lists are less common than tuples currently, I prefer them for two reasons:
>
> 1) All these settings are sequences of similar things. Such values are best represented with lists, unless they have to be immutable, in which case a tuple can be used. (tuples are both “namedtuples without names” and “immutable lists” in Python.)
>
> 2) Lists aren’t prone to the “missing comma in single-item tuple” problem which bites beginners and experienced pythonistas alike. Django even has code to defend against this mistake for a handful of settings. Search for “tuple_settings” in the source.

I agree with your preference for lists, for the same two reasons.

> Surprisingly, it seems that there isn’t a backwards compatibility problem with changing the type to lists, as the following pattern still works:
>
> # myproject/settings.py
> from django.conf.global_settings import FILE_UPLOAD_HANDLERS
> FILE_UPLOAD_HANDLERS += ('myproject.uploadhandler.FooBarUploadHandler',)
>
> Proof:
>
>>>> foo = ['abc']
>>>> foo += ('def',)
>>>> foo
> ['abc', ‘def’]
>
> I can’t think of another circumstance it which the type of the default value will make a difference.
>
> So… can we normalize the code and satisfy my OCD? Or should I just stop caring and move on? ;-)

Unfortunately `__iadd__` and `__add__` do not have the same behavior here:

>>> foo = ['abc']
>>> foo = foo + ('def',)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can only concatenate list (not "tuple") to list

So I think there is a backwards-compatibility issue.

Personally, I would love to decide to just bite this bullet and
normalize to lists, but I think it would need to be marked as a
backwards-incompatibility in the release notes, and it would certainly
bite people.

Carl

signature.asc

Michael Manfre

unread,
Dec 17, 2014, 4:03:55 PM12/17/14
to django-d...@googlegroups.com
+1 for lists.


--
You received this message because you are subscribed to the Google Groups "Django developers  (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To post to this group, send email to django-d...@googlegroups.com.
Visit this group at http://groups.google.com/group/django-developers.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/5491ED93.2080506%40oddbird.net.
For more options, visit https://groups.google.com/d/optout.

Aymeric Augustin

unread,
Dec 17, 2014, 4:04:22 PM12/17/14
to django-d...@googlegroups.com
On 17 déc. 2014, at 21:54, Carl Meyer <ca...@oddbird.net> wrote:

> So I think there is a backwards-compatibility issue.

Indeed.

> Personally, I would love to decide to just bite this bullet and
> normalize to lists, but I think it would need to be marked as a
> backwards-incompatibility in the release notes, and it would certainly
> bite people.

We can do that. The error is easy to fix if it occurs. Technically
django.conf.global_settings is a private API.

But I feel guilty to break code just for consistency and aesthetics :-/

--
Aymeric.




Collin Anderson

unread,
Dec 17, 2014, 4:20:41 PM12/17/14
to django-d...@googlegroups.com
I agree lists are the way to go. I have heard that tuples are faster, but I don't think that outweighs comma issue and inconsistency.

global_settings isn't completely undocumented, based on greping the docs. Seems to me we should at least make the docs and project_template consistent and use lists everywhere.

Andrea Corbellini

unread,
Dec 17, 2014, 4:27:19 PM12/17/14
to django-d...@googlegroups.com
On Wed, Dec 17, 2014 at 9:48 PM, Aymeric Augustin <aymeric....@polytechnique.org> wrote:
Surprisingly, it seems that there isn’t a backwards compatibility problem with changing the type to lists, as the following pattern still works: # myproject/settings.py from django.conf.global_settings import FILE_UPLOAD_HANDLERS FILE_UPLOAD_HANDLERS += ('myproject.uploadhandler.FooBarUploadHandler',) Proof:
foo = ['abc'] foo += ('def',) foo
['abc', ‘def’]

Well, technically, there is a potential backward incompatibility: += for lists is a synonym for .extend().

Proof:

>>> a = [1,2,3]
>>> b = a
>>> b += (4,)
>>> a
[1, 2, 3, 4]
>>> b
[1, 2, 3, 4]


>>> a = (1,2,3)
>>> b = a
>>> b += (4,)
>>> a
(1, 2, 3)
>>> b
(1, 2, 3, 4)

Russell Keith-Magee

unread,
Dec 17, 2014, 6:40:22 PM12/17/14
to Django Developers
I agree that lists are preferable to tuples.

As for backwards incompatibility: we can update the new project template, and we can update the docs; but I don't think we can play the "global_settings is internal API" card here. The file global_settings might not be formally documented, but the contents are, and the default settings provided by Django are documented; and even if they weren't, this is a high traffic area of the Django API.

One option for handling existing projects might be to define our own subclass of list that defines __add__, __iadd__, and __radd__ such that it will accept a tuple, converting to a list, and raise a DeprecationWarning; in a later version, we can replace that subclass with a simple list. We wouldn't document this class, and it would only be used in global_settings.py. This would cover the most common use case (adding something to a default setting), and provide a migration path. Thoughts?

Yours,
Russ Magee %-)
 

Carl Meyer

unread,
Dec 17, 2014, 6:48:40 PM12/17/14
to django-d...@googlegroups.com
This is clever, but on second thought I'm trying to figure out in what
scenario a backwards-compatibility would actually occur here. In the
context of a user's settings modules, global_settings plays no role at
all: you can't add to a global setting default in your settings.py
(unless you've imported global_settings yourself, which is certainly
making use of undocumented internals).

So it seems to me that the only scenario in which this would actually
cause a back-compat problem would be if someone is using a tuple
setting, which they are not setting themselves (and thus are using the
global default), and they are adding to it in their runtime code (not in
their settings file). For instance:

my_ctx_procs = settings.TEMPLATE_CONTEXT_PROCESSORS + ('another',)

The common case of appending to a setting in your settings.py (due to
use of some kind of split-settings) should not be impacted at all.

I guess this is still enough of a backwards-incompatibility that we
should have a deprecation process, but it won't bite nearly as many
people as I'd initially thought it would.

FWIW, I think the subclass-of-list approach is neat enough, I'd be in
favor of going ahead and doing this with that approach, if someone's
motivated to write the patch.

Carl

signature.asc

Ryan Hiebert

unread,
Dec 17, 2014, 6:57:59 PM12/17/14
to django-d...@googlegroups.com

> On Dec 17, 2014, at 5:48 PM, Carl Meyer <ca...@oddbird.net> wrote:
>
> On 12/17/2014 04:39 PM, Russell Keith-Magee wrote:
>>
>> I agree that lists are preferable to tuples.
>>
>> One option for handling existing projects might be to define our own
>> subclass of list that defines __add__, __iadd__, and __radd__ such that it
>> will accept a tuple, converting to a list, and raise a DeprecationWarning;
>> in a later version, we can replace that subclass with a simple list. We
>> wouldn't document this class, and it would only be used in
>> global_settings.py. This would cover the most common use case (adding
>> something to a default setting), and provide a migration path. Thoughts?
>
> FWIW, I think the subclass-of-list approach is neat enough, I'd be in
> favor of going ahead and doing this with that approach, if someone's
> motivated to write the patch.
>
What would __iadd__ do in this subclass? Would it behave like tuple and
create a new DjangoList, or would it behave like list and extend the
original list?

I’m interested at taking a whack at it, though I can imagine somebody else
getting it done faster.

Ryan

Carl Meyer

unread,
Dec 17, 2014, 7:12:59 PM12/17/14
to django-d...@googlegroups.com
For maximum backwards-compatibility during the deprecation period, if
it's called with a tuple, it should create and return a new tuple, I
think. That way the deprecation warning only gets fired once for a
particular setting, which is all that's needed, even if they go and add
to the resulting value several more times.

If it's called with a list, it should behave as a normal list does.

And before you get too far, you may want to wait and see if any other
core devs step in to tell me I'm crazy and there's no way we should have
a deprecation path just to switch some settings from tuples to lists.

(I'm only in favor of it myself because I think in practice the impact
will be small.)

Carl

signature.asc

Ryan Hiebert

unread,
Dec 17, 2014, 7:22:05 PM12/17/14
to django-d...@googlegroups.com
Thanks for the warning, and your solution makes perfect sense to me.
I’m gonna go ahead and keep working on it for fun, but I understand
that we might find that it’s not worth the deprecation period, and
I’m OK with that.

Thinking about it a bit, I’m going to see if just watching for tuple
and returning a tuple, otherwise returning a native list might be
sufficient.

Ryan

Russell Keith-Magee

unread,
Dec 18, 2014, 1:49:31 AM12/18/14
to Django Developers
That's a fair point. The benefit for an __add__ definition is likely to be a lot smaller than I originally thought.

The only place I can think that it might pop up is in older (pre @override_settings) test harnesses; that said, a failure during test isn't a major inconvenience

So - I retract my suggestion - I think I can live with just documenting this as a backwards compatibility.

Yours,
Russ Magee %-)

Ryan Hiebert

unread,
Dec 18, 2014, 1:57:50 AM12/18/14
to django-d...@googlegroups.com

> On Dec 18, 2014, at 12:49 AM, Russell Keith-Magee <rus...@keith-magee.com> wrote:
>
> So - I retract my suggestion - I think I can live with just documenting this as a backwards compatibility.

Sounds good. In case anyone is interested, I made a pull request (not complete) with an implementation of a ‘ConfList’ that could detect operations with tuples. Scrapping it doesn’t bother me, it was a fun challenge. Perhaps someone else will think it’s interesting too.

https://github.com/django/django/pull/3752

Carl Meyer

unread,
Dec 18, 2014, 7:56:47 AM12/18/14
to django-d...@googlegroups.com
Works for me!

Carl

signature.asc

Collin Anderson

unread,
Jan 16, 2015, 10:32:10 AM1/16/15
to django-d...@googlegroups.com
Hi All,

Should change tuples to lists in more places in the docs?

Collin

Andreas Kahnert

unread,
Jan 19, 2015, 6:35:10 AM1/19/15
to django-d...@googlegroups.com
Hi all,

I'm strongly against lists. Lists are mutable objects, their components can be changed in place. The settings are initialized at server start and after that changes on them arn't reflected. Therefore all settings should be tuples from my point of view. Using a custom list/tuple class for "easy" notation within the settings.py might be an option, but after server startup all of those should be immutable. So for the sake of logic, take tuples, please.

Andreas

Florian Apolloner

unread,
Jan 19, 2015, 8:20:51 AM1/19/15
to django-d...@googlegroups.com


On Monday, January 19, 2015 at 12:35:10 PM UTC+1, Andreas Kahnert wrote:
I'm strongly against lists. Lists are mutable objects, their components can be changed in place. The settings are initialized at server start and after that changes on them arn't reflected. Therefore all settings should be tuples from my point of view. Using a custom list/tuple class for "easy" notation within the settings.py might be an option, but after server startup all of those should be immutable. So for the sake of logic, take tuples, please.

As long as  something like settings.MY_SETTING=(1,); settings.MY_SETTING+=(1,2,3) works, that argument is kinda moot imo.

Cheers,
Florian

Andreas Kahnert

unread,
Jan 19, 2015, 9:45:18 AM1/19/15
to django-d...@googlegroups.com
I'm not talking about modifications inside the settings.py but in other place. With lists, unexperienced devs might do things like: from django.conf import settings; settings.TEMPLATE_DIRS[3] = '/my_tpls'; and expect to work out good. (This doesn't violate the docs, since technicaly settings.TEMPLATE_DIRS is still the same list, means the settings variable itself hasn't been changed.) This is realy just a question of logic: lists are mutable - settings are immutable; see the conflict?

Marc Tamlyn

unread,
Jan 19, 2015, 9:49:37 AM1/19/15
to django-d...@googlegroups.com
I think Florian's point would be that you can still do:

from django.conf import settings
settings.TEMPLATE_DIRS += ('foo',)

if it is a tuple, so I don't really see how it being a tuple is making it necessarily more safe than a list - is the above code really much different to:

from django.conf import settings
settings.TEMPLATE_DIRS.append('foo')

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To post to this group, send email to django-d...@googlegroups.com.
Visit this group at http://groups.google.com/group/django-developers.

Andreas Kahnert

unread,
Jan 19, 2015, 10:05:46 AM1/19/15
to django-d...@googlegroups.com
Test Code:
old_var = settings.TEMPLATE_DIRS
settings.TEMPLATE_DIRS += ('foo',) if isinstance(settings.TEMPLATE_DIRS, tuple) else ['foo']
old_var is settings.TEMPLATE_DIRS  # will return True if it was a list; will return False if it was a tuple, since a new tuple was assigned to settings.TEMPLATE_DIRS (violating the docs)

This was just a silly example, but if think of modularity and so on, this could get a disaster. The assignment could be somewhere in a helper-function where it's not obvious that the list originates from the settings. Another helper-function might use settings.TEMPLATE_DIRS to iterate over (maybe to validate all templates are reachable or something) yielding different results than the framework actual usage. Debuging this would be pretty hard (especially for those who arn't aware of the subtile differences between lists and tuples)

Collin Anderson

unread,
Jan 19, 2015, 11:19:13 AM1/19/15
to django-d...@googlegroups.com
Hi Andreas,

I agree that tuples do slightly help enforce that settings are supposed to be immutable, and I agree that if someone were to try to modify the settings the way you showed it would be very hard to debug. However, I think it's a pretty rare case.

I think a much more common case is the trailing comma problem with single element tuples. This can also be very frustrating for beginners. I'd personally rather help out the beginner cases than someone attempting to do things that they shouldn't be doing.

I also think lists of tuples are easier to read than tuples of tuples.

Anyone could still use tuples in their settings if they want the extra strength.

What do you think?

Collin

Florian Apolloner

unread,
Jan 19, 2015, 11:35:44 AM1/19/15
to django-d...@googlegroups.com
On Monday, January 19, 2015 at 3:45:18 PM UTC+1, Andreas Kahnert wrote:
I'm not talking about modifications inside the settings.py but in other place. With lists, unexperienced devs might do things like: from django.conf import settings; settings.TEMPLATE_DIRS[3] = '/my_tpls'; and expect to work out good.

And with tuples they just do settings.TEMPLATE_DIRS = list(settings.TEMPLATE_DIRS) followed by your example. What I am trying to say is that a developer ignoring the docs will always run into issues, no matter how hard we try to prevent it.

This is realy just a question of logic: lists are mutable - settings are immutable; see the conflict?

Well, what is your suggestion for the dictionaries in the settings then ;) In the end it just doesn't matter if it's a list or a tuple -- you can "mutate" it anyways. For the functionality of Django it makes no difference if you altered the setting in place or just replace it -- stuff __will__ break.

Cheers,
Florian

Andreas Kahnert

unread,
Jan 19, 2015, 12:15:09 PM1/19/15
to django-d...@googlegroups.com
Well, yep. You can't prevent programmers to do stupid things in python. But I'm kind of a theroretician and it hurts me if I see that exactly that what it should not be is proposed as the standard. And for the dicts: In my private code-base I use a frozendict c-package I wrote.

@Collin: The notation used within settings.py isn't that important. But I think in the moment the framework constructs the settings object all sequences (might be generators as well) should be turned into tuples.

For the trailing-comma-problem: I notate every (globally available) constant sequence in the pattern:
A = (
    1,
    2,
)
which is perfectly PEP-conformant and makes reodering elements manually also more easy because you can cut'n'paste whole lines.

Andreas Kahnert

unread,
Jan 19, 2015, 12:20:11 PM1/19/15
to django-d...@googlegroups.com
PS: python should be able to access tuple members faster, because it can be implemented as array instead of double-linked-structs which are necessary mutable lists. But as far as I know it doesn't.

Loïc Bistuer

unread,
Jan 19, 2015, 12:53:26 PM1/19/15
to django-d...@googlegroups.com
Hi Andreas,

As Florian pointed out, you can't mutate a tuple, but you can mutate the settings object, so using a tuple or a frozendict won't buy you much.

Regarding the theoretical perspective, tuples aren't meant to be immutable lists. Tuples are for heterogenous collections of fixed size (e.g. GPS coordinates); whereas lists are for homogenous collections of variable size, which suits perfectly our settings use-case. Of course Python being Python you can use them however you like but let's not talk about theory in that case.

Cheers

--
Loïc
> --
> You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
> To post to this group, send email to django-d...@googlegroups.com.
> Visit this group at http://groups.google.com/group/django-developers.
> To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/07fd597a-01d2-4f6c-845b-5587a19b3263%40googlegroups.com.

Andreas Kahnert

unread,
Jan 19, 2015, 1:43:59 PM1/19/15
to django-d...@googlegroups.com
Hi Loïc,

I agree that we should not discuss about the theoretical aspects too much (while I disagree on your distinction, the API difference is just their mutability, so unless you refer to python intern algorithms for sort- /lookup- optimization (if so, excuse me) your distinction is just your personal taste)

The main point is the accidential assignment to list members / extension of the list in places where it's not obvious that the list of subject is part of the settings. Passing the whole settings object through functions makes no sense since you can always get it by importing, which minimizes the risk of accidently assigning to it.

Loïc Bistuer

unread,
Jan 19, 2015, 1:55:59 PM1/19/15
to django-d...@googlegroups.com


> On Jan 20, 2015, at 01:43, Andreas Kahnert <kah...@cruise-systems.com> wrote:
>
> Hi Loïc,
>
> I agree that we should not discuss about the theoretical aspects too much (while I disagree on your distinction, the API difference is just their mutability, so unless you refer to python intern algorithms for sort- /lookup- optimization (if so, excuse me) your distinction is just your personal taste)

Presumably more than just my personal taste: https://docs.python.org/2/faq/design.html#why-are-there-separate-tuple-and-list-data-types.

--
Loïc

Andreas Kahnert

unread,
Jan 19, 2015, 2:36:06 PM1/19/15
to django-d...@googlegroups.com
Interesting,  ... so excuse me.
The next point also clearifys my PS from above, lists are over-allocated dynamic sized arrays. (this explains why python is such an memory eater as well as why I experienced performance loss when using the mutability of lists extensivly)


Am Montag, 19. Januar 2015 19:55:59 UTC+1 schrieb Loïc Bistuer:

Presumably more than just my personal taste: https://docs.python.org/2/faq/design.html#why-are-there-separate-tuple-and-list-data-types.

--
Loïc


But coordinates have homogenous members (floats) as djangos setting sequences have (strings), both are of fixed size (those they have after you declared them),
So this still doesn't change my (theoretical) opinion.

Andreas Kahnert

unread,
Jan 19, 2015, 3:13:07 PM1/19/15
to django-d...@googlegroups.com
I advertise that strongly against lists, because we actually had that kind of issue in our company.
One colleague created a list with phrases for some verbose logging in the settings.py. In the view function he promoted this list together with the actual data, also a list which is used for storing the data afterwards, to another function. The other function was implemented by another colleague, he was aware that he should not modify the second list for not corrupting the data to be safed. So he appended the data components to the first list zipped it to an dict and called the logging function. The result was that every log entry contained all data from previous calls and the server loked down very quick. It took them a day to debug this.

Michael Manfre

unread,
Jan 19, 2015, 3:30:09 PM1/19/15
to django-d...@googlegroups.com
The situation you described was definitely a learning experience for your company. Your strong opinion in favor of tuples is also noted.

For the various reasons stated in this thread, I'm still +1 for lists.

Regards,
Michael Manfre

On Mon, Jan 19, 2015 at 3:13 PM, Andreas Kahnert <kah...@cruise-systems.com> wrote:
I advertise that strongly against lists, because we actually had that kind of issue in our company.
One colleague created a list with phrases for some verbose logging in the settings.py. In the view function he promoted this list together with the actual data, also a list which is used for storing the data afterwards, to another function. The other function was implemented by another colleague, he was aware that he should not modify the second list for not corrupting the data to be safed. So he appended the data components to the first list zipped it to an dict and called the logging function. The result was that every log entry contained all data from previous calls and the server loked down very quick. It took them a day to debug this.

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To post to this group, send email to django-d...@googlegroups.com.
Visit this group at http://groups.google.com/group/django-developers.

Carl Meyer

unread,
Jan 19, 2015, 3:39:48 PM1/19/15
to django-d...@googlegroups.com
There is nothing in this anecdote that is specific to Django settings,
or even to Django. The appropriate lesson to be learned from it is
general to Python: no function that takes mutable objects as parameters
should ever mutate those objects (unless that side-effect is its
intended purpose, and that fact is clearly advertised in its
contract/documentation/docstring). Hopefully the second colleague in
your anecdote learned that lesson.

I don't see a reason here to prefer tuples over lists in settings.

Carl

signature.asc

Aymeric Augustin

unread,
Jan 19, 2015, 4:26:59 PM1/19/15
to django-d...@googlegroups.com
On 19 janv. 2015, at 21:13, Andreas Kahnert <kah...@cruise-systems.com> wrote:
> I advertise that strongly against lists, because we actually had that kind of issue in our company.

Hi Andreas,

This is probably obvious, but I thought I’d mention it just in case — you can keep
using tuples in your projects. We’re just talking about standardizing the docs and
the default values.

I understand your arguments and I can see how your experience led you there.
However, like others, I believe that encouraging “almost immutable” values would
provide a false sense of security and cannot be a substitute to an understanding
of Python’s data model.

By “almost immutable” I refer to the fact that even if settings.FOO is immutable
you can still overwrite it, especially with += whose difference with append will be
lost on someone who doesn’t understand the data model.

--
Aymeric.




Andreas Kahnert

unread,
Jan 20, 2015, 12:52:51 PM1/20/15
to django-d...@googlegroups.com
Just for completness: accidential assignment to the settings object itself could be easily prevented with a __setattr__ method on its class, since django yields on various other places about configuration problems it could not be wrong if the programmer gets noted about an illegal assignment. If everything works fine the method will only get called during startup, so there is no runtime overhead. Simplified example:
def __setattr__(self, key, val):
    if self.configured:
        raise Exception('settings can not be changed after server startup')
    super(LazySettings, self).__setattr__(key, val)

@Carl Meyer: At the first hand you're right, a thing all programmers should know about (if they call themself so), but he assumed there existed some kind of copy-on-read semantic for the settings, because you get something different when imported from django.conf instead directly and because it's a "magical" lazy object.


But since you all seem to like lists that much, maybe a compromise would be to explicitly note in the docs that there is a danger in using lists which can be prevented by tuple usage.

Aymeric Augustin

unread,
Jan 20, 2015, 2:40:54 PM1/20/15
to django-d...@googlegroups.com
On 20 janv. 2015, at 18:52, Andreas Kahnert <kah...@cruise-systems.com> wrote:

> But since you all seem to like lists that much, maybe a compromise would be to explicitly note in the docs that there is a danger in using lists which can be prevented by tuple usage.

As explained in my previous email, tuples don’t help much. I’m against stating that using tuples is somehow safer.

--
Aymeric.




Tom Christie

unread,
Jan 20, 2015, 6:17:28 PM1/20/15
to django-d...@googlegroups.com
Hi Andreas,

  I'm completely in agreement with you that *in theory* using tuples would be a (very marginal) improvement. I also happen think that the idea that tuples are semantically different from simply being  immutable lists is a nonsense - regardless of what a particular section of documentation may or may not say, language features are defined solely in terms of their behavior, they do not have dreams, hopes and grand philosophical outlooks on how they should be used.

  However, the simple case that tuples have a far poorer syntax in python than lists, and are *very* easy for beginners to get wrong is a good enough reason to prefer the usage of lists consistently.

  ("a string")

  ("a tuple",)

Beginners will not be following your "I notate every (globally available) constant sequence in the pattern" advice, and no amount of documentation is sufficient to prevent it being a very simple and easy error, that might be difficult for a beginner to track down. I think that's a bigger and easier trap than intentional assignment.

> accidental assignment to the settings object itself could be easily prevented with a __setattr__ method on its class

I'd suggest treating that as a separate issue - perhaps if you or someone else came up with a pull request that enforced immutability of the settings object that'd be considered on it's own merits. (Note that you could perfectly well also deal with making translating list and dict objects into immutable objects at *that* point of API, even if they're not in the settings module.) I haven't given that any great thought, so expect it would have it's own set of obstacles to overcome, but I think it's a different issue to the topic at hand here, which is really just about settling on an acceptable and consistent style.


> maybe a compromise would be to explicitly note in the docs

I'd be against that as unnecessary fluff - doing one thing in the code and recommending another in the docs just introduces noise and uncertainty.

The topic's been discussed more that it really deserves, but I understand that it can be frustrating if it feels like your reasoned arguments are being brickwalled. I wanted to at least contribute and note that I do agree with you in theory, even if practically I'd say that lists throughout is consistent, clear, and slightly less likely for developers to get wrong.

Cheers,

  Tom

Sambhav Satija

unread,
Jan 21, 2015, 3:18:40 AM1/21/15
to django-d...@googlegroups.com
So, I've been working on a patch (PFA) . As being discussed, lists are easier for beginners to follow, and tuples provide a false sense of security. With that in mind, I've simply changed pretty much all the tuples in global_settings and template_settings to lists, and warn about the usage of tuples at startup time. I'm going through the documentation and changing it in the necessary places if this thing goes through. Suggestions ?
tuple_to_list.patch

Tom Christie

unread,
Jan 21, 2015, 8:02:37 AM1/21/15
to django-d...@googlegroups.com
> So, I've been working on a patch ... Suggestions?

Normalizing on lists as the default throughout is good. Warning about using tuples and putting their usage on a deprecation path seems a little unnecessary. I don't think that was discussed in this thread, but I've only scanned through, so I could be wrong.

If nothing else let's at least treat those as two *separately reviewable* pull requests.

Sambhav Satija

unread,
Jan 21, 2015, 8:08:12 AM1/21/15
to django-d...@googlegroups.com
While I understand that turning it into a deprecation warning would be way out of bounds, That was simply meant to say that maybe we should raise some warning at startup time that'll ensure that the developer at least knows what he's up against if he puts in tuples instead of lists.

Aymeric Augustin

unread,
Jan 21, 2015, 9:44:37 AM1/21/15
to django-d...@googlegroups.com
As explained above and discussed on the #django-dev IRC channel, it's an acceptable choice to use tuples, even though it isn't the default Django chose. Please don't raise warnings or do anything else to discourage using tuples.

Writing this patch consists in:

- going though the 22 settings whose default value is currently a tuple
- doing a "find-all" in the Django repository with the setting name
- adjusting the code (including surrounding comments), docs and tests

I would suggest making one commit per setting, for ease of review, but if you already made lots of local changes this isn't a big deal.

-- 
Aymeric.


--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To post to this group, send email to django-d...@googlegroups.com.
Visit this group at http://groups.google.com/group/django-developers.

For more options, visit https://groups.google.com/d/optout.



--
Aymeric.

Andreas Kahnert

unread,
Jan 22, 2015, 7:32:14 AM1/22/15
to django-d...@googlegroups.com
Hi again,
Well, I can acknoledge that your reasons for list (beginner friendly) are as good as my reasons for tuples (seems to be more logical choice for things that are static). To say it in other words, my idea was simply: Use tuples and the programmer will know that these arn't ment to be altered at runtime.
But this reformulation made me thought of the docs comment I suggested. And probably the docs should clearly state (in https://docs.djangoproject.com/en/1.6/topics/settings/#creating-your-own-settings):
The settings are solely for configuration of django and its components / extensions, but not for initial/default values of your application, because the settings have to be imported in a special way (through django.conf; sidenote - it states there: "For settings that are sequences, Django itself uses tuples, rather than lists, but this is only a convention")
At the end, this was what the confusion between my colleages caused and what his true programming-theoretical mistake was. (nowadays all of our apps have a definitions.py module)

I hope this is something all could agree with and ends the discussion I caused.

Tom Evans

unread,
Feb 19, 2015, 8:22:26 AM2/19/15
to django-d...@googlegroups.com
On Thu, Jan 22, 2015 at 12:32 PM, Andreas Kahnert
<kah...@cruise-systems.com> wrote:
> Hi again,
> Well, I can acknoledge that your reasons for list (beginner friendly) are as
> good as my reasons for tuples (seems to be more logical choice for things
> that are static). To say it in other words, my idea was simply: Use tuples
> and the programmer will know that these arn't ment to be altered at runtime.

It is incorrect to say that the reason for lists is "beginner
friendliness". It may well make things friendlier for beginners, but
what it definitely helps with is for more advanced deployment
configuration and for modifying settings from base or default settings
files.

Secondly, settings are *only* altered at run time. The module pointed
at by DJANGO_SETTINGS_MODULE is imported, its code is run, and the
settings object is produced. From this point on, yes, settings should
not be modified, but that tells nothing about how they can be modified
within the settings module during runtime but before being frozen in
the settings object.

From my POV therefore, it is doubly wrong to have tuples and say this
is because the values are meant to be immutable, because it does not
reflect reality.

For instance:

from project.default_settings import *
DEBUG=True
INSTALLED_APPS.append('django_debug_toolbar')
LOGGING['loggers']['homepage'] = { 'handlers': 'logfile', 'loglevel': DEBUG }

All of this modification is perfectly valid, and this is why (imo) the
default should be list instead of tuples.

Cheers

Tom
Reply all
Reply to author
Forward
0 new messages