list indices must be integers or slices, not str
Hi all
C:\Users\E7280>python
Python 3.9.7 (tags/v3.9.7:1016ef3, Aug 30 2021, 20:19:38) [MSC v.1929 64
bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> x = list(range(10))
>>>
>>> '{x[1]}'.format(**vars())
'1'
>>>
>>> '{x[-1]}'.format(**vars())
Traceback (most recent call last):
File "", line 1, in
TypeError: list indices must be integers or slices, not str
>>>
Can anyone explain this error? It seems that a negative index is deemed
to be a string in this case.
Thanks
Frank Millman
--
https://mail.python.org/mailman/listinfo/python-list
Re: list indices must be integers or slices, not str
On Wed, 20 Jul 2022 at 18:34, Frank Millman wrote:
>
> Hi all
>
> C:\Users\E7280>python
> Python 3.9.7 (tags/v3.9.7:1016ef3, Aug 30 2021, 20:19:38) [MSC v.1929 64
> bit (AMD64)] on win32
> Type "help", "copyright", "credits" or "license" for more information.
> >>>
> >>> x = list(range(10))
> >>>
> >>> '{x[1]}'.format(**vars())
> '1'
> >>>
> >>> '{x[-1]}'.format(**vars())
> Traceback (most recent call last):
>File "", line 1, in
> TypeError: list indices must be integers or slices, not str
> >>>
>
> Can anyone explain this error? It seems that a negative index is deemed
> to be a string in this case.
>
Yeah, that does seem a little odd. What you're seeing is the same as
this phenomenon:
>>> "{x[1]} {x[spam]}".format(x={1: 42, "spam": "ham"})
'42 ham'
>>> "{x[1]} {x[spam]}".format(x={"1": 42, "spam": "ham"})
Traceback (most recent call last):
File "", line 1, in
KeyError: 1
But I can't find it documented anywhere that digits-only means
numeric. The best I can find is:
https://docs.python.org/3/library/string.html#formatstrings
"""The arg_name can be followed by any number of index or attribute
expressions. An expression of the form '.name' selects the named
attribute using getattr(), while an expression of the form '[index]'
does an index lookup using __getitem__()."""
and in the corresponding grammar:
field_name::= arg_name ("." attribute_name | "[" element_index "]")*
index_string ::= +
In other words, any sequence of characters counts as an argument, as
long as it's not ambiguous. It doesn't seem to say that "all digits is
interpreted as an integer, everything else is interpreted as a
string". ISTM that a negative number should be interpreted as an
integer too, but that might be a backward compatibility break.
ChrisA
--
https://mail.python.org/mailman/listinfo/python-list
Re: Pip upgrade causing issues in 3.10
On 7/20/22, Mike Dewhirst wrote: > On 20/07/2022 4:43 am, David Raymond wrote: >> C:\Program Files\Python310\Scripts>..\python.exe -m pip install --upgrade >> pip >> ERROR: Could not install packages due to an OSError: [WinError 32] The >> process cannot access the file because it is being used by another >> process: 'c:\\program files\\python310\\scripts\\' > There's your problem. The 'other' process is your cmd.exe within which > you are typing etc. > > Python scripts dir should be on the path so you don't have to execute > anything from within it. Windows is obviously tripping over its own toes > trying to delete and install something in the same dir while you also > have your foot in it. This should only occur if uninstalling pip deletes all of the files in the "Scripts" directory. In this case, pip will 'compress' the individual delete operations to remove the entire directory. It begins by trying to 'stash' the "Scripts" directory, i.e. by renaming it to a temporary adjacent name. It uses shutil.move() for this, which tries os.rename() and falls back on shutil.copytree() and shutil.rmtree(). Of course this fails with a sharing violation if the directory is open as the working directory in any process, including the current Python process, because an open for a working directory doesn't share delete/rename access. pip fails to handle this error. It crashes and leaves a mess. The empty "Scripts" directory and the copytree() copy aren't rolled back properly, and neither are the stashed (renamed) "pip" and "pip*dist-info" directories in site packages. This is not user error. It is a bug in pip. It should be able to recover gracefully from failing to delete the directory. Moreover, it shouldn't even have to roll back the operations if it deleted the directory due to compression of explicit removals from the install "RECORD". In particular there is no reason to delete the "Scripts" directory, even if it's left empty. -- https://mail.python.org/mailman/listinfo/python-list
Re: list indices must be integers or slices, not str
On 2022-07-20 11:37 AM, Chris Angelico wrote:
On Wed, 20 Jul 2022 at 18:34, Frank Millman wrote:
Hi all
C:\Users\E7280>python
Python 3.9.7 (tags/v3.9.7:1016ef3, Aug 30 2021, 20:19:38) [MSC v.1929 64
bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> x = list(range(10))
>>>
>>> '{x[1]}'.format(**vars())
'1'
>>>
>>> '{x[-1]}'.format(**vars())
Traceback (most recent call last):
File "", line 1, in
TypeError: list indices must be integers or slices, not str
>>>
Can anyone explain this error? It seems that a negative index is deemed
to be a string in this case.
Yeah, that does seem a little odd. What you're seeing is the same as
this phenomenon:
"{x[1]} {x[spam]}".format(x={1: 42, "spam": "ham"})
'42 ham'
"{x[1]} {x[spam]}".format(x={"1": 42, "spam": "ham"})
Traceback (most recent call last):
File "", line 1, in
KeyError: 1
But I can't find it documented anywhere that digits-only means
numeric. The best I can find is:
https://docs.python.org/3/library/string.html#formatstrings
"""The arg_name can be followed by any number of index or attribute
expressions. An expression of the form '.name' selects the named
attribute using getattr(), while an expression of the form '[index]'
does an index lookup using __getitem__()."""
and in the corresponding grammar:
field_name::= arg_name ("." attribute_name | "[" element_index "]")*
index_string ::= +
In other words, any sequence of characters counts as an argument, as
long as it's not ambiguous. It doesn't seem to say that "all digits is
interpreted as an integer, everything else is interpreted as a
string". ISTM that a negative number should be interpreted as an
integer too, but that might be a backward compatibility break.
Thanks for investigating this further. I agree it seems odd.
As quoted above, an expression of the form '[index]' does an index
lookup using __getitem()__.
The only __getitem__() that I can find is in the operator module, and
that handles negative numbers just fine.
Do you think it is worth me raising an issue, if only to find out the
rationale if there is one?
Frank
--
https://mail.python.org/mailman/listinfo/python-list
Re: list indices must be integers or slices, not str
On 2022-07-20 12:31 PM, Frank Millman wrote:
On 2022-07-20 11:37 AM, Chris Angelico wrote:
On Wed, 20 Jul 2022 at 18:34, Frank Millman wrote:
Hi all
C:\Users\E7280>python
Python 3.9.7 (tags/v3.9.7:1016ef3, Aug 30 2021, 20:19:38) [MSC v.1929 64
bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> x = list(range(10))
>>>
>>> '{x[1]}'.format(**vars())
'1'
>>>
>>> '{x[-1]}'.format(**vars())
Traceback (most recent call last):
File "", line 1, in
TypeError: list indices must be integers or slices, not str
>>>
Can anyone explain this error? It seems that a negative index is deemed
to be a string in this case.
Yeah, that does seem a little odd. What you're seeing is the same as
this phenomenon:
"{x[1]} {x[spam]}".format(x={1: 42, "spam": "ham"})
'42 ham'
"{x[1]} {x[spam]}".format(x={"1": 42, "spam": "ham"})
Traceback (most recent call last):
File "", line 1, in
KeyError: 1
But I can't find it documented anywhere that digits-only means
numeric. The best I can find is:
https://docs.python.org/3/library/string.html#formatstrings
"""The arg_name can be followed by any number of index or attribute
expressions. An expression of the form '.name' selects the named
attribute using getattr(), while an expression of the form '[index]'
does an index lookup using __getitem__()."""
and in the corresponding grammar:
field_name ::= arg_name ("." attribute_name | "["
element_index "]")*
index_string ::= +
In other words, any sequence of characters counts as an argument, as
long as it's not ambiguous. It doesn't seem to say that "all digits is
interpreted as an integer, everything else is interpreted as a
string". ISTM that a negative number should be interpreted as an
integer too, but that might be a backward compatibility break.
Thanks for investigating this further. I agree it seems odd.
As quoted above, an expression of the form '[index]' does an index
lookup using __getitem()__.
The only __getitem__() that I can find is in the operator module, and
that handles negative numbers just fine.
Do you think it is worth me raising an issue, if only to find out the
rationale if there is one?
Frank
I saw this from Paul Rubin - for some reason his posts appear in google
groups, but not python-list.
"It seems to only want integer constants. x[2+2] and x[k] where k=2
don't work either.
I think the preferred style these days is f'{x[-1]}' which works."
Unfortunately the 'f' option does not work for me in this case, as I am
using a string object, not a string literal.
Frank
--
https://mail.python.org/mailman/listinfo/python-list
Re: list indices must be integers or slices, not str
On Wed, 20 Jul 2022 at 20:55, Frank Millman wrote:
>
> On 2022-07-20 11:37 AM, Chris Angelico wrote:
> > On Wed, 20 Jul 2022 at 18:34, Frank Millman wrote:
> >>
> >> Hi all
> >>
> >> C:\Users\E7280>python
> >> Python 3.9.7 (tags/v3.9.7:1016ef3, Aug 30 2021, 20:19:38) [MSC v.1929 64
> >> bit (AMD64)] on win32
> >> Type "help", "copyright", "credits" or "license" for more information.
> >> >>>
> >> >>> x = list(range(10))
> >> >>>
> >> >>> '{x[1]}'.format(**vars())
> >> '1'
> >> >>>
> >> >>> '{x[-1]}'.format(**vars())
> >> Traceback (most recent call last):
> >> File "", line 1, in
> >> TypeError: list indices must be integers or slices, not str
> >> >>>
> >>
> >> Can anyone explain this error? It seems that a negative index is deemed
> >> to be a string in this case.
> >>
> >
> > Yeah, that does seem a little odd. What you're seeing is the same as
> > this phenomenon:
> >
> "{x[1]} {x[spam]}".format(x={1: 42, "spam": "ham"})
> > '42 ham'
> "{x[1]} {x[spam]}".format(x={"1": 42, "spam": "ham"})
> > Traceback (most recent call last):
> >File "", line 1, in
> > KeyError: 1
> >
> > But I can't find it documented anywhere that digits-only means
> > numeric. The best I can find is:
> >
> > https://docs.python.org/3/library/string.html#formatstrings
> > """The arg_name can be followed by any number of index or attribute
> > expressions. An expression of the form '.name' selects the named
> > attribute using getattr(), while an expression of the form '[index]'
> > does an index lookup using __getitem__()."""
> >
> > and in the corresponding grammar:
> >
> > field_name::= arg_name ("." attribute_name | "[" element_index
> > "]")*
> > index_string ::= +
> >
> > In other words, any sequence of characters counts as an argument, as
> > long as it's not ambiguous. It doesn't seem to say that "all digits is
> > interpreted as an integer, everything else is interpreted as a
> > string". ISTM that a negative number should be interpreted as an
> > integer too, but that might be a backward compatibility break.
> >
>
> Thanks for investigating this further. I agree it seems odd.
>
> As quoted above, an expression of the form '[index]' does an index
> lookup using __getitem()__.
>
> The only __getitem__() that I can find is in the operator module, and
> that handles negative numbers just fine.
In general, __getitem__ is the method used to handle those sorts of lookups:
class X:
def __getitem__(self, item):
print("Get item", type(item), item)
"{x[0]} {x[1]} {x[-1]} {x[spam]} {x[1.0]}".format(x=X())
Outside of a format directive, you'd need to quote those:
x[0], x[1], x["spam"]
The distinction is that unquoted bare numbers are interpreted as
integers, not as strings. I'm unable to find the exact definition of
that documented.
> Do you think it is worth me raising an issue, if only to find out the
> rationale if there is one?
>
I'd wait for other people's responses first, there may be a better
insight to be found than what I was able to come across.
ChrisA
--
https://mail.python.org/mailman/listinfo/python-list
Re: list indices must be integers or slices, not str
On Wed, 20 Jul 2022 at 21:06, Frank Millman wrote:
> I saw this from Paul Rubin - for some reason his posts appear in google
> groups, but not python-list.
>
> "It seems to only want integer constants. x[2+2] and x[k] where k=2
> don't work either.
Yes, that's for the same reason that x[spam] can be used usefully with
a dictionary. Otherwise you'd need to use quotes. It makes perfect
sense that both 2+2 and k are treated as strings.
> I think the preferred style these days is f'{x[-1]}' which works."
Not true; there's no single "preferred style", and f-strings are
absolutely NOT replacements for everything else. They have their
place, as do the others. Yes, including percent formatting, it is not
deprecated, and it's really tiresome when people claim that it is.
> Unfortunately the 'f' option does not work for me in this case, as I am
> using a string object, not a string literal.
Right. An f-string uses the exact syntax of a Python expression, which
is often too powerful, but also restricts it to the string literal
style (since it's actual code, not a method call). For other purposes,
.format() is a better choice.
ChrisA
--
https://mail.python.org/mailman/listinfo/python-list
Re: list indices must be integers or slices, not str
On 20/07/2022 11:37, Chris Angelico wrote:
On Wed, 20 Jul 2022 at 18:34, Frank Millman wrote:
Hi all
C:\Users\E7280>python
Python 3.9.7 (tags/v3.9.7:1016ef3, Aug 30 2021, 20:19:38) [MSC v.1929 64
bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> x = list(range(10))
>>>
>>> '{x[1]}'.format(**vars())
'1'
>>>
>>> '{x[-1]}'.format(**vars())
Traceback (most recent call last):
File "", line 1, in
TypeError: list indices must be integers or slices, not str
>>>
Can anyone explain this error? It seems that a negative index is deemed
to be a string in this case.
Yeah, that does seem a little odd. What you're seeing is the same as
this phenomenon:
"{x[1]} {x[spam]}".format(x={1: 42, "spam": "ham"})
'42 ham'
"{x[1]} {x[spam]}".format(x={"1": 42, "spam": "ham"})
Traceback (most recent call last):
File "", line 1, in
KeyError: 1
But I can't find it documented anywhere that digits-only means
numeric.
I found
https://peps.python.org/pep-3101/
"""
PEP 3101 – Advanced String Formatting
...
An example of the ‘getitem’ syntax:
"My name is {0[name]}".format(dict(name='Fred'))
It should be noted that the use of ‘getitem’ within a format string is
much more limited than its conventional usage. In the above example, the
string ‘name’ really is the literal string ‘name’, not a variable named
‘name’. The rules for parsing an item key are very simple. If it starts
with a digit, then it is treated as a number, otherwise it is used as a
string.
Because keys are not quote-delimited, it is not possible to specify
arbitrary dictionary keys (e.g., the strings “10” or “:-]”) from within
a format string.
"""
--
https://mail.python.org/mailman/listinfo/python-list
Re: list indices must be integers or slices, not str
On 20/07/2022 12:08, Chris Angelico wrote:
On Wed, 20 Jul 2022 at 20:55, Frank Millman wrote:
On 2022-07-20 11:37 AM, Chris Angelico wrote:
> On Wed, 20 Jul 2022 at 18:34, Frank Millman wrote:
>>
>> Hi all
>>
>> C:\Users\E7280>python
>> Python 3.9.7 (tags/v3.9.7:1016ef3, Aug 30 2021, 20:19:38) [MSC v.1929 64
>> bit (AMD64)] on win32
>> Type "help", "copyright", "credits" or "license" for more information.
>> >>>
>> >>> x = list(range(10))
>> >>>
>> >>> '{x[1]}'.format(**vars())
>> '1'
>> >>>
>> >>> '{x[-1]}'.format(**vars())
>> Traceback (most recent call last):
>> File "", line 1, in
>> TypeError: list indices must be integers or slices, not str
>> >>>
>>
>> Can anyone explain this error? It seems that a negative index is deemed
>> to be a string in this case.
>>
>
> Yeah, that does seem a little odd. What you're seeing is the same as
> this phenomenon:
>
"{x[1]} {x[spam]}".format(x={1: 42, "spam": "ham"})
> '42 ham'
"{x[1]} {x[spam]}".format(x={"1": 42, "spam": "ham"})
> Traceback (most recent call last):
>File "", line 1, in
> KeyError: 1
>
> But I can't find it documented anywhere that digits-only means
> numeric. The best I can find is:
>
> https://docs.python.org/3/library/string.html#formatstrings
> """The arg_name can be followed by any number of index or attribute
> expressions. An expression of the form '.name' selects the named
> attribute using getattr(), while an expression of the form '[index]'
> does an index lookup using __getitem__()."""
>
> and in the corresponding grammar:
>
> field_name::= arg_name ("." attribute_name | "[" element_index "]")*
> index_string ::= +
>
> In other words, any sequence of characters counts as an argument, as
> long as it's not ambiguous. It doesn't seem to say that "all digits is
> interpreted as an integer, everything else is interpreted as a
> string". ISTM that a negative number should be interpreted as an
> integer too, but that might be a backward compatibility break.
>
Thanks for investigating this further. I agree it seems odd.
As quoted above, an expression of the form '[index]' does an index
lookup using __getitem()__.
The only __getitem__() that I can find is in the operator module, and
that handles negative numbers just fine.
In general, __getitem__ is the method used to handle those sorts of lookups:
class X:
def __getitem__(self, item):
print("Get item", type(item), item)
"{x[0]} {x[1]} {x[-1]} {x[spam]} {x[1.0]}".format(x=X())
Outside of a format directive, you'd need to quote those:
x[0], x[1], x["spam"]
The distinction is that unquoted bare numbers are interpreted as
integers, not as strings. I'm unable to find the exact definition of
that documented.
Do you think it is worth me raising an issue, if only to find out the
rationale if there is one?
I'd wait for other people's responses first, there may be a better
insight to be found than what I was able to come across.
It's mentioned in PEP 3101 (Advanced String Formatting):
"""
The rules for parsing an item key are very simple. If it starts with a
digit, then it is treated as a number, otherwise it is used as a string.
"""
I have a vague memory of it being discussed on python-dev, but it was a
long time ago.
--
https://mail.python.org/mailman/listinfo/python-list
Re: list indices must be integers or slices, not str
On Wed, 20 Jul 2022 at 23:50, Peter Otten <[email protected]> wrote: > > I found > > https://peps.python.org/pep-3101/ > > """ > PEP 3101 – Advanced String Formatting > ... > An example of the ‘getitem’ syntax: > > "My name is {0[name]}".format(dict(name='Fred')) > > It should be noted that the use of ‘getitem’ within a format string is > much more limited than its conventional usage. In the above example, the > string ‘name’ really is the literal string ‘name’, not a variable named > ‘name’. The rules for parsing an item key are very simple. If it starts > with a digit, then it is treated as a number, otherwise it is used as a > string. > Cool. I think this is a good justification for a docs patch, since that really should be mentioned somewhere other than a historical document. ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: list indices must be integers or slices, not str
On 7/20/22 05:04, Frank Millman wrote:
> I think the preferred style these days is f'{x[-1]}' which works."
>
> Unfortunately the 'f' option does not work for me in this case, as I am
> using a string object, not a string literal.
For that you could consider
https://pypi.org/project/f-yeah/
(straying a bit off thread subject by now, admittedly)
--
https://mail.python.org/mailman/listinfo/python-list
exec() an locals() puzzle
I wish I could understand the following behaviour:
1. This works as I expect it to work:
def f():
i = 1
print(locals())
exec('y = i; print(y); print(locals())')
print(locals())
exec('y *= 2')
print('ok:', eval('y'))
f()
{'i': 1}
1
{'i': 1, 'y': 1}
{'i': 1, 'y': 1}
ok: 2
2. I can access the value of y with eval() too:
def f():
i = 1
print(locals())
exec('y = i; print(y); print(locals())')
print(locals())
u = eval('y')
print(u)
f()
{'i': 1}
1
{'i': 1, 'y': 1}
{'i': 1, 'y': 1}
1
3. When I change variable name u -> y, somehow locals() in the body of
the function loses an entry:
def f():
i = 1
print(locals())
exec('y = i; print(y); print(locals())')
print(locals())
y = eval('y')
print(y)
f()
{'i': 1}
1
{'i': 1, 'y': 1}
{'i': 1}
---NameError
Traceback (most recent call last)
Input In [1], in () 7 print(y) 8 # y
= eval('y') 9 #print('ok:', eval('y'))---> 10 f()
Input In [1], in f() 4 exec('y = i; print(y); print(locals())')
5 print(locals())> 6 y = eval('y') 7 print(y)
File :1, in
NameError: name 'y' is not defined1.
Another thing: within the first exec(), the print order seems
reversed. What is going on?
BTW, I am using python 3.8.13.
George
--
https://mail.python.org/mailman/listinfo/python-list
Re: Are there any benefits of a shared build python, compared to a static build python?
> On 20 Jul 2022, at 18:09, Tianhe wrote: > > Python by default builds the library `libpythonMAJOR.MINOR.a` and > statically links it into the interpreter. Also it has an `--enable-shared`, > (https://docs.python.org/3/using/configure.html#cmdoption-enable-shared) > flag, which will build a shared library `libpythonMAJOR.MINOR.so.1.0`, and > dynamically link it to the interpreter. > > Are there any benefits of a shared build python, compared to a static build > python? Is there any performance difference? What appears to be important is being able to do link time optimisation of python code. I think Debian starting doing this first and other distro followed after seeing the big performance improvement Debian got. Barry > > I found a related question on SO and is it like he said ( > https://stackoverflow.com/a/73035776/5983841), shared built vs statically > built python only affects the "Embedding Python in Another Application" > scenario ? > > -- > > Regards, > > Micky > -- > https://mail.python.org/mailman/listinfo/python-list > -- https://mail.python.org/mailman/listinfo/python-list
Re: exec() an locals() puzzle
On 7/20/22, george trojan wrote:
>
> 1. This works as I expect it to work:
>
> def f():
> i = 1
> print(locals())
> exec('y = i; print(y); print(locals())')
> print(locals())
> exec('y *= 2')
> print('ok:', eval('y'))
> f()
In CPython, the locals of a function scope (as opposed to a class
scope or module scope) are optimized by storing them in an array in
the current frame. locals(), however, always returns the non-optimized
locals mapping of the current frame, i.e. the value of
sys._getframe(0).f_locals. In the case of optimized locals, the
locals() call first updates this dict with a snapshot of the current
values of local variables. This is useful for introspection, but
modifying the snapshot cannot extend or modify the optimized local
variables of the function scope.
exec() and eval() default to using the global and local variable
mappings that are returned by globals() and locals(). This allows them
to access the snapshot of the containing function's optimized locals,
but they can't extend or modify the function's optimized locals. At
most they can add dynamic locals to the snapshot, as used by
subsequent calls to locals(), exec() and eval().
--
https://mail.python.org/mailman/listinfo/python-list
Re: list indices must be integers or slices, not str
offtopic
If you want a pure-python but definitely a more hacky implementation,
you can play around with inspect.stack() and get the variables from
the outer frames.
# code:
x = 32
y = 42
printf("Hello x={x}, y={y}", x=27)
# output:
Hello x=27, y=42
The implementation of printf() was never released in PyPI (I guess I never saw
it as more than a challenge).
But the implementation is quite simple (I did a post about it):
https://book-of-gehn.github.io/articles/2021/07/11/Home-Made-Python-F-String.html
Thanks,
Martin.
On Wed, Jul 20, 2022 at 10:46:35AM -0600, Mats Wichmann wrote:
On 7/20/22 05:04, Frank Millman wrote:
I think the preferred style these days is f'{x[-1]}' which works."
Unfortunately the 'f' option does not work for me in this case, as I am
using a string object, not a string literal.
For that you could consider
https://pypi.org/project/f-yeah/
(straying a bit off thread subject by now, admittedly)
--
https://mail.python.org/mailman/listinfo/python-list
--
https://mail.python.org/mailman/listinfo/python-list
Re: exec() an locals() puzzle
I did a few tests
# test 1
def f():
i = 1
print(locals())
exec('y = i; print(y); print(locals())')
print(locals())
a = eval('y')
print(locals())
u = a
print(u)
f()
{'i': 1}
1
{'i': 1, 'y': 1}
{'i': 1, 'y': 1}
{'i': 1, 'y': 1, 'a': 1}
1
# test 2
def f():
i = 1
print(locals())
exec('y = i; print(y); print(locals())')
print(locals())
a = eval('y')
print(locals())
y = a
print(y)
f()
{'i': 1}
1
{'i': 1, 'y': 1}
{'i': 1}
Traceback (most recent call last):
NameError: name 'y' is not defined
So test 1 and 2 are the same except that the variable 'y' is not
present/present in the f's code.
When it is not present, exec() modifies the f's locals and adds an 'y'
to it but when the variable 'y' is present in the code (even if not
present in the locals()), exec() does not add any 'y' (and the next
eval() then fails)
The interesting part is that if the 'y' variable is in the f's code
*and* it is defined in the f's locals, no error occur but once again the
exec() does not modify f's locals:
# test 3
def f():
i = 1
y = 42
print(locals())
exec('y = i; print(y); print(locals())')
print(locals())
a = eval('y')
print(locals())
y = a
print(y)
f()
{'i': 1, 'y': 42}
1
{'i': 1, 'y': 1}
{'i': 1, 'y': 42}
{'i': 1, 'y': 42, 'a': 42}
42
Why does this happen? No idea.
I may be related with this:
# test 4
def f():
i = 1
print(locals())
exec('y = i; print(y); print(locals())')
print(locals())
print(y)
f()
Traceback (most recent call last):
NameError: name 'y' is not defined
Despite exec() adds the 'y' variable to f's locals, the variable is not
accessible/visible from f's code.
So, a few observations (by no means this is how the vm works):
1) each function has a set of variables defined by the code (let's call
this "code-defined locals" or "cdef-locals").
2) each function also has a set of "runtime locals" accessible from
locals().
3) exec() can add variables to locals() (runtime) set but it cannot add
any to cdef-locals.
4) locals() may be a superset of cdef-locals (but entries in cdef-locals
which value is still undefined are not shown in locals())
5) due rule 4, exec() cannot add a variable to locals() if it is already
present in the in cdef-locals.
6) when eval() runs, it uses locals() set for lookup
Perhaps rule 5 is to prevent exec() to modify any arbitrary variable of
the caller...
Anyways, nice food for our brains.
On Wed, Jul 20, 2022 at 04:56:02PM +, george trojan wrote:
I wish I could understand the following behaviour:
1. This works as I expect it to work:
def f():
i = 1
print(locals())
exec('y = i; print(y); print(locals())')
print(locals())
exec('y *= 2')
print('ok:', eval('y'))
f()
{'i': 1}
1
{'i': 1, 'y': 1}
{'i': 1, 'y': 1}
ok: 2
2. I can access the value of y with eval() too:
def f():
i = 1
print(locals())
exec('y = i; print(y); print(locals())')
print(locals())
u = eval('y')
print(u)
f()
{'i': 1}
1
{'i': 1, 'y': 1}
{'i': 1, 'y': 1}
1
3. When I change variable name u -> y, somehow locals() in the body of
the function loses an entry:
def f():
i = 1
print(locals())
exec('y = i; print(y); print(locals())')
print(locals())
y = eval('y')
print(y)
f()
{'i': 1}
1
{'i': 1, 'y': 1}
{'i': 1}
---NameError
Traceback (most recent call last)
Input In [1], in () 7 print(y) 8 # y
= eval('y') 9 #print('ok:', eval('y'))---> 10 f()
Input In [1], in f() 4 exec('y = i; print(y); print(locals())')
5 print(locals())> 6 y = eval('y') 7 print(y)
File :1, in
NameError: name 'y' is not defined1.
Another thing: within the first exec(), the print order seems
reversed. What is going on?
BTW, I am using python 3.8.13.
George
--
https://mail.python.org/mailman/listinfo/python-list
--
https://mail.python.org/mailman/listinfo/python-list
Re: list indices must be integers or slices, not str
Frank Millman schreef op 20/07/2022 om 13:04:
>> On Wed, 20 Jul 2022 at 18:34, Frank Millman wrote:
>>> >>>
>>> >>> x = list(range(10))
>>> >>>
>>> >>> '{x[1]}'.format(**vars())
>>> '1'
>>> >>>
>>> >>> '{x[-1]}'.format(**vars())
>>> Traceback (most recent call last):
>>> File "", line 1, in
>>> TypeError: list indices must be integers or slices, not str
>>> >>>
>>>
>>> Can anyone explain this error? It seems that a negative index is deemed
>>> to be a string in this case.
>>>
>>
>> [...]
>>
"It seems to only want integer constants. x[2+2] and x[k] where k=2
don't work either.
I think the preferred style these days is f'{x[-1]}' which works."
Unfortunately the 'f' option does not work for me in this case, as I am
using a string object, not a string literal.
I've always found a bit dirty to pass indiscriminate symbol tables like
the one from globals() or vars() or vars(some_object) to a formatting
method, leaving the formatting string free to access any of it. I prefer
to make things more explicit. Can't you make a dict with a selection of
things you possible want to format?
In a sense I think you're looking for a more complete templating
solution than what Python's formatting mechanisms are designed for.
Maybe you should consider a full template engine, like Jinja?
--
"There is no cause so noble that it will not attract fuggheads."
-- Larry Niven
--
https://mail.python.org/mailman/listinfo/python-list
