# Re: pep 8 constants

Discussion in 'Python' started by Brendan Miller, Jan 14, 2009.

1. ### Brendan MillerGuest

> FOO = 1
>
> def f(x=FOO):
> ...
>
>
>
> def f(x=1):
> ...

I tend to use constants as a means of avoiding the proliferation of
magic literals for maintenance reasons... Like say if your example of
FOO would have been used in 10 places. Maybe it is more pythonic to
simply denote such a thing as simply a normal variable? That doesn't
seem to give a hint that it shouldn't be assigned a second time.

Brendan Miller, Jan 14, 2009

2. ### Steven D'ApranoGuest

On Tue, 13 Jan 2009 23:26:54 -0800, Brendan Miller wrote:

> I tend to use constants as a means of avoiding the proliferation of
> magic literals for maintenance reasons... Like say if your example of
> FOO would have been used in 10 places. Maybe it is more pythonic to
> simply denote such a thing as simply a normal variable?

But it isn't a "normal variable", it's a named constant, or at least it
would be if Python enforced constanticity. Or constantness. Or whatever.

> That doesn't
> seem to give a hint that it shouldn't be assigned a second time.

Absolutely. It's rather sad that I can do this:

import math
math.pi = 3.0

I like the ability to shoot myself in the foot, thank you very much, but
I should at least get a warning when I'm about to do so:

math.PI = 3.0 # use God-like powers to change a constant

Changing the laws of physics, one fundamental constant at a time-ly y'rs,

--
Steven

Steven D'Aprano, Jan 14, 2009

3. ### MRABGuest

Francesco Bochicchio wrote:
> On Wed, 14 Jan 2009 08:13:30 +0000, Steven D'Aprano wrote:
>
>
>> Absolutely. It's rather sad that I can do this:
>>
>> import math
>> math.pi = 3.0
>>
>> I like the ability to shoot myself in the foot, thank you very much, but
>> I should at least get a warning when I'm about to do so:
>>
>> math.PI = 3.0 # use God-like powers to change a constant
>>
>>

>
> Constants would be a nice addition in python, sure enough.
> But I'm not sure that this can be done without a run-time check every time
> the constant is used, and python is already slow enough. Maybe a check
> that is disabled when running with optimizing flags ?
>
> But I'm sure this discussion has been already made and the FINAL WORD has
>
>>> class Constants(object):

def __setattr__(self, key, value):
if key in self.__dict__:
raise ValueError("Can't change constant")
self.__dict__[key] = value

>>> c = Constants()
>>> c.PI = 3.0
>>> c.PI

3.0
>>> c.PI = 4.0

Traceback (most recent call last):
File "<pyshell#22>", line 1, in <module>
c.PI = 4.0
File "<pyshell#19>", line 4, in __setattr__
raise ValueError("Can't change constant")
ValueError: Can't change constant

MRAB, Jan 18, 2009
4. ### Brendan MillerGuest

> Constants would be a nice addition in python, sure enough.

My original question was about PEP-8 and whether it is pythonic to use
all caps to denote a variable that shouldn't be changed. More of a
style question than a language question.

I actually think *enforcing* constantness seems to go against the
grain of the language so to speek

Brendan Miller, Jan 20, 2009
5. ### Steven D'ApranoGuest

On Mon, 19 Jan 2009 19:11:16 -0800, Brendan Miller wrote:

>> Constants would be a nice addition in python, sure enough.

>
> My original question was about PEP-8 and whether it is pythonic to use
> all caps to denote a variable that shouldn't be changed. More of a style
> question than a language question.
>
> I actually think *enforcing* constantness seems to go against the grain
> of the language so to speek

Why? Python has an infinite number of constants. The only difference is
that they are immutable objects, not names.

But regardless... yes, it is in my opinion Pythonic to use ALLCAPS to
designate constants (by convention). It isn't in PEP 8, but I don't think
that matters unless PEP 8 suggests a different convention.

--
Steven

Steven D'Aprano, Jan 20, 2009
6. ### Rhodri JamesGuest

On Tue, 20 Jan 2009 04:58:30 -0000, Ben Finney
<> wrote:

> Unless someone's going to argue that â€œVariable Namesâ€ doesn't apply to
> constant names, even though Python doesn't make the distinction.

Python doesn't make the distinction, which is precisely why making the
distinction through CONVENTIONAL_NAMING_PRACTICE is useful.

--
Rhodri James *-* Wildebeeste Herder to the Masses

Rhodri James, Jan 21, 2009
7. ### Brian Allen Vanderburg IIGuest

wrote:
> Constants would be a nice addition in python, sure enough.
> But I'm not sure that this can be done without a run-time check every time
> the constant is used, and python is already slow enough. Maybe a check
> that is disabled when running with optimizing flags ?
>
> But I'm sure this discussion has been already made and the FINAL WORD has
>
> Ciao
> ----
> FB
> --
> http://mail.python.org/mailman/listinfo/python-list
>

One idea to make constants possible would be to extend properties to be
able to exist at the module level as well as the class level:

@property
def pi():
return 3.14159.....

print(pi) # prints 3.14159....
pi=32 # Raise an error Cannot set attribute ...

Brian Vanderburg II

Brian Allen Vanderburg II, Jan 22, 2009
8. ### Steve HoldenGuest

Brian Allen Vanderburg II wrote:
> wrote:
>> Constants would be a nice addition in python, sure enough.
>> But I'm not sure that this can be done without a run-time check every
>> time
>> the constant is used, and python is already slow enough. Maybe a check
>> that is disabled when running with optimizing flags ?
>>
>> But I'm sure this discussion has been already made and the FINAL WORD has
>>
>> Ciao
>> ----
>> FB
>> --
>> http://mail.python.org/mailman/listinfo/python-list
>>

> One idea to make constants possible would be to extend properties to be
> able to exist at the module level as well as the class level:
>
> @property
> def pi():
> return 3.14159.....
>
> print(pi) # prints 3.14159....
> pi=32 # Raise an error Cannot set attribute ...
>

I don't understand why this would print 3.14159 ... instead of <function
__math__.pi>, or whatever.

property would clearly have to do something very different in module
scope in order to make this work.

regards
Steve
--
Steve Holden +1 571 484 6266 +1 800 494 3119
Holden Web LLC http://www.holdenweb.com/

Steve Holden, Jan 23, 2009
9. ### Ethan FurmanGuest

Steve Holden wrote:
> Brian Allen Vanderburg II wrote:
>
>> wrote:
>>
>>>Constants would be a nice addition in python, sure enough.
>>>But I'm not sure that this can be done without a run-time check every
>>>time
>>>the constant is used, and python is already slow enough. Maybe a check
>>>that is disabled when running with optimizing flags ?
>>>
>>>But I'm sure this discussion has been already made and the FINAL WORD has
>>>
>>>Ciao
>>>----
>>>FB

>>
>>One idea to make constants possible would be to extend properties to be
>>able to exist at the module level as well as the class level:
>>
>>@property
>>def pi():
>> return 3.14159.....
>>
>>print(pi) # prints 3.14159....
>>pi=32 # Raise an error Cannot set attribute ...
>>

>
> I don't understand why this would print 3.14159 ... instead of <function
> __math__.pi>, or whatever.
>
> property would clearly have to do something very different in module
> scope in order to make this work.
>
> regards
> Steve

--> class tester(object):
.... @property
.... def pi(self):
.... return 3.141596
....
--> testee = tester()
--> testee.pi
3.1415959999999998

Looks like that's how property works, so the same behavior on a module
level would do as Brian suggests.
--
~Ethan~

Ethan Furman, Feb 25, 2009
10. ### Steve HoldenGuest

Ethan Furman wrote:
> Steve Holden wrote:
>> Brian Allen Vanderburg II wrote:
>>
>>> wrote:
>>>
>>>> Constants would be a nice addition in python, sure enough.
>>>> But I'm not sure that this can be done without a run-time check every
>>>> time
>>>> the constant is used, and python is already slow enough. Maybe a check
>>>> that is disabled when running with optimizing flags ?
>>>>
>>>> But I'm sure this discussion has been already made and the FINAL
>>>> WORD has
>>>>
>>>> Ciao
>>>> ----
>>>> FB
>>>
>>> One idea to make constants possible would be to extend properties to be
>>> able to exist at the module level as well as the class level:
>>>
>>> @property
>>> def pi():
>>> return 3.14159.....
>>>
>>> print(pi) # prints 3.14159....
>>> pi=32 # Raise an error Cannot set attribute ...
>>>

>>
>> I don't understand why this would print 3.14159 ... instead of <function
>> __math__.pi>, or whatever.
>>
>> property would clearly have to do something very different in module
>> scope in order to make this work.
>>
>> regards
>> Steve

>
> --> class tester(object):
> ... @property
> ... def pi(self):
> ... return 3.141596
> ...
> --> testee = tester()
> --> testee.pi
> 3.1415959999999998
>
> Looks like that's how property works, so the same behavior on a module
> level would do as Brian suggests.

But that's at the class level, not the module level.

regards
Steve
--
Steve Holden +1 571 484 6266 +1 800 494 3119
Holden Web LLC http://www.holdenweb.com/

Steve Holden, Feb 25, 2009
11. ### Gabriel GenellinaGuest

En Tue, 24 Feb 2009 22:52:20 -0200, Ethan Furman <>
escribió:

> Steve Holden wrote:
>> Brian Allen Vanderburg II wrote:
>>
>>> One idea to make constants possible would be to extend properties to be
>>> able to exist at the module level as well as the class level:
>>>
>>> @property
>>> def pi():
>>> return 3.14159.....
>>>
>>> print(pi) # prints 3.14159....
>>> pi=32 # Raise an error Cannot set attribute ...
>>>

>> I don't understand why this would print 3.14159 ... instead of
>> <function
>> __math__.pi>, or whatever.
>> property would clearly have to do something very different in module
>> scope in order to make this work.
>> regards
>> Steve

>
> --> class tester(object):
> ... @property
> ... def pi(self):
> ... return 3.141596
> ...
> --> testee = tester()
> --> testee.pi
> 3.1415959999999998
>
> Looks like that's how property works, so the same behavior on a module
> level would do as Brian suggests.

Note that:
- you defined the property inside the *class* tester
- then, you created an *instance* of such class
- you retrieve pi from the instance
- if you retrieve pi from the class (tester.pi), you get a property
object, not a float.
- if you directly attach the property to the instance, testee.pi returns
a property object, not a float.
Finally, consider that modules are instances of type `module`; all modules
are instances of the same type.

How do you propose to make properties work at the module level?

--
Gabriel Genellina

Gabriel Genellina, Feb 25, 2009
12. ### Steve HoldenGuest

Gabriel Genellina wrote:
> En Tue, 24 Feb 2009 22:52:20 -0200, Ethan Furman <>
> escribió:
>
>> Steve Holden wrote:
>>> Brian Allen Vanderburg II wrote:
>>>
>>>> One idea to make constants possible would be to extend properties to be
>>>> able to exist at the module level as well as the class level:
>>>>
>>>> @property
>>>> def pi():
>>>> return 3.14159.....
>>>>
>>>> print(pi) # prints 3.14159....
>>>> pi=32 # Raise an error Cannot set attribute ...
>>>>
>>> I don't understand why this would print 3.14159 ... instead of
>>> <function
>>> __math__.pi>, or whatever.
>>> property would clearly have to do something very different in module
>>> scope in order to make this work.
>>> regards
>>> Steve

>>
>> --> class tester(object):
>> ... @property
>> ... def pi(self):
>> ... return 3.141596
>> ...
>> --> testee = tester()
>> --> testee.pi
>> 3.1415959999999998
>>
>> Looks like that's how property works, so the same behavior on a module
>> level would do as Brian suggests.

>
> Note that:
> - you defined the property inside the *class* tester
> - then, you created an *instance* of such class
> - you retrieve pi from the instance
> - if you retrieve pi from the class (tester.pi), you get a property
> object, not a float.
> - if you directly attach the property to the instance, testee.pi
> returns a property object, not a float.
> Finally, consider that modules are instances of type `module`; all
> modules are instances of the same type.
>
> How do you propose to make properties work at the module level?
>

Thanks, Gabriel. I was beginning to think there was something terribly

regards
Steve
--
Steve Holden +1 571 484 6266 +1 800 494 3119
Holden Web LLC http://www.holdenweb.com/

Steve Holden, Feb 25, 2009
13. ### Bruno DesthuilliersGuest

(snip - about using ALL_CAPS for pseudo-constants)
> Perhaps I'd even
> argue for an update to PEP 8 that endorses this as conventional.

+1

I've been a bit surprised last time I checked PEP8 to find out this
wasn't already the case - I would have sweared it was.

Bruno Desthuilliers, Feb 25, 2009
14. ### Bruno DesthuilliersGuest

Brian Allen Vanderburg II a écrit :
> wrote:
>> Constants would be a nice addition in python, sure enough.
>> But I'm not sure that this can be done without a run-time check every
>> time
>> the constant is used, and python is already slow enough. Maybe a check
>> that is disabled when running with optimizing flags ?
>>
>> But I'm sure this discussion has been already made and the FINAL WORD has
>>
>>

> One idea to make constants possible would be to extend properties to be
> able to exist at the module level as well as the class level:
>
> @property
> def pi():
> return 3.14159.....
>
> print(pi) # prints 3.14159....
> pi=32 # Raise an error Cannot set attribute ...
>

There are a couple problems with this suggestion:

- it would require modifying lookup rules to allow the protocol
descriptor to be invoked on instance attributes[1] - which is not
actually the case, by design.

- it adds the overhead of a method and a function call for what is
mostly a simple "constant" attribute lookup.

FWIW, while it would already work for class-level pseudo-constants
(using a very simple custom descriptor), I'd qualify such usage as a WTF.

Bruno Desthuilliers, Feb 25, 2009
15. ### Bruno DesthuilliersGuest

Ethan Furman a écrit :
> Steve Holden wrote:
>> Brian Allen Vanderburg II wrote:
>>

(snip)
>>> One idea to make constants possible would be to extend properties to be
>>> able to exist at the module level as well as the class level:
>>>
>>> @property
>>> def pi():
>>> return 3.14159.....
>>>
>>> print(pi) # prints 3.14159....
>>> pi=32 # Raise an error Cannot set attribute ...
>>>

>>
>> I don't understand why this would print 3.14159 ... instead of <function
>> __math__.pi>, or whatever.
>>
>> property would clearly have to do something very different in module
>> scope in order to make this work.
>>

>
> --> class tester(object):
> ... @property
> ... def pi(self):
> ... return 3.141596
> ...
> --> testee = tester()
> --> testee.pi
> 3.1415959999999998
>
> Looks like that's how property works, so the same behavior on a module
> level would do as Brian suggests.

s/module/instance/

At runtime, modules are instances of the module type - so 'module-level'
names are really instance attributes of the module instance -, and the
descriptor protocol is only invoked for class attributes.

Bruno Desthuilliers, Feb 25, 2009
16. ### Robin BeckerGuest

well this sort of awful hackery will allow you to put read only constants on an
existing module

>>> import reportlab
>>> reportlab.__class__
>>> class MyModule(reportlab.__class__):

.... @property
.... def pi(self):
.... return 3
....
>>> z=MyModule('reportlab')
>>> z.__dict__.update(reportlab.__dict__)
>>> z.pi

3
>>> import sys
>>> sys.modules['reportlab']=z
>>> del reportlab
>>> import reportlab
>>> reportlab.pi

3
>>> reportlab.pi=4

Traceback (most recent call last):
File "<interactive input>", line 1, in <module>
AttributeError: can't set attribute
>>>

so I guess if you write your own module class and then use a special importer
you can create module like objects with read only attributes.

--
Robin Becker

Robin Becker, Feb 25, 2009
17. ### Bruno DesthuilliersGuest

Robin Becker a écrit :
> well this sort of awful hackery will allow you to put read only
> constants on an existing module
>

(snip example code)
>
> so I guess if you write your own module class and then use a special
> importer you can create module like objects with read only attributes.
>

Fine technical solution. But, err, isn't all this a bit overkill for
something that can easily be handled by a simple convention ?-)

Bruno Desthuilliers, Feb 25, 2009
18. ### Robin BeckerGuest

Bruno Desthuilliers wrote:
> Robin Becker a écrit :
>> well this sort of awful hackery will allow you to put read only
>> constants on an existing module
>>

> (snip example code)
>>
>> so I guess if you write your own module class and then use a special
>> importer you can create module like objects with read only attributes.
>>

>
> Fine technical solution. But, err, isn't all this a bit overkill for
> something that can easily be handled by a simple convention ?-)

.......
--
Robin Becker

Robin Becker, Feb 25, 2009
19. ### Rhodri JamesGuest

On Wed, 25 Feb 2009 08:48:27 -0000, Bruno Desthuilliers
<> wrote:

> Ben Finney a Ã©crit :
> (snip - about using ALL_CAPS for pseudo-constants)
>> Perhaps I'd even
>> argue for an update to PEP 8 that endorses this as conventional.

>
> +1
>
> I've been a bit surprised last time I checked PEP8 to find out this
> wasn't already the case - I would have sweared it was.

It is. Aahz added it a few weeks ago.

--
Rhodri James *-* Wildebeeste Herder to the Masses

Rhodri James, Feb 26, 2009
20. ### Ethan FurmanGuest

Steve Holden wrote:
> Gabriel Genellina wrote:
>
>>En Tue, 24 Feb 2009 22:52:20 -0200, Ethan Furman <>
>>escribió:
>>
>>
>>>Steve Holden wrote:
>>>
>>>>Brian Allen Vanderburg II wrote:
>>>>
>>>>
>>>>>One idea to make constants possible would be to extend properties to be
>>>>>able to exist at the module level as well as the class level:
>>>>>
>>>>>@property
>>>>>def pi():
>>>>> return 3.14159.....
>>>>>
>>>>>print(pi) # prints 3.14159....
>>>>>pi=32 # Raise an error Cannot set attribute ...
>>>>>
>>>>
>>>> I don't understand why this would print 3.14159 ... instead of
>>>><function
>>>>__math__.pi>, or whatever.
>>>> property would clearly have to do something very different in module
>>>>scope in order to make this work.
>>>> regards
>>>> Steve
>>>
>>>--> class tester(object):
>>>... @property
>>>... def pi(self):
>>>... return 3.141596
>>>...
>>>--> testee = tester()
>>>--> testee.pi
>>>3.1415959999999998
>>>
>>>Looks like that's how property works, so the same behavior on a module
>>>level would do as Brian suggests.

>>
>>Note that:
>> - you defined the property inside the *class* tester
>> - then, you created an *instance* of such class
>> - you retrieve pi from the instance
>> - if you retrieve pi from the class (tester.pi), you get a property
>>object, not a float.
>> - if you directly attach the property to the instance, testee.pi
>>returns a property object, not a float.
>>Finally, consider that modules are instances of type `module`; all
>>modules are instances of the same type.
>>
>>How do you propose to make properties work at the module level?
>>

>
> Thanks, Gabriel. I was beginning to think there was something terribly
> obvious I had completely missed.
>
> regards
> Steve

Yes, Thanks, Gabriel!