Page 1 of 1

Private const() variables aren't defined

Posted: Wed Sep 11, 2019 4:51 pm
by cdwilson
Can someone help me understand why private const() variables aren't defined?

Code: Select all

>>> A = const(1)
>>> A
1
>>> _B = const(2)
>>> _B
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name '_B' isn't defined

Re: Private const() variables aren't defined

Posted: Thu Sep 12, 2019 6:42 am
by jimmo
This is because you're running this in the REPL.

There's a neat optimisation that MicroPython does to save memory based on hte convention that variables starting with _ are "private". So they will only apply to the scope of the current module being compiled.

Each statement executed on the REPL kind of like making a file containing that statement and compiling it.

But yeah, it works if you access it inside the same module. e.g. if you had foo.py:

Code: Select all

A = const(1)
_B = const(2)
print(A + _B)
that works just fine - the print will use _B correctly. If you run

Code: Select all

import foo
print(foo.A) # fine
print(foo._B) # doesn't exist
This feature is really useful for drivers where you might have a whole list of consts (e.g. I2C register addresses) but no point having them hang around as variables. It was implemented in https://github.com/micropython/micropyt ... dc8edd5e0a likely based on Peter's suggestion in viewtopic.php?f=3&t=1941

Re: Private const() variables aren't defined

Posted: Thu Sep 12, 2019 6:46 am
by kevinkk525
That is the theory.
But in practice this is not true.

I do very often use this in my code (although it is wrong):

Code: Select all

import foo
print(foo._private_variable)
And in the repl I can still use private variables, just not defined as const:

Code: Select all

>>> _B="hi"
>>> _B
'hi'
>>> _C=const(3)
>>> _C
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name '_C' isn't defined

Re: Private const() variables aren't defined

Posted: Thu Sep 12, 2019 7:45 am
by pythoncoder
It seems to work as I'd expect. Consider foo.py

Code: Select all

from micropython import const
_A = const(1)
_B = 2
C = 3
At the REPL

Code: Select all

>>> from foo import *
>>> dir()
['const', '__name__', 'C']
Names with underscores are not exported. This is standard Python. Now try:

Code: Select all

>>> import foo
>>> foo._A
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute '_A'
>>> foo._B
2
>>> foo.C
3
>>> 
Python3 behaves similarly for _B and C (except that const is, of course, unsupported). The Python3 rule is that names beginning with an underscore are not imported when using from foo import *. They are available in foo's namespace - but as you say it's poor form to access them.

Re: Private const() variables aren't defined

Posted: Thu Sep 12, 2019 8:00 am
by kevinkk525
Ah sorry, I understood that part wrong. Thanks Peter.
In that regard it does work as expected.

I guess the initial question has been answered by jimmo however it is strange to me because why can I declare _B with a string but not with const (in repl)? Shouldn't the same explanation apply to this too? If _B="hi" works then I would expect it to work with const too.

Code: Select all

>>> _B="hi"
>>> _B
'hi'
>>> _C=const(3)
>>> _C
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name '_C' isn't defined

Re: Private const() variables aren't defined

Posted: Thu Sep 12, 2019 8:43 am
by jimmo
kevinkk525 wrote:
Thu Sep 12, 2019 8:00 am
Shouldn't the same explanation apply to this too? If _B="hi" works then I would expect it to work with const too.
This optimisation exists purely to save memory - the const() variables starting with underscores don't even exist, their value just gets substituted at compile time.

But when you're not using const() (as in your _B="hi" example), the variable has to exist anyway, so maintaining cpython compatibility makes more sense. And as Peter showed, it does the right thing not showing up in dir().

Re: Private const() variables aren't defined

Posted: Thu Sep 12, 2019 9:01 am
by kevinkk525
I guess it makes sense although it is confusing in repl to have a different behaviour between const and strings.

Re: Private const() variables aren't defined

Posted: Thu Sep 12, 2019 9:59 pm
by cdwilson
Thanks for the explanations!
Each statement executed on the REPL kind of like making a file containing that statement and compiling it.
I didn't realize this was how the REPL worked. For anyone else coming across this later, this example makes it pretty clear:

Code: Select all

>>> _B = const(2)
>>> _B
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name '_B' isn't defined
>>> _B = const(2); _B
2

Re: Private const() variables aren't defined

Posted: Fri Sep 13, 2019 6:40 am
by pythoncoder
kevinkk525 wrote:
Thu Sep 12, 2019 9:01 am
I guess it makes sense although it is confusing in repl to have a different behaviour between const and strings.
The optimisation is important in device drivers where, for readability, you might want a lot of integer symbolic constants. This allows them to be used at zero cost (in RAM and in performance).