Re: Fwd: IDLE: clearing the screen

2024-06-04 Thread Cameron Simpson via Python-list

On 04Jun2024 22:43, Rob Cliffe  wrote:

import os
def cls(): x=os.system("cls")

Now whenever you type
cls()
it will clear the screen and show the prompt at the top of the screen.

(The reason for the "x=" is: os.system returns a result, in this case 
0.  When you evaluate an expression in the IDE, the IDE prints the 
result.  So without the "x=" you get an extra line at the top of the 
screen containing "0".)


Not if it's in a function, because the IDLE prints the result if it 
isn't None, and your function returns None. So:


def cls():
os.system("cls")

should be just fine.
--
https://mail.python.org/mailman/listinfo/python-list


Re: Flubbed it in the second interation through the string: range error... HOW?

2024-05-29 Thread Cameron Simpson via Python-list

On 29May2024 01:14, Thomas Passin  wrote:
Also, it's 2024 ... time to start using f-strings (because they are 
more readable than str.format())


By which Thomas means stuff like this:

print(f'if block {name[index]} and index {index}')

Notice the leading "f'". Personally I wouldn't even go that far, just:

print('if block', name[index], 'and index', index)

But there are plenty of places where f-strings are very useful.
--
https://mail.python.org/mailman/listinfo/python-list


Re: Terminal Emulator

2024-05-14 Thread Cameron Simpson via Python-list

On 14May2024 18:44, Gordinator  wrote:
I wish to write a terminal emulator in Python. I am a fairly competent 
Python user, and I wish to try a new project idea. What references can 
I use when writing my terminal emulator? I wish for it to be a true 
terminal emulator as well, not just a Tk text widget or something like 
that.


Start with the `pty` module.
--
https://mail.python.org/mailman/listinfo/python-list


Re: First two bytes of 'stdout' are lost

2024-04-11 Thread Cameron Simpson via Python-list

On 11Apr2024 14:42, Olivier B.  wrote:

I am trying to use StringIO to capture stdout, in code that looks like this:

import sys
from io import StringIO
old_stdout = sys.stdout
sys.stdout = mystdout = StringIO()
print( "patate")
mystdout.seek(0)
sys.stdout = old_stdout
print(mystdout.read())

Well, it is not exactly like this, since this works properly


Aye, I just tried that. All good.


This code is actually run from C++ using the C Python API.
This worked quite well, so the code was right at some point. But now,
two things changed:
- Now using python 3.11.7 instead of 3.7.12
- Now using only the python limited C API


Maybe you should post the code then: the exact Python code and the exact 
C++ code.



And it seems that now, mystdout.read() always misses the first two
characters that have been written to stdout.

My first ideas was something related to the BOM improperly truncated
at some point, but i am manipulating UTF-8, so the bom would be 3
bytes, not 2.


I didn't think UTF-8 needed a BOM. Somone will doubtless correct me.

However, does the `mystdout.read()` code _know_ you're using UTF-8? I 
have the vague impression that eg some Windows systems default to UTF-16 
of some flavour, possibly _with_ a BOM.


I'm suggesting that you rigorously check that the bytes->text bits know 
what text encoding they're using. If you've left an encoding out 
anywhere, put it in explicitly.



Hopefully someone has a clue on what would have changed in Python for
this to stop working compared to python 3.7?


None at all, alas. My experience with the Python C API is very limited.
--
https://mail.python.org/mailman/listinfo/python-list


Re: How to Add ANSI Color to User Response

2024-04-11 Thread Cameron Simpson via Python-list

On 10Apr2024 23:41, Alan Gauld  wrote:

Normally, for any kind of fancy terminal work, I'd say use curses.


My problem with curses is that it takes over the whole terminal - you 
need to manage everything from that point on. Great if you want it (eg 
some full-terminal tool like `top`) but complex overkill for small 
interactive (or not interactive) commands which are basicly printing 
lines of text. Which is what many of my scripts are.


That said, you don't _have_ to use curses to run the whole terminal. You 
can use it to just look up the terminal capabilities and use those 
strings. I haven't tried that for colours, but here's some same code 
from my `cs.upd` module using curses to look up various cursor motion 
type things:


... up the top ...
try:
  import curses
except ImportError as curses_e:
  warning("cannot import curses: %s", curses_e)
  curses = None

... later we cache the available motions ...
try:
  # pylint: disable=no-member
  curses.setupterm(fd=backend_fd)
except TypeError:
  pass
else:
  for ti_name in (
  'vi',  # cursor invisible
  'vs',  # cursor visible
  'cuu1',  # cursor up one line
  'dl1',  # delete one line
  'il1',  # insert one line
  'el',  # clear to end of line
  ):
# pylint: disable=no-member
s = curses.tigetstr(ti_name)
if s is not None:
  s = s.decode('ascii')
self._ti_strs[ti_name] = s

... then a method to access the cache ...
def ti_str(self, ti_name):
  ''' Fetch the terminfo capability string named `ti_name`.
  Return the string or `None` if not available.
  '''
  return self._ti_strs.get(ti_name, None)

... and even later, use the method ...
# emit cursor_up
cursor_up = self.ti_str('cuu1')
movetxts.append(cursor_up * (to_slot - from_slot))

Generally, when I add ANSI colours I do it via a little module of my 
own, `cs.ansi_colour`, which you can get from PyPI using `pip`.


The two most useful items in it for someone else are probably 
`colourise` and `colourise_patterns`. Link:

https://github.com/cameron-simpson/css/blob/26504f1df55e1bbdef00c3ff7f0cb00b2babdc01/lib/python/cs/ansi_colour.py#L96

I particularly use it to automatically colour log messages on a 
terminal, example code:

https://github.com/cameron-simpson/css/blob/26504f1df55e1bbdef00c3ff7f0cb00b2babdc01/lib/python/cs/logutils.py#L824
--
https://mail.python.org/mailman/listinfo/python-list


Re: Variable scope inside and outside functions - global statement being overridden by assignation unless preceded by reference

2024-03-07 Thread Cameron Simpson via Python-list

On 06Mar2024 15:12, Jacob Kruger  wrote:
So, this does not make sense to me in terms of the following snippet 
from the official python docs page:

https://docs.python.org/3/faq/programming.html

"In Python, variables that are only referenced inside a function are 
implicitly global. If a variable is assigned a value anywhere within 
the function’s body, it’s assumed to be a local unless explicitly 
declared as global."


So, I would then assume that if I explicitly include a variable name 
inside the global statement, then even just assigning it a new value 
should update the variable in the global context, outside the 
function?


Yes. Note that the "global" namespace is the module in which the 
function is defined.


x = 1

def f(n):
global x
x += n

This updates the `x` global variable in the module where `f` was 
defined.


If you import `f` and use it in another module it will _still_ update 
`x` in the original module namespace.

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


Re: Variable scope inside and outside functions - global statement being overridden by assignation unless preceded by reference

2024-03-05 Thread Cameron Simpson via Python-list

On 05Mar2024 20:13, Jacob Kruger  wrote:
Now, what almost seems to be occurring, is that while just manipulating 
the contents of a referenced variable is fine in this context, the 
moment I try to reassign it, that's where the issue is occurring .


Because there are no variable definitions in Python, when you write a 
function Python does a static analysis of it to decide which variables 
are local and which are not. If there's an assignment to a variable, it 
is a local variable.  _Regardless_ of whether that assignment has been 
executed, or gets executed at all (eg in an if-statement branch which 
doesn't fire).


You can use `global` or `nonlocal` to change where Python looks for a 
particular name.


In the code below, `f1` has no local variables and `f2` has an `x` and 
`l1` local variable.


x = 1
l1 = [1, 2, 3]

def f1():
print("f1 ...")
l1[1] = 5   # _not_ an assignment to "l1"
print("in f1, x =", x, "l1 =", l1)

def f2():
print("f2 ...")
x = 3
l1 = [6, 7, 9]  # assignment to "l1"
print("in f2, x =", x, "l1 =", l1)

print("outside, x =", x, "l1 =", l1)
f1()
print("outside after f1, x =", x, "l1 =", l1)
f2()
print("outside after f2, x =", x, "l1 =", l1)

Cheers,
Cameron Simpson 
--
https://mail.python.org/mailman/listinfo/python-list


Re: Can one output something other than 'nan' for not a number values?

2024-02-16 Thread Cameron Simpson via Python-list

On 16Feb2024 22:12, Chris Green  wrote:

I'm looking for a simple way to make NaN values output as something
like '-' or even just a space instead of the string 'nan'.  This would
then make it much easier to handle outputting values from sensors when
not all sensors are present.

So, for example, my battery monitoring program outputs:-

   Battery Voltages and Currents
   Leisure Battery - 12.42 volts  -0.52 Amps
   Starter Battery - 12.34 volts  -0.01 Amps

If the starter battery sensor has failed, or is disconnected, I see:-

   Battery Voltages and Currents
   Leisure Battery - 12.42 volts  -0.52 Amps
   Starter Battery -   nan voltsnan Amps


What I would like is for those 'nan' strings to be just a '-' or
something similar.

Obviously I can write conditional code to check for float('nan')
values but is there a neater way with any sort of formatting string or
other sort of cleverness?


The simplest thing is probably just a function writing it how you want 
it:


def float_s(f):
if isnan(f):
return "-"
return str(f)

and then use eg:

print(f'value is {float_s(value)}')

or whatever fits your code.

Cheers,
Cameron Simpson 

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


Re: A question about import

2024-02-16 Thread Cameron Simpson via Python-list

On 16Feb2024 20:32, MRAB  wrote:

On 2024-02-16 20:07, Gabor Urban via Python-list wrote:

I need something about modules to be clarified.

Suppose I have written a module eg: ModuleA which imports an other
module, let us say the datetime.

If I import ModuleA in a script, will be datetime imported automatically?


Yes. When a module is imported it can import other modules.


But note that `datetime` does not magicly get put in the script's 
namespace.


Module A:

import datetime

Script:

import A

In the code in module A the name datetime is known and can be used.

In the code in the script the name A is known and can be used. Importing 
A does not magicly set the name datetime in the script's namespace - 
imagine the the pollution!


You _can_ access it as A.datetime because it is in the A module's 
namespace. But really if you just wanted datetime for direct use in the 
script you would import it there too:


import datetime
import A

Note that the datetime module is only actually loaded once. The import 
binds the name into your local namespace like any other variable.


Cheers,
Cameron Simpson 
--
https://mail.python.org/mailman/listinfo/python-list


Re: Is there a way to implement the ** operator on a custom object

2024-02-09 Thread Cameron Simpson via Python-list

On 09Feb2024 18:56, Left Right  wrote:

But, more to the point: extending collections.abc.Mapping may or may
not be possible in OP's case.


We don't yet know if that's what the OP had in mind yet, anyway.


Also, if you are doing this through inheritance, this seems really
convoluted: why not just inherit from dict? -- less methods to
implement, less stuff to import etc.


There's a rule of thumb that we _tend_ not to subclass the builtins; it 
certainly has its pitfalls to do with object creation/initialisation.  
That said, I have some classes which subclass dict, int, str and 
namedtuple.


Cheers,
Cameron Simpson 
--
https://mail.python.org/mailman/listinfo/python-list


Re: Is there a way to implement the ** operator on a custom object

2024-02-08 Thread Cameron Simpson via Python-list

On 08Feb2024 12:21, tony.fl...@btinternet.com  wrote:
I know that mappings by default support the ** operator, to unpack the 
mapping into key word arguments.


Has it been considered implementing a dunder method for the ** 
operator so you could unpack an object into a key word argument, and 
the developer could choose which keywords would be generated (or could 
even generate 'virtual' attributes).


Can you show us why you think that would look like in code?

Note that Python already has `a ** b` to raise `a` to the power of `b`, 
and it has a bunder method `__pow__` which you can define.

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


Re: How would you name this dictionary?

2024-01-21 Thread Cameron Simpson via Python-list

On 21Jan2024 23:39, bagra...@live.com  wrote:

class NameMe(dict):
   def __missing__(self, key):
   return key


I would need to know more about what it might be used for. What larger 
problem led you to writing a `dict` subclass with this particular 
`__missing__` implementation?

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


Re: Type hints - am I doing it right?

2023-12-13 Thread Cameron Simpson via Python-list

On 13Dec2023 09:19, Frank Millman  wrote:

I am adding type hints to my code base.

[...]

In the other module I have this -

 def config_database(db_params):

To add a type hint, I now have this -

 def config_database(db_params: configparser.SectionProxy):

To get this to work, I have to add 'import configparser' at the top of 
the module.


I have three separate modules, one for each database, with a subclass 
containing the methods and attributes specific to that database. Each 
one has a connect() method which receives db_params as a parameter. 
Now I have to add 'import configparser' at the top of each of these 
modules in order to type hint the method.


This seems verbose. If it is the correct way of doing it I can live 
with it, but I wondered if there was an easier way.


Not really. It's like any other name - it needs importing if you're 
going to use it.


You can make the hint itself more compact:

from configparser import SectionProxy
...
def config_database(db_params: SectionProxy):

Or you could be a bit more agnostic:

from typing import Mapping
...
def config_database(db_params: Mapping):

since I imagine config_database() would accept any kind of mapping 
(dicts, etc etc).


Cheers,
Cameron Simpson 
--
https://mail.python.org/mailman/listinfo/python-list


Re: Newline (NuBe Question)

2023-11-15 Thread Cameron Simpson via Python-list

On 15Nov2023 07:25, Grizzy Adams  wrote:

Have this (from an online "classes" tutorial)


Response inline below.


students = []
grades = []
for s in geographyClass:
students.append(geographyStudent(s))
for s in students:
   grades.append(s.school)
   grades.append(s.name)
   grades.append(s.finalGrade())
   if s.finalGrade()>82:
   grades.append("Pass")
   else:
   grades.append("Fail")
print(grades)

--- End Code Snippit  ---

I have extended (from tutorial) it a bit, I would really like to have a newline
at end of each record, I have searched (and tested) but cant get "\n" 
to give a newline, I get "Mydata\n"


It would be useful to:
- see some of the things you've tried
- what their output actually was
- what output you actually want to achieve


Do I need to replace "append" with "print", or is there a way to get the
newline in as I append to list?


I think you're confusing output (print) with your data (the list of 
grades).


Is the code above genuinely what you're running?

I ask because it looks to me that you're:
- appending all the individual grade fields (school, name, ...) to one 
  long grades list containing all the data from all the students

- you're printing that single enormous list in one go at the end

What I'm imagine you want is one line of grade information per student.

Remember that indentation is important in Python. You're grades code 
looks like this:


grades = []
for s in students:
grades.append(s.school)
grades.append(s.name)
grades.append(s.finalGrade())
if s.finalGrade()>82:
grades.append("Pass")
else:
grades.append("Fail")
print(grades)

This:
- makes an empty list
- gathers up all of the student data
- prints the data in one go

I think you may want to do the first and last steps on a per student 
basis, not just once at the start and the end. So you might want to 
rearrange things:


for s in students:
grades = []
grades.append(s.school)
grades.append(s.name)
grades.append(s.finalGrade())
if s.finalGrade()>82:
grades.append("Pass")
else:
grades.append("Fail")
print(grades)

Cheers,
Cameron Simpson 
--
https://mail.python.org/mailman/listinfo/python-list


Re: Checking if email is valid

2023-11-02 Thread Cameron Simpson via Python-list

On 02Nov2023 17:04, Chris Angelico  wrote:

On Thu, 2 Nov 2023 at 15:20, AVI GROSS via Python-list
 wrote:
Yes, it would be nice if there was a syntax for sending a test 
message sort

of like an ACK that is not delivered to the recipient but merely results in
some status being sent back such as DELIVERABLE or NO SUCH USER or even
MAILBOX FULL.


Yes, it would! Spammers would be able to use this syntax to figure out
exactly which addresses actually have real people connected to it. It
would save them so much trouble! Brilliant idea.


Hmm. IIRC...

https://datatracker.ietf.org/doc/html/rfc2821#section-4.1.1.6

I think a lot of mail receivers don't honour this one, for exactly the 
reasons above.


Cheers,
Cameron Simpson 
--
https://mail.python.org/mailman/listinfo/python-list


Re: Checking if email is valid

2023-11-01 Thread Cameron Simpson via Python-list

On 01Nov2023 14:08, Grant Edwards  wrote:

On 2023-11-01, Simon Connah via Python-list  wrote:

I'm building a simple project using smtplib and have a
question. I've been doing unit testing but I'm not sure how to check
if an email message is valid.

[...]

Could someone push me in the right direction please? I just want to
find out if a string is a valid email address.


I confess that I punt "syntactically valid" to email.utils.getaddresses:
https://docs.python.org/3/library/email.utils.html#email.utils.getaddresses

"Deliverable"? I'm prepared to just send to it and hope not to get a 
bounce; delivery of email is, after all, asynchronous. (Even if it were 
going direct to the primary MX, I still hand it to the local mail system 
to deal with.)


"A real person or entity"? A lot of systems do the round trip thing: 
here's a special unique and opaue URL,please visit it to confirm receipt 
of this email (implying email is 'real"). You see this a lot when 
signing up for things. And for plenty of things I generate a random 
throw away address at mailinator.com (looking at you, every "catch up" 
free online TV streaming service who still wants me to log in).


Cheers,
Cameron Simpson 
--
https://mail.python.org/mailman/listinfo/python-list


Re: return type same as class gives NameError.

2023-10-22 Thread Cameron Simpson via Python-list

On 22Oct2023 17:50, Antoon Pardon  wrote:

I have the following small module:
=-=-=-=-=-=-=-=-=-=-=-= 8< =-=-=-=-=-=-=-=-=-=-=-=-=
class Pnt (NamedTuple):
   x: float
   y: float

   def __add__(self, other: PNT) -> Pnt:
   return Pnt(self[0] + other[0], self[1] + other[1])


When this function is defined, the class "Pnt" has not yet been defined.  
That happens afterwards.


You want a forward reference, eg:

def __add__(self, other: PNT) -> "Pnt":

A type checker will resolve this after the fact, when it encounters the 
string in the type annotation.


This message:

NameError: name 'Pnt' is not defined. Did you mean: 'PNT'?

is unfortunate, because you have a very similar "PNT" name in scope. But 
it isn't what you want.


Cheers,
Cameron Simpson 
--
https://mail.python.org/mailman/listinfo/python-list


Re: Where I do ask for a new feature

2023-10-20 Thread Cameron Simpson via Python-list

On 19Oct2023 20:16, Bongo Ferno  wrote:
A with statement makes clear that the alias is an alias and is local, 
and it automatically clears the variable after the block code is used.


No it doesn't:

>>> with open('/dev/null') as f:
...   print(f)
...
<_io.TextIOWrapper name='/dev/null' mode='r' encoding='UTF-8'>
>>> print(f)
<_io.TextIOWrapper name='/dev/null' mode='r' encoding='UTF-8'>
--
https://mail.python.org/mailman/listinfo/python-list


Re: Why doc call `__init__` as a method rather than function?

2023-09-17 Thread Cameron Simpson via Python-list

On 15Sep2023 10:49, scruel tao  wrote:

```python

class A:

...   def __init__(self):
... pass
...
```

On many books and even the official documents, it seems that many authors prefer to call `__init__` 
as a "method" rather than a "function".
The book PYTHON CRASH COURSE  mentioned that "A function that’s part of a class is a 
method.", however, ` A.__init__` tells that `__init__` is a function...


As mentioned, methods in Python _are_ functions for use with a class.


A.__init__



a = A()
a.__init__


>
I wonder how can I call `__init__` as? Consider the output above.
Maybe both are OK?


As you can see, they're both legal expressions.

The thing about `__init__` is that it's usually called automatically 
which you make a new object. Try putting a `print()` call in your 
`__init__` method, then make a new instance of `A`.


The purpose of `__init__` is to initialise the object's attribute/state 
after the basic, empty-ish, object is made.


Like other dunder methods (methods named with double underscores front 
and back) it is called automatically for you. In a subclass the 
`__init__` method calls the subperclass `__init__` and then does 
whatever additional things might be wanted by the subclass.


Let's look at what you used above:

>>> A.__init__


Here's we've just got a reference to the function you supposlied with 
the class definition for class `A`.


This:

>>> a = A()
>>> a.__init__


Here's you've accessed the name `__init__` via an existing instance of 
`A`, your variable `a`. At this point you haven't called it. So you've 
got a callable thing which is a binding of the function to the object 
`a` i.e. when you call it, the "bound method" knows that t is associated 
with `a` and puts that in as the first argument (usually named `self`).


Cheers,
Cameron Simpson 
--
https://mail.python.org/mailman/listinfo/python-list


Re: Imports and dot-notation

2023-08-09 Thread Cameron Simpson via Python-list

On 09Aug2023 12:30, Oliver Schinagl  wrote:
Looking at a python projects code and repository layout, we see the 
following directory structure.



/project/core
/project/components/module1
...
/project/components/moduleN
/projects/util

(this is far from complete, but enough to help paint a picture.

Some modules import other modules, and I see (at the very least) two 
(kind of three?) different ways of doing so.


`from project.components.module1 import function1, function2 as func, 
CONST1, CONST2 as CONST`


or maybe even (which has as an advantage that it becomes clear which 
namespace something belongs to


`from project.components.module1 import function1, function2 as 
module1_function2, CONST1, CONST2 as MODULE1_CONST2`


but then it really just becomes personal preference, as the number of 
characters saved on typing is almost negative (due to having a more 
complex import).



but also the dot notation being used

`from project.components import module1`

where obviously the functions are invoked as `module1.function1` etc

I hope the above is clear enough from an example.


Simply put, which of the two would be considered cleaner and more pythonic?


This is almost entirely a programmer preference thing.

The Zen, as usual, offers guideance but not dictates.

As you say, the module1.func form is very clear and has its beauty.  
Personally I lean towards the single name flavour, sometimes with a 
rename. FOr example, with os.path I often go:


from os.path import join as joinpath

and likewise for several other names from there, because the bare names 
are very generic (eg "join"). I see to be alone here. Many other people 
use:


import os.path

and use the full os.path.join in their code, which I find jarring and 
visually noisy.


Now for a bit more thought, looking at PEP8, we notes about imports, 
but sadly PEP8 does not state which method is better/preferred. While 
obviously in the end, it's always the maintainers choice in what they 
prefer, so are tabs vs spaces and PEP8 is opinionated about that too 
(in a good way, even though I'm not a fan :p).


PEP8 is for the stdlib source code; that said it is also the basis for 
most Python coding styles in the wild.


For me, the Zen's "readability counts" is the most important guideline; 
and to this end, your "module1.function" is an entirely reasonable 
response, particularly if you've got a lot of imports. But it does make 
for more verbose code, and that works against readability to a degree.


This is why it's all subjective.

Particular workplaces may mandate particular styles, but in your 
personal code? Do what seem best, and experience will cause that to 
evolve over time.


Also, the style can depend on the code you're working on. For a small 
module with few imports the:


from module1 import funcname

can be a win because the code is short, and this short form of funcname 
is both clear and readable. But in a very long piece of code with many 
imports you might go for module1.funcname for clarity, particularly if 
funcname is generic or overlaps with another similar imported name.


Cheers,
Cameron Simpson 
--
https://mail.python.org/mailman/listinfo/python-list


Re: Where is the error?

2023-08-07 Thread Cameron Simpson via Python-list

On 07Aug2023 08:02, Barry  wrote:

On 7 Aug 2023, at 05:28, Cameron Simpson via Python-list 
 wrote:
Used to use a Pascal compiler once which was uncannily good at 
suggesting where you'd missing a semicolon.


Was that on DEC VMS? It was a goal at DEC for its compilers to do this well.


No, a PDP-11 using V7 UNIX.


They could output the errors in a machine readable format to allow editors to 
auto fix.
I am learning rust and it is very good at suggesting fixes.
There is a command to apply fixes automatically, cargo fix.


Neat.

Cheers,
Cameron Simpson 
--
https://mail.python.org/mailman/listinfo/python-list


Re: Where is the error?

2023-08-06 Thread Cameron Simpson via Python-list

On 06Aug2023 22:41, Peter J. Holzer  wrote:

Mostly, error messages got a lot better in Python 3.10, but this one had
me scratching my head for a few minutes.

Consider this useless and faulty script:

r = {
   "x": (1 + 2 + 3)
   "y": (4 + 5 + 6)
   "z": (7 + 8 + 9)
}


[...]

Python 3.10 and 3.11 report:


 File "/home/hjp/tmp/foo", line 2
   "x": (1 + 2 + 3)
 ^^
SyntaxError: invalid syntax. Perhaps you forgot a comma?


The error message is now a lot better, of course, but the fact that it
points at the expression *before* the error completely threw me. The
underlined expression is clearly not missing a comma, nor is there an
error before that.


Well, it's hard to underline a token which isn't present. But maybe the 
message could be more evocative:


SyntaxError: invalid syntax. Perhaps you forgot a comma after the 
underlined code?


Is this "clairvoyant" behaviour a side-effect of the new parser or was
that a deliberate decision?


I have the vague impression the new parser enabled the improved 
reporting.


Used to use a Pascal compiler once which was uncannily good at 
suggesting where you'd missing a semicolon.


Cheers,
Cameron Simpson 
--
https://mail.python.org/mailman/listinfo/python-list


Re: isinstance()

2023-08-02 Thread Cameron Simpson via Python-list

On 03Aug2023 10:14, dn  wrote:
Can you please explain why a multi-part second-argument must be a 
tuple and not any other form of collection-type?


The signature is: isinstance(object, classinfo)
leading to "classinfo" of:

1/ a single class/type, eg int
2/ a tuple of same, eg ( int, str, )
3/ a union type, eg int | str (v3.10+)


help(isinstance) (in 3.8) says class_or_tuple.

I would speculate that requiring a tuple has two advantages:
- it may lend itself to promotion to a set for comparison with the MRO 
  of object (IIRC the "foo in (a,b,c)" is optimised this way also), and 
  this in turn may hint at the Hashable requirement
- it is _frugal_ in what we expect there, leaving open a future meaning 
  for something else in that place (for example, isinstance well 
  predates type annotations, and a looser kind of argument might have 
  precluded this new usage)


There's similar language in this try/except documentation:
file:///Users/cameron/var/doc/python/3.8.0/reference/compound_stmts.html#index-10

 For an except clause with an expression, that expression is 
 evaluated, and the clause matches the exception if the resulting 
 object is “compatible” with the exception. An object is compatible 
 with an exception if it is the class or a base class of the 
 exception object or a tuple containing an item compatible with the 
 exception.


To my mind the tuple requirement lends itself to a distinct syntax (the 
brackets) and frugal use of the meaning of what values can occur there.


Cheers,
Cameron Simpson 
--
https://mail.python.org/mailman/listinfo/python-list


Re: Should NoneType be iterable?

2023-06-20 Thread Cameron Simpson via Python-list

On 21Jun2023 10:09, Chris Angelico  wrote:

On Wed, 21 Jun 2023 at 09:59, Cameron Simpson via Python-list
 wrote:
I wasted some time the other evening on an API which returned a 
string

or None. My own API, and the pain it caused tells me that that API
design choice isn't good (it's an automatic attribute based on a tag,
returning None if the tag isn't there). My experience so far is that it
_looks_ handy so that you can safely say "foo.bar" all the time, but as
soon a you do something with the value you're in for a world of
None-checking.


https://peps.python.org/pep-0505/



Hmm. Thanks. - Cameron Simpson 
--
https://mail.python.org/mailman/listinfo/python-list


Re: Should NoneType be iterable?

2023-06-20 Thread Cameron Simpson via Python-list

On 21Jun2023 03:01, Greg Ewing  wrote:

On 20/06/23 7:36 pm, Barry wrote:

I have some APIs that do return None or a list.
The None says that a list is not available and that the caller is
responsible with dealing in a application-domain specific with
with that situation.


In that case, the caller should probably be checking for
None rather than blindly trying to iterate over the result.


I wasted some time the other evening on an API which returned a string 
or None. My own API, and the pain it caused tells me that that API 
design choice isn't good (it's an automatic attribute based on a tag, 
returning None if the tag isn't there). My experience so far is that it 
_looks_ handy so that you can safely say "foo.bar" all the time, but as 
soon a you do something with the value you're in for a world of 
None-checking.


I'm rethinking that choice right now. Just the other day I removed a 
setting in a related class which provided an automatic default value 
because, again, while handy for careless use it caused hard to debug 
problems because the default would flow out the call chain until it was 
unsuitable, making the cause hard to trace.


And of course I'm very -1 on None acquiring iteration or other features.  
Fail early, fail often!


Cheers,
Cameron Simpson 
--
https://mail.python.org/mailman/listinfo/python-list