Mailing List Archive

.0 in name
May I know (1) why can the name start with a number?(2) where in the doc is it?!>>> import pdb>>> pdb.run('(a for a in "")')> <string>(1)<module>()(Pdb) s--Call--> <string>(1)<genexpr>()(Pdb) a.0 = <str_iterator object at 0xb685b100>(Pdb) c>>>Sent from Samsung tablet.
--
https://mail.python.org/mailman/listinfo/python-list
Re: .0 in name [ In reply to ]
On Sat, 2022-05-14 at 00:47 +0800, bryangan41 wrote:

> May I know (1) why can the name start with a number?

The name of an attribute must be an identifier. An identifier cannot
begin with a decimal number.

> (2) where in the doc is it?!

https://docs.python.org/3/reference/lexical_analysis.html#identifiers

Paul

--
https://mail.python.org/mailman/listinfo/python-list
Re: .0 in name [ In reply to ]
Bryan,
As has been pointed out, it is very common in possibly all programming languages to not allow digits at the start of many identifiers. It makes it hard to parse for numbers which tend to start with digits. Some languages even have special rules on not starting a number with a zero unless you mean for it to be seen as octal (or 0x for hexadecimal) and many other rules exist.

There are languages where 12x means 12*x so even the lack of an operator ...

There are exceptions that often are not really exceptions. You can use all kinds of unusual variables in some quoted context. It is valid (albeit not encouraged) to use backquoted

The following is perfectly allowed in R:

> `5x^2 + 2.3x` <- 666 > `+-+-+` <- 1000 > 1 + 2 * `5x^2 + 2.3x` + `+-+-+` [1] 2333 
And there are often issued when you do things like create the name of a column of data in a data.frame with embedded spaces and other anomalies requiring special handling.
So why you wonder where it is documented that variables cannot be what you feel like is a bit puzzling! 


-----Original Message-----
From: bryangan41 <bryangan41@gmail.com>
To: python-list@python.org
Sent: Fri, May 13, 2022 12:47 pm
Subject: .0 in name

May I know (1) why can the name start with a number?(2) where in the doc is it?!>>> import pdb>>> pdb.run('(a for a in "")')> <string>(1)<module>()(Pdb) s--Call--> <string>(1)<genexpr>()(Pdb) a.0 = <str_iterator object at 0xb685b100>(Pdb) c>>>Sent from Samsung tablet.
--
https://mail.python.org/mailman/listinfo/python-list
--
https://mail.python.org/mailman/listinfo/python-list
Re: .0 in name [ In reply to ]
On Fri, 2022-05-13 at 22:02 +0000, Avi Gross via Python-list wrote:

> So why you wonder where it is documented that variables cannot be
> what you feel like is a bit puzzling! 

I had just assumed on good faith that the request to the documentation
would be so that the OP could determine what is valid identifier
syntax.

Paul


--
https://mail.python.org/mailman/listinfo/python-list
Re: .0 in name [ In reply to ]
Boy do I hate when I see my code mangled by the stupid AOL mailer.

Not that anyone cares, but the code should be read with each line starting with the "> " prompt.

If I leave lots of blank lines, it may work, but as the illustration is not in python, I will now remove the prompts:


`5x^2 + 2.3x` <- 666

`+-+-+` <- 1000

1 + 2 * `5x^2 + 2.3x` + `+-+-+`

output: 2333 

There are rarely good reasons for such silly variable names but as long as you let it know to leave the quoted regions alone when parsing and look them us as exact entries in various environments, it works fine.

To add to what others already wrote, many languages have serious requirements you need to be aware of and not assume otherwise. Some allow underscores in names and may limit that in the first part or may in some cases suggest or require it. Some have rules about whether a variable of one kind should start with an uppercase letter. Some allow periods in names although an initial period may make it invisible for some purposes. And, some newer languages allow all kinds of UNICODE characters and perhaps even some that can be seen as numeric but aren't exactly 0-9. 

? ? ?
 ... ? ?



-----Original Message-----
From: Avi Gross via Python-list <python-list@python.org>
To: python-list@python.org <python-list@python.org>
Sent: Fri, May 13, 2022 6:02 pm
Subject: Re: .0 in name

Bryan,
As has been pointed out, it is very common in possibly all programming languages to not allow digits at the start of many identifiers. It makes it hard to parse for numbers which tend to start with digits. Some languages even have special rules on not starting a number with a zero unless you mean for it to be seen as octal (or 0x for hexadecimal) and many other rules exist.

There are languages where 12x means 12*x so even the lack of an operator ...

There are exceptions that often are not really exceptions. You can use all kinds of unusual variables in some quoted context. It is valid (albeit not encouraged) to use backquoted

The following is perfectly allowed in R:

> `5x^2 + 2.3x` <- 666 > `+-+-+` <- 1000 > 1 + 2 * `5x^2 + 2.3x` + `+-+-+` [1] 2333 
And there are often issued when you do things like create the name of a column of data in a data.frame with embedded spaces and other anomalies requiring special handling.
So why you wonder where it is documented that variables cannot be what you feel like is a bit puzzling! 


-----Original Message-----
From: bryangan41 <bryangan41@gmail.com>
To: python-list@python.org
Sent: Fri, May 13, 2022 12:47 pm
Subject: .0 in name

May I know (1) why can the name start with a number?(2) where in the doc is it?!>>> import pdb>>> pdb.run('(a for a in "")')> <string>(1)<module>()(Pdb) s--Call--> <string>(1)<genexpr>()(Pdb) a.0 = <str_iterator object at 0xb685b100>(Pdb) c>>>Sent from Samsung tablet.
--
https://mail.python.org/mailman/listinfo/python-list
--
https://mail.python.org/mailman/listinfo/python-list
--
https://mail.python.org/mailman/listinfo/python-list
Re: .0 in name [ In reply to ]
This is not what @Avi menat by "silly variable names" but:

3D_position

2nd_floor_area

3M_PostIt_size

3rd_degree_polynomial

360_degree_view

12_hours_later

and ???
2_fast_2_furious

--
Regards,
=dn
--
https://mail.python.org/mailman/listinfo/python-list
Re: .0 in name [ In reply to ]
You left out 3CPO, Dave.

Names with numerals are not unreasonable in some circumstances.

But programming languages are not a full spectrum of real life. They can have reserved words too so you may not be able to use "while" and if you choose to create a function that masks another, you cannot complain that you assumed the computer would be smart enough to figure out which one you wanted. Yes, some languages encourage multiple functions with the same name but different signatures. Bottom line is each has RULES and some serious SUGGESTIONS. It is what it is, not what you want it to be.
But although starting with a numeral is verboten for variable names, may I suggest that a relatively invisible character can make a name like _3CPO that will be allowed. But be careful as Python programs often have conventions on use of the underscore and don't even think about a dundering name like __init__ ...


-----Original Message-----
From: dn <PythonList@DancesWithMice.info>
To: python-list@python.org
Sent: Sat, May 14, 2022 12:33 am
Subject: Re: .0 in name

This is not what @Avi menat by "silly variable names" but:

3D_position

2nd_floor_area

3M_PostIt_size

3rd_degree_polynomial

360_degree_view

12_hours_later

and ???
2_fast_2_furious

--
Regards,
=dn
--
https://mail.python.org/mailman/listinfo/python-list
--
https://mail.python.org/mailman/listinfo/python-list
Re: .0 in name [ In reply to ]
Am 13.05.2022 um 23:23 schrieb Paul Bryan:
> On Sat, 2022-05-14 at 00:47 +0800, bryangan41 wrote:
>
>> May I know (1) why can the name start with a number?
>
> The name of an attribute must be an identifier. An identifier cannot
> begin with a decimal number.

I'm not sure about the first statement. Feeding

[print("locals:", locals()) or c for c in "ab"]

to the REPL, the result is

locals: {'.0': <str_iterator object at 0x0000000002D2B160>, 'c': 'a'}
locals: {'.0': <str_iterator object at 0x0000000002D2B160>, 'c': 'b'}
['a', 'b']

i.e. there is a variable of name .0 in the local namespace within the
list comprehension, and .0 is definitely not an identifier.

I came across this while investigating another problem with list
comprehensions, and I think the original post was about list comprehensions.

There also can be non-identifier names in the global namespace and as
attributes, e.g. using the REPL again:

globals()["42"] = "The Answer"
globals()

outputs (see last entry)

{'__name__': '__main__', '__doc__': None, '__package__': None,
'__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__':
None, '__annotations__': {}, '__builtins__': <module 'builtins'
(built-in)>, '42': 'The Answer'}

and

class Cls:
def __init__(self, lst):
for i, e in enumerate(lst):
self.__dict__[str(i)] = e

obj = Cls([31, 42, 53])
getattr(obj, "1")

works and outputs

42

>> (2) where in the doc is it?!
>
> https://docs.python.org/3/reference/lexical_analysis.html#identifiers

That refers to identifiers, i.e. names that are recognised as such by
the lexer, i.e. that can be written directly in Python source code.

As shown above, names that are not identifiers can be used in several
namespaces and as attributes. It's just a bit harder to use
non-identifier names than identifiers.
Whether it's a good idea to use them at all is a different question.

I think the OP wondered about the .0 in the local namespace within list
comprehensions. Unfortunately I cannot say much about that.

> Paul

Ralf M.
--
https://mail.python.org/mailman/listinfo/python-list
Re: .0 in name [ In reply to ]
On Sun, 29 May 2022 at 06:41, Ralf M. <Ralf_M@t-online.de> wrote:
>
> Am 13.05.2022 um 23:23 schrieb Paul Bryan:
> > On Sat, 2022-05-14 at 00:47 +0800, bryangan41 wrote:
> >
> >> May I know (1) why can the name start with a number?
> >
> > The name of an attribute must be an identifier. An identifier cannot
> > begin with a decimal number.
>
> I'm not sure about the first statement. Feeding
>
> [print("locals:", locals()) or c for c in "ab"]
>
> to the REPL, the result is
>
> locals: {'.0': <str_iterator object at 0x0000000002D2B160>, 'c': 'a'}
> locals: {'.0': <str_iterator object at 0x0000000002D2B160>, 'c': 'b'}
> ['a', 'b']
>
> i.e. there is a variable of name .0 in the local namespace within the
> list comprehension, and .0 is definitely not an identifier.
>
> I came across this while investigating another problem with list
> comprehensions, and I think the original post was about list comprehensions.
>

There are a few quirks with comprehensions, and to understand that
".0", you have to first understand two very important aspects of
scoping with regard to comprehensions.

(Note: For simplicity, I'm going to refer in general to
"comprehensions", and I am not going to count Python 2. My example
will be a list comp, but a generator expression also behaves like
this, as do other comprehensions.)

Consider this function:

def spam():
ham = "initial"
ham = [locals() for x in "q"]
return ham

The disassembly module can be very helpful here. The precise output
will vary with Python version, but the points I'm making should be
valid for all current versions. Here's how it looks in a December
build of Python 3.11 (yeah, my Python's getting a bit old now, I
should update at some point):

>>> dis.dis(spam)
2 0 LOAD_CONST 1 ('initial')
2 STORE_FAST 0 (ham)

3 4 LOAD_CONST 2 (<code object <listcomp> at
0x7fb6a0cfa6b0, file "<stdin>", line 3>)
6 MAKE_FUNCTION 0
8 LOAD_CONST 3 ('q')
10 GET_ITER
12 CALL_FUNCTION 1
14 STORE_FAST 0 (ham)

4 16 LOAD_FAST 0 (ham)
18 RETURN_VALUE

Disassembly of <code object <listcomp> at 0x7fb6a0cfa6b0, file
"<stdin>", line 3>:
3 0 BUILD_LIST 0
2 LOAD_FAST 0 (.0)
>> 4 FOR_ITER 5 (to 16)
6 STORE_FAST 1 (x)
8 LOAD_GLOBAL 0 (locals)
10 CALL_FUNCTION 0
12 LIST_APPEND 2
14 JUMP_ABSOLUTE 2 (to 4)
>> 16 RETURN_VALUE
>>>

Okay, that's a lot of raw data, but let's pull out a few useful things from it.

Line 2 initializes ham in an unsurprising way. Grab a constant, store
it in a local. Easy.

Line three. We grab the code object for the list comp, and make a
function (that's necessary for closures). Then, *still in the context
of the spam function*, we grab the constant "q", and get an iterator
from it. Leaving that on the top of the stack, we call the list
comprehension's function, and store the result into 'ham'.

The comprehension itself loads the fast local from slot zero (name
".0") and iterates over it. Slot zero is the first argument, so
that's the string iterator that we left there for the function.

So why IS this? There are a few reasons, but the main one is generator
expressions. Replacing the list comp with a genexp gives this result:

>>> spam()
<generator object spam.<locals>.<genexpr> at 0x7fb6a0780890>

The actual iteration (row 4 in the genexp in the above disassembly of
<listcomp>) doesn't happen until you iterate over this value. But it
would be extremely confusing if, in that situation, errors didn't show
up until much later. What if, instead of iterating over a string, you
tried to iterate over a number? Where should the traceback come from?
Or what if you're iterating over a variable, and you change what's in
that variable?

def wat():
stuff = "hello"
ucase = (l.upper() for l in stuff)
stuff = "goodbye"
return "".join(ucase)

Does this return "HELLO" or "GOODBYE"? Since stuff gets evaluated
immediately, it returns HELLO, and that's consistent for list comps
and genexps.

But because of that, there needs to be a parameter to carry that
iterator through, and every parameter needs a name. If the generated
name collided with any identifier that you actually wanted, it would
be extremely confusing; so to keep everything safe, the interpreter
generates a name you couldn't possibly want - same as for the function
itself, which is named "<listcomp>" or "<genexpr>", angle brackets
included.

That's a fairly long-winded way to put it, but that's why you can have
variables with bizarre names :)

ChrisA
--
https://mail.python.org/mailman/listinfo/python-list
Re: .0 in name [ In reply to ]
On 5/28/22, Chris Angelico <rosuav@gmail.com> wrote:
>
> be extremely confusing; so to keep everything safe, the interpreter
> generates a name you couldn't possibly want - same as for the function
> itself, which is named "<listcomp>" or "<genexpr>", angle brackets
> included.

To clarify, "<listcomp>" is the co_name and co_qualname value of the
code object, which was compiled for the list comprehension. These
names are also used as the __name__ and __qualname__ of the temporary
object that's created by MAKE_FUNCTION. They are not identifiers. The
code object is a constant, which is referenced solely by its index in
the co_consts tuple. The temporary function is referenced on the
stack.
--
https://mail.python.org/mailman/listinfo/python-list
Re: .0 in name [ In reply to ]
On Sun, 29 May 2022 at 08:26, Eryk Sun <eryksun@gmail.com> wrote:
>
> On 5/28/22, Chris Angelico <rosuav@gmail.com> wrote:
> >
> > be extremely confusing; so to keep everything safe, the interpreter
> > generates a name you couldn't possibly want - same as for the function
> > itself, which is named "<listcomp>" or "<genexpr>", angle brackets
> > included.
>
> To clarify, "<listcomp>" is the co_name and co_qualname value of the
> code object, which was compiled for the list comprehension. These
> names are also used as the __name__ and __qualname__ of the temporary
> object that's created by MAKE_FUNCTION. They are not identifiers. The
> code object is a constant, which is referenced solely by its index in
> the co_consts tuple. The temporary function is referenced on the
> stack.

Correct. Every function has a name, important for tracebacks and such,
but with lambda functions, the internal functions of comprehensions,
and so on, there's no actual name binding for it. So the interpreter
generates a name that won't collide with any actual name that you'd
have assigned anything to.

ChrisA
--
https://mail.python.org/mailman/listinfo/python-list