From mmssdd1920 at gmail.com  Sat May  1 02:37:54 2021
From: mmssdd1920 at gmail.com (Msd De)
Date: Sat, 1 May 2021 12:07:54 +0530
Subject: [Tutor] err in integration
Message-ID: <CAOacnXmHJSzqeFxh-2wam8W-mMjrPsXY0_77YEMNqP3th5JQDA@mail.gmail.com>

Dear Sir,
I would like to print the error in numerical calculation.
I get this error
*Traceback (most recent call last):*


*  File "DFF_test.py", line 45, in <module>    print("The numerical result
is {:J1} (+-{:err})".format(J1, err))ValueError: Invalid conversion
specification*

*Here is the code*
import numpy as np
import math
import array as arr
from scipy import integrate

B=38.68
T=10.0/B

IL1=int(501-20*T)
IL2=int(501+20*T)
FF=[]
for i in range(0, IL1+1):
xx=-25.0+(i-1)*0.05
FF.append(-xx)
for i in range(IL1+1, IL2+1):
xx=-25.0+(i-1)*0.05
FF.append(np.log(1+np.exp(-B*xx))/B)
for i in range(IL2+1, 1002):
FF.append(0)

array_FF=np.zeros(1001)
for j in range(1001):
array_FF[int(j)]=(FF[j])
np.savetxt('FF.txt', array_FF, delimiter='  ')

eta1=10.0;evb=3.0
DFFF=[]
def DFF(Ex):
for j in range(64):
x1=Ex[j]-eta1
x2=x1+evb
xI1=501+20*x1
xI2=501+20*x2
NI11=int(xI1)
NI12=int(xI2)
FFxI1=array_FF[NI11]+(xI1-NI11)*(array_FF[NI11+1]-array_FF[NI11])
FFxI2=array_FF[NI12]+(xI2-NI12)*(array_FF[NI12+1]-array_FF[NI12])
DFFF=(FFxI1-FFxI2)
return DFFF

EL = 0.0
EH=10.0
J1, err=integrate.fixed_quad(DFF, EL, EH, n=64)
print("The numerical result is {:J1} (+-{:err})".format(J1, err))

From cs at cskk.id.au  Sat May  1 02:59:20 2021
From: cs at cskk.id.au (Cameron Simpson)
Date: Sat, 1 May 2021 16:59:20 +1000
Subject: [Tutor] err in integration
In-Reply-To: <CAOacnXmHJSzqeFxh-2wam8W-mMjrPsXY0_77YEMNqP3th5JQDA@mail.gmail.com>
References: <CAOacnXmHJSzqeFxh-2wam8W-mMjrPsXY0_77YEMNqP3th5JQDA@mail.gmail.com>
Message-ID: <YIz8SCu92hqzdVVa@cskk.homeip.net>

On 01May2021 12:07, Msd De <mmssdd1920 at gmail.com> wrote:
>Dear Sir,
>I would like to print the error in numerical calculation.
>I get this error
>*Traceback (most recent call last):*
>
>*  File "DFF_test.py", line 45, in <module>    print("The numerical result
>is {:J1} (+-{:err})".format(J1, err))ValueError: Invalid conversion
>specification*

You don't want the colon before the parameter names in your format 
string. Text after the colon is a format specifier (eg to print the 
value in a particular way), rather than what you want, which is to name 
the value you want to print.

Try this:

    print("The numerical result is {J1} (+-{err})".format(J1, err))

Actually, that won't work: your providing _positional_ values to 
.format(). Try this:

    print("The numerical result is {J1} (+-{err})".format(J1=J1, err=err))

Also, you can do this more simply with a "format string", thus:

    print(f"The numerical result is {J1} (+-{err})")

which pulls the parameter values straight our of your local variables.

Cheers,
Cameron Simpson <cs at cskk.id.au>

From manpritsinghece at gmail.com  Sat May  1 03:23:54 2021
From: manpritsinghece at gmail.com (Manprit Singh)
Date: Sat, 1 May 2021 12:53:54 +0530
Subject: [Tutor] Replacing comma with dot and dot with comma in a string
Message-ID: <CAO1OCwbdwuWd8pN4ABWv6zxgvYPbp-eSWibB1ntXLJFy2j5PJw@mail.gmail.com>

Dear sir ,

consider a string
st = "as.hjtk,rah,lop."

Now I have to  replace all commas with dots and all dots with commas. The
answer should be 'as,hjtk.rah.lop,'
Now for doing this i have used translate and maketrans as below:
st = "as.hjtk,rah,lop."
trans = str.maketrans({",": ".", ".":","})
ans = st.translate(trans)
print(ans)
which gives the right answer.
Just need to know if my understanding iabout translate and maketrans is
correct or not ?
I have passed a dict inside maketrans, for making a  translation table for
to be passed to translate . the dict contains the first key value pair as
"," : "." because the comma needed to be replaced with a dot similarly
second key value pair is "." : "," because a dot is needed to be replaced
with a comma in the string .

Regards
Manprit Singh

From mmssdd1920 at gmail.com  Sat May  1 03:19:44 2021
From: mmssdd1920 at gmail.com (Msd De)
Date: Sat, 1 May 2021 12:49:44 +0530
Subject: [Tutor] err in integration
In-Reply-To: <YIz8SCu92hqzdVVa@cskk.homeip.net>
References: <CAOacnXmHJSzqeFxh-2wam8W-mMjrPsXY0_77YEMNqP3th5JQDA@mail.gmail.com>
 <YIz8SCu92hqzdVVa@cskk.homeip.net>
Message-ID: <CAOacnX=nAJp=cEh9BrZUwhrUJEwi9XAoBhAASjaw6hhcGLGzVw@mail.gmail.com>

Dear Sir,
Thank you for your email

I tried this :
print("The numerical result is {J1} (+-{err})".format(J1=J1, err=err))
o/p is :
The numerical result is 0.203920669888 (+-None)
I would like it print number in place of +-None
Thanks

On Sat, May 1, 2021 at 12:30 PM Cameron Simpson <cs at cskk.id.au> wrote:

> On 01May2021 12:07, Msd De <mmssdd1920 at gmail.com> wrote:
> >Dear Sir,
> >I would like to print the error in numerical calculation.
> >I get this error
> >*Traceback (most recent call last):*
> >
> >*  File "DFF_test.py", line 45, in <module>    print("The numerical result
> >is {:J1} (+-{:err})".format(J1, err))ValueError: Invalid conversion
> >specification*
>
> You don't want the colon before the parameter names in your format
> string. Text after the colon is a format specifier (eg to print the
> value in a particular way), rather than what you want, which is to name
> the value you want to print.
>
> Try this:
>
>     print("The numerical result is {J1} (+-{err})".format(J1, err))
>
> Actually, that won't work: your providing _positional_ values to
> .format(). Try this:
>
>     print("The numerical result is {J1} (+-{err})".format(J1=J1, err=err))
>
> Also, you can do this more simply with a "format string", thus:
>
>     print(f"The numerical result is {J1} (+-{err})")
>
> which pulls the parameter values straight our of your local variables.
>
> Cheers,
> Cameron Simpson <cs at cskk.id.au>
> _______________________________________________
> Tutor maillist  -  Tutor at python.org
> To unsubscribe or change subscription options:
> https://mail.python.org/mailman/listinfo/tutor
>

From seisenb3 at emich.edu  Sat May  1 12:10:22 2021
From: seisenb3 at emich.edu (Sofia Eisenbeiser)
Date: Sat, 1 May 2021 12:10:22 -0400
Subject: [Tutor] ERROR when attempting installation
Message-ID: <CAMdyJcq0er_ga8_Lr_2sHOrRFB+_KzjiNDCTx6tTQ9k3gU22-g@mail.gmail.com>

Hello!

I'm new to Python and need to install a (very cool) program called
DeepLabCut.

Using Windows PowerShell to try to install the program but  when I run *pip
install deeplabcut==2.1.10.4* I am receiving:* ERROR: Could not find a
version that satisfies the requirement opencv-python-headless~=3.4.9.33
(from deeplabcut) (from versions: 3.4.10.37, 3.4.11.39, 3.4.11.41,
3.4.11.43, 3.4.11.45, 3.4.13.47, 4.3.0.38, 4.4.0.40, 4.4.0.42, 4.4.0.44,
4.4.0.46, 4.5.1.48)*
*ERROR: No matching distribution found for opencv-python-headless~=3.4.9.33*

I've been searching online but can't figure out how to fix it. I have
Python 3.9 installed & am using an updated version of pip.


Thank you!

From mats at wichmann.us  Sat May  1 12:20:17 2021
From: mats at wichmann.us (Mats Wichmann)
Date: Sat, 1 May 2021 10:20:17 -0600
Subject: [Tutor] ERROR when attempting installation
In-Reply-To: <CAMdyJcq0er_ga8_Lr_2sHOrRFB+_KzjiNDCTx6tTQ9k3gU22-g@mail.gmail.com>
References: <CAMdyJcq0er_ga8_Lr_2sHOrRFB+_KzjiNDCTx6tTQ9k3gU22-g@mail.gmail.com>
Message-ID: <886780c3-73b0-976d-5188-f5c2bf4b0e35@wichmann.us>

On 5/1/21 10:10 AM, Sofia Eisenbeiser wrote:
> Hello!
> 
> I'm new to Python and need to install a (very cool) program called
> DeepLabCut.
> 
> Using Windows PowerShell to try to install the program but  when I run *pip
> install deeplabcut==2.1.10.4* I am receiving:* ERROR: Could not find a
> version that satisfies the requirement opencv-python-headless~=3.4.9.33
> (from deeplabcut) (from versions: 3.4.10.37, 3.4.11.39, 3.4.11.41,
> 3.4.11.43, 3.4.11.45, 3.4.13.47, 4.3.0.38, 4.4.0.40, 4.4.0.42, 4.4.0.44,
> 4.4.0.46, 4.5.1.48)*
> *ERROR: No matching distribution found for opencv-python-headless~=3.4.9.33*
> 
> I've been searching online but can't figure out how to fix it. I have
> Python 3.9 installed & am using an updated version of pip.

You ended up with everything too modern :)

You need to get in contact with the project you're trying to install, 
and find out what their status is.  It's listing required versions of 
its dependencies.  If you go search on pypi.org, you'll see that the one 
it's complaining about has moved *way* beyond the pinned version:

https://pypi.org/project/opencv-python-headless/#files

and apparently the version that old is no longer available.  Only the 
DeepLabCut folks can know how to proceed...



From __peter__ at web.de  Sat May  1 13:04:28 2021
From: __peter__ at web.de (Peter Otten)
Date: Sat, 1 May 2021 19:04:28 +0200
Subject: [Tutor] err in integration
In-Reply-To: <CAOacnX=nAJp=cEh9BrZUwhrUJEwi9XAoBhAASjaw6hhcGLGzVw@mail.gmail.com>
References: <CAOacnXmHJSzqeFxh-2wam8W-mMjrPsXY0_77YEMNqP3th5JQDA@mail.gmail.com>
 <YIz8SCu92hqzdVVa@cskk.homeip.net>
 <CAOacnX=nAJp=cEh9BrZUwhrUJEwi9XAoBhAASjaw6hhcGLGzVw@mail.gmail.com>
Message-ID: <169f7fdb-2146-d76e-42e3-a51c82d86159@web.de>

On 01/05/2021 09:19, Msd De wrote:

> I tried this :
> print("The numerical result is {J1} (+-{err})".format(J1=J1, err=err))
> o/p is :
> The numerical result is 0.203920669888 (+-None)
> I would like it print number in place of +-None
> Thanks

According to the docs

https://docs.scipy.org/doc/scipy/reference/generated/scipy.integrate.fixed_quad.html

"""
scipy.integrate.fixed_quad(func, a, b, args=(), n=5)
Compute a definite integral using fixed-order Gaussian quadrature.

[...]

Returns
val float
Gaussian quadrature approximation to the integral

none None
Statically returned value of None
"""

the algorithm you chose does not provide an error margin.
You might consider an alternative that does, like:

https://docs.scipy.org/doc/scipy/reference/generated/scipy.integrate.quadrature.html#scipy.integrate.quadrature

"""
scipy.integrate.quadrature(func, a, b, args=(), tol=1.49e-08,
rtol=1.49e-08, maxiter=50, vec_func=True, miniter=1)[source]
Compute a definite integral using fixed-tolerance Gaussian quadrature.

[...]

Returns
val float
Gaussian quadrature approximation (within tolerance) to integral.

err float
Difference between last two estimates of the integral.
"""

From __peter__ at web.de  Sat May  1 13:04:28 2021
From: __peter__ at web.de (Peter Otten)
Date: Sat, 1 May 2021 19:04:28 +0200
Subject: [Tutor] err in integration
In-Reply-To: <CAOacnX=nAJp=cEh9BrZUwhrUJEwi9XAoBhAASjaw6hhcGLGzVw@mail.gmail.com>
References: <CAOacnXmHJSzqeFxh-2wam8W-mMjrPsXY0_77YEMNqP3th5JQDA@mail.gmail.com>
 <YIz8SCu92hqzdVVa@cskk.homeip.net>
 <CAOacnX=nAJp=cEh9BrZUwhrUJEwi9XAoBhAASjaw6hhcGLGzVw@mail.gmail.com>
Message-ID: <169f7fdb-2146-d76e-42e3-a51c82d86159@web.de>

On 01/05/2021 09:19, Msd De wrote:

> I tried this :
> print("The numerical result is {J1} (+-{err})".format(J1=J1, err=err))
> o/p is :
> The numerical result is 0.203920669888 (+-None)
> I would like it print number in place of +-None
> Thanks

According to the docs

https://docs.scipy.org/doc/scipy/reference/generated/scipy.integrate.fixed_quad.html

"""
scipy.integrate.fixed_quad(func, a, b, args=(), n=5)
Compute a definite integral using fixed-order Gaussian quadrature.

[...]

Returns
val float
Gaussian quadrature approximation to the integral

none None
Statically returned value of None
"""

the algorithm you chose does not provide an error margin.
You might consider an alternative that does, like:

https://docs.scipy.org/doc/scipy/reference/generated/scipy.integrate.quadrature.html#scipy.integrate.quadrature

"""
scipy.integrate.quadrature(func, a, b, args=(), tol=1.49e-08, 
rtol=1.49e-08, maxiter=50, vec_func=True, miniter=1)[source]
Compute a definite integral using fixed-tolerance Gaussian quadrature.

[...]

Returns
val float
Gaussian quadrature approximation (within tolerance) to integral.

err float
Difference between last two estimates of the integral.
"""


From alan.gauld at yahoo.co.uk  Sat May  1 13:35:31 2021
From: alan.gauld at yahoo.co.uk (alan.gauld at yahoo.co.uk)
Date: Sat, 01 May 2021 18:35:31 +0100
Subject: [Tutor] Replacing comma with dot and dot with comma in a string
In-Reply-To: <CAO1OCwbdwuWd8pN4ABWv6zxgvYPbp-eSWibB1ntXLJFy2j5PJw@mail.gmail.com>
References: <8eed79f4-d11f-4de9-870c-b19a1ffedd9b.ref@email.android.com>
Message-ID: <8eed79f4-d11f-4de9-870c-b19a1ffedd9b@email.android.com>

   Yes, that looks like a good use of maketrans. I'm not sure I would have
   thought of it but it works well here.
   Ps sorry for top posting, it's my phone...
   On 1 May 2021 08:23, Manprit Singh <manpritsinghece at gmail.com> wrote:

     Dear sir ,

     consider a string
     st = "as.hjtk,rah,lop."

     Now I have to  replace all commas with dots and all dots with commas.
     The
     answer should be 'as,hjtk.rah.lop,'
     Now for doing this i have used translate and maketrans as below:
     st = "as.hjtk,rah,lop."
     trans = str.maketrans({",": ".", ".":","})
     ans = st.translate(trans)
     print(ans)
     which gives the right answer.
     Just need to know if my understanding iabout translate and maketrans is
     correct or not ?
     I have passed a dict inside maketrans, for making a  translation table
     for
     to be passed to translate . the dict contains the first key value pair
     as
     "," : "." because the comma needed to be replaced with a dot similarly
     second key value pair is "." : "," because a dot is needed to be
     replaced
     with a comma in the string .

     Regards
     Manprit Singh
     _______________________________________________
     Tutor maillist  -  Tutor at python.org
     To unsubscribe or change subscription options:
     https://mail.python.org/mailman/listinfo/tutor

From PyTutor at DancesWithMice.info  Sat May  1 16:39:21 2021
From: PyTutor at DancesWithMice.info (dn)
Date: Sun, 2 May 2021 08:39:21 +1200
Subject: [Tutor] err in integration
In-Reply-To: <CAOacnX=nAJp=cEh9BrZUwhrUJEwi9XAoBhAASjaw6hhcGLGzVw@mail.gmail.com>
References: <CAOacnXmHJSzqeFxh-2wam8W-mMjrPsXY0_77YEMNqP3th5JQDA@mail.gmail.com>
 <YIz8SCu92hqzdVVa@cskk.homeip.net>
 <CAOacnX=nAJp=cEh9BrZUwhrUJEwi9XAoBhAASjaw6hhcGLGzVw@mail.gmail.com>
Message-ID: <d0606382-b138-5bb4-29ff-fec70c4e432d@DancesWithMice.info>

On 01/05/2021 19.19, Msd De wrote:
> Dear Sir,
> Thank you for your email
> 
> I tried this :
> print("The numerical result is {J1} (+-{err})".format(J1=J1, err=err))
> o/p is :
> The numerical result is 0.203920669888 (+-None)
> I would like it print number in place of +-None
> Thanks


Please re-read @Cameron's suggestion carefully. The simplified code uses
an f-string (Formatted string literals), so-named because the string
*commences* with the letter-f and can include object names, expressions,
etc, which are evaluated to produce a string-literal value - which you
wish to print but could equally-well be named and used elsewhere...

NB Python 3.6+

Web.Refs:
https://docs.python.org/release/3.6.0/reference/lexical_analysis.html#f-strings
https://www.python.org/dev/peps/pep-0498/



> On Sat, May 1, 2021 at 12:30 PM Cameron Simpson <cs at cskk.id.au> wrote:
> 
>> On 01May2021 12:07, Msd De <mmssdd1920 at gmail.com> wrote:
>>> Dear Sir,
>>> I would like to print the error in numerical calculation.
>>> I get this error
>>> *Traceback (most recent call last):*
>>>
>>> *  File "DFF_test.py", line 45, in <module>    print("The numerical result
>>> is {:J1} (+-{:err})".format(J1, err))ValueError: Invalid conversion
>>> specification*
>>
>> You don't want the colon before the parameter names in your format
>> string. Text after the colon is a format specifier (eg to print the
>> value in a particular way), rather than what you want, which is to name
>> the value you want to print.
>>
>> Try this:
>>
>>     print("The numerical result is {J1} (+-{err})".format(J1, err))
>>
>> Actually, that won't work: your providing _positional_ values to
>> .format(). Try this:
>>
>>     print("The numerical result is {J1} (+-{err})".format(J1=J1, err=err))
>>
>> Also, you can do this more simply with a "format string", thus:
>>
>>     print(f"The numerical result is {J1} (+-{err})")
>>
>> which pulls the parameter values straight our of your local variables.
>>
>> Cheers,
>> Cameron Simpson <cs at cskk.id.au>
>> _______________________________________________
>> Tutor maillist  -  Tutor at python.org
>> To unsubscribe or change subscription options:
>> https://mail.python.org/mailman/listinfo/tutor
>>
> _______________________________________________
> Tutor maillist  -  Tutor at python.org
> To unsubscribe or change subscription options:
> https://mail.python.org/mailman/listinfo/tutor
> 

-- 
Regards,
=dn

From PyTutor at DancesWithMice.info  Sun May  2 04:55:31 2021
From: PyTutor at DancesWithMice.info (dn)
Date: Sun, 2 May 2021 20:55:31 +1200
Subject: [Tutor] err in integration
In-Reply-To: <CAOacnXkg_+2mBGxJ3KOB2ySX3RQP47v8nHVrt_vAZhv+W6tqCg@mail.gmail.com>
References: <CAOacnXmHJSzqeFxh-2wam8W-mMjrPsXY0_77YEMNqP3th5JQDA@mail.gmail.com>
 <YIz8SCu92hqzdVVa@cskk.homeip.net>
 <CAOacnX=nAJp=cEh9BrZUwhrUJEwi9XAoBhAASjaw6hhcGLGzVw@mail.gmail.com>
 <d0606382-b138-5bb4-29ff-fec70c4e432d@DancesWithMice.info>
 <CAOacnXkg_+2mBGxJ3KOB2ySX3RQP47v8nHVrt_vAZhv+W6tqCg@mail.gmail.com>
Message-ID: <b2d00fda-fdd1-ee8f-f934-574e8a9713c9@DancesWithMice.info>

On 02/05/2021 20.27, Msd De wrote:
>
> I tried
> print(f"The numerical result is {J1} (+-{err})")
> this gives syntax error.
>
> Thanks in advance


The words you don't want to hear: "it works for me":

Python 3.9.2 (default, Feb 20 2021, 00:00:00)
[GCC 10.2.1 20201125 (Red Hat 10.2.1-9)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> J1 = 0.203920669888
>>> err = None
>>> print(f"The numerical result is {J1} (+-{err})")
The numerical result is 0.203920669888 (+-None)


Please see earlier note about Python version (3.6+) - that's when
f-strings were introduced.

Whilst I appreciated your personal reply, please post to the list -
others will assist, and likely faster (and yet others may have a similar
question or benefit from the learning-opportunity.

Please don't top-post. A conversation is normally in the sequence:
question, then answer...
-- 
Regards,
=dn

From manpritsinghece at gmail.com  Mon May  3 12:42:02 2021
From: manpritsinghece at gmail.com (Manprit Singh)
Date: Mon, 3 May 2021 22:12:02 +0530
Subject: [Tutor] Update values in python dicts
Message-ID: <CAO1OCwYgo-06Ap7uG94cM_kLOww8__xsUJJ2EBvfPXVoi5ae+Q@mail.gmail.com>

Dear sir ,
consider a dict as given below :
dic = {"A": 1, "B": 8, "H": 5, "L": 4, "K": 7}
I have to update those key value pairs, where the values are odd numbers,
all these values are to be incremented by 2 so after the update the same
dict will become :

dic = {'A': 3, 'B': 8, 'H': 7, 'L': 4, 'K': 9}

The way i am doing this is by executing the below written code:

dic = {"A": 1, "B": 8, "H": 5, "L": 4, "K": 7}
dic.update((x, y+2) for x, y in dic.items() if y%2 != 0)
print(dic)

gives the right answer.

Here a generator expression and update method is used. Instead of doing

this, the task can be done with a single for loop as below :

dic = {"A": 1, "B": 8, "H": 5, "L": 4, "K": 7}
for key, val in dic.items():
    if val%2 != 0:
        dic[key] = val + 2
print(dic)

which will give the desired result.

What should be preferred in this particular case . Kindly guide

Regards

Manprit Singh

From alan.gauld at yahoo.co.uk  Mon May  3 13:15:28 2021
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Mon, 3 May 2021 18:15:28 +0100
Subject: [Tutor] Update values in python dicts
In-Reply-To: <CAO1OCwYgo-06Ap7uG94cM_kLOww8__xsUJJ2EBvfPXVoi5ae+Q@mail.gmail.com>
References: <CAO1OCwYgo-06Ap7uG94cM_kLOww8__xsUJJ2EBvfPXVoi5ae+Q@mail.gmail.com>
Message-ID: <s6pb3g$11q7$1@ciao.gmane.io>

On 03/05/2021 17:42, Manprit Singh wrote:

> dic = {"A": 1, "B": 8, "H": 5, "L": 4, "K": 7}
> dic.update((x, y+2) for x, y in dic.items() if y%2 != 0)

> dic = {"A": 1, "B": 8, "H": 5, "L": 4, "K": 7}
> for key, val in dic.items():
>     if val%2 != 0:
>         dic[key] = val + 2

> What should be preferred in this particular case . Kindly guide

If you rename the vars in the first to match the second:

dic.update((key, val+2) for key, val in dic.items() if val%2)

Then there is very little to separate them. The explicit
loop is maybe slightly easier to read for a beginner
but probably slower to execute.

To make the update even more readable I'd probably opt
for a dict comprehension update argument:

dic.update({key:val+2 for key, val in dic.items() if val%2})

-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos



From phillor9 at gmail.com  Mon May  3 21:09:38 2021
From: phillor9 at gmail.com (Phil)
Date: Tue, 4 May 2021 11:09:38 +1000
Subject: [Tutor] How to find a word in a string
Message-ID: <ffa96524-f6c9-d8be-8384-1fd217c70047@gmail.com>

This is a bit trickier that I had at first thought, for example:

test = 'Do this, then do that.'

if 'this' in test.lower().split():
 ??? print('found')
else:
 ??? print('not found')

Does not find 'this' because of the comma.

I had experimented with .find() but that's not the answer either because 
if I was searching a sentence for 'is' it would be found in 'this' 
rather than only 'is' as a word. I also thought about striping all 
punctuation but that seems to be unnecessarily complicated.

So, how I might I deal with the comma in this case?

-- 
Regards,
Phil


From mats at wichmann.us  Mon May  3 21:20:29 2021
From: mats at wichmann.us (Mats Wichmann)
Date: Mon, 3 May 2021 19:20:29 -0600
Subject: [Tutor] How to find a word in a string
In-Reply-To: <ffa96524-f6c9-d8be-8384-1fd217c70047@gmail.com>
References: <ffa96524-f6c9-d8be-8384-1fd217c70047@gmail.com>
Message-ID: <bdccd36a-bffc-98fc-94be-e4906ea14151@wichmann.us>

On 5/3/21 7:09 PM, Phil wrote:
> This is a bit trickier that I had at first thought, for example:
> 
> test = 'Do this, then do that.'
> 
> if 'this' in test.lower().split():
>  ??? print('found')
> else:
>  ??? print('not found')
> 
> Does not find 'this' because of the comma.
> 
> I had experimented with .find() but that's not the answer either because 
> if I was searching a sentence for 'is' it would be found in 'this' 
> rather than only 'is' as a word. I also thought about striping all 
> punctuation but that seems to be unnecessarily complicated.
> 
> So, how I might I deal with the comma in this case?
> 


Depends on your requirements, which seem to be more complex...

without getting too fussy:


if 'this' in test:

beyond that, you're getting into the range of regular expressions, which 
we usually tell people "don't reach for them until you need to", but it 
does seem like your whole-word requirement means you may need to...


From phillor9 at gmail.com  Mon May  3 21:37:18 2021
From: phillor9 at gmail.com (Phil)
Date: Tue, 4 May 2021 11:37:18 +1000
Subject: [Tutor] How to find a word in a string
In-Reply-To: <bdccd36a-bffc-98fc-94be-e4906ea14151@wichmann.us>
References: <ffa96524-f6c9-d8be-8384-1fd217c70047@gmail.com>
 <bdccd36a-bffc-98fc-94be-e4906ea14151@wichmann.us>
Message-ID: <61310bcc-182d-757c-51b4-fd20cd20abab@gmail.com>

On 4/5/21 11:20 am, Mats Wichmann wrote:
>
> beyond that, you're getting into the range of regular expressions, 
> which we usually tell people "don't reach for them until you need to", 
> but it does seem like your whole-word requirement means you may need 
> to...
>
Although I've never used a regular expression I did search for an 
example but it started to become very complex. It seems to me that I 
have disregard all punctuation (not just the comma as in this case). 
I'll have to give this more thought.

-- 

Regards,
Phil


From phillor9 at gmail.com  Mon May  3 22:09:42 2021
From: phillor9 at gmail.com (Phil)
Date: Tue, 4 May 2021 12:09:42 +1000
Subject: [Tutor] How to find a word in a string - nearly correct
In-Reply-To: <bdccd36a-bffc-98fc-94be-e4906ea14151@wichmann.us>
References: <ffa96524-f6c9-d8be-8384-1fd217c70047@gmail.com>
 <bdccd36a-bffc-98fc-94be-e4906ea14151@wichmann.us>
Message-ID: <4352d14d-3d68-1839-e15d-44ebf3a73088@gmail.com>

On 4/5/21 11:20 am, Mats Wichmann wrote:
> On 5/3/21 7:09 PM, Phil wrote:
import re

result = re.search(r'\b' + 'this' + '\W', test)

print(result.group())

The output is 'this,' ,which is based on a white-space between words 
rather than punctuation. The search continues.

-- 
Regards,
Phil


From manpritsinghece at gmail.com  Tue May  4 00:03:29 2021
From: manpritsinghece at gmail.com (Manprit Singh)
Date: Tue, 4 May 2021 09:33:29 +0530
Subject: [Tutor] To get numeric prefix in a string if present
Message-ID: <CAO1OCwbzcuR4ETNd3oDQr+cQSuN7dpOswabjU8rUf2DPkd0o6A@mail.gmail.com>

Dear sir ,
Consider the problem of getting numeric prefix in a string if present.

st = "23fgh"
st1 = ""
for ele in st:
    if ele.isdigit():
        st1 += ele
    else:
        break
print(st1 or "Numeric prefix not in string" )

Here st variable contains the string from which the numeric prefix has to
be retrieved, which is 23 . The code written above gives the right answer.

My major question is - The way I have used break statement  with else  is
correct ?
iIam using an empty string st1 and then concatenating the digit  characters
with it, this doesn't feel pythonic. need to know any better way to solve
this .
Kindly guide

Regards
Manprit Singh

From jarkmx at gmail.com  Tue May  4 00:30:11 2021
From: jarkmx at gmail.com (jark AJ)
Date: Tue, 4 May 2021 00:30:11 -0400
Subject: [Tutor] Preserve Ordering in the Dict
Message-ID: <CAAaDumRpjJa+3PMrikXkBZW5q9+R95rA3tPkzvHkjdsPrkkvNA@mail.gmail.com>

Hi All,

       I am using Python 2.7.
I have a dictionary in the following format and when I print it, I get the
result not in the same order as shown. I am looking to preserve the order.
I looked at the ordered dict and sorted, however not able get the desired
result. Could you please help if there is a way we can achieve this, thanks
in advance!!

data = {
          "name": "my_name",
          "items": [
              {"type": "type_name",
               "details": [
                   {
                       "key": "key_name",
                       "value": "value_name"
                   }
               ]
               }
          ]
      }

print(data)


Current Result:

{'items': [{'type': 'type_name', 'details': [{'value': 'value_name', 'key':
'key_name'}]}], 'name': 'my_name'}

Desired Result:

{'name': 'my_name', 'items': [{'type': 'type_name', 'details': [{'key':
'key_name', 'value': 'value_name'}]}]}

From manpritsinghece at gmail.com  Tue May  4 03:30:06 2021
From: manpritsinghece at gmail.com (Manprit Singh)
Date: Tue, 4 May 2021 13:00:06 +0530
Subject: [Tutor] To get numeric prefix in a string if present
In-Reply-To: <CAO1OCwbzcuR4ETNd3oDQr+cQSuN7dpOswabjU8rUf2DPkd0o6A@mail.gmail.com>
References: <CAO1OCwbzcuR4ETNd3oDQr+cQSuN7dpOswabjU8rUf2DPkd0o6A@mail.gmail.com>
Message-ID: <CAO1OCwY7SLMa_fEYWNqZkphVaWKpC6E0u70pCYENaOmzop213A@mail.gmail.com>

 Dear Sir ,
st = "23fgh"
st[:st.index(st.lstrip("0123456789"))]
what about this ? This works well too for the said operation of getting the
numeric prefix of a string .

On Tue, May 4, 2021 at 9:33 AM Manprit Singh <manpritsinghece at gmail.com>
wrote:

> Dear sir ,
> Consider the problem of getting numeric prefix in a string if present.
>
> st = "23fgh"
> st1 = ""
> for ele in st:
>     if ele.isdigit():
>         st1 += ele
>     else:
>         break
> print(st1 or "Numeric prefix not in string" )
>
> Here st variable contains the string from which the numeric prefix has to
> be retrieved, which is 23 . The code written above gives the right answer.
>
> My major question is - The way I have used break statement  with else  is
> correct ?
> iIam using an empty string st1 and then concatenating the digit  characters
> with it, this doesn't feel pythonic. need to know any better way to solve
> this .
> Kindly guide
>
> Regards
> Manprit Singh
>
>

From __peter__ at web.de  Tue May  4 03:51:55 2021
From: __peter__ at web.de (Peter Otten)
Date: Tue, 4 May 2021 09:51:55 +0200
Subject: [Tutor] How to find a word in a string
In-Reply-To: <ffa96524-f6c9-d8be-8384-1fd217c70047@gmail.com>
References: <ffa96524-f6c9-d8be-8384-1fd217c70047@gmail.com>
Message-ID: <6b1a1f48-0bb3-00fb-748b-81203967da08@web.de>

On 04/05/2021 03:09, Phil wrote:
> This is a bit trickier that I had at first thought, for example:
>
> test = 'Do this, then do that.'
>
> if 'this' in test.lower().split():
>  ??? print('found')
> else:
>  ??? print('not found')
>
> Does not find 'this' because of the comma.
>
> I had experimented with .find() but that's not the answer either because
> if I was searching a sentence for 'is' it would be found in 'this'
> rather than only 'is' as a word. I also thought about striping all
> punctuation but that seems to be unnecessarily complicated.
>
> So, how I might I deal with the comma in this case?


If you want to avoid regular expressions you can replace punctuation
with spaces before splitting.
The obvious way would be

test.replace(".", " ").replace(",", " ").replace(...

but there's also str.translate() to deal with multiple (character)
replacements simultaneously:

 >>> punct = ",;:.!"
 >>> clean = str.maketrans(punct, " " * len(punct))
 >>> test = "Do this, then do that."
 >>> test.translate(clean)
'Do this  then do that '

 >>> if "this"in test.translate(clean).lower().split():
	print("found")


found

There are still problems like the "-" which may or may not be part of a
word.

From __peter__ at web.de  Tue May  4 03:51:55 2021
From: __peter__ at web.de (Peter Otten)
Date: Tue, 4 May 2021 09:51:55 +0200
Subject: [Tutor] How to find a word in a string
In-Reply-To: <ffa96524-f6c9-d8be-8384-1fd217c70047@gmail.com>
References: <ffa96524-f6c9-d8be-8384-1fd217c70047@gmail.com>
Message-ID: <6b1a1f48-0bb3-00fb-748b-81203967da08@web.de>

On 04/05/2021 03:09, Phil wrote:
> This is a bit trickier that I had at first thought, for example:
> 
> test = 'Do this, then do that.'
> 
> if 'this' in test.lower().split():
>  ??? print('found')
> else:
>  ??? print('not found')
> 
> Does not find 'this' because of the comma.
> 
> I had experimented with .find() but that's not the answer either because 
> if I was searching a sentence for 'is' it would be found in 'this' 
> rather than only 'is' as a word. I also thought about striping all 
> punctuation but that seems to be unnecessarily complicated.
> 
> So, how I might I deal with the comma in this case?


If you want to avoid regular expressions you can replace punctuation 
with spaces before splitting.
The obvious way would be

test.replace(".", " ").replace(",", " ").replace(...

but there's also str.translate() to deal with multiple (character) 
replacements simultaneously:

 >>> punct = ",;:.!"
 >>> clean = str.maketrans(punct, " " * len(punct))
 >>> test = "Do this, then do that."
 >>> test.translate(clean)
'Do this  then do that '

 >>> if "this"in test.translate(clean).lower().split():
	print("found")

	
found

There are still problems like the "-" which may or may not be part of a 
word.


From __peter__ at web.de  Tue May  4 04:05:59 2021
From: __peter__ at web.de (Peter Otten)
Date: Tue, 4 May 2021 10:05:59 +0200
Subject: [Tutor] To get numeric prefix in a string if present
In-Reply-To: <CAO1OCwY7SLMa_fEYWNqZkphVaWKpC6E0u70pCYENaOmzop213A@mail.gmail.com>
References: <CAO1OCwbzcuR4ETNd3oDQr+cQSuN7dpOswabjU8rUf2DPkd0o6A@mail.gmail.com>
 <CAO1OCwY7SLMa_fEYWNqZkphVaWKpC6E0u70pCYENaOmzop213A@mail.gmail.com>
Message-ID: <87aec965-7e8d-9e5c-46f7-ebdaac98b9ee@web.de>

On 04/05/2021 09:30, Manprit Singh wrote:

> st = "23fgh"
> st[:st.index(st.lstrip("0123456789"))]
> what about this ? This works well too for the said operation of getting the
> numeric prefix of a string .

What if the string contains only digits?

 >>> def numerical_prefix(s):
	return s[:s.index(s.lstrip("0123456789"))]

 >>> numerical_prefix("abc")
''
 >>> numerical_prefix("321abc")
'321'
 >>> numerical_prefix("321")  # wrong
''

Instead of using str.index() you could calculate the prefix length:

 >>> def numerical_prefix(s):
	return s[:len(s) - len(s.lstrip("0123456789"))]

 >>> numerical_prefix("abc")
''
 >>> numerical_prefix("321abc")
'321'
 >>> numerical_prefix("321")
'321'

From __peter__ at web.de  Tue May  4 04:05:59 2021
From: __peter__ at web.de (Peter Otten)
Date: Tue, 4 May 2021 10:05:59 +0200
Subject: [Tutor] To get numeric prefix in a string if present
In-Reply-To: <CAO1OCwY7SLMa_fEYWNqZkphVaWKpC6E0u70pCYENaOmzop213A@mail.gmail.com>
References: <CAO1OCwbzcuR4ETNd3oDQr+cQSuN7dpOswabjU8rUf2DPkd0o6A@mail.gmail.com>
 <CAO1OCwY7SLMa_fEYWNqZkphVaWKpC6E0u70pCYENaOmzop213A@mail.gmail.com>
Message-ID: <87aec965-7e8d-9e5c-46f7-ebdaac98b9ee@web.de>

On 04/05/2021 09:30, Manprit Singh wrote:

> st = "23fgh"
> st[:st.index(st.lstrip("0123456789"))]
> what about this ? This works well too for the said operation of getting the
> numeric prefix of a string .

What if the string contains only digits?

 >>> def numerical_prefix(s):
	return s[:s.index(s.lstrip("0123456789"))]

 >>> numerical_prefix("abc")
''
 >>> numerical_prefix("321abc")
'321'
 >>> numerical_prefix("321")  # wrong
''

Instead of using str.index() you could calculate the prefix length:

 >>> def numerical_prefix(s):
	return s[:len(s) - len(s.lstrip("0123456789"))]

 >>> numerical_prefix("abc")
''
 >>> numerical_prefix("321abc")
'321'
 >>> numerical_prefix("321")
'321'


From phillor9 at gmail.com  Tue May  4 04:19:46 2021
From: phillor9 at gmail.com (Phil)
Date: Tue, 4 May 2021 18:19:46 +1000
Subject: [Tutor] How to find a word in a string
In-Reply-To: <6b1a1f48-0bb3-00fb-748b-81203967da08@web.de>
References: <ffa96524-f6c9-d8be-8384-1fd217c70047@gmail.com>
 <6b1a1f48-0bb3-00fb-748b-81203967da08@web.de>
Message-ID: <0a8b80f9-ced4-b00a-dbab-aec4f8481097@gmail.com>

On 4/5/21 5:51 pm, Peter Otten wrote:
> but there's also str.translate() to deal with multiple (character)
> replacements simultaneously:

Thank you Peter, I wasn't aware of the translate or maketrans functions. 
The problem is, as you say, how would I differentiate between hyphenated 
words and the negative symbol?

I'll do some research into these functions tomorrow.

-- 

Regards,
Phil


From alan.gauld at yahoo.co.uk  Tue May  4 04:53:27 2021
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Tue, 4 May 2021 09:53:27 +0100
Subject: [Tutor] How to find a word in a string
In-Reply-To: <ffa96524-f6c9-d8be-8384-1fd217c70047@gmail.com>
References: <ffa96524-f6c9-d8be-8384-1fd217c70047@gmail.com>
Message-ID: <s6r227$dqf$1@ciao.gmane.io>

On 04/05/2021 02:09, Phil wrote:
> This is a bit trickier that I had at first thought, for example:

If you generalize the problem to parsing strings as actual text it
becomes a lot more difficult than you might think. Programming
languages are not natural language aware so they have no concept
of punctuation, words, phrases or sentences etc. For that you
need a natural language toolkit. Python has a library for this,
NLTK, but it has its own steepish learning curve and you have
to decide when your needs require its assistance.

However, the point is that without such a library you need to
do a lot of work to handle punctuation sensibly and reliably.

> test = 'Do this, then do that.'
> 
> if 'this' in test.lower().split():
>  ??? print('found')
> else:
>  ??? print('not found')

> rather than only 'is' as a word. I also thought about striping all 
> punctuation but that seems to be unnecessarily complicated.

One way or another you need to deal with the punctuation
since Python can't. There are multiple options and I see
others have covered the most likely choices - regex and
translate - but there is a whole world of special cases
waiting to catch you out.  Parsing natural language is
horrible.

-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos



From alan.gauld at yahoo.co.uk  Tue May  4 04:59:17 2021
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Tue, 4 May 2021 09:59:17 +0100
Subject: [Tutor] To get numeric prefix in a string if present
In-Reply-To: <CAO1OCwbzcuR4ETNd3oDQr+cQSuN7dpOswabjU8rUf2DPkd0o6A@mail.gmail.com>
References: <CAO1OCwbzcuR4ETNd3oDQr+cQSuN7dpOswabjU8rUf2DPkd0o6A@mail.gmail.com>
Message-ID: <s6r2d6$1jn$1@ciao.gmane.io>

On 04/05/2021 05:03, Manprit Singh wrote:
> Dear sir ,
> Consider the problem of getting numeric prefix in a string if present.
> 
> st = "23fgh"
> st1 = ""
> for ele in st:
>     if ele.isdigit():
>         st1 += ele
>     else:
>         break
> print(st1 or "Numeric prefix not in string" )
> 
> Here st variable contains the string from which the numeric prefix has to
> be retrieved, which is 23 . The code written above gives the right answer.
> 
> My major question is - The way I have used break statement  with else  is
> correct ?

Only commenting on the else part - yes, it is correct.
My only comment would be that I prefer to have the break in the first
clause so that it is easier to spot (if you have a lot of code in the
processing section which is not the case here) So I'd write it as:

for ele in st:
    if not ele.isdigit():
       break
    else:
       st1 += ele


But that really only matters if the other block is long, in
which case the break can "get lost"  in among the other code.

-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos



From la_spirou at hotmail.com  Mon May  3 23:56:54 2021
From: la_spirou at hotmail.com (P L)
Date: Tue, 4 May 2021 03:56:54 +0000
Subject: [Tutor] Regex
Message-ID: <DM5PR20MB1531C95343731A6731265CD99F5A9@DM5PR20MB1531.namprd20.prod.outlook.com>

Hello,

Having difficulty on an assignment, I have to extract a part of a string, from one key word to another character.

For example;

string = "Jan 31 01:33:12 ubuntu.local ticky: ERROR Tried to add information to closed ticket (mcintosh)"

I would like to extract from ERROR to ticket, so "ERROR Tried to add information to closed ticket"

Here's what I have so far:

with open("syslog.log", "r") as file:
    for error in file:
        if 'ERROR' not in error:
            continue
        pattern = r'(?:ERROR) [\w].+'
        result = re.search(pattern, error)
        print(result)

but my results are the following:
"ERROR Tried to add information to closed ticket (>"

Tried to make the search stop at the first open bracket, but when I try [^\(]*, does not work.

Thank you for your time!

From alan.gauld at yahoo.co.uk  Tue May  4 05:51:12 2021
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Tue, 4 May 2021 10:51:12 +0100
Subject: [Tutor] Regex
In-Reply-To: <DM5PR20MB1531C95343731A6731265CD99F5A9@DM5PR20MB1531.namprd20.prod.outlook.com>
References: <DM5PR20MB1531C95343731A6731265CD99F5A9@DM5PR20MB1531.namprd20.prod.outlook.com>
Message-ID: <s6r5eh$128l$1@ciao.gmane.io>

On 04/05/2021 04:56, P L wrote:

> Having difficulty on an assignment, I have to extract a part of a string, 
> from one key word to another character.

Is it a character or another substring? There is quite a big difference.
Based on your code I'll assume you mean substring.

> string = "Jan 31 01:33:12 ubuntu.local ticky: ERROR Tried to add information to closed ticket (mcintosh)"
> 
> I would like to extract from ERROR to ticket, so "ERROR Tried to add information to closed ticket"

You have jumped directly to regex, but that would always be my last
resort. Have you considered finding the index of the twoi strings and
then extracting a slice?

>>> s = "Jan 31 01:33:12 ubuntu.local ticky: ERROR Tried to add
information to closed ticket (mcintosh)"
>>> start = s.index('ERROR')
>>> end = s.index('ticket')+len('ticket')
>>> s[start:end]
'ERROR Tried to add information to closed ticket'
>>>

You can then generalize that to use string variables for the
start/end markers rather than literal strings.

> Here's what I have so far:
> 
> with open("syslog.log", "r") as file:
>     for error in file:
>         if 'ERROR' not in error:
>             continue
>         pattern = r'(?:ERROR) [\w].+'
>         result = re.search(pattern, error)

If you are going to use the same pattern many times its usually
better (ie faster) to compile the regex outside the loop and
then use the compiled version inside.

AS for your regex, I don't see how it will stop at 'ticket'?
The .+ will match everything to the end of the string.

I'd use the much simpler pattern: 'ERROR.+ticket'

> but my results are the following:
> "ERROR Tried to add information to closed ticket (>"

No idea how you got that.

-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos



From alan.gauld at yahoo.co.uk  Tue May  4 06:19:34 2021
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Tue, 4 May 2021 11:19:34 +0100
Subject: [Tutor] Regex
In-Reply-To: <s6r5eh$128l$1@ciao.gmane.io>
References: <DM5PR20MB1531C95343731A6731265CD99F5A9@DM5PR20MB1531.namprd20.prod.outlook.com>
 <s6r5eh$128l$1@ciao.gmane.io>
Message-ID: <s6r73n$3ct$1@ciao.gmane.io>

On 04/05/2021 10:51, Alan Gauld via Tutor wrote:
>>>> s = "Jan 31 01:33:12 ubuntu.local ticky: ERROR Tried to add
> information to closed ticket (mcintosh)"
>>>> start = s.index('ERROR')
>>>> end = s.index('ticket')+len('ticket')
>>>> s[start:end]
> 'ERROR Tried to add information to closed ticket'
>>>>

Following up my own post...

find() would be better than index() here since it returns -1 if not
found - which will work on the slice to give the whole remaining string...

Also I should have included start in the second search:

start = s.find('ERROR')
end = s.find('ticket',start)+len('ticket')
s[start:end]


-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos



From la_spirou at hotmail.com  Tue May  4 07:15:56 2021
From: la_spirou at hotmail.com (P L)
Date: Tue, 4 May 2021 11:15:56 +0000
Subject: [Tutor] Regex
In-Reply-To: <s6r73n$3ct$1@ciao.gmane.io>
References: <DM5PR20MB1531C95343731A6731265CD99F5A9@DM5PR20MB1531.namprd20.prod.outlook.com>
 <s6r5eh$128l$1@ciao.gmane.io>,<s6r73n$3ct$1@ciao.gmane.io>
Message-ID: <DM5PR20MB1531098D2C1694C48517031E9F5A9@DM5PR20MB1531.namprd20.prod.outlook.com>

I forgot to mention the assignment asks to try to solve via regex and I don't know the length of the string. It's a large system log file and I have to parse through each line and extract the sentence that follows the word ERROR. Sorry for not mentioning that.

________________________________
From: Tutor <tutor-bounces+la_spirou=hotmail.com at python.org> on behalf of Alan Gauld via Tutor <tutor at python.org>
Sent: May 4, 2021 6:19 AM
To: tutor at python.org <tutor at python.org>
Subject: Re: [Tutor] Regex

On 04/05/2021 10:51, Alan Gauld via Tutor wrote:
>>>> s = "Jan 31 01:33:12 ubuntu.local ticky: ERROR Tried to add
> information to closed ticket (mcintosh)"
>>>> start = s.index('ERROR')
>>>> end = s.index('ticket')+len('ticket')
>>>> s[start:end]
> 'ERROR Tried to add information to closed ticket'
>>>>

Following up my own post...

find() would be better than index() here since it returns -1 if not
found - which will work on the slice to give the whole remaining string...

Also I should have included start in the second search:

start = s.find('ERROR')
end = s.find('ticket',start)+len('ticket')
s[start:end]


--
Alan G
Author of the Learn to Program web site
https://na01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.alan-g.me.uk%2F&amp;data=04%7C01%7C%7C21773837b7914c3f347408d90ee63852%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C637557204210358462%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=NxRj61z2bFU%2B2BIhADhAt%2BiPBPEcW%2Fm7Ge9xc%2BvvtP0%3D&amp;reserved=0
https://na01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.amazon.com%2Fauthor%2Falan_gauld&amp;data=04%7C01%7C%7C21773837b7914c3f347408d90ee63852%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C637557204210358462%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=jyBj68gHiQxw1buFAwLU%2F8UUlUbIIWdv0d2Sm4yraaI%3D&amp;reserved=0
Follow my photo-blog on Flickr at:
https://na01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.flickr.com%2Fphotos%2Falangauldphotos&amp;data=04%7C01%7C%7C21773837b7914c3f347408d90ee63852%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C637557204210358462%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=K2MWegIG0nT54eqG1GsJ3R%2BdolXPvX3ia2gRfIyOWGs%3D&amp;reserved=0


_______________________________________________
Tutor maillist  -  Tutor at python.org
To unsubscribe or change subscription options:
https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fmail.python.org%2Fmailman%2Flistinfo%2Ftutor&amp;data=04%7C01%7C%7C21773837b7914c3f347408d90ee63852%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C637557204210358462%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=M%2FCR4dRjA2Vi2RCKEfjf1iGt%2BYZE5Ep0ZDYBmUZ1gJ0%3D&amp;reserved=0

From alan.gauld at yahoo.co.uk  Tue May  4 08:10:32 2021
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Tue, 4 May 2021 13:10:32 +0100
Subject: [Tutor] Regex
In-Reply-To: <DM5PR20MB1531098D2C1694C48517031E9F5A9@DM5PR20MB1531.namprd20.prod.outlook.com>
References: <DM5PR20MB1531C95343731A6731265CD99F5A9@DM5PR20MB1531.namprd20.prod.outlook.com>
 <s6r5eh$128l$1@ciao.gmane.io> <s6r73n$3ct$1@ciao.gmane.io>
 <DM5PR20MB1531098D2C1694C48517031E9F5A9@DM5PR20MB1531.namprd20.prod.outlook.com>
Message-ID: <s6rdjo$hvc$1@ciao.gmane.io>

On 04/05/2021 12:15, P L wrote:
> I forgot to mention the assignment asks to try to solve via regex 

Ok, I assumed a work assignment not a homework assignment...

>... extract the sentence that follows the word ERROR. 

That's a very different problem from the one you originally presented.
In that case the search is for any one of a number of sentence
terminators - ie any of '.','!','?' (more... in your example string
the 'sentence' does not have a terminator!)

But the regex should still be relatively straightforward if it starts
with ERROR and ends with one of the above terminators. Only the
terminating string changes from 'ticket' to a character group.

But note that the example you posted (ending in 'ticket') does not match
your new description of the problem. 'ticket' is not the end of the
sentence.

Half the problem in developing software is in getting the
specification exactly correct. Once you have that the solution
often effectively writes itself. Can you post a full and specific
description of what you are trying to do?

-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos



From __peter__ at web.de  Tue May  4 08:28:21 2021
From: __peter__ at web.de (Peter Otten)
Date: Tue, 4 May 2021 14:28:21 +0200
Subject: [Tutor] Regex
In-Reply-To: <s6r73n$3ct$1@ciao.gmane.io>
References: <DM5PR20MB1531C95343731A6731265CD99F5A9@DM5PR20MB1531.namprd20.prod.outlook.com>
 <s6r5eh$128l$1@ciao.gmane.io> <s6r73n$3ct$1@ciao.gmane.io>
Message-ID: <dc040a66-8b64-f07c-abb0-ad6e2d692ebf@web.de>

On 04/05/2021 12:19, Alan Gauld via Tutor wrote:
> On 04/05/2021 10:51, Alan Gauld via Tutor wrote:
>>>>> s = "Jan 31 01:33:12 ubuntu.local ticky: ERROR Tried to add
>> information to closed ticket (mcintosh)"
>>>>> start = s.index('ERROR')
>>>>> end = s.index('ticket')+len('ticket')
>>>>> s[start:end]
>> 'ERROR Tried to add information to closed ticket'
>>>>>
>
> Following up my own post...
>
> find() would be better than index() here since it returns -1 if not
> found - which will work on the slice to give the whole remaining string...
>
> Also I should have included start in the second search:
>
> start = s.find('ERROR')
> end = s.find('ticket',start)+len('ticket')
> s[start:end]

If possible I try to avoid that kind of arithmetic. Especially
str.find() with its return value of -1 for unsuccessful searches is a
bit of a bug magnet.

The following function includes the start token and returns anything
until but not including the end token, or the rest of the string if
there's no end token.

 >>> def span(s, start, end):
	a, b, c = s.partition(start)
	if not b: return ""
	return b + c.partition(end)[0]

 >>> span("before start ... end", "start", "end")
'start ... '
 >>> span("before start ...", "start", "end")
'start ...'
 >>> span("something else", "start", "end")
''
 >>> span("end before start ...", "start", "end")
'start ...'

 >>> s = ("Jan 31 01:33:12 ubuntu.local ticky: ERROR "
          "Tried to add information to closed ticket "
          "(mcintosh)")
 >>> span(s, "ERROR", "(")
'ERROR Tried to add information to closed ticket '
 >>> _.strip()  # get rid of enclosing whitespace
'ERROR Tried to add information to closed ticket'



From __peter__ at web.de  Tue May  4 08:28:21 2021
From: __peter__ at web.de (Peter Otten)
Date: Tue, 4 May 2021 14:28:21 +0200
Subject: [Tutor] Regex
In-Reply-To: <s6r73n$3ct$1@ciao.gmane.io>
References: <DM5PR20MB1531C95343731A6731265CD99F5A9@DM5PR20MB1531.namprd20.prod.outlook.com>
 <s6r5eh$128l$1@ciao.gmane.io> <s6r73n$3ct$1@ciao.gmane.io>
Message-ID: <dc040a66-8b64-f07c-abb0-ad6e2d692ebf@web.de>

On 04/05/2021 12:19, Alan Gauld via Tutor wrote:
> On 04/05/2021 10:51, Alan Gauld via Tutor wrote:
>>>>> s = "Jan 31 01:33:12 ubuntu.local ticky: ERROR Tried to add
>> information to closed ticket (mcintosh)"
>>>>> start = s.index('ERROR')
>>>>> end = s.index('ticket')+len('ticket')
>>>>> s[start:end]
>> 'ERROR Tried to add information to closed ticket'
>>>>>
> 
> Following up my own post...
> 
> find() would be better than index() here since it returns -1 if not
> found - which will work on the slice to give the whole remaining string...
> 
> Also I should have included start in the second search:
> 
> start = s.find('ERROR')
> end = s.find('ticket',start)+len('ticket')
> s[start:end]

If possible I try to avoid that kind of arithmetic. Especially 
str.find() with its return value of -1 for unsuccessful searches is a 
bit of a bug magnet.

The following function includes the start token and returns anything 
until but not including the end token, or the rest of the string if 
there's no end token.

 >>> def span(s, start, end):
	a, b, c = s.partition(start)
	if not b: return ""
	return b + c.partition(end)[0]

 >>> span("before start ... end", "start", "end")
'start ... '
 >>> span("before start ...", "start", "end")
'start ...'
 >>> span("something else", "start", "end")
''
 >>> span("end before start ...", "start", "end")
'start ...'

 >>> s = ("Jan 31 01:33:12 ubuntu.local ticky: ERROR "
          "Tried to add information to closed ticket "
          "(mcintosh)")
 >>> span(s, "ERROR", "(")
'ERROR Tried to add information to closed ticket '
 >>> _.strip()  # get rid of enclosing whitespace
'ERROR Tried to add information to closed ticket'




From la_spirou at hotmail.com  Tue May  4 09:15:20 2021
From: la_spirou at hotmail.com (P L)
Date: Tue, 4 May 2021 13:15:20 +0000
Subject: [Tutor] Regex
In-Reply-To: <s6rdjo$hvc$1@ciao.gmane.io>
References: <DM5PR20MB1531C95343731A6731265CD99F5A9@DM5PR20MB1531.namprd20.prod.outlook.com>
 <s6r5eh$128l$1@ciao.gmane.io> <s6r73n$3ct$1@ciao.gmane.io>
 <DM5PR20MB1531098D2C1694C48517031E9F5A9@DM5PR20MB1531.namprd20.prod.outlook.com>,
 <s6rdjo$hvc$1@ciao.gmane.io>
Message-ID: <DM5PR20MB15316A66AAF141EC90046DBA9F5A9@DM5PR20MB1531.namprd20.prod.outlook.com>

The assignment is to search for the word ERROR and the sentence that follows it. There is no terminator to the sentence, simply a blank space, as the following:

Jan 31 01:33:12 ubuntu.local ticky: ERROR Tried to add information to closed ticket (mcintosh)

That's one line from many, with varying sentence lengths and we're not supposed to print the usernames in the parentheses, or the parentheses itself. I would have preferred to use grep myself, but have to use regrex.

I decided to use re.sub and remove the parenthese and then use the script I posted before. I just don't think that's the best approach, seems inefficient. Feels like I can just use re.search but can't find the regex to describe it.

re.sub(r" ?\([^)]+\)", "", error)

Pat

________________________________
From: Tutor <tutor-bounces+la_spirou=hotmail.com at python.org> on behalf of Alan Gauld via Tutor <tutor at python.org>
Sent: May 4, 2021 8:10 AM
To: tutor at python.org <tutor at python.org>
Subject: Re: [Tutor] Regex

On 04/05/2021 12:15, P L wrote:
> I forgot to mention the assignment asks to try to solve via regex

Ok, I assumed a work assignment not a homework assignment...

>... extract the sentence that follows the word ERROR.

That's a very different problem from the one you originally presented.
In that case the search is for any one of a number of sentence
terminators - ie any of '.','!','?' (more... in your example string
the 'sentence' does not have a terminator!)

But the regex should still be relatively straightforward if it starts
with ERROR and ends with one of the above terminators. Only the
terminating string changes from 'ticket' to a character group.

But note that the example you posted (ending in 'ticket') does not match
your new description of the problem. 'ticket' is not the end of the
sentence.

Half the problem in developing software is in getting the
specification exactly correct. Once you have that the solution
often effectively writes itself. Can you post a full and specific
description of what you are trying to do?

--
Alan G
Author of the Learn to Program web site
https://na01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.alan-g.me.uk%2F&amp;data=04%7C01%7C%7Cfbb38651382f4becda0608d90ef5b9b3%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C637557270802984314%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=9IDEpuBENHsQwVHbT9JueHZYUz72IQVKF%2Fa1W2tdTLw%3D&amp;reserved=0
https://na01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.amazon.com%2Fauthor%2Falan_gauld&amp;data=04%7C01%7C%7Cfbb38651382f4becda0608d90ef5b9b3%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C637557270802984314%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=vVt6M63k%2B6FDHlW9Cq5i1DTy%2FitC36oxDG9tT2y7rKE%3D&amp;reserved=0
Follow my photo-blog on Flickr at:
https://na01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.flickr.com%2Fphotos%2Falangauldphotos&amp;data=04%7C01%7C%7Cfbb38651382f4becda0608d90ef5b9b3%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C637557270802984314%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=FXFxPEgAcZuqnV5WWM5pSY41rDqnzdBEUNk2Fq4cTPI%3D&amp;reserved=0


_______________________________________________
Tutor maillist  -  Tutor at python.org
To unsubscribe or change subscription options:
https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fmail.python.org%2Fmailman%2Flistinfo%2Ftutor&amp;data=04%7C01%7C%7Cfbb38651382f4becda0608d90ef5b9b3%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C637557270802984314%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=YGtdZCSXkGNjGNVdRoN1g4aFxbhyLf%2FvkrobB9QKFy4%3D&amp;reserved=0

From alan.gauld at yahoo.co.uk  Tue May  4 09:54:23 2021
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Tue, 4 May 2021 14:54:23 +0100
Subject: [Tutor] Regex
In-Reply-To: <DM5PR20MB15316A66AAF141EC90046DBA9F5A9@DM5PR20MB1531.namprd20.prod.outlook.com>
References: <DM5PR20MB1531C95343731A6731265CD99F5A9@DM5PR20MB1531.namprd20.prod.outlook.com>
 <s6r5eh$128l$1@ciao.gmane.io> <s6r73n$3ct$1@ciao.gmane.io>
 <DM5PR20MB1531098D2C1694C48517031E9F5A9@DM5PR20MB1531.namprd20.prod.outlook.com>
 <s6rdjo$hvc$1@ciao.gmane.io>
 <DM5PR20MB15316A66AAF141EC90046DBA9F5A9@DM5PR20MB1531.namprd20.prod.outlook.com>
Message-ID: <s6rjmg$jqa$1@ciao.gmane.io>

On 04/05/2021 14:15, P L wrote:
> The assignment is to search for the word ERROR and the sentence that follows it. > There is no terminator to the sentence, simply a blank space, as the
following:

This may not be your fault but that of your teacher, but that is a
terrible problem description. Almost impossible to use.

What is a sentence if it does not have a terminator?
It's really just a string.

So your problem is to extract the string beginning with ERROR.

> That's one line from many, with varying sentence lengths and we're not 
> supposed to print the usernames in the parentheses, or the parentheses itself. 

So again our description is inadequate. What do we do if there are
parens inside the string before the name?
Is the name always at the end of the line?

For example how do we deal with these two cases:

ERROR blah (de) blah (name)
ERROR blah blah (name) bloop bloop

What should be printed in each case?

If you can precisely define the problem then the code
should be relatively easy. But if you have a terrible
problem description you need to improve it before you
can solve it. Either by asking questions or by making
assumptions. But document those assumptions (in comments?)
so you know how to fix/change them if need be.

> I would have preferred to use grep myself, 

But grep is just a regex recognizer. You still have
to write the correct regex. And grep won't break up
the line to only include the bits you want.

> I decided to use re.sub and remove the parenthese and 
> then use the script I posted before. 

I think that's more complex than need be.

The simplest regex that might match your problem definition
(so far) is:

re.search(r'ERROR[^(]*', string)

Which matches ERROR followed by any number of non '(' characters.
It will include the space so you might want to strip() the result
if you need to lose the space. (Your problem definition doesn't
make it clear if the space is part of the "sentence" or not)

-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos



From __peter__ at web.de  Tue May  4 09:59:04 2021
From: __peter__ at web.de (Peter Otten)
Date: Tue, 4 May 2021 15:59:04 +0200
Subject: [Tutor] Regex
In-Reply-To: <DM5PR20MB15316A66AAF141EC90046DBA9F5A9@DM5PR20MB1531.namprd20.prod.outlook.com>
References: <DM5PR20MB1531C95343731A6731265CD99F5A9@DM5PR20MB1531.namprd20.prod.outlook.com>
 <s6r5eh$128l$1@ciao.gmane.io> <s6r73n$3ct$1@ciao.gmane.io>
 <DM5PR20MB1531098D2C1694C48517031E9F5A9@DM5PR20MB1531.namprd20.prod.outlook.com>
 <s6rdjo$hvc$1@ciao.gmane.io>
 <DM5PR20MB15316A66AAF141EC90046DBA9F5A9@DM5PR20MB1531.namprd20.prod.outlook.com>
Message-ID: <733b3005-1736-bb44-5756-92b0f316c9a5@web.de>

On 04/05/2021 15:15, P L wrote:
> The assignment is to search for the word ERROR and the sentence that follows it. There is no terminator to the sentence, simply a blank space, as the following:
>
> Jan 31 01:33:12 ubuntu.local ticky: ERROR Tried to add information to closed ticket (mcintosh)

Well, if the sentence is guaranteed to be followed by a space and an
opening parenthesis you can use that as the "terminator":

 >>> s = "Jan 31 01:33:12 ubuntu.local ticky: ERROR Tried to add
information to closed ticket (mcintosh)"
 >>> import re
 >>> re.search(r"(ERROR .*?) \(", s).group(1)
'ERROR Tried to add information to closed ticket'

Alternatively, with a lookahead assertion:

 >>> re.search(r"ERROR .*?(?= \()", s).group()
'ERROR Tried to add information to closed ticket'

From __peter__ at web.de  Tue May  4 09:59:04 2021
From: __peter__ at web.de (Peter Otten)
Date: Tue, 4 May 2021 15:59:04 +0200
Subject: [Tutor] Regex
In-Reply-To: <DM5PR20MB15316A66AAF141EC90046DBA9F5A9@DM5PR20MB1531.namprd20.prod.outlook.com>
References: <DM5PR20MB1531C95343731A6731265CD99F5A9@DM5PR20MB1531.namprd20.prod.outlook.com>
 <s6r5eh$128l$1@ciao.gmane.io> <s6r73n$3ct$1@ciao.gmane.io>
 <DM5PR20MB1531098D2C1694C48517031E9F5A9@DM5PR20MB1531.namprd20.prod.outlook.com>
 <s6rdjo$hvc$1@ciao.gmane.io>
 <DM5PR20MB15316A66AAF141EC90046DBA9F5A9@DM5PR20MB1531.namprd20.prod.outlook.com>
Message-ID: <733b3005-1736-bb44-5756-92b0f316c9a5@web.de>

On 04/05/2021 15:15, P L wrote:
> The assignment is to search for the word ERROR and the sentence that follows it. There is no terminator to the sentence, simply a blank space, as the following:
> 
> Jan 31 01:33:12 ubuntu.local ticky: ERROR Tried to add information to closed ticket (mcintosh)

Well, if the sentence is guaranteed to be followed by a space and an 
opening parenthesis you can use that as the "terminator":

 >>> s = "Jan 31 01:33:12 ubuntu.local ticky: ERROR Tried to add 
information to closed ticket (mcintosh)"
 >>> import re
 >>> re.search(r"(ERROR .*?) \(", s).group(1)
'ERROR Tried to add information to closed ticket'

Alternatively, with a lookahead assertion:

 >>> re.search(r"ERROR .*?(?= \()", s).group()
'ERROR Tried to add information to closed ticket'


From Richard at Damon-Family.org  Tue May  4 10:07:26 2021
From: Richard at Damon-Family.org (Richard Damon)
Date: Tue, 4 May 2021 10:07:26 -0400
Subject: [Tutor] Regex
In-Reply-To: <DM5PR20MB15316A66AAF141EC90046DBA9F5A9@DM5PR20MB1531.namprd20.prod.outlook.com>
References: <DM5PR20MB1531C95343731A6731265CD99F5A9@DM5PR20MB1531.namprd20.prod.outlook.com>
 <s6r5eh$128l$1@ciao.gmane.io> <s6r73n$3ct$1@ciao.gmane.io>
 <DM5PR20MB1531098D2C1694C48517031E9F5A9@DM5PR20MB1531.namprd20.prod.outlook.com>
 <s6rdjo$hvc$1@ciao.gmane.io>
 <DM5PR20MB15316A66AAF141EC90046DBA9F5A9@DM5PR20MB1531.namprd20.prod.outlook.com>
Message-ID: <71c468c6-2fe0-fc97-9d87-82b5feb87b63@Damon-Family.org>

It sounds like what you want is a Regex that first matches the token
ERROR, then has a capture group to catch a sequence of words, and then a
terminal ( (that is not in the capture). Maybe if some messages don't
have the (username) add alternatives to the terminal. You then use
.group on the results of the match to extract the capture.

On 5/4/21 9:15 AM, P L wrote:
> The assignment is to search for the word ERROR and the sentence that follows it. There is no terminator to the sentence, simply a blank space, as the following:
>
> Jan 31 01:33:12 ubuntu.local ticky: ERROR Tried to add information to closed ticket (mcintosh)
>
> That's one line from many, with varying sentence lengths and we're not supposed to print the usernames in the parentheses, or the parentheses itself. I would have preferred to use grep myself, but have to use regrex.
>
> I decided to use re.sub and remove the parenthese and then use the script I posted before. I just don't think that's the best approach, seems inefficient. Feels like I can just use re.search but can't find the regex to describe it.
>
> re.sub(r" ?\([^)]+\)", "", error)
>
> Pat
>
> ________________________________
> From: Tutor <tutor-bounces+la_spirou=hotmail.com at python.org> on behalf of Alan Gauld via Tutor <tutor at python.org>
> Sent: May 4, 2021 8:10 AM
> To: tutor at python.org <tutor at python.org>
> Subject: Re: [Tutor] Regex
>
> On 04/05/2021 12:15, P L wrote:
>> I forgot to mention the assignment asks to try to solve via regex
> Ok, I assumed a work assignment not a homework assignment...
>
>> ... extract the sentence that follows the word ERROR.
> That's a very different problem from the one you originally presented.
> In that case the search is for any one of a number of sentence
> terminators - ie any of '.','!','?' (more... in your example string
> the 'sentence' does not have a terminator!)
>
> But the regex should still be relatively straightforward if it starts
> with ERROR and ends with one of the above terminators. Only the
> terminating string changes from 'ticket' to a character group.
>
> But note that the example you posted (ending in 'ticket') does not match
> your new description of the problem. 'ticket' is not the end of the
> sentence.
>
> Half the problem in developing software is in getting the
> specification exactly correct. Once you have that the solution
> often effectively writes itself. Can you post a full and specific
> description of what you are trying to do?
>
> --
> Alan G
> Author of the Learn to Program web site
> https://na01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.alan-g.me.uk%2F&amp;data=04%7C01%7C%7Cfbb38651382f4becda0608d90ef5b9b3%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C637557270802984314%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=9IDEpuBENHsQwVHbT9JueHZYUz72IQVKF%2Fa1W2tdTLw%3D&amp;reserved=0
> https://na01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.amazon.com%2Fauthor%2Falan_gauld&amp;data=04%7C01%7C%7Cfbb38651382f4becda0608d90ef5b9b3%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C637557270802984314%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=vVt6M63k%2B6FDHlW9Cq5i1DTy%2FitC36oxDG9tT2y7rKE%3D&amp;reserved=0
> Follow my photo-blog on Flickr at:
> https://na01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.flickr.com%2Fphotos%2Falangauldphotos&amp;data=04%7C01%7C%7Cfbb38651382f4becda0608d90ef5b9b3%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C637557270802984314%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=FXFxPEgAcZuqnV5WWM5pSY41rDqnzdBEUNk2Fq4cTPI%3D&amp;reserved=0
>
>
> _______________________________________________
> Tutor maillist  -  Tutor at python.org
> To unsubscribe or change subscription options:
> https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fmail.python.org%2Fmailman%2Flistinfo%2Ftutor&amp;data=04%7C01%7C%7Cfbb38651382f4becda0608d90ef5b9b3%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C637557270802984314%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=YGtdZCSXkGNjGNVdRoN1g4aFxbhyLf%2FvkrobB9QKFy4%3D&amp;reserved=0
> _______________________________________________
> Tutor maillist  -  Tutor at python.org
> To unsubscribe or change subscription options:
> https://mail.python.org/mailman/listinfo/tutor


-- 
Richard Damon


From breamoreboy at gmail.com  Tue May  4 12:54:41 2021
From: breamoreboy at gmail.com (Mark Lawrence)
Date: Tue, 4 May 2021 17:54:41 +0100
Subject: [Tutor] Preserve Ordering in the Dict
In-Reply-To: <CAAaDumRpjJa+3PMrikXkBZW5q9+R95rA3tPkzvHkjdsPrkkvNA@mail.gmail.com>
References: <CAAaDumRpjJa+3PMrikXkBZW5q9+R95rA3tPkzvHkjdsPrkkvNA@mail.gmail.com>
Message-ID: <c177794e-9770-adac-0f7c-4d703aa6e30d@gmail.com>

On 04/05/2021 05:30, jark AJ wrote:
> Hi All,
> 
>         I am using Python 2.7.
> I have a dictionary in the following format and when I print it, I get the
> result not in the same order as shown. I am looking to preserve the order.
> I looked at the ordered dict and sorted, however not able get the desired
> result. Could you please help if there is a way we can achieve this, thanks
> in advance!!
> 
> data = {
>            "name": "my_name",
>            "items": [
>                {"type": "type_name",
>                 "details": [
>                     {
>                         "key": "key_name",
>                         "value": "value_name"
>                     }
>                 ]
>                 }
>            ]
>        }
> 
> print(data)
> 
> 
> Current Result:
> 
> {'items': [{'type': 'type_name', 'details': [{'value': 'value_name', 'key':
> 'key_name'}]}], 'name': 'my_name'}
> 
> Desired Result:
> 
> {'name': 'my_name', 'items': [{'type': 'type_name', 'details': [{'key':
> 'key_name', 'value': 'value_name'}]}]}

This 
https://docs.python.org/2.7/library/collections.html#ordereddict-objects 
should just work so what went wrong when you tried it?


-- 
My fellow Pythonistas, ask not what our language can do for you, ask
what you can do for our language.

Mark Lawrence


From la_spirou at hotmail.com  Tue May  4 13:33:01 2021
From: la_spirou at hotmail.com (P L)
Date: Tue, 4 May 2021 17:33:01 +0000
Subject: [Tutor] Regex
In-Reply-To: <733b3005-1736-bb44-5756-92b0f316c9a5@web.de>
References: <DM5PR20MB1531C95343731A6731265CD99F5A9@DM5PR20MB1531.namprd20.prod.outlook.com>
 <s6r5eh$128l$1@ciao.gmane.io> <s6r73n$3ct$1@ciao.gmane.io>
 <DM5PR20MB1531098D2C1694C48517031E9F5A9@DM5PR20MB1531.namprd20.prod.outlook.com>
 <s6rdjo$hvc$1@ciao.gmane.io>
 <DM5PR20MB15316A66AAF141EC90046DBA9F5A9@DM5PR20MB1531.namprd20.prod.outlook.com>,
 <733b3005-1736-bb44-5756-92b0f316c9a5@web.de>
Message-ID: <DM5PR20MB15318E9AF8AE6749D3962CC79F5A9@DM5PR20MB1531.namprd20.prod.outlook.com>

Super, re.search(r"ERROR.*?) \(",s).group(1) was exactly what I was looking for.

Thanks again, apologies for not making it clear!

Cheers

________________________________
From: Tutor <tutor-bounces+la_spirou=hotmail.com at python.org> on behalf of Peter Otten <__peter__ at web.de>
Sent: May 4, 2021 9:59 AM
To: tutor at python.org <tutor at python.org>
Subject: Re: [Tutor] Regex

On 04/05/2021 15:15, P L wrote:
> The assignment is to search for the word ERROR and the sentence that follows it. There is no terminator to the sentence, simply a blank space, as the following:
>
> Jan 31 01:33:12 ubuntu.local ticky: ERROR Tried to add information to closed ticket (mcintosh)

Well, if the sentence is guaranteed to be followed by a space and an
opening parenthesis you can use that as the "terminator":

 >>> s = "Jan 31 01:33:12 ubuntu.local ticky: ERROR Tried to add
information to closed ticket (mcintosh)"
 >>> import re
 >>> re.search(r"(ERROR .*?) \(", s).group(1)
'ERROR Tried to add information to closed ticket'

Alternatively, with a lookahead assertion:

 >>> re.search(r"ERROR .*?(?= \()", s).group()
'ERROR Tried to add information to closed ticket'
_______________________________________________
Tutor maillist  -  Tutor at python.org
To unsubscribe or change subscription options:
https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fmail.python.org%2Fmailman%2Flistinfo%2Ftutor&amp;data=04%7C01%7C%7Cddad8692c30a49d9ea4f08d90f04e069%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C637557335875222875%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=EeNpJMadBfNkQnN7%2FcIWc4iVuAiZ8gCD10bXzgKFrB4%3D&amp;reserved=0

From cs at cskk.id.au  Tue May  4 18:02:43 2021
From: cs at cskk.id.au (Cameron Simpson)
Date: Wed, 5 May 2021 08:02:43 +1000
Subject: [Tutor] How to find a word in a string - nearly correct
In-Reply-To: <4352d14d-3d68-1839-e15d-44ebf3a73088@gmail.com>
References: <4352d14d-3d68-1839-e15d-44ebf3a73088@gmail.com>
Message-ID: <YJHEg4lRkV3DNhD1@cskk.homeip.net>

On 04May2021 12:09, Phil <phillor9 at gmail.com> wrote:
>On 4/5/21 11:20 am, Mats Wichmann wrote:
>>On 5/3/21 7:09 PM, Phil wrote:
>import re
>
>result = re.search(r'\b' + 'this' + '\W', test)

You can write that in one go like this:

    result = re.search(r'\bthis\W', test)

OTOH, keeping them separate may aid debugging.

>The output is 'this,' ,which is based on a white-space between words 
>rather than punctuation. The search continues.

That's because you included the trailing "nonword" character in your 
regexp. Had you considered that "\b" matches a word boundary at the 
start _or_ the end?

    \bthis\b

Bearing in mind that "word" is a lexical idea in regexps and may not be 
meaningful in nonEnglish settings.

For reference, the special flavour of regexps in Python is documents (at 
length, alas), here:

    https://docs.python.org/3/library/re.html#regular-expression-syntax

The other thing to keep in mind is that if you're matching something 
dependent on the surrounding context you can:

Use a group:

    \W(this)\W

and access the grouped part, eg in the above result.group(1) is "this".

Use a look-ahead or look-behind match:

    (?<!\w)this(?!\w)

These are tests, and are not included in the matched text. The leading 
one texts for _not_ matching a "word character \w" before they text and 
the trailing one tests for _not_ matching a word character after the 
text. But only the stuff in between is part of the result ("this").

You can see this can get pretty complex pretty fast. But \b for a "word 
boundary" is very useful.

Cheers,
Cameron Simpson <cs at cskk.id.au>

From phillor9 at gmail.com  Tue May  4 20:57:01 2021
From: phillor9 at gmail.com (Phil)
Date: Wed, 5 May 2021 10:57:01 +1000
Subject: [Tutor] How to find a word in a string - nearly correct
In-Reply-To: <YJHEg4lRkV3DNhD1@cskk.homeip.net>
References: <4352d14d-3d68-1839-e15d-44ebf3a73088@gmail.com>
 <YJHEg4lRkV3DNhD1@cskk.homeip.net>
Message-ID: <758a38da-2ce1-fdd6-b89c-65541fdb4724@gmail.com>

On 5/5/21 8:02 am, Cameron Simpson wrote:
> On 04May2021 12:09, Phil <phillor9 at gmail.com> wrote:
>> On 4/5/21 11:20 am, Mats Wichmann wrote:
>>> On 5/3/21 7:09 PM, Phil wrote:
>> import re
>>
>> result = re.search(r'\b' + 'this' + '\W', test)
> You can write that in one go like this:
>
>      result = re.search(r'\bthis\W', test)
>
> OTOH, keeping them separate may aid debugging.
>
>> The output is 'this,' ,which is based on a white-space between words
>> rather than punctuation. The search continues.
> That's because you included the trailing "nonword" character in your
> regexp. Had you considered that "\b" matches a word boundary at the
> start _or_ the end?
>
>      \bthis\b
>
Thank you Cameron, more useful information to file away.

-- 

Regards,
Phil


From cantgz20 at wfu.edu  Wed May  5 16:03:09 2021
From: cantgz20 at wfu.edu (Gregory Zane Cantrell III)
Date: Wed, 5 May 2021 16:03:09 -0400
Subject: [Tutor] Python Troubleshooting
Message-ID: <23CAF20F-0B6A-456E-88BA-337D95F18C4B@hxcore.ol>

   Hi,



   I am trying to set up my Anaconda Pathway to link to my computer. For some
   reason, I am unable to download packages that are outside of the base
   packages. I have used StackOverflow for questions, but I am unable to
   resolve the issue. Is it possible for someone to walk me through the
   Anaconda Prompt monitor, so I can download certain packages.



   Sincerely,

   Zane Cantrell



From alan.gauld at yahoo.co.uk  Thu May  6 05:06:44 2021
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Thu, 6 May 2021 10:06:44 +0100
Subject: [Tutor] Python Troubleshooting
In-Reply-To: <23CAF20F-0B6A-456E-88BA-337D95F18C4B@hxcore.ol>
References: <23CAF20F-0B6A-456E-88BA-337D95F18C4B@hxcore.ol>
Message-ID: <s70bj4$ra5$1@ciao.gmane.io>

On 05/05/2021 21:03, Gregory Zane Cantrell III wrote:

>    I am trying to set up my Anaconda Pathway to link to my computer. For some
>    reason, I am unable to download packages that are outside of the base
>    packages. I have used StackOverflow for questions, but I am unable to
>    resolve the issue. Is it possible for someone to walk me through the
>    Anaconda Prompt monitor, so I can download certain packages.

This list is really aimed at the core Python language and standard
library. While there are some anaconda users here you are more
likely to get help on a dedicated anaconda forum such as:

https://groups.google.com/a/continuum.io/g/anaconda

-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos



From manpritsinghece at gmail.com  Thu May  6 19:45:02 2021
From: manpritsinghece at gmail.com (Manprit Singh)
Date: Fri, 7 May 2021 05:15:02 +0530
Subject: [Tutor] Problem of finding the first odd number in the list
Message-ID: <CAO1OCwbn-ZBQqDX6PpPCyk73i_HEynHbvXTVk3m6yYJx=fXvLw@mail.gmail.com>

Dear sir ,

Let us consider  a list lst = [2, 4, 7, 9, 0], the first odd number in the
list is 7.
The code i have written for it is given below:
for i in lst:
    if i%2 != 0:
        break
print("First odd number in the list is", i)

Gives the right answer 7

The target variable i will retain the value 7 as it is the value of i when
break statement executes . Is my understanding correct ? the way i have
solved the problem is correct ?

Kindly guide.

Regards
Manprit Singh

From __peter__ at web.de  Fri May  7 02:59:19 2021
From: __peter__ at web.de (Peter Otten)
Date: Fri, 7 May 2021 08:59:19 +0200
Subject: [Tutor] Problem of finding the first odd number in the list
In-Reply-To: <CAO1OCwbn-ZBQqDX6PpPCyk73i_HEynHbvXTVk3m6yYJx=fXvLw@mail.gmail.com>
References: <CAO1OCwbn-ZBQqDX6PpPCyk73i_HEynHbvXTVk3m6yYJx=fXvLw@mail.gmail.com>
Message-ID: <s72og4$mmk$1@ciao.gmane.io>

On 07/05/2021 01:45, Manprit Singh wrote:

> Let us consider  a list lst = [2, 4, 7, 9, 0], the first odd number in the
> list is 7.
> The code i have written for it is given below:
> for i in lst:
>      if i%2 != 0:
>          break
> print("First odd number in the list is", i)
> 
> Gives the right answer 7
> 
> The target variable i will retain the value 7 as it is the value of i when
> break statement executes . Is my understanding correct ? 

Yes.

> the way i have
> solved the problem is correct ?

No.

Hint: What happens if the list doesn't contain any odd numbers? If it 
doesn't contain any elements?


From leamhall at gmail.com  Thu May  6 20:52:36 2021
From: leamhall at gmail.com (Leam Hall)
Date: Thu, 6 May 2021 20:52:36 -0400
Subject: [Tutor] Is there a simpler way to remove from a set?
Message-ID: <e88af42f-60f6-82c7-8c2b-d35971ff9515@gmail.com>

Base code:

###
def build_dir_set(my_list, exclude_dirs):
   my_set  = set()
   for item in my_list:
     path = Path(item)
     parent = str(path.parent)
     my_set.add(parent)
   my_new_set = set()
   for exclude_dir in exclude_dirs:
     for parent in my_set:
       if re.match(exclude_dir, parent):
         my_new_set.add(parent)
   return my_set - my_new_set
###

Where "my_list" and "exclude_dirs" are lists of directories

For example, "my_list" might include:
	/opt/backup/home/me/Desktop/Documents/my_cool_file.txt
	/opt/backup/home/me/lang/git/software/src/cute_image.jpg
	/home/me/lang/git/this/noop.py
	/home/me/lang/git/that/anop.py

And "exclude_dirs" might be"
	/home/me/lang/git

The return should be a set of directories that do not start with any
of the excluded directory names:
	/opt/backup/home/me/Desktop/Documents
	/opt/backup/home/me/lang/git/software/src

I couldn't remove from the set during iteration, python complained. 
Hence having to make a second set. The project is pretty useful for 
those of us who make a lot of backup copies of files. I have 30-50 
copies of some files, and the returned set will be the directories that 
are safe to remove files from. The exclude_dirs are where the 'to keep' 
files will be kept.

If you care to read Perl, I'm converting some old code to Python:

  https://github.com/LeamHall/admin_tools/blob/master/find_copies.pl

Can this be made cleaner?

Thanks!

Leam

-- 
Site Reliability Engineer  (reuel.net/resume)
Scribe: The Domici War     (domiciwar.net)
General Ne'er-do-well      (github.com/LeamHall)

From alan.gauld at yahoo.co.uk  Fri May  7 06:57:19 2021
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Fri, 7 May 2021 11:57:19 +0100
Subject: [Tutor] Is there a simpler way to remove from a set?
In-Reply-To: <e88af42f-60f6-82c7-8c2b-d35971ff9515@gmail.com>
References: <e88af42f-60f6-82c7-8c2b-d35971ff9515@gmail.com>
Message-ID: <s736eg$sc2$1@ciao.gmane.io>

On 07/05/2021 01:52, Leam Hall wrote:

> def build_dir_set(my_list, exclude_dirs):
>    my_set  = set()
>    for item in my_list:
>      path = Path(item)
>      parent = str(path.parent)
>      my_set.add(parent)
>    my_new_set = set()
>    for exclude_dir in exclude_dirs:
>      for parent in my_set:
>        if re.match(exclude_dir, parent):
>          my_new_set.add(parent)
>    return my_set - my_new_set
> ###
> 
> I couldn't remove from the set during iteration, python complained. 

Can you expand on that, show us the code?
It should be possible without building a second set.
But it may be because you are trying to delete something
from the set you are iterating over?

      for parent in my_set:
        if re.match(dir, parent):
          my_new_set.add(parent)

Couldn't this be a set generator?

parent_set = set(parent for parent in my_set if re.match(dir, parent))

Which should be slightly faster...

And couldn't you use  str.startswith() instead of re.match()
Which should also be slightly faster
ie

exclude_set = set()
for dir in exlude_dirs:
   matches = set(parent for parent in parent_set
                        if parent.startswith(dir))
   exclude_set.add(matches)
return parent_set-exclude_set

Which is slightly shorter if nothing else! :-)

-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos



From mats at wichmann.us  Fri May  7 09:57:42 2021
From: mats at wichmann.us (Mats Wichmann)
Date: Fri, 7 May 2021 07:57:42 -0600
Subject: [Tutor] Is there a simpler way to remove from a set?
In-Reply-To: <e88af42f-60f6-82c7-8c2b-d35971ff9515@gmail.com>
References: <e88af42f-60f6-82c7-8c2b-d35971ff9515@gmail.com>
Message-ID: <424b9929-7479-7a3b-36de-f1a9766d79bb@wichmann.us>

On 5/6/21 6:52 PM, Leam Hall wrote:
> Base code:
> 
> ###
> def build_dir_set(my_list, exclude_dirs):
>  ? my_set? = set()
>  ? for item in my_list:
>  ??? path = Path(item)
>  ??? parent = str(path.parent)
>  ??? my_set.add(parent)
>  ? my_new_set = set()
>  ? for exclude_dir in exclude_dirs:
>  ??? for parent in my_set:
>  ????? if re.match(exclude_dir, parent):
>  ??????? my_new_set.add(parent)
>  ? return my_set - my_new_set
> ###
> 
> Where "my_list" and "exclude_dirs" are lists of directories
> 
> For example, "my_list" might include:
>  ????/opt/backup/home/me/Desktop/Documents/my_cool_file.txt
>  ????/opt/backup/home/me/lang/git/software/src/cute_image.jpg
>  ????/home/me/lang/git/this/noop.py
>  ????/home/me/lang/git/that/anop.py
> 
> And "exclude_dirs" might be"
>  ????/home/me/lang/git
> 
> The return should be a set of directories that do not start with any
> of the excluded directory names:
>  ????/opt/backup/home/me/Desktop/Documents
>  ????/opt/backup/home/me/lang/git/software/src
> 
> I couldn't remove from the set during iteration, python complained. 
> Hence having to make a second set.

To take Alan's reply down to an even shorter one:

The "simpler way" is to not add entries that don't qualify, then you 
have nothing to remove.  That requires a slightly different way of 
thinking about your code.

There is, however, nothing wrong in general with using set operations 
like you do to remove unwanted entries from a set.

From __peter__ at web.de  Fri May  7 17:00:19 2021
From: __peter__ at web.de (Peter Otten)
Date: Fri, 7 May 2021 23:00:19 +0200
Subject: [Tutor] Is there a simpler way to remove from a set?
In-Reply-To: <e88af42f-60f6-82c7-8c2b-d35971ff9515@gmail.com>
References: <e88af42f-60f6-82c7-8c2b-d35971ff9515@gmail.com>
Message-ID: <s749ov$ep1$1@ciao.gmane.io>

On 07/05/2021 02:52, Leam Hall wrote:
> Base code:
> 
> ###
> def build_dir_set(my_list, exclude_dirs):
>  ? my_set? = set()
>  ? for item in my_list:
>  ??? path = Path(item)
>  ??? parent = str(path.parent)
>  ??? my_set.add(parent)
>  ? my_new_set = set()
>  ? for exclude_dir in exclude_dirs:
>  ??? for parent in my_set:
>  ????? if re.match(exclude_dir, parent):
>  ??????? my_new_set.add(parent)
>  ? return my_set - my_new_set
> ###
> 
> Where "my_list" and "exclude_dirs" are lists of directories

> Can this be made cleaner?

When I want make things "clean" I usually put the "dirty" parts under 
the rug -- or rather into helper functions. The function above would become

def build_dir_set(children, exclude_dirs):
     parents = (get_parent(child) for child in children)
     return {
         dir for dir in parents if not is_excluded(dir, exclude_dirs)
     }

At this point I might reason about parents -- how likely are duplicate 
parents? If there are many, or is_excluded() is costly I might create a 
set instead of the generator expression before applying the filter, i.e.

     parents = {get_parent(child) for child in children}

Now for the helper functions -- get_parent() is obvious:

def get_parent(path):
     return str(Path(path.parent))

However, the Path object seems superfluous if you want strings:

def get_parent(path):
     return os.path.dirname(path)

OK, that's a single function, so it could be inlined.

Now for is_excluded(): using almost your code:

def is_excluded(dir, exclude_dirs):
     for exclude_dir in exclude_dirs:
         if re.match(exclude_dir, dir):
             return True
     return False

To me it seems clearer because it is just a check and does not itself 
build a set. If you are happy* with the test you can consolidate the 
regex to

def is_excluded(dir, exclude_dirs):
     return re.compile("|".join(exclude_dirs).match(dir)

or, using startswith() as suggested by Alan,

def is_excluded(dir, exclude_dirs):
     assert isinstance(exclude_dirs, tuple), "startswith() wants a tuple"
     return dir.startswith(exclude_dirs)

Again we have a single function in the body that we might inline. The 
final function then becomes

def build_dir_set(children, exclude_dirs):
     exclude_dirs = tuple(exclude_dirs)
     parents = {os.path.basename(child) for child in children}
     return {
         dir for dir in parents if not dir.startswith(exclude_dirs)
     }

(*) I think I would /not/ be happy with startswith -- I'd cook up 
something based on os.path.commonpath() to avoid partial matches of 
directory names; at the moment /foo/bar in exclude_dirs would suppress 
/foo/barbaz from the result set.

Also, I'd like to remind you that paths may contain characters that have 
a special meaning in regular expressions -- if you are using them at 
least apply re.escape() before you feed a path to re.compile().

PS: All code untested.


From leamhall at gmail.com  Fri May  7 08:04:37 2021
From: leamhall at gmail.com (Leam Hall)
Date: Fri, 7 May 2021 08:04:37 -0400
Subject: [Tutor] Is there a simpler way to remove from a set?
In-Reply-To: <s736eg$sc2$1@ciao.gmane.io>
References: <e88af42f-60f6-82c7-8c2b-d35971ff9515@gmail.com>
 <s736eg$sc2$1@ciao.gmane.io>
Message-ID: <d7a2de8e-58a4-e957-bfd4-d25e7c115511@gmail.com>



On 5/7/21 6:57 AM, Alan Gauld via Tutor wrote:
> On 07/05/2021 01:52, Leam Hall wrote:
> 
>> def build_dir_set(my_list, exclude_dirs):
>>     my_set  = set()
>>     for item in my_list:
>>       path = Path(item)
>>       parent = str(path.parent)
>>       my_set.add(parent)
>>     my_new_set = set()
>>     for exclude_dir in exclude_dirs:
>>       for parent in my_set:
>>         if re.match(exclude_dir, parent):
>>           my_new_set.add(parent)
>>     return my_set - my_new_set
>> ###
>>
>> I couldn't remove from the set during iteration, python complained.
> 
> Can you expand on that, show us the code?
> It should be possible without building a second set.
> But it may be because you are trying to delete something
> from the set you are iterating over?
> 
>        for parent in my_set:
>          if re.match(dir, parent):
>            my_new_set.add(parent)
> 
> Couldn't this be a set generator?
> 
> parent_set = set(parent for parent in my_set if re.match(dir, parent))
> 
> Which should be slightly faster...
> 
> And couldn't you use  str.startswith() instead of re.match()
> Which should also be slightly faster
> ie
> 
> exclude_set = set()
> for dir in exlude_dirs:
>     matches = set(parent for parent in parent_set
>                          if parent.startswith(dir))
>     exclude_set.add(matches)
> return parent_set-exclude_set
> 
> Which is slightly shorter if nothing else! :-)
> 

Well, Alan, you did ask!   :)

The process I'm working on is documented:

https://github.com/LeamHall/admin_tools/blob/master/docs/find_copies.txt

I started playing with your suggestions. One big change is pulling the 
logic for getting the parent directory into its own method. That means I 
can use the "full_set - exclude_set" for more than just directories. I 
also added a "match" parameter. When matching files, the match must be 
exact, not just close.

The "seed.list" is made by using a "locate" on a few files. The code 
will eventually go through the seed.list, get the directories, and then 
walk down those directories to add any sub-directories. It will also 
search for files in those directories, and get their size. The 
master_data dict will have keys of file names. Each of those will be a 
dict of file sizes, and each of those will be a set of directories where 
that file name of that file size resides.

When it comes time to use the --purge option, the file names and paths 
will be put back together and the files removed. And I will have a lot 
more space on my hard drives.

The actual, current, full code listing:

###
#!/usr/bin/env python3

# name:       find_copies.py
# version:    0.0.1
# date:       20210506
# desc:       Tool to help clean up old versions of files.

from pathlib import Path

def build_set_from_file(file):
   '''
   Given a file that has been verified to exist, make a set
   from the lines in the file.

   '''
   my_set = set()
   if Path(file).is_file():
     readfile = open(file, 'r')
     for line in readfile.readlines():
       line = line.strip()
       my_set.add(line)
   return my_set

def build_dir_set(dirs):
   '''
   Given a list of full file paths, make a set of the parent directory
     names as strings.
   '''
   dir_set = set()
   for item in dirs:
     path    = Path(item)
     parent  = str(path.parent)
     dir_set.add(parent)
   return dir_set

def build_clean_set(full_set, exclude_list, match = 'full'):
   '''
   Given a set (or list), and a set/list of items to be excluded,
     return a set of the original set/list minus the excluded items.
   Optionally, match the exclusion on the entire string, or the
     beginning. If there's a use for it, then endswith, too.
   '''

   exclude_set = set()
   for exclude in exclude_list:
     for item in full_set:
       if ( ( match == 'starts' and item.startswith(exclude) ) or
           ( match == 'full' and item == exclude ) ):
         exclude_set.add(item)
   return full_set - exclude_set


if __name__ == '__main__':

   master_data = dict()

   # Need to verify if these files exist.
   exclude_files_file  = 'data/exclude_files.list'
   exclude_dirs_file   = 'data/excluded_dirs.list'
   seed_file_file      = 'data/seed.list'

   exclude_files       = build_set_from_file(exclude_files_file)
   exclude_dirs        = build_set_from_file(exclude_dirs_file)
   seed_files          = build_set_from_file(seed_file_file)
   seed_dirs           = build_dir_set(seed_files)
   search_dirs         = build_clean_set(seed_dirs, exclude_dirs, 'starts')

   print("There are {} files in the exclude 
set.".format(len(exclude_files)))
   print("There are {} dirs in the exclude set.".format(len(exclude_dirs)))
   print("There are {} dirs in the seed set.".format(len(seed_dirs)))
   for item in sorted(search_dirs):
     print(item)

###
-- 
Site Reliability Engineer  (reuel.net/resume)
Scribe: The Domici War     (domiciwar.net)
General Ne'er-do-well      (github.com/LeamHall)

From leamhall at gmail.com  Fri May  7 10:25:16 2021
From: leamhall at gmail.com (Leam Hall)
Date: Fri, 7 May 2021 10:25:16 -0400
Subject: [Tutor] Is there a simpler way to remove from a set?
In-Reply-To: <424b9929-7479-7a3b-36de-f1a9766d79bb@wichmann.us>
References: <e88af42f-60f6-82c7-8c2b-d35971ff9515@gmail.com>
 <424b9929-7479-7a3b-36de-f1a9766d79bb@wichmann.us>
Message-ID: <49d60e67-c1fa-4833-ea7e-08cc104b19af@gmail.com>

On 5/7/21 9:57 AM, Mats Wichmann wrote:

> To take Alan's reply down to an even shorter one:
> 
> The "simpler way" is to not add entries that don't qualify, then you 
> have nothing to remove.? That requires a slightly different way of 

> thinking about your code.
> 
> There is, however, nothing wrong in general with using set operations 
> like you do to remove unwanted entries from a set.

Agreed. I was trying to figure out how to iterate through the exclude 
list as the full list was gone through, but couldn't figure out how. 
Still processing it, mentally.

Leam

-- 
Site Reliability Engineer  (reuel.net/resume)
Scribe: The Domici War     (domiciwar.net)
General Ne'er-do-well      (github.com/LeamHall)


From alan.gauld at yahoo.co.uk  Sat May  8 06:19:14 2021
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Sat, 8 May 2021 11:19:14 +0100
Subject: [Tutor] Is there a simpler way to remove from a set?
In-Reply-To: <d7a2de8e-58a4-e957-bfd4-d25e7c115511@gmail.com>
References: <e88af42f-60f6-82c7-8c2b-d35971ff9515@gmail.com>
 <s736eg$sc2$1@ciao.gmane.io> <d7a2de8e-58a4-e957-bfd4-d25e7c115511@gmail.com>
Message-ID: <s75oj3$aom$1@ciao.gmane.io>

On 07/05/2021 13:04, Leam Hall wrote:

Hi Leam,

What I asked for was details of how "Python complained"
when you tried to do it without building 2 sets. It still
seems like you should be able to filter the elements in
a single pass...

However,

> def build_set_from_file(file):
>    my_set = set()
>    if Path(file).is_file():
>      readfile = open(file, 'r')
>      for line in readfile.readlines():

Files are iterable, just use

for line in open(file):

No need for readlines()

>        line = line.strip()
>        my_set.add(line)
>    return my_set

And you could use a generator expression:

if Path(file).is_file():
   return set(line.strip() for line in open(file))


> def build_dir_set(dirs):
>    dir_set = set()
>    for item in dirs:
>      path    = Path(item)
>      parent  = str(path.parent)
>      dir_set.add(parent)
>    return dir_set

Again, you could use a generator expression
but its getting a bit messier here.

return set(str(Path(item).parent()) for item in dirs)


-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos



From PyTutor at DancesWithMice.info  Sat May  8 18:21:36 2021
From: PyTutor at DancesWithMice.info (dn)
Date: Sun, 9 May 2021 10:21:36 +1200
Subject: [Tutor] Is there a simpler way to remove from a set?
In-Reply-To: <d7a2de8e-58a4-e957-bfd4-d25e7c115511@gmail.com>
References: <e88af42f-60f6-82c7-8c2b-d35971ff9515@gmail.com>
 <s736eg$sc2$1@ciao.gmane.io> <d7a2de8e-58a4-e957-bfd4-d25e7c115511@gmail.com>
Message-ID: <d9e2e05e-b5d9-12ff-c1f3-cadd0e810cbd@DancesWithMice.info>

On 08/05/2021 00.04, Leam Hall wrote:
> On 5/7/21 6:57 AM, Alan Gauld via Tutor wrote:
>> On 07/05/2021 01:52, Leam Hall wrote:
>>
>>> def build_dir_set(my_list, exclude_dirs):
>>> ??? my_set? = set()
>>> ??? for item in my_list:
>>> ????? path = Path(item)
>>> ????? parent = str(path.parent)
>>> ????? my_set.add(parent)
>>> ??? my_new_set = set()
>>> ??? for exclude_dir in exclude_dirs:
>>> ????? for parent in my_set:
>>> ??????? if re.match(exclude_dir, parent):
>>> ????????? my_new_set.add(parent)
>>> ??? return my_set - my_new_set

...

>>
>> Couldn't this be a set generator?

This Socratic-question offers solid advice. Please research "generators"
(if haven't already) ...


> The process I'm working on is documented:
> https://github.com/LeamHall/admin_tools/blob/master/docs/find_copies.txt
> 
> I started playing with your suggestions. One big change is pulling the
> logic for getting the parent directory into its own method. That means I
> can use the "full_set - exclude_set" for more than just directories. I
> also added a "match" parameter. When matching files, the match must be
> exact, not just close.
> 
> The "seed.list" is made by using a "locate" on a few files. The code
> will eventually go through the seed.list, get the directories, and then
> walk down those directories to add any sub-directories. It will also
> search for files in those directories, and get their size. The
> master_data dict will have keys of file names. Each of those will be a
> dict of file sizes, and each of those will be a set of directories where
> that file name of that file size resides.
> 
> When it comes time to use the --purge option, the file names and paths
> will be put back together and the files removed. And I will have a lot
> more space on my hard drives.


Are you allowing yourself to be 'railroaded' or 'blinkered' by the spec?

What I mean by this, is that the specifications have been written in a
particular way, with the idea of presenting the coder with as clear a
picture as possible - covering 'all the bases' in a step-by-step,
topic-by-topic fashion.

However, the spec does not set out to be, and should not, be seen as a
'map' of code-structure - nor as some sort of top-level description of
the solution-code. That is not to say that it shouldn't be included
in/with the code, but that once the coder has understood the problem to
be solved, the spec becomes a template for acceptance testing rather
than code-writing!

If my quick scan (mea culpa!) is correct, the required action comes down
to "purge unwanted files?directories". NB the word "purge" should be
understood as wider than a simple 'del filename', including logging, etc.

In the ?good, old, days our training was to start with the "output", use
that to map the "process", and finally to work backwards to the "input"
required to achieve the objective. NB it's not so 'true' these days with
real-time, screen interactions, etc; but it will work well in the design
this application.

So, (at the risk of sounding like kindergarten) the first code to write
is (if following TDD, is a test to verify) Python code which given a
filename, deletes same from the file-system/device. QED!

Now (working backwards) the question becomes, before purging, 'which
filename(s) should be purged?'.

Let me restate this as pseudo-code:

    give me the next filename (to be purged)
    purge filename

Here's where generators come into their own. Instead of producing sets
(or any Python collection) and then refining same, before
working-through the actual function(s) of the program; a generator will
respond with the next 'subject', until there are no more - and then
tidily concludes any looping mechanism.

At some stage we can add reporting. Does this require an extra piece of
data? Remember that generators can "yield" a data-structure not merely a
single value, eg the ComSc example of Fibonacci Numbers. Thus a "switch"
which can be used to inform the reporting, alongside the filename. In
this manner we can amend the above pseudo-code to:

    give me the next filename and switch
    log filename (labelled according to switch)
    purge filename according to switch

NB you may prefer to 'act' first, and 'log' second.

Jumping ahead a few steps, notice that the PSL's directory-traversal
facilities all are/have the appearance of a generator - giving you one
directory or file per loop!

The 'mainline' has become quite "clean" (and thus 'readable'), and the
'dirty details' can indeed be "put under the rug" of well-named
functions, each performing a unit of work, and contributing to the
generator's results...

YMMV!
-- 
-- 
Regards,
=dn

From leamhall at gmail.com  Sat May  8 19:48:56 2021
From: leamhall at gmail.com (Leam Hall)
Date: Sat, 8 May 2021 19:48:56 -0400
Subject: [Tutor] Is there a simpler way to remove from a set?
In-Reply-To: <d9e2e05e-b5d9-12ff-c1f3-cadd0e810cbd@DancesWithMice.info>
References: <e88af42f-60f6-82c7-8c2b-d35971ff9515@gmail.com>
 <s736eg$sc2$1@ciao.gmane.io> <d7a2de8e-58a4-e957-bfd4-d25e7c115511@gmail.com>
 <d9e2e05e-b5d9-12ff-c1f3-cadd0e810cbd@DancesWithMice.info>
Message-ID: <cabe790e-3bc9-d6f1-157d-9f4d88e1079d@gmail.com>

On 5/8/21 6:21 PM, dn via Tutor wrote lots of good questions, to include:

> Are you allowing yourself to be 'railroaded' or 'blinkered' by the spec?

Lots to think about! The good news is that I'm the one coming up with 
the requirement, so the issues are relevant. The bad news is that I'm 
the one coming up with the requirement, so the processes are limited to 
my understanding.

The 'purge' option is desired, but is the second priority. The origin of 
the issue comes from my printer not liking Linux, it can't print a plain 
text document. I got into the habit of writing docx files in Libre/Open 
Office, and making backup copies. And archive copies. And backups of the 
archives...

A few months ago I admitted there was an issue. The solution is to 
convert everything to text and put it into version control. The first 
priority of the program is to find all copies of files in the given 
directories, and sort them into two lists; "only one version of this 
file" and "more than one version of this file". The file size is the 
definition of "different version".

With those lists I can convert the single version files into text and 
put them into version control. Then I figure out which of the "multiple 
versions" is the right version, convert that and then stuff it into 
version control. This process is manual, which is why the "purge" comes 
afterwards. I can get the two lists, make sure everything is in version 
control, and they purge afterwards.

The (old version) code walks down the given directories; it uses a queue 
to track which directories have not been checked for files. Does that 
make sense?


On 5/8/21 6:19 AM, Alan Gauld via Tutor wrote:
 > What I asked for was details of how "Python complained"
 > when you tried to do it without building 2 sets.

My apologies for the misunderstanding! When I saw your request for the 
code, I took it to mean my code, not the error code.

I've already edited that bit out, but it seemed that the set got upset 
if the number of items in the set changed during iteration. I couldn't 
remember how to break out of two levels of iteration:

   for dir in dirs:
     for exclude_dir in exclude_dirs:
       if dir.startswith(exclude_dir):
         # Remove it and go to the next 'for dir in dirs'
         # At this point it complained about dirs changing, IIRC.

The combination of not knowing how to break out of multiple levels, and 
the iterator not liking the changes of life, led me to the use of two sets.

Leam

-- 
Site Reliability Engineer  (reuel.net/resume)
Scribe: The Domici War     (domiciwar.net)
General Ne'er-do-well      (github.com/LeamHall)

From alan.gauld at yahoo.co.uk  Sun May  9 12:46:26 2021
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Sun, 9 May 2021 17:46:26 +0100
Subject: [Tutor] Is there a simpler way to remove from a set?
In-Reply-To: <cabe790e-3bc9-d6f1-157d-9f4d88e1079d@gmail.com>
References: <e88af42f-60f6-82c7-8c2b-d35971ff9515@gmail.com>
 <s736eg$sc2$1@ciao.gmane.io> <d7a2de8e-58a4-e957-bfd4-d25e7c115511@gmail.com>
 <d9e2e05e-b5d9-12ff-c1f3-cadd0e810cbd@DancesWithMice.info>
 <cabe790e-3bc9-d6f1-157d-9f4d88e1079d@gmail.com>
Message-ID: <s793l2$2a6$1@ciao.gmane.io>

On 09/05/2021 00:48, Leam Hall wrote:

> I've already edited that bit out, but it seemed that the set got upset 
> if the number of items in the set changed during iteration. I couldn't 
> remember how to break out of two levels of iteration:
> 
>    for dir in dirs:
>      for exclude_dir in exclude_dirs:
>        if dir.startswith(exclude_dir):
>          # Remove it and go to the next 'for dir in dirs'
>          # At this point it complained about dirs changing, IIRC.

           break

Should be enough. it breaks out of the immediate loop,
so in this case will go up to the top level loop.

Quick check:

>>> for i in [1,2,3]:
	print('outer',i)
	for j in [5,6,7]:
		print('inner',j)
		break

	
outer 1
inner 5
outer 2
inner 5
outer 3
inner 5
>>>

Seems to work.

-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos



From edwinconnell at gmail.com  Mon May 10 14:59:08 2021
From: edwinconnell at gmail.com (Ed Connell)
Date: Mon, 10 May 2021 13:59:08 -0500
Subject: [Tutor] list generation
Message-ID: <CADmpvFGkHkKD9r-34KvYj7h_WDWeeD5DeV_df-+4jNDNwBYG-A@mail.gmail.com>

What is the best way to create a list of constant values of a given length?

gen_list( 78, 4 ) should generate [ 78, 78, 78, 78  ].

and

gen_list( 'pop', 2 ) should produce [ 'pop', 'pop' ]

Thanks,

Ed
-- 
I have a right and a left brain, but there is nothing right in the left one
and there is nothing left in the right one!

From david at lowryduda.com  Mon May 10 17:01:27 2021
From: david at lowryduda.com (David Lowry-Duda)
Date: Mon, 10 May 2021 17:01:27 -0400
Subject: [Tutor] list generation
In-Reply-To: <CADmpvFGkHkKD9r-34KvYj7h_WDWeeD5DeV_df-+4jNDNwBYG-A@mail.gmail.com>
References: <CADmpvFGkHkKD9r-34KvYj7h_WDWeeD5DeV_df-+4jNDNwBYG-A@mail.gmail.com>
Message-ID: <YJmfJx/5wAhDkfTs@icerm-dld>

On Mon, May 10, 2021 at 01:59:08PM -0500, Ed Connell wrote:
> What is the best way to create a list of constant values of a given length?
> 
> gen_list( 78, 4 ) should generate [ 78, 78, 78, 78  ].
> 
> and
> 
> gen_list( 'pop', 2 ) should produce [ 'pop', 'pop' ]

It's not obvious to me what "best" means here, but something like

    def gen_list(val, num):
        return [val]*num

seems to get pretty far.

This sounds to me like a secondary problem, sought to solve some main 
problem. It might be a good idea to go ahead and specify the main 
problem too, if there is one.

- DLD

From mats at wichmann.us  Mon May 10 17:02:42 2021
From: mats at wichmann.us (Mats Wichmann)
Date: Mon, 10 May 2021 15:02:42 -0600
Subject: [Tutor] list generation
In-Reply-To: <CADmpvFGkHkKD9r-34KvYj7h_WDWeeD5DeV_df-+4jNDNwBYG-A@mail.gmail.com>
References: <CADmpvFGkHkKD9r-34KvYj7h_WDWeeD5DeV_df-+4jNDNwBYG-A@mail.gmail.com>
Message-ID: <426103be-b420-1239-6d8d-592e848d89ff@wichmann.us>

On 5/10/21 12:59 PM, Ed Connell wrote:
> What is the best way to create a list of constant values of a given length?
> 
> gen_list( 78, 4 ) should generate [ 78, 78, 78, 78  ].
> 
> and
> 
> gen_list( 'pop', 2 ) should produce [ 'pop', 'pop' ]
> 
> Thanks,
> 
> Ed
> 

without claiming "best", the * operator works...

x = [78] * 4


From breamoreboy at gmail.com  Mon May 10 16:53:16 2021
From: breamoreboy at gmail.com (Mark Lawrence)
Date: Mon, 10 May 2021 21:53:16 +0100
Subject: [Tutor] list generation
In-Reply-To: <CADmpvFGkHkKD9r-34KvYj7h_WDWeeD5DeV_df-+4jNDNwBYG-A@mail.gmail.com>
References: <CADmpvFGkHkKD9r-34KvYj7h_WDWeeD5DeV_df-+4jNDNwBYG-A@mail.gmail.com>
Message-ID: <f26e71a0-b102-e2e6-8de3-3c2d74c66d64@gmail.com>

On 10/05/2021 19:59, Ed Connell wrote:
> What is the best way to create a list of constant values of a given length?
> 
> gen_list( 78, 4 ) should generate [ 78, 78, 78, 78  ].
> 
> and
> 
> gen_list( 'pop', 2 ) should produce [ 'pop', 'pop' ]
> 
> Thanks,
> 
> Ed
> 

https://docs.python.org/3/library/itertools.html#itertools.repeat

My personal opinion is that if you don't reach for the itertools module 
fairly often you're not really writing python :)

-- 
My fellow Pythonistas, ask not what our language can do for you, ask
what you can do for our language.

Mark Lawrence


From alan.gauld at yahoo.co.uk  Mon May 10 17:15:06 2021
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Mon, 10 May 2021 22:15:06 +0100
Subject: [Tutor] list generation
In-Reply-To: <CADmpvFGkHkKD9r-34KvYj7h_WDWeeD5DeV_df-+4jNDNwBYG-A@mail.gmail.com>
References: <CADmpvFGkHkKD9r-34KvYj7h_WDWeeD5DeV_df-+4jNDNwBYG-A@mail.gmail.com>
Message-ID: <s7c7ov$10qq$1@ciao.gmane.io>

On 10/05/2021 19:59, Ed Connell wrote:
> What is the best way to create a list of constant values of a given length?
> 
> gen_list( 78, 4 ) should generate [ 78, 78, 78, 78  ].
> 
> and
> 
> gen_list( 'pop', 2 ) should produce [ 'pop', 'pop' ]


If it is simple literal values as shown then the multiplication operator
works.

multi = [val] * number

But be aware that it produces a list with multiple references to
the same object so, if the object is more complex, specifically
if it is mutable(list, dictionary,set,instance), then changing
one element will change the others too.

problem = [[1]] * 3   #->[[1],[1],[1]]
problem[0].append(2)  #->[[1,2],[1,2],[1,2]]  !!

In that case a list comprehension is preferred:

no_prob = [[1] for n in range(3)]
no_prob[0].append(2)   #->[[1,2],[1],[1]]

HTH
-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos



From lijin.abc at gmail.com  Mon May 10 22:36:15 2021
From: lijin.abc at gmail.com (Jin Li)
Date: Mon, 10 May 2021 21:36:15 -0500
Subject: [Tutor] What is the python idiom to transfer Bash arrays to Python
 lists?
Message-ID: <CABP_fjociaB+JXsEEkiLE7jkYcYgdTam93VMJ3F+CMjx=0QxDQ@mail.gmail.com>

Hi,

I want to transfer Bash arrays into Python lists so that they can be
used in the python script. For example,

```Bash
arr1=(1 2 3)
arr2=(a b c)
# run main.py, and assign arr1 and arr2 to python list variables
```

What is the python idiom to do this? Thank you.

Best regards,
Jin

From alan.gauld at yahoo.co.uk  Tue May 11 04:05:04 2021
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Tue, 11 May 2021 09:05:04 +0100
Subject: [Tutor] What is the python idiom to transfer Bash arrays to
 Python lists?
In-Reply-To: <CABP_fjociaB+JXsEEkiLE7jkYcYgdTam93VMJ3F+CMjx=0QxDQ@mail.gmail.com>
References: <CABP_fjociaB+JXsEEkiLE7jkYcYgdTam93VMJ3F+CMjx=0QxDQ@mail.gmail.com>
Message-ID: <s7ddrg$g1q$1@ciao.gmane.io>

On 11/05/2021 03:36, Jin Li wrote:
> Hi,
> 
> I want to transfer Bash arrays into Python lists so that they can be
> used in the python script. For example,
> 
> ```Bash
> arr1=(1 2 3)
> arr2=(a b c)
> # run main.py, and assign arr1 and arr2 to python list variables
> ```
> 
> What is the python idiom to do this? Thank you.

There isn't really an idiom for doing this as its not a common
requirement. There are two possibilities that spring to mind:

1) assign the arrays to environment variables and
use os.getenv() from python
2) pass the arrays as command line arguments to
main.py and read them with sys.argv.

In both cases they will come to python as strings that
you will need to convert to lists using split() plus
whatever type conversions are necessary.
Here is an example:

############ testarr.sh ###
#! /bin/bash

a=(1,2,3)
echo "a is " $a

python testarr.py $a

echo "done"

########## testarr.py #####
import sys

L = [int(s) for s in sys.argv[-1].split(',')]

print('L=',L)
#############################

Which produces:
a is  1,2,3
L= [1, 2, 3]
done

HTH
-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos



From learn2program at gmail.com  Tue May 11 04:47:17 2021
From: learn2program at gmail.com (Alan Gauld)
Date: Tue, 11 May 2021 09:47:17 +0100
Subject: [Tutor] list generation
In-Reply-To: <CADmpvFH3W=ZXstvXK18ygr5bT8n7V8RdUsgBjvAUOFaQ9mNtng@mail.gmail.com>
References: <CADmpvFGkHkKD9r-34KvYj7h_WDWeeD5DeV_df-+4jNDNwBYG-A@mail.gmail.com>
 <s7c7ov$10qq$1@ciao.gmane.io>
 <CADmpvFH3W=ZXstvXK18ygr5bT8n7V8RdUsgBjvAUOFaQ9mNtng@mail.gmail.com>
Message-ID: <d69d4684-e219-e5f8-1be4-6039ea7ae5f8@yahoo.co.uk>


On 11/05/2021 01:12, Ed Connell wrote:
> Thanks for your help. (All)
>
> I was working with? 'map' and the function that it was mapping needed
> 2 arguments.? The first was a list of values.? The second was always
> the same - like 2.? Thus I needed a list of 2s or whatever at least as
> long as the first list.? (Like [ 2, 2, ...2 ])? Of course I could use
> a simple loop.? Then I hit on [ 2 for _ in range( length ) .? But I
> like yours best - [ 2 ] * length.? Thanks again.

The usual way I'd solve that is to use a lambda expression:

result = map(lambda x: foo(x,2), collection)

Which will call the lamba with x from collection.

Then the lambda calls foo() with x as the first and 2 as the second
argument.


-- 

Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos


From mmssdd1920 at gmail.com  Tue May 11 07:11:50 2021
From: mmssdd1920 at gmail.com (Msd De)
Date: Tue, 11 May 2021 16:41:50 +0530
Subject: [Tutor] nested integral
Message-ID: <CAOacnX=raKzzhpSbyjf-+8nAdmAs5B2DAEQae=7=Azfd8JWR2A@mail.gmail.com>

NameError: name 'fixed_quad' is not defined

I am currently writing a program that involves nested integrals.
Every source that I have seen to do this either involves lambda or creating
a definition that outputs an equation.
So, my question is, is there any way to integrate it without doing that?
Here's part of my code:

LB=0.0
UB=etatip
K001_Intg=[None]*64;K0d1_Intg=[None]*64;Kd01_Intg=[None]*64;Kdd1_Intg=[None]*64
def kfac_11(eta, Ex):  #variable is eta
distGen=array_defl[i]
sumK00=0.0;sumK0d=0.0;sumKd0=0.0;sumKdd=0.0
for j in range(64): #column for eta values
xp=array_xefl[int(j),int(i)]
global ak1
global ak2
ak1 = numpy.sqrt(2*FCON*Ex)
ak2 = numpy.sqrt(2*FCON*(Ex-deltaprime))
a=2*FCON*abs(EL-Ex)
b = 2*FCON*abs(ER - EL)/distGen
#print ak1,ak2,FCON,EL,a,b
aminbd =2*FCON*abs(ER - Ex)
X10=(TWOTHRD/b)*a**ONEHALF
X1d=(TWOTHRD/b)*(aminbd)**ONEHALF
#print aminbd,X10,X1d
BIX10=iv(N,X10)
BIX1d=iv(N,X1d)
BKX10=kv(N,X10)
BKX1d=kv(N,X1d)
#print BIX10,BIX1d,BKX10,BKX1d
BIpX10=0.5*((iv(N1,X10))+(iv(N2,X10)))
BIpX1d=0.5*((iv(N1,X1d))+(iv(N2,X1d)))
BKpX10= - 0.5*((kv(N1,X10))+(kv(N2,X10)))
BKpX1d= - 0.5*((kv(N1,X1d))+(kv(N2,X1d)))
KIthrdX10X1d=BKX10*BIX1d- BKX10*BIX1d
KIthrdX1dX10=BKX1d*BIX10- BKX1d*BIX10
IKX10X1d=BIX10*BKX1d- BIX1d*BKX10
KIX10X1d=-IKX10X1d
KIX1dX10=BKX1d*BIX10- BKX10*BIX1d
detGama=ONEHALF**TWOTHRD/((X10*X1d)**THRD*IKX10X1d)
W=-ONEHALF*b**THRD/detGama
X1ofxp=(TWOTHRD/b )*(a-b*xp)**ONEHALF
BKX1ofxp=kv(N,X1ofxp)
BIX1ofxp=iv(N,X1ofxp)
KIthrdX1X10=BKX1ofxp*BIX10 - BKX10*BIX1ofxp
KIthrdX1dX1=BKX1d*BIX1ofxp - BKX1ofxp*BIX1d
F0_xp=KIthrdX1X10*(ONEHALF*X1ofxp)**TWOTHRD/detGama
Fd_xp=KIthrdX1dX1*(ONEHALF*X1ofxp)**TWOTHRD/detGama

f_xp=FCON*(phi1-phi2+evb)*(-1.0+xp/distGen+np.log((1+eta)/(1-eta))/np.log((1+etatip)/(1.0-etatip)))
#eta
etaTerm=(d/etatip)*(np.sqrt((ximat[j]**2-eta**2)/(1-eta**2)))
K001_Intg=F0_xp*Fd_xp*f_xp*etaTerm/W
K0d1_Intg=Kdd_0*F0_xp**2*f_xp*etaTerm/W
Kd01_Intg=K00_0*Fd_xp**2*f_xp*etaTerm/W
Kdd1_Intg=F0_xp*Fd_xp*f_xp*etaTerm/W

arr_KFact=[]
sumK00=0.0;sumK0d=0.0;sumKd0=0.0;sumKdd=0.0
K00_F=integrate.fixed_quad(K001_Intg, LB, UB, n=64)
K0d_F=integrate.fixed_quad(K0d1_Intg, LB, UB, n=64)
Kd0_F=integrate.fixed_quad(Kd01_Intg, LB, UB, n=64)
Kdd_F=integrate.fixed_quad(Kdd1_Intg, LB, UB, n=64)
sumK00=sumK00+K00_F
sumK0d=sumK0d+K0d_F
sumKd0=sumKd0+Kd0_F
sumKdd=sumKdd+Kdd_F

K00intg=sumK00
K0dintg=sumK0d
Kd0intg=sumKd0
Kddintg=sumKdd

K00_1=K00_0*(1+K00intg)
K0d_1=K0d_0+K0dintg
Kd0_1=Kd0_0+Kd0intg
Kdd_1=Kdd_0*(1.0+Kddintg)
# print K00_1,K0d_1,Kd0_1,Kdd_1

TP_1 =
abs(2.0*1j*ak1*Kdd_1/((1j*ak2-K0d_1)*(1j*ak1+Kd0_1)+K00_1*Kdd_1))**2.0
DEx_11=(ak2/ak1)*TP_1
return DEx_11

def DEx11(Ex):  # 64 values of array_defl
distGen=array_defl[i]
return fixed_quad(kfac_11, LB, UB, n=64, args=(Ex))

JRuss11={}
ELOW11Russ=EMIN
EHIGH11Russ=ESTG1
array_JRuss11=np.zeros(64)
for i in range(64): #64 values of dfl(xi)
JRuss11[i]=fixed_quad(lambda Ex: DEx11(Ex),ELOW11Russ, EHIGH11Russ, n=64)
# JRuss11[k]=integrate.fixed_quad(DEx11, ELOW11Russ, EHIGH11Russ, n=64)
array_JRuss11[int(i)]=(JRuss11[i][0])

From alan.gauld at yahoo.co.uk  Tue May 11 08:38:01 2021
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Tue, 11 May 2021 13:38:01 +0100
Subject: [Tutor] nested integral
In-Reply-To: <CAOacnX=raKzzhpSbyjf-+8nAdmAs5B2DAEQae=7=Azfd8JWR2A@mail.gmail.com>
References: <CAOacnX=raKzzhpSbyjf-+8nAdmAs5B2DAEQae=7=Azfd8JWR2A@mail.gmail.com>
Message-ID: <s7dtr9$1il$1@ciao.gmane.io>

On 11/05/2021 12:11, Msd De wrote:
> NameError: name 'fixed_quad' is not defined

Always post the full error message, it contains a lot
of useful data.

> I am currently writing a program that involves nested integrals.
> Every source that I have seen to do this either involves lambda or creating
> a definition that outputs an equation.
> So, my question is, is there any way to integrate it without doing that?

My question is: why would you want to?
That's like asking if it's possible to square a number without using
multiplication (yes, via repeated addition - but why?!) If the option
is there for a simpler solution then why not use it?

> Here's part of my code:

Please always post to the list using plain text. Otherwise
the mail system strips out spacing and your code becomes
virtually impossible to read/debug.

> 
> 
> def DEx11(Ex):  # 64 values of array_defl
> distGen=array_defl[i]
> return fixed_quad(kfac_11, LB, UB, n=64, args=(Ex))

This looks like the source of your error. You forgot to
prefix it with the module name.

Compare with:

> # JRuss11[k]=integrate.fixed_quad(DEx11, ELOW11Russ, EHIGH11Russ, n=64)

-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos



From __peter__ at web.de  Tue May 11 10:15:06 2021
From: __peter__ at web.de (Peter Otten)
Date: Tue, 11 May 2021 16:15:06 +0200
Subject: [Tutor] list generation
In-Reply-To: <d69d4684-e219-e5f8-1be4-6039ea7ae5f8@yahoo.co.uk>
References: <CADmpvFGkHkKD9r-34KvYj7h_WDWeeD5DeV_df-+4jNDNwBYG-A@mail.gmail.com>
 <s7c7ov$10qq$1@ciao.gmane.io>
 <CADmpvFH3W=ZXstvXK18ygr5bT8n7V8RdUsgBjvAUOFaQ9mNtng@mail.gmail.com>
 <d69d4684-e219-e5f8-1be4-6039ea7ae5f8@yahoo.co.uk>
Message-ID: <s7e3ha$k11$1@ciao.gmane.io>

On 11/05/2021 10:47, Alan Gauld wrote:
> 
> On 11/05/2021 01:12, Ed Connell wrote:
>> Thanks for your help. (All)
>>
>> I was working with? 'map' and the function that it was mapping needed
>> 2 arguments.? The first was a list of values.? The second was always
>> the same - like 2.? Thus I needed a list of 2s or whatever at least as
>> long as the first list.? (Like [ 2, 2, ...2 ])? Of course I could use
>> a simple loop.? Then I hit on [ 2 for _ in range( length ) .? But I
>> like yours best - [ 2 ] * length.? Thanks again.
> 
> The usual way I'd solve that is to use a lambda expression:
> 
> result = map(lambda x: foo(x,2), collection)

For completeness I'd like to mention what has become the most common way 
to spell this in Python:

result = [foo(x, 2) for x in collection]

> Which will call the lamba with x from collection.
> 
> Then the lambda calls foo() with x as the first and 2 as the second
> argument.




From alan.gauld at yahoo.co.uk  Tue May 11 11:25:02 2021
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Tue, 11 May 2021 16:25:02 +0100
Subject: [Tutor] list generation
In-Reply-To: <s7e3ha$k11$1@ciao.gmane.io>
References: <CADmpvFGkHkKD9r-34KvYj7h_WDWeeD5DeV_df-+4jNDNwBYG-A@mail.gmail.com>
 <s7c7ov$10qq$1@ciao.gmane.io>
 <CADmpvFH3W=ZXstvXK18ygr5bT8n7V8RdUsgBjvAUOFaQ9mNtng@mail.gmail.com>
 <d69d4684-e219-e5f8-1be4-6039ea7ae5f8@yahoo.co.uk>
 <s7e3ha$k11$1@ciao.gmane.io>
Message-ID: <s7e7ke$n76$1@ciao.gmane.io>

On 11/05/2021 15:15, Peter Otten wrote:

> For completeness I'd like to mention what has become the most common way 
> to spell this in Python:
> 
> result = [foo(x, 2) for x in collection]

Good catch, I meant to mention comprehensions as an alternative
to map() but forgot.

-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos



From mmssdd1920 at gmail.com  Wed May 12 01:27:47 2021
From: mmssdd1920 at gmail.com (Msd De)
Date: Wed, 12 May 2021 10:57:47 +0530
Subject: [Tutor] Double integration in Python
Message-ID: <CAOacnXnLZZEj1ARE2c+Xkgf_4YbO12bFQSQf08YY8_FL_j36Fw@mail.gmail.com>

I have equations which involve double integration.

g is a function of Ex and y. D is a function of K00_1 which is a function
of Ex

The bounds for y (LB,UB) and the bounds for Ex(Exmin, Exmax) which are
predetermined.

The equations are:


K?00_1 = K00_0 + ? g( Ex , y) dy

Integrand = ? D(K00_1(Ex) dEx


How to implement this double integration in python.

Thanks in advance.

Msd de

From leamhall at gmail.com  Wed May 12 07:07:39 2021
From: leamhall at gmail.com (Leam Hall)
Date: Wed, 12 May 2021 07:07:39 -0400
Subject: [Tutor] Is there a simpler way to remove from a set?
In-Reply-To: <s736eg$sc2$1@ciao.gmane.io>
References: <e88af42f-60f6-82c7-8c2b-d35971ff9515@gmail.com>
 <s736eg$sc2$1@ciao.gmane.io>
Message-ID: <f527cbab-8942-cbb5-fe1b-bc91fabd5a87@gmail.com>

On 5/7/21 6:57 AM, Alan Gauld via Tutor wrote:

> Couldn't this be a set generator?

It has been a mind-numbing few days, and I'm thankfully back to this. 
Oddly enough, I picked up where I left off in the Python book I'm 
reading ("Python 3 Object-Oriented Programming", Phillips) and the next 
section was on generators.

I think this will give me what I'm looking for in a cleaner way. Off to 
try it out!

Leam

-- 
Site Reliability Engineer  (reuel.net/resume)
Scribe: The Domici War     (domiciwar.net)
General Ne'er-do-well      (github.com/LeamHall)

From pmazek at otwock.pl  Wed May 12 08:46:20 2021
From: pmazek at otwock.pl (Piotr Mazek)
Date: Wed, 12 May 2021 14:46:20 +0200
Subject: [Tutor] Looking for help in sqlite3 UPDATE and DELETE selection in
 treeview (ttk tkinter)
Message-ID: <01fc01d7472c$cf26ab30$6d740190$@otwock.pl>

Welcome Tutor,

 

I am just a hobbyist, but with need to know more especially in programming
in Python.

I'm writing application to manage sqlite3 database in window made in tkinter
with treeview.

Successfully wrote two functions: to show database, and to add new row.

But stuck on Update and delete selection. I think there are some stupid
mistakes, but can't see them.

 

Here is part of my code:

 

    def updateRecord():

 

        def updateR():

            conn = sqlite3.connect('db_member.db')

            c = conn.cursor()

 

            # INSERT into table

# I wish to get values from selection and place them in corresponding Entry
fields, then change some value and save new state

            c.execute("UPDATE `member` SET (:mem_id, :firstname, :lastname,
:address)"))

            conn.commit()

            conn.close()

            updateRoot.destroy()

 

        updateRoot = Toplevel()

            

        updateRoot.title("Update record")

        updateRoot.iconbitmap('printer.ico')

        

        lbl_fname = Label(updateRoot, text="First Name")

        lbl_fname.grid(row=0, column=0, pady=10)

        lbl_lname = Label(updateRoot, text="Last Name")

        lbl_lname.grid(row=1, column=0, pady=10)

        lbl_addr = Label(updateRoot, text="Address")

        lbl_addr.grid(row=2, column=0, pady=10)

 

        en_fname = Entry(updateRoot)

        en_fname.grid(row=0, column=1, padx=10)

        en_lname = Entry(updateRoot)

        en_lname.grid(row=1, column=1, padx=10)

        en_addr = Entry(updateRoot)

        en_addr.grid(row=2, column=1, padx=10)

 

        btn = Button(updateRoot, text="Update", command=updateR)

        btn.grid(row=3, column=1, columnspan=2, sticky='we', padx=20)

 

        updateRoot.mainloop()

 

    def deleteRecord():

 

        conn = sqlite3.connect('db_member.db')

        c = conn.cursor()

 

        # DELETE from table

# two lines above deletes from treeview only but not from database file

        userid = tree.selection()[0]

        tree.delete(userid)

# here I have no idea how to delete selected row from database

        c.execute("DELETE FROM `member` WHERE mem_id = ?", (userid))

        

        conn.commit()

        conn.close()

 

 

 

Can you please tell me how to solve my problem?

 

Best regards,

Diego


From alan.gauld at yahoo.co.uk  Wed May 12 19:19:17 2021
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Thu, 13 May 2021 00:19:17 +0100
Subject: [Tutor] Looking for help in sqlite3 UPDATE and DELETE selection
 in treeview (ttk tkinter)
In-Reply-To: <01fc01d7472c$cf26ab30$6d740190$@otwock.pl>
References: <01fc01d7472c$cf26ab30$6d740190$@otwock.pl>
Message-ID: <s7hnpm$3l5$1@ciao.gmane.io>

On 12/05/2021 13:46, Piotr Mazek wrote:

> I'm writing application to manage sqlite3 database in window made in tkinter
> with treeview.
> 
> Successfully wrote two functions: to show database, and to add new row.

Well done, the rest should be straightforward.

> But stuck on Update and delete selection. I think there are some stupid
> mistakes, but can't see them.

There are a few odd things in your code. See comments below...

>     def updateRecord():
> 
>         def updateR():
>             conn = sqlite3.connect('db_member.db')
>             c = conn.cursor()
>             # INSERT into table
> # I wish to get values from selection and place them in corresponding Entry
> fields, then change some value and save new state
> 
>             c.execute("UPDATE `member` SET (:mem_id, :firstname, :lastname,
> :address)"))

First point:
This will UPDATE every row in the table. If you only want to
modify a single row you need a WHERE clause to specify
the row(or rows) affected.

Second:
I've never seen the :mem_id syntax before. I assume it substitutes the
local variable name somehow? But I can't find any documentation of that
style?

Normally I'd expect an update statement to look like:

update = """
UPDATE or ROLLBACK member
SET
mem_id=?
firstname=?
lastname=?
address=?
WHERE mem_id = ?
"""

cur.execute(update,(mem_id, firstname, lastname, address, mem_id))

>             conn.commit()
>             conn.close()
> 
>             updateRoot.destroy()

>         updateRoot = Toplevel()
>         updateRoot.title("Update record")
>         updateRoot.iconbitmap('printer.ico')
>         lbl_fname = Label(updateRoot, text="First Name")
>         lbl_fname.grid(row=0, column=0, pady=10)
>         lbl_lname = Label(updateRoot, text="Last Name")
>         lbl_lname.grid(row=1, column=0, pady=10)
>         lbl_addr = Label(updateRoot, text="Address")
>         lbl_addr.grid(row=2, column=0, pady=10)
>         en_fname = Entry(updateRoot)
>         en_fname.grid(row=0, column=1, padx=10)
>         en_lname = Entry(updateRoot)
>         en_lname.grid(row=1, column=1, padx=10)
>         en_addr = Entry(updateRoot)
>         en_addr.grid(row=2, column=1, padx=10)
>         btn = Button(updateRoot, text="Update", command=updateR)
>         btn.grid(row=3, column=1, columnspan=2, sticky='we', padx=20)
> 
>         updateRoot.mainloop()

I may be wrong but I don't think you need to call mainloop()
here, the parent mainloop() will see the events for your
TopLevel too. I think...

>     def deleteRecord():
>         conn = sqlite3.connect('db_member.db')
>         c = conn.cursor()
> 
>         # DELETE from table
>         userid = tree.selection()[0]
>         tree.delete(userid)
> 
> # here I have no idea how to delete selected row from database
> 
>         c.execute("DELETE FROM `member` WHERE mem_id = ?", (userid))

You need to pass the arguments as a tuple, simply putting parens around
is not enough, you need a comma after the userid, its the comma that
makes it a tuple.

Also, I notice that you are putting the table name in quotes. That
should not be necessary (and may be an error?) since the entire SQL
statement is already in quotes. I certainly never quote table names
in my SQL. That may be part of the source of  the problem?


>         conn.commit()
>         conn.close()
Finally, I notice you are not detecting errors. You should really
use a try/except to catch database error exceptions and take
action (eg Rollback). You can re-raise them during debugging
if you want to see the stack-trace.

Of course you may have simplified the code for clarity in which
case just ignore me! :-)

-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos



From leamhall at gmail.com  Thu May 13 20:24:09 2021
From: leamhall at gmail.com (Leam Hall)
Date: Thu, 13 May 2021 20:24:09 -0400
Subject: [Tutor] Is there a simpler way to remove from a set?
In-Reply-To: <s793l2$2a6$1@ciao.gmane.io>
References: <e88af42f-60f6-82c7-8c2b-d35971ff9515@gmail.com>
 <s736eg$sc2$1@ciao.gmane.io> <d7a2de8e-58a4-e957-bfd4-d25e7c115511@gmail.com>
 <d9e2e05e-b5d9-12ff-c1f3-cadd0e810cbd@DancesWithMice.info>
 <cabe790e-3bc9-d6f1-157d-9f4d88e1079d@gmail.com> <s793l2$2a6$1@ciao.gmane.io>
Message-ID: <1906732c-5f33-a464-6a59-8aec2af422f8@gmail.com>

I appreciate all the feedback and ideas on this, you helped me learn. Here's
what I've worked it down to, so far.

###
#!/usr/bin/env python3

full_list = ['one', 'two', 'three', 'hilly', 'sam', 'free bird',
   'gollum', 'one', 'one']

excludes = ['tw', 'f', 'g']

def sw(thing, sw_list):
   for sw_l in sw_list:
     if thing.startswith(sw_l):
       return True
   return False

trim_list = set(item for item in full_list if not sw(item, excludes))

print("Looking at trim_list")
for t in trim_list:
   print(t)

###


-- 
Site Reliability Engineer  (reuel.net/resume)
Scribe: The Domici War     (domiciwar.net)
General Ne'er-do-well      (github.com/LeamHall)

From phillor9 at gmail.com  Fri May 14 00:53:48 2021
From: phillor9 at gmail.com (Phil)
Date: Fri, 14 May 2021 14:53:48 +1000
Subject: [Tutor] Multiple inheritance
Message-ID: <add6360a-6906-d062-d713-26033eada219@gmail.com>

Thank you for reading this.

This question relates to multiple inheritance rather than a question 
about wxPython. The code actually works, or did until I tried to create 
a separate meter class . The problem, as I see it, is that the MyForm 
class is not inheriting the Meter class and there are bound to be other 
errors as well. I'm sorry to burden the list with this much code.

import wx
import math

class Meter():
 ??? def __init__(self, start_x):
 ??????? self.angle = 180? # start with the pointer pointing to the left
 ??????? self.rad = 0
 ??????? self.start_x = start_x? # the starting point of the pointer
 ??????? self.start_y = 200
 ??????? self.length = 50? # the length of the pointer
 ??????? self.inc_amount = 5

class MyForm(wx.Frame, Meter):
 ??? def __init__(self):
 ??????? wx.Frame.__init__(self, None, wx.ID_ANY, "Meter Test", 
size=(300, 300))

 ??????? # This results in a syntax error
 ??????? Meter.__init__(self, start_x)
 ??????? # I also tried super

 ??????? '''
 ??????? These variables have been moved to the meter class

 ??????? self.angle = 180? # start with the pointer pointing to the left
 ??????? self.rad = 0
 ??????? self.start_x = 200? # the starting point of the pointer
 ??????? self.start_y = 200
 ??????? self.length = 50? # the length of the pointer
 ??????? self.inc_amount = 5
 ??????? '''
 ??????? self.InitUI()

 ??? def InitUI(self):

 ??????? self.Bind(wx.EVT_PAINT, self.OnPaint)

 ??????? panel = wx.Panel(self, wx.ID_ANY)

 ??????? self.timer = wx.Timer(self)
 ??????? self.Bind(wx.EVT_TIMER, self.update, self.timer)
 ??????? self.timer.Start(100)

 ??? def update(self, event):
 ??????? m = Meter(200) # m.self.angle etc is not correct here. 
Shouldn't the Meter class variables

 ??? ??? ??? ??? ??? ??? ??? ??? ??? #? be inherited and be useable with 
the need for m.self?

 ??????? if self.angle == 360:
 ??????????? self.inc_amount *= -1

 ??????? self.angle += self.inc_amount

 ??????? if self.angle == 180:
 ??????????? self.inc_amount *= -1

 ??????? self.rad = (self.angle * math.pi / 180)

 ??????? self.Refresh()

 ??? def OnPaint(self, e):
 ??????? dc = wx.PaintDC(self)

 ??????? # Create graphics context
 ??????? gc = wx.GraphicsContext.Create(dc)

 ??????? if gc:
 ??????????? gc.SetPen(wx.RED_PEN)
 ??????????? path = gc.CreatePath()

 ??????????? path.AddArc(self.start_x, self.start_y, 60, math.radians(180),
 ??????????????????????? math.radians(0), 1)
 ??????????? path.AddLineToPoint(140, self.start_y)
 ??????????? #gc.StrokePath(path)
 ??????????? gc.DrawPath(path)

 ??????????? x = int(self.start_x + math.cos(self.rad) * self.length)
 ??????????? y = int(self.start_y + math.sin(self.rad) * self.length)

 ??????????? dc.DrawLine(self.start_x, self.start_y, x, y)


# Run the program
if __name__ == "__main__":
 ??? app = wx.App()
 ??? frame = MyForm().Show()
 ??? app.MainLoop()

-- 

Regards,
Phil


From cs at cskk.id.au  Fri May 14 03:04:57 2021
From: cs at cskk.id.au (Cameron Simpson)
Date: Fri, 14 May 2021 17:04:57 +1000
Subject: [Tutor] Multiple inheritance
In-Reply-To: <add6360a-6906-d062-d713-26033eada219@gmail.com>
References: <add6360a-6906-d062-d713-26033eada219@gmail.com>
Message-ID: <YJ4hGS4gD7gPBgOy@cskk.homeip.net>

This seems to have a bunch of "blank" characters which are not Python 
indentation characters (space, TAB). Like, 0xa0 and embedded DEL 
characters. Is this cut/paste from your actual code?

Pretending that the whitespace issues were not there, random other 
comments:

On 14May2021 14:53, Phil <phillor9 at gmail.com> wrote:
>This question relates to multiple inheritance rather than a question 
>about wxPython. The code actually works, or did until I tried to create 
>a separate meter class . The problem, as I see it, is that the MyForm 
>class is not inheriting the Meter class and there are bound to be other 
>errors as well. I'm sorry to burden the list with this much code.

But it does! Try printing MyForm.__mro__ to see the method resolution 
order.

>import wx
>import math
>
>class Meter():

You don't need the () in Python 3.

>??? def __init__(self, start_x):
>??????? self.angle = 180? # start with the pointer pointing to the left
>??????? self.rad = 0
>??????? self.start_x = start_x? # the starting point of the pointer
>??????? self.start_y = 200
>??????? self.length = 50? # the length of the pointer
>??????? self.inc_amount = 5

Looks fine.

>class MyForm(wx.Frame, Meter):

Also fine.

>??? def __init__(self):
>??????? wx.Frame.__init__(self, None, wx.ID_ANY, "Meter Test", size=(300, 300))
>??????? # This results in a syntax error
>??????? Meter.^?^?^?^?__init__(self, start_x)

Well, yeah! There are literal DEL characters in there!

If you clean that up, or just retype it, it should work.

But... Where does start_x come from? I don't see it in the arguments to 
MyForm.__init__.

>??????? # I also tried super

super().method is good to finding method in a superclass. Here you need 
to call each superclass __init__ separately with distinct arguments.

>??????? self.InitUI()
>
>??? def InitUI(self):
>
>??????? self.Bind(wx.EVT_PAINT, self.OnPaint)
>
>??????? panel = wx.Panel(self, wx.ID_ANY)
>
>??????? self.timer = wx.Timer(self)
>??????? self.Bind(wx.EVT_TIMER, self.update, self.timer)
>??????? self.timer.Start(100)
>
>??? def update(self, event):
>??????? m = Meter(200) # m.self.angle etc is not correct here. 
>Shouldn't the Meter class variables
>??? ??? ??? ??? ??? ??? ??? ??? ??? #? be inherited and be useable with 
>the need for m.self?

Yes. Once you fix your Meter.__init__(self,...) above it should be fine.

Cheers,
Cameron Simpson <cs at cskk.id.au>

From phillor9 at gmail.com  Fri May 14 05:27:09 2021
From: phillor9 at gmail.com (Phil)
Date: Fri, 14 May 2021 19:27:09 +1000
Subject: [Tutor] Multiple inheritance
In-Reply-To: <YJ4hGS4gD7gPBgOy@cskk.homeip.net>
References: <add6360a-6906-d062-d713-26033eada219@gmail.com>
 <YJ4hGS4gD7gPBgOy@cskk.homeip.net>
Message-ID: <fa7f3977-8af0-c4db-a21f-b53976eceea1@gmail.com>

On 14/5/21 5:04 pm, Cameron Simpson wrote:

Thank you Cameron,
> This seems to have a bunch of "blank" characters which are not Python
> indentation characters (space, TAB). Like, 0xa0 and embedded DEL
> characters. Is this cut/paste from your actual code?
The code was copied from IDLE and pasted directly into Thunderbird. If 
need be, I'll copy and past from Visual Studio Code.
>
> But it does! Try printing MyForm.__mro__ to see the method resolution
> order.
I will.
>
>> import wx
>> import math
>>
>> class Meter():
> You don't need the () in Python 3.

I had tried without the braces.


>>  ??? def __init__(self):
>>  ??????? wx.Frame.__init__(self, None, wx.ID_ANY, "Meter Test", size=(300, 300))
>>  ??????? # This results in a syntax error
>>  ??????? Meter.^?^?^?^?__init__(self, start_x)
> Well, yeah! There are literal DEL characters in there!
>
> If you clean that up, or just retype it, it should work.
Those characters aren't in the original file and Meter.__init__(self, 
start_x) results in a syntax error.
>
> But... Where does start_x come from? I don't see it in the arguments to
> MyForm.__init__.

start_x is a variable in the Meter class. Maybe what I'm trying to 
achieve is the problem? What I'd like to do is create a Meter class so 
that I can import it into some other programme.


> super().method is good to finding method in a superclass. Here you need
> to call each superclass __init__ separately with distinct arguments.

Super, from what I've read, is not really necessary. It sounds like a 
complication that I can do without, at least for now.


>
>>  ??????? self.InitUI()
>>
>>  ??? def InitUI(self):
>>
>>  ??????? self.Bind(wx.EVT_PAINT, self.OnPaint)
>>
>>  ??????? panel = wx.Panel(self, wx.ID_ANY)
>>
>>  ??????? self.timer = wx.Timer(self)
>>  ??????? self.Bind(wx.EVT_TIMER, self.update, self.timer)
>>  ??????? self.timer.Start(100)
>>
>>  ??? def update(self, event):
>>  ??????? m = Meter(200) # m.self.angle etc is not correct here.
>> Shouldn't the Meter class variables
>>  ??? ??? ??? ??? ??? ??? ??? ??? ??? #? be inherited and be useable with
>> the need for m.self?
> Yes. Once you fix your Meter.__init__(self,...) above it should be fine.

I retyped that line in Visual Studio (Pylance), just in case, and the 
error is "invalid character in identifier". However, selecting __init__ 
from the suggestion list solved that problem. Start_x generates a "not 
defined error". As above, start_x is a Meter class variable. How do I 
get around that problem?

-- 

Regards,
Phil


From phillor9 at gmail.com  Fri May 14 05:53:47 2021
From: phillor9 at gmail.com (Phil)
Date: Fri, 14 May 2021 19:53:47 +1000
Subject: [Tutor] Multiple inheritance - almost correct, I think
In-Reply-To: <YJ4hGS4gD7gPBgOy@cskk.homeip.net>
References: <add6360a-6906-d062-d713-26033eada219@gmail.com>
 <YJ4hGS4gD7gPBgOy@cskk.homeip.net>
Message-ID: <3ffb6770-00cc-2095-d978-04e95db22e65@gmail.com>

On 14/5/21 5:04 pm, Cameron Simpson wrote:

A cut and copy from VS Code instead of IDLE.

Traceback (most recent call last):
 ? File "/home/phil/Python/wxpython_meter_test.py", line 83, in <module>
 ??? frame = MyForm().Show()
 ? File "/home/phil/Python/wxpython_meter_test.py", line 19, in __init__
 ??? Meter.__init__(self, Meter.start_x)
AttributeError: type object 'Meter' has no attribute 'start_x'

Line 19 is:
Meter.__init__(self, Meter.start_x)

This now appears to be the only error.

importwx
importmath
classMeter:
def__init__(self, start_x):
self.angle= 180# start with the pointer pointing to the left
self.rad= 0
self.start_x= start_x# the starting point of the pointer
self.start_y= 200
self.length= 50# the length of the pointer
self.inc_amount= 5
classMyForm(wx.Frame, Meter):
def__init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY, "Meter Test", size=(300, 300))
Meter.__init__(self, Meter.start_x)
#m = Meter(200)
#print(m.angle)
'''
These variables have been moved to the meter class
self.angle = 180 # start with the pointer pointing to the left
self.rad = 0
self.start_x = 200 # the starting point of the pointer
self.start_y = 200
self.length = 50 # the length of the pointer
self.inc_amount = 5
'''
self.InitUI()
defInitUI(self):
self.Bind(wx.EVT_PAINT, self.OnPaint)
panel= wx.Panel(self, wx.ID_ANY)
self.timer= wx.Timer(self)
self.Bind(wx.EVT_TIMER, self.update, self.timer)
self.timer.Start(100)
defupdate(self, event):
#m = Meter(200) # m.self.angle etc is not correct here
ifMeter.angle== 360:
Meter.inc_amount*= -1
Meter.angle+= Meter.inc_amount
ifself.angle== 180:
Meter.inc_amount*= -1
Meter.rad= (Meter.angle* math.pi/ 180)
self.Refresh()
defOnPaint(self, e):
dc= wx.PaintDC(self)
# Create graphics context
gc= wx.GraphicsContext.Create(dc)
ifgc:
gc.SetPen(wx.RED_PEN)
path= gc.CreatePath()
path.AddArc(Meter.start_x, Meter.start_y, 60, math.radians(180),
math.radians(0), 1)
path.AddLineToPoint(140, self.start_y)
#gc.StrokePath(path)
gc.DrawPath(path)
x= int(Meter.start_x+ math.cos(Meter.rad) * Meter.length)
y= int(Meter.start_y+ math.sin(Meter.rad) * Meter.length)
dc.DrawLine(Meter.start_x, Meter.start_y, x, y)
if__name__== "__main__":
app= wx.App()
frame= MyForm().Show()
app.MainLoop()

-- 
Regards,
Phil


From phillor9 at gmail.com  Fri May 14 05:57:14 2021
From: phillor9 at gmail.com (Phil)
Date: Fri, 14 May 2021 19:57:14 +1000
Subject: [Tutor] Multiple inheritance
In-Reply-To: <YJ4hGS4gD7gPBgOy@cskk.homeip.net>
References: <add6360a-6906-d062-d713-26033eada219@gmail.com>
 <YJ4hGS4gD7gPBgOy@cskk.homeip.net>
Message-ID: <c8b0555a-b3bc-7249-2573-f75f9be2a83b@gmail.com>

On 14/5/21 5:04 pm, Cameron Simpson wrote:

I see that the indentation is missing from the VS Code copy. Perhaps 
there is enough to spot the problem with the code.

-- 

Regards,
Phil


From alan.gauld at yahoo.co.uk  Fri May 14 06:31:29 2021
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Fri, 14 May 2021 11:31:29 +0100
Subject: [Tutor] Multiple inheritance
In-Reply-To: <fa7f3977-8af0-c4db-a21f-b53976eceea1@gmail.com>
References: <add6360a-6906-d062-d713-26033eada219@gmail.com>
 <YJ4hGS4gD7gPBgOy@cskk.homeip.net>
 <fa7f3977-8af0-c4db-a21f-b53976eceea1@gmail.com>
Message-ID: <s7lji2$12h8$1@ciao.gmane.io>

On 14/05/2021 10:27, Phil wrote:
> On 14/5/21 5:04 pm, Cameron Simpson wrote:

>> But... Where does start_x come from? I don't see it in the arguments to
>> MyForm.__init__.
> 
> start_x is a variable in the Meter class. Maybe what I'm trying to 
> achieve is the problem? What I'd like to do is create a Meter class so 
> that I can import it into some other programme.

Thats fine, but unrelated to multiple inheritance and what's happening
here. That's just a normal class definition. but you can only pass in
arguments that are visible at the point of calling the method. You
cannot refer to instance variables before the instance has been
initialized (by __init__) and even then you need to prefix the name with
the instance 9self in this case)

>> super().method is good to finding method in a superclass. Here you need
>> to call each superclass __init__ separately with distinct arguments.
> 
> Super, from what I've read, is not really necessary. It sounds like a 
> complication that I can do without, at least for now.

super() is not really necessary in single inheritance it is
however essential in multiple inheritance or you can get
very weird cyclic behaviour and incomplete or multiple
initialization of attributes.

Always use super() in multiple inheritance cases, and its
usually better in single inheritance too, for consistency
if nothing else! super in Python2 was a bit of a mess, but
in python 3 super is clean and effective.

> I retyped that line in Visual Studio (Pylance), just in case, and the 
> error is "invalid character in identifier". However, selecting __init__ 
> from the suggestion list solved that problem. Start_x generates a "not 
> defined error". As above, start_x is a Meter class variable. How do I 
> get around that problem?

You can't. Ignore the MI issue and consider Meter as a
stand-alone class. You have defined its __init__() as
taking an argument. So you must theefore provide that
argument.

class Meter():
     def __init__(self, start_x):
         self.angle = 180  # start with the pointer pointing to the left
         self.rad = 0
         self.start_x = start_x  # the starting point of the pointer
         self.start_y = 200
         self.length = 50  # the length of the pointer
         self.inc_amount = 5

start_x inside Meter does not exist until after init() is executed.
And init requires that you provide a value. This is true regardless
of whether you create a stand-alone instance of Meter or if you
inherit from Meter.

You could define a default value:

class Meter():
     def __init__(self, start_x=0):...

That would allow you to call init without a start_x and ensure
it always had some value. But you can never change startx unless
you pass a value into init() startx does not exist until after
init() has been called.

Incidentally, I doubt very much whether you really want to
use MI here.  A Form is very unlikely to be a Meter. It may
contain a meter but it is not a Meter itself, and inheritance
implements an "is-a" relationship.

The very fact tat your Meter class has no methods other than
init() suggests it is merely a data container. As such it would
be better to pass a Meter instance into the form init() and store
it as an instance attribute of the form.

MI is a very powerful and useful tool but it brings with it a
host of added complexity and should only be used when it is
genuinely needed. In all other cases containment and delegation
are usually better options.

-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos



From alan.gauld at yahoo.co.uk  Fri May 14 06:33:54 2021
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Fri, 14 May 2021 11:33:54 +0100
Subject: [Tutor] Multiple inheritance - almost correct, I think
In-Reply-To: <3ffb6770-00cc-2095-d978-04e95db22e65@gmail.com>
References: <add6360a-6906-d062-d713-26033eada219@gmail.com>
 <YJ4hGS4gD7gPBgOy@cskk.homeip.net>
 <3ffb6770-00cc-2095-d978-04e95db22e65@gmail.com>
Message-ID: <s7ljmi$12h8$2@ciao.gmane.io>

On 14/05/2021 10:53, Phil wrote:

> classMyForm(wx.Frame, Meter):
> def__init__(self):
> wx.Frame.__init__(self, None, wx.ID_ANY, "Meter Test", size=(300, 300))
> Meter.__init__(self, Meter.start_x)

As per my other post, you cannot do this. Meter.start_x
does not exist at this point. it is created inside Meter.init()
and uses the value passed into init to initialize itself.


-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos



From phillor9 at gmail.com  Fri May 14 06:58:20 2021
From: phillor9 at gmail.com (Phil)
Date: Fri, 14 May 2021 20:58:20 +1000
Subject: [Tutor] Multiple inheritance
In-Reply-To: <s7lji2$12h8$1@ciao.gmane.io>
References: <add6360a-6906-d062-d713-26033eada219@gmail.com>
 <YJ4hGS4gD7gPBgOy@cskk.homeip.net>
 <fa7f3977-8af0-c4db-a21f-b53976eceea1@gmail.com>
 <s7lji2$12h8$1@ciao.gmane.io>
Message-ID: <6dc95b8b-2723-02e6-0a99-7ec26c4747f4@gmail.com>

On 14/5/21 8:31 pm, Alan Gauld via Tutor wrote:
> You can't. Ignore the MI issue and consider Meter as a
> stand-alone class. You have defined its __init__() as
> taking an argument. So you must theefore provide that
> argument.

Thank you Alan, I think this is what's required. Still, m = Meter(200) 
and then print(m.angle) doesn't generate an error but doesn't print 
anything as far as I can tell. Also, how do I tell the MyForm class 
methods (update() and OnPaint()) that the variables angle etc belong to 
the Meter class? That's why I was attempting to inherit the Meter class.

import wx
import math

class Meter:
 ??? def __init__(self, start_x):
 ??????? self.angle = 180? # start with the pointer pointing to the left
 ??????? self.rad = 0
 ??????? self.start_x = start_x? # the starting point of the pointer
 ??????? self.start_y = 200
 ??????? self.length = 50? # the length of the pointer
 ??????? self.inc_amount = 5

class MyForm(wx.Frame):
 ??? def __init__(self):
 ??????? wx.Frame.__init__(self, None, wx.ID_ANY, "Meter Test", 
size=(300, 300))

 ??????? #Meter.__init__(self, 200)#Meter.start_x)

 ??????? m = Meter(200)
 ??????? print(m.angle)

 ??????? '''
 ??????? These variables have been moved to the meter class

 ??????? self.angle = 180? # start with the pointer pointing to the left
 ??????? self.rad = 0
 ??????? self.start_x = 200? # the starting point of the pointer
 ??????? self.start_y = 200
 ??????? self.length = 50? # the length of the pointer
 ??????? self.inc_amount = 5
 ??????? '''
 ??????? self.InitUI()

 ??? def InitUI(self):

 ??????? self.Bind(wx.EVT_PAINT, self.OnPaint)

 ??????? panel = wx.Panel(self, wx.ID_ANY)

 ??????? self.timer = wx.Timer(self)
 ??????? self.Bind(wx.EVT_TIMER, self.update, self.timer)
 ??????? self.timer.Start(100)

 ??? def update(self, event):
 ??????? if m.angle == 360:
 ??????????? Meter.inc_amount *= -1

 ??????? Meter.angle += Meter.inc_amount

 ??????? if self.angle == 180:
 ??????????? Meter.inc_amount *= -1

 ??????? Meter.rad = (Meter.angle * math.pi / 180)

 ??????? self.Refresh()

 ??? def OnPaint(self, e):
 ??????? dc = wx.PaintDC(self)

 ??????? # Create graphics context
 ??????? gc = wx.GraphicsContext.Create(dc)

 ??????? if gc:
 ??????????? gc.SetPen(wx.RED_PEN)
 ??????????? path = gc.CreatePath()

 ??????????? path.AddArc(Meter.start_x, Meter.start_y, 60, 
math.radians(180),
 ??????????????????????? math.radians(0), 1)
 ??????????? path.AddLineToPoint(140, self.start_y)
 ??????????? #gc.StrokePath(path)
 ??????????? gc.DrawPath(path)

 ??????????? x = int(Meter.start_x + math.cos(Meter.rad) * Meter.length)
 ??????????? y = int(Meter.start_y + math.sin(Meter.rad) * Meter.length)

 ??????????? dc.DrawLine(Meter.start_x, Meter.start_y, x, y)


if __name__ == "__main__":
 ??? app = wx.App()
 ??? frame = MyForm().Show()
 ??? app.MainLoop()


>
> class Meter():
>       def __init__(self, start_x):
>           self.angle = 180  # start with the pointer pointing to the left
>           self.rad = 0
>           self.start_x = start_x  # the starting point of the pointer
>           self.start_y = 200
>           self.length = 50  # the length of the pointer
>           self.inc_amount = 5
>
> start_x inside Meter does not exist until after init() is executed.
> And init requires that you provide a value. This is true regardless
> of whether you create a stand-alone instance of Meter or if you
> inherit from Meter.
>
> You could define a default value:
>
> class Meter():
>       def __init__(self, start_x=0):...
>
> That would allow you to call init without a start_x and ensure
> it always had some value. But you can never change startx unless
> you pass a value into init() startx does not exist until after
> init() has been called.
>
> Incidentally, I doubt very much whether you really want to
> use MI here.  A Form is very unlikely to be a Meter. It may
> contain a meter but it is not a Meter itself, and inheritance
> implements an "is-a" relationship.
>
> The very fact tat your Meter class has no methods other than
> init() suggests it is merely a data container. As such it would
> be better to pass a Meter instance into the form init() and store
> it as an instance attribute of the form.
>
> MI is a very powerful and useful tool but it brings with it a
> host of added complexity and should only be used when it is
> genuinely needed. In all other cases containment and delegation
> are usually better options.
>

-- 
Regards,
Phil


From alan.gauld at yahoo.co.uk  Fri May 14 08:18:53 2021
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Fri, 14 May 2021 13:18:53 +0100
Subject: [Tutor] Multiple inheritance
In-Reply-To: <6dc95b8b-2723-02e6-0a99-7ec26c4747f4@gmail.com>
References: <add6360a-6906-d062-d713-26033eada219@gmail.com>
 <YJ4hGS4gD7gPBgOy@cskk.homeip.net>
 <fa7f3977-8af0-c4db-a21f-b53976eceea1@gmail.com>
 <s7lji2$12h8$1@ciao.gmane.io>
 <6dc95b8b-2723-02e6-0a99-7ec26c4747f4@gmail.com>
Message-ID: <s7lprd$17nh$1@ciao.gmane.io>

On 14/05/2021 11:58, Phil wrote:

> Thank you Alan, I think this is what's required. Still, m = Meter(200) 
> and then print(m.angle) doesn't generate an error but doesn't print 
> anything

It should do, it should print 180.
It works for me...

>>> class Meter:
      def __init__(self, start_x):
          self.angle = 180  # start with the pointer pointing to the left
          self.rad = 0
          self.start_x = start_x  # the starting point of the pointer
          self.start_y = 200
          self.length = 50  # the length of the pointer
          self.inc_amount = 5


>>> m = Meter(200)
>>> print(m.angle)
180


> Also, how do I tell the MyForm class 
> methods (update() and OnPaint()) that the variables angle etc belong to 
> the Meter class? 

class MyForm(wx.Frame):
   def __init__(self, aMeter,....):
      wx.Frame.__init(....)
      self.meter = aMeter
      .... as before

[Aside: You will often see people referring to Model/View architecture
in connection with GUI projects(and even Web systems). This is an
example of a Model/View relationship. The Meter is a model of
something in the problem domain and your form is a GUI view
of that model. The view is separate from the model but tightly
coupled to it. Problem domain logic and rules should be built as
methods of the Meter class, representation features should be
in the view class. This makes it easier to move the model to
a different application - possibly web based - in the future.
You only need to create a new view class for the new UI.)


def update(self):
   if self.meter.angle == 360:....

>  ??? def update(self, event):
>  ??????? if m.angle == 360:

Note that if you do use MI rather than containment you would
write this as

      def update(self, event):
          if self.angle == 360:

The inherited Meter attributes are part of the Form class
they are not in any separate m instance. Just as the genes
you inherited from your parents are actually part of you not
something separate.

>  ??????????? Meter.inc_amount *= -1

So this becomes 9using cotainment)

self.meter.inc_amount *= -1

and using MI:

self.inc_amount *= -1

>  ??? def OnPaint(self, e):
>  ??????? dc = wx.PaintDC(self)
> 
>  ??????? # Create graphics context
>  ??????? gc = wx.GraphicsContext.Create(dc)
> 
>  ??????? if gc:
>  ??????????? gc.SetPen(wx.RED_PEN)
>  ??????????? path = gc.CreatePath()
> 
>  ??????????? path.AddArc(Meter.start_x, 
                           Meter.start_y, 60,
 math.radians(180),                           math.radians(0), 1)


Becomes
>              path.AddArc(self.meter.start_x,
                           self.meter.start_y, 60,
                           math.radians(180),
                           math.radians(0), 1)

or with MI:

>              path.AddArc(self.start_x,
                           self.start_y, 60,
                           math.radians(180),
                           math.radians(0), 1)


etc...
-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos



From nathan-tech at hotmail.com  Fri May 14 09:00:28 2021
From: nathan-tech at hotmail.com (nathan Smith)
Date: Fri, 14 May 2021 14:00:28 +0100
Subject: [Tutor] getting network device names
Message-ID: <DB7PR07MB50939EDCB9FC6485DD59A591E4509@DB7PR07MB5093.eurprd07.prod.outlook.com>

Hi list,


I figured I'd ask here in case I'm missing something.

I'm trying to write a small program that would be able to get a list of 
devices connected to the same one as my laptop, EG the devices on the 
router and display that in a list of IP and device name.

I'm running python 3.8 on windows and so far can get a list of IP 
addresses through the arp -a command and putting it through os.popen to 
process the results.

As far as I can see though the only way to get the device names is 
through nmap which does not come by default on windows and doesn't look 
like it's made to be distributed as part of a package.

I know though that socket.gethostname() returns my local computer's 
name, so wonder if I am missing something?

Maybe I can do some form of call to the dns of the router itself?

socket.gethostbyaddr(an-ip-address) times out for local IP addresses.


Thanks for any help

Nathan


From mats at wichmann.us  Fri May 14 09:41:53 2021
From: mats at wichmann.us (Mats Wichmann)
Date: Fri, 14 May 2021 07:41:53 -0600
Subject: [Tutor] getting network device names
In-Reply-To: <DB7PR07MB50939EDCB9FC6485DD59A591E4509@DB7PR07MB5093.eurprd07.prod.outlook.com>
References: <DB7PR07MB50939EDCB9FC6485DD59A591E4509@DB7PR07MB5093.eurprd07.prod.outlook.com>
Message-ID: <c82d15e9-bec0-1b72-6ebd-d8423fc178f4@wichmann.us>

On 5/14/21 7:00 AM, nathan Smith wrote:
> Hi list,
> 
> 
> I figured I'd ask here in case I'm missing something.
> 
> I'm trying to write a small program that would be able to get a list of 
> devices connected to the same one as my laptop, EG the devices on the 
> router and display that in a list of IP and device name.
> 
> I'm running python 3.8 on windows and so far can get a list of IP 
> addresses through the arp -a command and putting it through os.popen to 
> process the results.
> 
> As far as I can see though the only way to get the device names is 
> through nmap which does not come by default on windows and doesn't look 
> like it's made to be distributed as part of a package.
> 
> I know though that socket.gethostname() returns my local computer's 
> name, so wonder if I am missing something?
> 
> Maybe I can do some form of call to the dns of the router itself?
> 
> socket.gethostbyaddr(an-ip-address) times out for local IP addresses.


not really a Python question...  Windows doesn't return hostnames, only 
ip addresses, from the arp command.  gethostbyaddr() could be useful, or 
you could call out to the system again and use the nslookup Windows 
command, but both depend on there being someone to answer - a properly 
configured dns server for your local domain, and/or a hosts file that 
has entries to do that transformation of ip to name.




From robertvstepp at gmail.com  Fri May 14 23:29:39 2021
From: robertvstepp at gmail.com (boB Stepp)
Date: Fri, 14 May 2021 22:29:39 -0500
Subject: [Tutor] How does the interpreter determine how many decimal places
 to display for a float?
Message-ID: <CANDiX9+UeuJjn9Ez_NEVJ28JWydqBD+N0qp7VMO2s50HGf4okw@mail.gmail.com>

In "15. Floating Point Arithmetic:  Issues and Limitations" at
https://docs.python.org/3/tutorial/floatingpoint.html it says:

<quote>
Interestingly, there are many different decimal numbers that share the
same nearest approximate binary fraction. For example, the numbers 0.1
and 0.10000000000000001 and
0.1000000000000000055511151231257827021181583404541015625 are all
approximated by 3602879701896397 / 2 ** 55. Since all of these decimal
values share the same approximation, any one of them could be
displayed while still preserving the invariant eval(repr(x)) == x.

Historically, the Python prompt and built-in repr() function would
choose the one with 17 significant digits, 0.10000000000000001.
Starting with Python 3.1, Python (on most systems) is now able to
choose the shortest of these and simply display 0.1.
</quote>

How does >= Python 3.1 determine the "shortest of these"?

TIA!
boB Stepp

From phillor9 at gmail.com  Sat May 15 01:03:00 2021
From: phillor9 at gmail.com (Phil)
Date: Sat, 15 May 2021 15:03:00 +1000
Subject: [Tutor] Multiple inheritance
In-Reply-To: <s7lprd$17nh$1@ciao.gmane.io>
References: <add6360a-6906-d062-d713-26033eada219@gmail.com>
 <YJ4hGS4gD7gPBgOy@cskk.homeip.net>
 <fa7f3977-8af0-c4db-a21f-b53976eceea1@gmail.com>
 <s7lji2$12h8$1@ciao.gmane.io>
 <6dc95b8b-2723-02e6-0a99-7ec26c4747f4@gmail.com>
 <s7lprd$17nh$1@ciao.gmane.io>
Message-ID: <627018ca-10d8-e0f3-adbf-60f740603b77@gmail.com>

On 14/5/21 10:18 pm, Alan Gauld via Tutor wrote:
> Thank you Alan for your detailed reply, however, there is still a problem.
> It should do, it should print 180.
> It works for me...
It did for me too, the number 180 was lost among the error messages.
>
> class MyForm(wx.Frame):
>     def __init__(self, aMeter,....):
>        wx.Frame.__init(....)
>        self.meter = aMeter
>        .... as before
As soon as I saw "self.meter = Meter" I said to myself "that's the 
answer" and so I excitedly added that line and "self.meter." where 
required, but.
> def update(self):
>     if self.meter.angle == 360:....

At this point the error is "AttributeError: type object 'Meter' has no 
attribute 'angle'". An error that I've become very familiar with since I 
started this project.

The same error message continues for each Meter variable.

I've checked and rechecked to make sure that I've entered the text 
correctly and so there must be some other subtle error.

Thank you for your patience.

-- 
Regards,
Phil


From phillor9 at gmail.com  Sat May 15 01:46:39 2021
From: phillor9 at gmail.com (Phil)
Date: Sat, 15 May 2021 15:46:39 +1000
Subject: [Tutor] Multiple inheritance - solved
In-Reply-To: <s7lprd$17nh$1@ciao.gmane.io>
References: <add6360a-6906-d062-d713-26033eada219@gmail.com>
 <YJ4hGS4gD7gPBgOy@cskk.homeip.net>
 <fa7f3977-8af0-c4db-a21f-b53976eceea1@gmail.com>
 <s7lji2$12h8$1@ciao.gmane.io>
 <6dc95b8b-2723-02e6-0a99-7ec26c4747f4@gmail.com>
 <s7lprd$17nh$1@ciao.gmane.io>
Message-ID: <10c81fd4-72d4-4a12-472e-381bff4f92cc@gmail.com>

On 14/5/21 10:18 pm, Alan Gauld via Tutor wrote:

> class MyForm(wx.Frame):
>     def __init__(self, aMeter,....):
>        wx.Frame.__init(....)
>        self.meter = aMeter
>        .... as before

It finally dawned on that "= Meter" should be "= Meter(200)".

-- 

Regards,
Phil


From __peter__ at web.de  Sat May 15 04:37:21 2021
From: __peter__ at web.de (Peter Otten)
Date: Sat, 15 May 2021 10:37:21 +0200
Subject: [Tutor] How does the interpreter determine how many decimal
 places to display for a float?
In-Reply-To: <CANDiX9+UeuJjn9Ez_NEVJ28JWydqBD+N0qp7VMO2s50HGf4okw@mail.gmail.com>
References: <CANDiX9+UeuJjn9Ez_NEVJ28JWydqBD+N0qp7VMO2s50HGf4okw@mail.gmail.com>
Message-ID: <s7o180$ae8$1@ciao.gmane.io>

On 15/05/2021 05:29, boB Stepp wrote:

> How does >= Python 3.1 determine the "shortest of these"?

This is an interesting question...

A little digging in the Python source turns up

https://github.com/python/cpython/blob/main/Python/dtoa.c

Does that answer your question? Well, it didn't help me, so I looked for 
the original code and found what seems to be the corresponding paper

David M. Gay:
Correctly Rounded Binary-Decimal and Decimal-Binary Conversion
https://ampl.com/REFS/rounding.pdf

which in turn leads to

Guy L. Steele Jr., Jon L White:
How to Print Floating-Point Numbers Accurately

https://lists.nongnu.org/archive/html/gcl-devel/2012-10/pdfkieTlklRzN.pdf


Hope that helps ;)


From alan.gauld at yahoo.co.uk  Sat May 15 09:10:08 2021
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Sat, 15 May 2021 14:10:08 +0100
Subject: [Tutor] Multiple inheritance - solved
In-Reply-To: <10c81fd4-72d4-4a12-472e-381bff4f92cc@gmail.com>
References: <add6360a-6906-d062-d713-26033eada219@gmail.com>
 <YJ4hGS4gD7gPBgOy@cskk.homeip.net>
 <fa7f3977-8af0-c4db-a21f-b53976eceea1@gmail.com>
 <s7lji2$12h8$1@ciao.gmane.io>
 <6dc95b8b-2723-02e6-0a99-7ec26c4747f4@gmail.com>
 <s7lprd$17nh$1@ciao.gmane.io>
 <10c81fd4-72d4-4a12-472e-381bff4f92cc@gmail.com>
Message-ID: <s7oh7h$p94$1@ciao.gmane.io>

On 15/05/2021 06:46, Phil wrote:
> On 14/5/21 10:18 pm, Alan Gauld via Tutor wrote:
> 
>> class MyForm(wx.Frame):
>>     def __init__(self, aMeter,....):
>>        wx.Frame.__init(....)
>>        self.meter = aMeter
>>        .... as before
> 
> It finally dawned on that "= Meter" should be "= Meter(200)".

notice I did not write

= Meter

I wrote

= aMeter

In other words, the argument passed to __init__().

To pass the Meter(200) you would  write

myform = MyForm(Meter(200), ...other args....)

If you assign Meter(200) inside init you always get
the same Meter values.


-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos



From robertvstepp at gmail.com  Sat May 15 14:45:17 2021
From: robertvstepp at gmail.com (boB Stepp)
Date: Sat, 15 May 2021 13:45:17 -0500
Subject: [Tutor] How does the interpreter determine how many decimal
 places to display for a float?
In-Reply-To: <s7o180$ae8$1@ciao.gmane.io>
References: <CANDiX9+UeuJjn9Ez_NEVJ28JWydqBD+N0qp7VMO2s50HGf4okw@mail.gmail.com>
 <s7o180$ae8$1@ciao.gmane.io>
Message-ID: <CANDiX9Kfq8QCr6H6b=8_j1-gJDh2hLMusNoAbrqCr8jfcBt-aA@mail.gmail.com>

On Sat, May 15, 2021 at 3:38 AM Peter Otten <__peter__ at web.de> wrote:
>
> On 15/05/2021 05:29, boB Stepp wrote:
>
> > How does >= Python 3.1 determine the "shortest of these"?
>
> This is an interesting question...

More interesting than I suspected based on what you have uncovered.

> A little digging in the Python source turns up
>
> https://github.com/python/cpython/blob/main/Python/dtoa.c

How did you ever suspect to look here?  "dtoa" = ?  Decimal to ASCII?
I would have never suspected I should look here.

I have not studied C.  Looking over the referenced source code,  why
do C programmers use such cryptic acronyms for their naming?  I looked
up the C standard for naming and there is no prohibition on using
descriptive names.  The naming used in this file is reminiscent of my
distant FORTRAN days.  Ugh!

> Does that answer your question? Well, it didn't help me, so I looked for
> the original code and found what seems to be the corresponding paper
>
> David M. Gay:
> Correctly Rounded Binary-Decimal and Decimal-Binary Conversion
> https://ampl.com/REFS/rounding.pdf
>
> which in turn leads to
>
> Guy L. Steele Jr., Jon L White:
> How to Print Floating-Point Numbers Accurately
>
> https://lists.nongnu.org/archive/html/gcl-devel/2012-10/pdfkieTlklRzN.pdf
>
>
> Hope that helps ;)

Looks like some light after dinner reading.  ~(:>))

Thanks!
boB Stepp

From joao.oliveira at ufob.edu.br  Sat May 15 13:58:04 2021
From: joao.oliveira at ufob.edu.br (Joao Carlos Silva de Oliveira Matos)
Date: Sat, 15 May 2021 14:58:04 -0300
Subject: [Tutor] Create a database from api requests
Message-ID: <CAN8ghrArbmAYk84hC2extrbdN1JEOUM=xRQtm3nmRAL8ZK1bdw@mail.gmail.com>

Hello everyone,

My friends and I play tournaments every week and we decided to create a
league with the sum of points from each weekly tournament. The results can
be accessed via API Rest. The API response is a nested JSON file.
I started to run the code on the first of May, using a filter to only get
results from that day on. But I am realizing that the code is taking more
and more time to load since the amount of data only increases.
So I need to set up a database. Searching through the internet I saw two
accessible ways. The first one is to save this data in cache in an SQLite
file, the other one is to transform it into CSV and append new data every
day.
Could someone tell me what is the best strategy here? Transforming nested
JSON in data frames does not look so simple. I would like my code to run as
quickly as possible. Would anyone have good documentation or examples for
me to study?

--

From smile2me at nobodiesfool.com  Sat May 15 10:13:20 2021
From: smile2me at nobodiesfool.com (me)
Date: Sat, 15 May 2021 16:13:20 +0200
Subject: [Tutor] TypeError: 'str' object is not callable
Message-ID: <2356938.TbpgK9xzaQ@django019>

Hello,

I'm on my very first steps with python and I have a problem where I don't see, 
what's wrong.

This is the code:
-----<snip>-----------
#!/usr/bin/env python3
import glob

class foo:
    def __init__(self, path):
        self.path = path


    def path(self):
        return self.path


def main():
    hs = []
    drives = glob.glob('/dev/sd?') 
    for d in drives:
        print(d)
        hs.append(foo(d))
    for e in hs:
        print(e.path())


if __name__ == '__main__':
    main()
-----<snap>-----------

and this is the error message:
Traceback (most recent call last):
  File "test.py", line 24, in <module>
    main()
  File "test.py", line 20, in main
    print(e.path())
TypeError: 'str' object is not callable

Ok, I understand, that str() will be called internally by conversion of print 
argument. But that argument should already be a string.
So I don't know, how this could happen



From alan.gauld at yahoo.co.uk  Sat May 15 17:49:05 2021
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Sat, 15 May 2021 22:49:05 +0100
Subject: [Tutor] How does the interpreter determine how many decimal
 places to display for a float?
In-Reply-To: <CANDiX9Kfq8QCr6H6b=8_j1-gJDh2hLMusNoAbrqCr8jfcBt-aA@mail.gmail.com>
References: <CANDiX9+UeuJjn9Ez_NEVJ28JWydqBD+N0qp7VMO2s50HGf4okw@mail.gmail.com>
 <s7o180$ae8$1@ciao.gmane.io>
 <CANDiX9Kfq8QCr6H6b=8_j1-gJDh2hLMusNoAbrqCr8jfcBt-aA@mail.gmail.com>
Message-ID: <s7pfkh$rj2$1@ciao.gmane.io>

On 15/05/2021 19:45, boB Stepp wrote:

> I have not studied C.  Looking over the referenced source code,  why
> do C programmers use such cryptic acronyms for their naming?  ... 
> The naming used in this file is reminiscent of my
> distant FORTRAN days.  Ugh!

That's basically it. C and Fortran are kind of concurrent.
The earliest C compilers had name length limits of 6
(or sometimes 8) characters. You could have names up
to 32 characters but only the first 6 (or 8) counted
for uniqueness.

That tradition has become somewhat embedded even though
modern C allows names of hundreds of characters!

-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos



From alan.gauld at yahoo.co.uk  Sat May 15 17:54:22 2021
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Sat, 15 May 2021 22:54:22 +0100
Subject: [Tutor] Create a database from api requests
In-Reply-To: <CAN8ghrArbmAYk84hC2extrbdN1JEOUM=xRQtm3nmRAL8ZK1bdw@mail.gmail.com>
References: <CAN8ghrArbmAYk84hC2extrbdN1JEOUM=xRQtm3nmRAL8ZK1bdw@mail.gmail.com>
Message-ID: <s7pfuf$ca2$1@ciao.gmane.io>

On 15/05/2021 18:58, Joao Carlos Silva de Oliveira Matos via Tutor wrote:

> results from that day on. But I am realizing that the code is taking more
> and more time to load since the amount of data only increases.
> So I need to set up a database.


Indeed. and if using Python SQLite is the obvious choice since
a) Its the simplest SQL database around
b) it uses a single file and no client.server requirements
c) Sqlite comes in the Python standard library.

The only snag is if multiple people are trying to update
it at the same time, in which case you probably need
MySql or PostGres.

But you will need to spend some time learning SQL if you
are not already familiar. There are many SQLite tutorials
on the web. One example, including how to use python is
my tutorial. Look at the section on "Working with databases"...

Accessing SQLite using SQL from Python is something we
can help with once you reach that stage.


-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos



From alan.gauld at yahoo.co.uk  Sat May 15 18:05:07 2021
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Sat, 15 May 2021 23:05:07 +0100
Subject: [Tutor] TypeError: 'str' object is not callable
In-Reply-To: <2356938.TbpgK9xzaQ@django019>
References: <2356938.TbpgK9xzaQ@django019>
Message-ID: <s7pgij$j04$1@ciao.gmane.io>

On 15/05/2021 15:13, me wrote:
> Hello,
> 
> I'm on my very first steps with python and I have a problem where I don't see, 
> what's wrong.
> 
> This is the code:
> -----<snip>-----------
> #!/usr/bin/env python3
> import glob
> 
> class foo:

This is a *terrible* name for a class. Use a noun that describes
what it represents! In this case it is a wrapper around a
string which represents a path.

Not very useful, but at least calling it Path would be
more descriptive.


>     def __init__(self, path):
>         self.path = path
>     def path(self):
>         return self.path

The issue here is the order on which the code is executed.
When you first run the code the class definition is executed which
defines a method called self.path and another called self.__init__.

When you create a new instance of the class self.init is executed.
What it does is create a new binding of self.path to the string
variable path. The old binding to the method is now lost.

> def main():
>     hs = []
>     drives = glob.glob('/dev/sd?') 
>     for d in drives:
>         print(d)
>         hs.append(foo(d))

Each instance of foo overwrites the method with the string d.

>     for e in hs:
>         print(e.path())
>
>

So now, when you call e.path() you are trying to call the string.

A simple solution to this is to use a different name for
the attribute path. A common trick is to put an underscore
in front:

def __init__(self.path):
    self._path = path

def path(self):
    return self._path

A more general option is to use an article prefix such as 'the':

def __init__(self.path):
    self.thePath = path

def path(self):
    return self.thePath


HTH
-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos



From mats at wichmann.us  Sat May 15 18:16:16 2021
From: mats at wichmann.us (Mats Wichmann)
Date: Sat, 15 May 2021 16:16:16 -0600
Subject: [Tutor] TypeError: 'str' object is not callable
In-Reply-To: <s7pgij$j04$1@ciao.gmane.io>
References: <2356938.TbpgK9xzaQ@django019> <s7pgij$j04$1@ciao.gmane.io>
Message-ID: <77f91ed0-2ba1-f852-3551-4077edbd4eac@wichmann.us>

On 5/15/21 4:05 PM, Alan Gauld via Tutor wrote:
> On 15/05/2021 15:13, me wrote:
>> Hello,
>>
>> I'm on my very first steps with python and I have a problem where I don't see,
>> what's wrong.
>>
>> This is the code:
>> -----<snip>-----------
>> #!/usr/bin/env python3
>> import glob
>>
>> class foo:
> 
> This is a *terrible* name for a class. Use a noun that describes
> what it represents! In this case it is a wrapper around a
> string which represents a path.
> 
> Not very useful, but at least calling it Path would be
> more descriptive.
> 
> 
>>      def __init__(self, path):
>>          self.path = path
>>      def path(self):
>>          return self.path
> 
> The issue here is the order on which the code is executed.
> When you first run the code the class definition is executed which
> defines a method called self.path and another called self.__init__.
> 
> When you create a new instance of the class self.init is executed.
> What it does is create a new binding of self.path to the string
> variable path. The old binding to the method is now lost.
> 
>> def main():
>>      hs = []
>>      drives = glob.glob('/dev/sd?')
>>      for d in drives:
>>          print(d)
>>          hs.append(foo(d))
> 
> Each instance of foo overwrites the method with the string d.
> 
>>      for e in hs:
>>          print(e.path())
>>
>>
> 
> So now, when you call e.path() you are trying to call the string.
> 
> A simple solution to this is to use a different name for
> the attribute path. A common trick is to put an underscore
> in front:
> 
> def __init__(self.path):
>      self._path = path
> 
> def path(self):
>      return self._path
> 
> A more general option is to use an article prefix such as 'the':
> 
> def __init__(self.path):
>      self.thePath = path
> 
> def path(self):
>      return self.thePath

Or, since it's Python, which doesn't _force_ you to use getters and 
setters, just dispense with the method entirely and access the path 
attribute directly. So this should work:

import glob

class foo:
     def __init__(self, path):
         self.path = path


def main():
     hs = []
     drives = glob.glob('/dev/sd?')
     for d in drives:
         print(d)
         hs.append(foo(d))
     for e in hs:
         print(e.path)


if __name__ == '__main__':
     main()


(note for future learnings: there's a standard library module called 
pathlib which is designed to work with paths, might end up being useful 
someday rather than rolling your own - I realize this one is just a 
learning exercise)



From phillor9 at gmail.com  Sat May 15 19:13:30 2021
From: phillor9 at gmail.com (Phil)
Date: Sun, 16 May 2021 09:13:30 +1000
Subject: [Tutor] Multiple inheritance - solved
In-Reply-To: <s7oh7h$p94$1@ciao.gmane.io>
References: <add6360a-6906-d062-d713-26033eada219@gmail.com>
 <YJ4hGS4gD7gPBgOy@cskk.homeip.net>
 <fa7f3977-8af0-c4db-a21f-b53976eceea1@gmail.com>
 <s7lji2$12h8$1@ciao.gmane.io>
 <6dc95b8b-2723-02e6-0a99-7ec26c4747f4@gmail.com>
 <s7lprd$17nh$1@ciao.gmane.io>
 <10c81fd4-72d4-4a12-472e-381bff4f92cc@gmail.com> <s7oh7h$p94$1@ciao.gmane.io>
Message-ID: <33c4d830-eb26-b25c-6902-0493d3999b93@gmail.com>

On 15/5/21 11:10 pm, Alan Gauld via Tutor wrote:
> notice I did not write
> = Meter
>
> I wrote
>
> = aMeter

Thanks Alan, I assumed the "a" was a typo.

-- 

Regards,
Phil


From alan.gauld at yahoo.co.uk  Sat May 15 19:55:20 2021
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Sun, 16 May 2021 00:55:20 +0100
Subject: [Tutor] TypeError: 'str' object is not callable
In-Reply-To: <77f91ed0-2ba1-f852-3551-4077edbd4eac@wichmann.us>
References: <2356938.TbpgK9xzaQ@django019> <s7pgij$j04$1@ciao.gmane.io>
 <77f91ed0-2ba1-f852-3551-4077edbd4eac@wichmann.us>
Message-ID: <s7pn18$giv$1@ciao.gmane.io>

On 15/05/2021 23:16, Mats Wichmann wrote:

> Or, since it's Python, which doesn't _force_ you to use getters and 
> setters, just dispense with the method entirely and access the path 
> attribute directly. So this should work:
> 
> import glob
> 
> class foo:
>      def __init__(self, path):
>          self.path = path
> 
> def main():
>      hs = []
>      drives = glob.glob('/dev/sd?')
>      for d in drives:
>          print(d)
>          hs.append(foo(d))
>      for e in hs:
>          print(e.path)

Even better dispense with the class entirely and
just use a variable:

def main():
      hs = []
      drives = glob.glob('/dev/sd?')
      for d in drives:
          print(d)
          hs.append(d)
      for e in hs:
          print(e)


-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos



From __peter__ at web.de  Sun May 16 11:34:11 2021
From: __peter__ at web.de (Peter Otten)
Date: Sun, 16 May 2021 17:34:11 +0200
Subject: [Tutor] How does the interpreter determine how many decimal
 places to display for a float?
In-Reply-To: <CANDiX9Kfq8QCr6H6b=8_j1-gJDh2hLMusNoAbrqCr8jfcBt-aA@mail.gmail.com>
References: <CANDiX9+UeuJjn9Ez_NEVJ28JWydqBD+N0qp7VMO2s50HGf4okw@mail.gmail.com>
 <s7o180$ae8$1@ciao.gmane.io>
 <CANDiX9Kfq8QCr6H6b=8_j1-gJDh2hLMusNoAbrqCr8jfcBt-aA@mail.gmail.com>
Message-ID: <s7re1i$15ii$1@ciao.gmane.io>

On 15/05/2021 20:45, boB Stepp wrote:
> On Sat, May 15, 2021 at 3:38 AM Peter Otten <__peter__ at web.de> wrote:
>>
>> On 15/05/2021 05:29, boB Stepp wrote:
>>
>>> How does >= Python 3.1 determine the "shortest of these"?
>>
>> This is an interesting question...
> 
> More interesting than I suspected based on what you have uncovered.
> 
>> A little digging in the Python source turns up
>>
>> https://github.com/python/cpython/blob/main/Python/dtoa.c
> 
> How did you ever suspect to look here?

Actually I didn't. In a local copy of the CPython source I looked into

Objects/floatobject.c

for the repr() implementation, found it was basically

PyOS_double_to_string()

searched the source tree for its implementation which is in

Python/pystrtod.c

Getting here should be possible with only cursory knowledge of C, an 
editor, and grep.

While the last step may be a bit harder the general recipe is very 
simple: start a some point and jump from function call to function 
definition until you have found the actual operation you are interested 
in. You can professionalize this and use a debugger or an IDE feature, 
but just grep -- and print() when you are really lost -- is not much slower.


   "dtoa" = ?  Decimal to ASCII?
> I would have never suspected I should look here.
> 
> I have not studied C.  Looking over the referenced source code,  why
> do C programmers use such cryptic acronyms for their naming?

As Alan hints, the short "cryptic" names are likely the old ones, and 
there are only a few ones that are or were heavily used. Most of the 
functions in the CPython source have descriptive names. Because there 
are no namespaces names even tend to get too long for readable code.


I looked
> up the C standard for naming and there is no prohibition on using
> descriptive names.  The naming used in this file is reminiscent of my
> distant FORTRAN days.  Ugh!
> 
>> Does that answer your question? Well, it didn't help me, so I looked for
>> the original code and found what seems to be the corresponding paper
>>
>> David M. Gay:
>> Correctly Rounded Binary-Decimal and Decimal-Binary Conversion
>> https://ampl.com/REFS/rounding.pdf
>>
>> which in turn leads to
>>
>> Guy L. Steele Jr., Jon L White:
>> How to Print Floating-Point Numbers Accurately
>>
>> https://lists.nongnu.org/archive/html/gcl-devel/2012-10/pdfkieTlklRzN.pdf
>>
>>
>> Hope that helps ;)
> 
> Looks like some light after dinner reading.  ~(:>))
> 
> Thanks!
> boB Stepp
> _______________________________________________
> Tutor maillist  -  Tutor at python.org
> To unsubscribe or change subscription options:
> https://mail.python.org/mailman/listinfo/tutor
> 



From robertvstepp at gmail.com  Sun May 16 12:48:53 2021
From: robertvstepp at gmail.com (boB Stepp)
Date: Sun, 16 May 2021 11:48:53 -0500
Subject: [Tutor] How does the interpreter determine how many decimal
 places to display for a float?
In-Reply-To: <s7re1i$15ii$1@ciao.gmane.io>
References: <CANDiX9+UeuJjn9Ez_NEVJ28JWydqBD+N0qp7VMO2s50HGf4okw@mail.gmail.com>
 <s7o180$ae8$1@ciao.gmane.io>
 <CANDiX9Kfq8QCr6H6b=8_j1-gJDh2hLMusNoAbrqCr8jfcBt-aA@mail.gmail.com>
 <s7re1i$15ii$1@ciao.gmane.io>
Message-ID: <CANDiX9+m5d63SW_BkPpc+bkhfVHfCiSw-q8p_WmQL2SDxOxCTw@mail.gmail.com>

On Sun, May 16, 2021 at 10:35 AM Peter Otten <__peter__ at web.de> wrote:
>
> On 15/05/2021 20:45, boB Stepp wrote:
> > On Sat, May 15, 2021 at 3:38 AM Peter Otten <__peter__ at web.de> wrote:
> >>
> >> On 15/05/2021 05:29, boB Stepp wrote:

> While the last step may be a bit harder the general recipe is very
> simple: start a some point and jump from function call to function
> definition until you have found the actual operation you are interested
> in. You can professionalize this and use a debugger or an IDE feature,
> but just grep -- and print() when you are really lost -- is not much slower.

This is helpful.  However, I tend to (so far) be clumsy in finding a
decent starting point.  Since your original reply I have been poking
around the cpython source and am getting a better handle on how it is
arranged.  Hopefully this will help me in the future.

>    "dtoa" = ?  Decimal to ASCII?
> > I would have never suspected I should look here.
> >
> > I have not studied C.  Looking over the referenced source code,  why
> > do C programmers use such cryptic acronyms for their naming?
>
> As Alan hints, the short "cryptic" names are likely the old ones, and
> there are only a few ones that are or were heavily used. Most of the
> functions in the CPython source have descriptive names. Because there
> are no namespaces names even tend to get too long for readable code.

Hmm.  This makes me wonder if even a person such as myself might be
able to contribute to Python by renaming "cryptic" old-style C-naming
with more modern descriptive names?  I wonder how many many files
would be involved in such a project to just clean up the naming in
dtoa.c?  But I don't have time now to do such, but I can see it as
something I might be able to do.  Just a stray thought...

Thanks, Peter,
boB Stepp

From robertvstepp at gmail.com  Sun May 16 13:15:27 2021
From: robertvstepp at gmail.com (boB Stepp)
Date: Sun, 16 May 2021 12:15:27 -0500
Subject: [Tutor] How does the interpreter determine how many decimal
 places to display for a float?
In-Reply-To: <0ag2agd71l4o1nrn6ubkj3tefjqupqgsn6@4ax.com>
References: <CANDiX9+UeuJjn9Ez_NEVJ28JWydqBD+N0qp7VMO2s50HGf4okw@mail.gmail.com>
 <s7o180$ae8$1@ciao.gmane.io>
 <CANDiX9Kfq8QCr6H6b=8_j1-gJDh2hLMusNoAbrqCr8jfcBt-aA@mail.gmail.com>
 <0ag2agd71l4o1nrn6ubkj3tefjqupqgsn6@4ax.com>
Message-ID: <CANDiX9L2SQSbmaDdgW82NA+w5XoGeq4K9ybrbY7ZwRMxo2oLsQ@mail.gmail.com>

On Sun, May 16, 2021 at 11:12 AM Dennis Lee Bieber
<wlfraed at ix.netcom.com> wrote:
>
> On Sat, 15 May 2021 13:45:17 -0500, boB Stepp <robertvstepp at gmail.com>
> declaimed the following:
>
> >
> >I have not studied C.  Looking over the referenced source code,  why
> >do C programmers use such cryptic acronyms for their naming?  I looked
> >up the C standard for naming and there is no prohibition on using
> >descriptive names.  The naming used in this file is reminiscent of my
> >distant FORTRAN days.  Ugh!
> >
>         FORTRAN started in the late 1950s. C goes back to about 1970. Memory on
> large mainframes of that error was still measured in kBytes. The Xerox
> Sigma 6 used at my college (all the way up to and past 1980) was a 1970 or
> so design -- it was spec'd to support 512kBytes (128kWords @ 32-bits;
> 16-bit was a half-word) and managed some 60+ (text) terminals scattered
> over campus. A large program with lots of long names would result in
> compiler tables consuming most of the memory. C & UNIX sort of developed
> together -- ever look at the core shell commands in UNIX: ls, cp, mv, cd =>
> list, copy, move, change_directory?

When I started college in 1975 my university had just recently
installed a mainframe from the IBM 360 family.  I no longer remember
any relevant specs.  This is what I fed my card stacks into to run
programs from the few FORTRAN classes I took and later programs
relevant to my physics major.

I understand about the Unix commands having their usually *brief"
names and that this usage continues till the present.  As it does with
programs like gVim/Vim/vi that started way back when.  I did find it
somewhat surprising that any CPython code would use "cryptic" naming,
since Python originated circa 1989 (Is that about right when GvR
started his project?) when I wouldn't think these naming limitations
still existed for C.

>         Also, compilers may have functioned (and I think GCC still does) by
> generating ASSEMBLER source code, which then got fed to the system
> assembler program. Many assemblers had a 6-8 character LABEL field, and the
> variable/function names from the source language had to be mashed into that
> label field -- and they also had to fit into the assembler
> label->relative_address tables.

This is new to me and helps to provide more context.  Thanks!

boB Stepp

From alan.gauld at yahoo.co.uk  Sun May 16 14:54:56 2021
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Sun, 16 May 2021 19:54:56 +0100
Subject: [Tutor] How does the interpreter determine how many decimal
 places to display for a float?
In-Reply-To: <CANDiX9L2SQSbmaDdgW82NA+w5XoGeq4K9ybrbY7ZwRMxo2oLsQ@mail.gmail.com>
References: <CANDiX9+UeuJjn9Ez_NEVJ28JWydqBD+N0qp7VMO2s50HGf4okw@mail.gmail.com>
 <s7o180$ae8$1@ciao.gmane.io>
 <CANDiX9Kfq8QCr6H6b=8_j1-gJDh2hLMusNoAbrqCr8jfcBt-aA@mail.gmail.com>
 <0ag2agd71l4o1nrn6ubkj3tefjqupqgsn6@4ax.com>
 <CANDiX9L2SQSbmaDdgW82NA+w5XoGeq4K9ybrbY7ZwRMxo2oLsQ@mail.gmail.com>
Message-ID: <s7rpq1$9n6$1@ciao.gmane.io>

On 16/05/2021 18:15, boB Stepp wrote:

> somewhat surprising that any CPython code would use "cryptic" naming,
> since Python originated circa 1989 (Is that about right when GvR
> started his project?) when I wouldn't think these naming limitations
> still existed for C.

I still have an old DOS C compiler - "Mix C" - that I used
from about 1985 when I got my first PC to the present day
(running under Dosbox on Linux). It can take 32 character
names but only the first 8 characters count. That's only 4
years before Python... I use this because it's a pre-ANSI
compiler so compatible with the original K&R book. Handy
for checking ancient C examples and articles... (gcc probably
has a flag to do the same but I'm too lazy to look! :-)

And many veteran C programmers to this day will still use
very short variable names, especially inside functions,
through force of habit/tradition/community practice.
Indeed I know several who would never consider using
names longer than 5 characters inside a function(*)
 - just to save typing if nothing else!
(Function parameter names tend to be longer to document
the function API. And globals are usually sensible names too.
Likewise struct(aka record) definitions and field names
usually have sensible names, although the instance vars
of said structs will often be short.)

(*)That may sound bad but remember that good C practice says
functions should be short - less than 25 lines - to fit on
a single screen (ie. an old VT100 80x24 terminal...)
If your function is only 10-20 lines long finding the variable
and tracking it is not such a big deal.

-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos



From alan.gauld at yahoo.co.uk  Sun May 16 14:59:17 2021
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Sun, 16 May 2021 19:59:17 +0100
Subject: [Tutor] How does the interpreter determine how many decimal
 places to display for a float?
In-Reply-To: <CANDiX9+m5d63SW_BkPpc+bkhfVHfCiSw-q8p_WmQL2SDxOxCTw@mail.gmail.com>
References: <CANDiX9+UeuJjn9Ez_NEVJ28JWydqBD+N0qp7VMO2s50HGf4okw@mail.gmail.com>
 <s7o180$ae8$1@ciao.gmane.io>
 <CANDiX9Kfq8QCr6H6b=8_j1-gJDh2hLMusNoAbrqCr8jfcBt-aA@mail.gmail.com>
 <s7re1i$15ii$1@ciao.gmane.io>
 <CANDiX9+m5d63SW_BkPpc+bkhfVHfCiSw-q8p_WmQL2SDxOxCTw@mail.gmail.com>
Message-ID: <s7rq25$uh3$1@ciao.gmane.io>

On 16/05/2021 17:48, boB Stepp wrote:

> This is helpful.  However, I tend to (so far) be clumsy in finding a
> decent starting point.  Since your original reply I have been poking
> around the cpython source and am getting a better handle on how it is
> arranged.  

If you aren't already be sure to spend 15 minutes learning ctags.
It makes navigating around C code very much easier since you can
put your cursor(in vi./vim) on a function name and "goto tag"
which will take you straight into the correct file at the
function definition.

Modern IDEs tend to have similar capabilities but ctags is
the original Unix way of doing that.

-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos



From joao.oliveira at ufob.edu.br  Sun May 16 16:47:41 2021
From: joao.oliveira at ufob.edu.br (Joao Carlos Silva de Oliveira Matos)
Date: Sun, 16 May 2021 17:47:41 -0300
Subject: [Tutor] Create a database from api requests
In-Reply-To: <thu2ag1euup8qec3k1q1f7n66kv4n8ijgc@4ax.com>
References: <CAN8ghrArbmAYk84hC2extrbdN1JEOUM=xRQtm3nmRAL8ZK1bdw@mail.gmail.com>
 <u8h2aghpg0h72ve46bmgo8dgfrndpo12cr@4ax.com>
 <thu2ag1euup8qec3k1q1f7n66kv4n8ijgc@4ax.com>
Message-ID: <CAN8ghrBstzdVL1+gg7iVV6DDHz2zSvDXoDKOuAaWtziR3NaCbw@mail.gmail.com>

Thanks a lot. Your answers were much more enlightening than I expected. I
have already written everything down and will start my studies in SQLite
right away.

Em dom., 16 de mai. de 2021 ?s 17:06, Dennis Lee Bieber <
wlfraed at ix.netcom.com> escreveu:

> On Sun, 16 May 2021 13:12:53 -0400, Dennis Lee Bieber
> <wlfraed at ix.netcom.com> declaimed the following:
>
> >On Sat, 15 May 2021 14:58:04 -0300, Joao Carlos Silva de Oliveira Matos
> via
> >Tutor <tutor at python.org> declaimed the following:
> >
> >>My friends and I play tournaments every week and we decided to create a
> >>league with the sum of points from each weekly tournament. The results
> can
> >>be accessed via API Rest. The API response is a nested JSON file.
> >>I started to run the code on the first of May, using a filter to only get
> >>results from that day on. But I am realizing that the code is taking more
> >>and more time to load since the amount of data only increases.
> >
> >       You are going to have that problem with any form you change to --
> even
> >a server-side database is going to return lots of data as the database
> >grows in size.
> >
>
>         Or did you mean to imply that you are just accessing someone else's
> web-application (your initial paragraph doesn't give any information about
> how these "tournaments" are tracked and updated).
>
>         In that case, yes... a LOCAL SQLite3 database with an update pass
> fetching only data since the last run would be feasible instead of fetching
> everything from the start of the history...
>
>
> --
>         Wulfraed                 Dennis Lee Bieber         AF6VN
>         wlfraed at ix.netcom.com
> http://wlfraed.microdiversity.freeddns.org/
>
> _______________________________________________
> Tutor maillist  -  Tutor at python.org
> To unsubscribe or change subscription options:
> https://mail.python.org/mailman/listinfo/tutor
>


-- 

Jo?o Carlos Silva de Oliveira Matos
Bolsista de Inova??o e Tecnologia
PROFNIT - Centro das Humanidades - UFOB
Mat. 2020100150

From roel at roelschroeven.net  Sun May 16 12:00:27 2021
From: roel at roelschroeven.net (Roel Schroeven)
Date: Sun, 16 May 2021 18:00:27 +0200
Subject: [Tutor] How does the interpreter determine how many decimal
 places to display for a float?
In-Reply-To: <CANDiX9Kfq8QCr6H6b=8_j1-gJDh2hLMusNoAbrqCr8jfcBt-aA@mail.gmail.com>
References: <CANDiX9+UeuJjn9Ez_NEVJ28JWydqBD+N0qp7VMO2s50HGf4okw@mail.gmail.com>
 <s7o180$ae8$1@ciao.gmane.io>
 <CANDiX9Kfq8QCr6H6b=8_j1-gJDh2hLMusNoAbrqCr8jfcBt-aA@mail.gmail.com>
Message-ID: <s7rfir$1587$1@ciao.gmane.io>

boB Stepp schreef op 15/05/2021 om 20:45:
> How did you ever suspect to look here?  "dtoa" = ?  Decimal to ASCII?

Double to ASCII, I'm guessing. C has two floating point types: float and 
double. Float has 32 bits, double has twice as many, 64 (at least on the 
platforms I'm familiar with; I don't know if that is universal). C's 
double corresponds to Python's float.

'd' for double is also used in C stdlib functions like strtod, and dtoa 
is named analog to itoa (int to ascii).

This style of short cryptic function names has its roots in early C/Unix 
habits, on computers with very limited memory and slow I/O over teletypes.

-- 
"Honest criticism is hard to take, particularly from a relative, a
friend, an acquaintance, or a stranger."
         -- Franklin P. Jones

Roel Schroeven


From alan.gauld at yahoo.co.uk  Sun May 16 19:08:23 2021
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Mon, 17 May 2021 00:08:23 +0100
Subject: [Tutor] How does the interpreter determine how many decimal
 places to display for a float?
In-Reply-To: <k6u2agd20gsk4ktk6f8nv3sqk82jpkfnjb@4ax.com>
References: <CANDiX9+UeuJjn9Ez_NEVJ28JWydqBD+N0qp7VMO2s50HGf4okw@mail.gmail.com>
 <s7o180$ae8$1@ciao.gmane.io>
 <CANDiX9Kfq8QCr6H6b=8_j1-gJDh2hLMusNoAbrqCr8jfcBt-aA@mail.gmail.com>
 <0ag2agd71l4o1nrn6ubkj3tefjqupqgsn6@4ax.com>
 <CANDiX9L2SQSbmaDdgW82NA+w5XoGeq4K9ybrbY7ZwRMxo2oLsQ@mail.gmail.com>
 <s7rpq1$9n6$1@ciao.gmane.io> <k6u2agd20gsk4ktk6f8nv3sqk82jpkfnjb@4ax.com>
Message-ID: <s7s8l7$2s7$1@ciao.gmane.io>

On 16/05/2021 21:01, Dennis Lee Bieber wrote:
> On Sun, 16 May 2021 19:54:56 +0100, Alan Gauld via Tutor <tutor at python.org>
> declaimed the following:

>> years before Python... I use this because it's a pre-ANSI
>> compiler so compatible with the original K&R book. 

> """
> The support for old-style C-Code has been removed a long time ago. Must
> be one of the 3.x Compiler which last supported old-style.
> """

I guess I'd better keep my Mix C compiler going then! :-)


-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos



From cs at cskk.id.au  Mon May 17 18:34:40 2021
From: cs at cskk.id.au (Cameron Simpson)
Date: Tue, 18 May 2021 08:34:40 +1000
Subject: [Tutor] ctags (was: How does the interpreter determine how many
 decimal places to display for a float?)
In-Reply-To: <s7rq25$uh3$1@ciao.gmane.io>
References: <s7rq25$uh3$1@ciao.gmane.io>
Message-ID: <YKLvgMTeuxeQgxG/@cskk.homeip.net>

On 16May2021 19:59, Alan Gauld <alan.gauld at yahoo.co.uk> wrote:
>On 16/05/2021 17:48, boB Stepp wrote:
>> This is helpful.  However, I tend to (so far) be clumsy in finding a
>> decent starting point.  Since your original reply I have been poking
>> around the cpython source and am getting a better handle on how it is
>> arranged.
>
>If you aren't already be sure to spend 15 minutes learning ctags.
>It makes navigating around C code very much easier since you can
>put your cursor(in vi./vim) on a function name and "goto tag"
>which will take you straight into the correct file at the
>function definition.

I want to point out that ctags works well also for Python! I use it 
extensively.

Cheers,
Cameron Simpson <cs at cskk.id.au>

From phillor9 at gmail.com  Tue May 18 03:21:54 2021
From: phillor9 at gmail.com (Phil)
Date: Tue, 18 May 2021 17:21:54 +1000
Subject: [Tutor] Using trigonometry to draw a circle
Message-ID: <075c43b7-ffee-937c-03ab-6cf32dba695f@gmail.com>

While this question is not exactly Python related, I'm trying to 
understand how I can incorporate trig functions into Python code.

Take for example a circle.

radius = 60
x_centre = 100
y_centre = 100

for angle in range(0,45):
 ? ? x = math.cos(angle) * radius + x_centre
 ? ? y = math.sin(angle) * radius + y_centre
 ??? plot(x, y)

Increasing the steps in the range function adds more points to the 
circle, but still draws a full circle. How would I draw part of a circle 
by giving a function the starting and ending angles along the circumference?

I spent most of the afternoon searching the Internet for an answer and, 
while I found many articles on unit circles, I couldn't find the answer 
I was looking for.

-- 
Regards,
Phil


From joel.goldstick at gmail.com  Tue May 18 04:12:10 2021
From: joel.goldstick at gmail.com (Joel Goldstick)
Date: Tue, 18 May 2021 04:12:10 -0400
Subject: [Tutor] Using trigonometry to draw a circle
In-Reply-To: <075c43b7-ffee-937c-03ab-6cf32dba695f@gmail.com>
References: <075c43b7-ffee-937c-03ab-6cf32dba695f@gmail.com>
Message-ID: <CAPM-O+yajai=wwSLiWXGADdghbBpYBJ5AOooOTsfHN-hWmRT6w@mail.gmail.com>

On Tue, May 18, 2021 at 3:23 AM Phil <phillor9 at gmail.com> wrote:
>
> While this question is not exactly Python related, I'm trying to
> understand how I can incorporate trig functions into Python code.
>
> Take for example a circle.
>
> radius = 60
> x_centre = 100
> y_centre = 100
>
> for angle in range(0,45):
>      x = math.cos(angle) * radius + x_centre
>      y = math.sin(angle) * radius + y_centre
>      plot(x, y)
>
> Increasing the steps in the range function adds more points to the
> circle, but still draws a full circle. How would I draw part of a circle
> by giving a function the starting and ending angles along the circumference?
>
> I spent most of the afternoon searching the Internet for an answer and,
> while I found many articles on unit circles, I couldn't find the answer
> I was looking for.
>
> --
> Regards,
> Phil
>
> _______________________________________________
> Tutor maillist  -  Tutor at python.org
> To unsubscribe or change subscription options:
> https://mail.python.org/mailman/listinfo/tutor

Note: Your code doesn't include the import of math, or the import of
where plot comes from.

More to the point (no pun intended), those math functions are defined
for radians, not degrees.  There are 2*pi radians in a circle, and 360
degrees.  So, you need to convert degrees to radians.

The code below prints radians from 0 to 90 degrees.

>>> for angle in range(91):
...     print(angle*2*math.pi/360)
...
0.0
0.017453292519943295
0.03490658503988659
...
...
...
1.53588974175501
1.5533430342749535
1.5707963267948966

-- 
Joel Goldstick

From phillor9 at gmail.com  Tue May 18 04:26:10 2021
From: phillor9 at gmail.com (Phil)
Date: Tue, 18 May 2021 18:26:10 +1000
Subject: [Tutor] Using trigonometry to draw a circle
In-Reply-To: <CAPM-O+yajai=wwSLiWXGADdghbBpYBJ5AOooOTsfHN-hWmRT6w@mail.gmail.com>
References: <075c43b7-ffee-937c-03ab-6cf32dba695f@gmail.com>
 <CAPM-O+yajai=wwSLiWXGADdghbBpYBJ5AOooOTsfHN-hWmRT6w@mail.gmail.com>
Message-ID: <5142a35c-a268-d2a3-b06f-dfeb20d8ebbf@gmail.com>

On 18/5/21 6:12 pm, Joel Goldstick wrote:
> More to the point (no pun intended), those math functions are defined
> for radians, not degrees.  There are 2*pi radians in a circle, and 360
> degrees.  So, you need to convert degrees to radians.
Thanks Joel,

x = math.cos(angle / 180) * radius + x_centre
...

Solves that problem. Now I think I can see how I can construct a function that draws part of a circle given the start and end angle along the circumference.

-- 

Regards,
Phil


From phillor9 at gmail.com  Tue May 18 04:30:55 2021
From: phillor9 at gmail.com (Phil)
Date: Tue, 18 May 2021 18:30:55 +1000
Subject: [Tutor] Using trigonometry to draw a circle
In-Reply-To: <CAPM-O+yajai=wwSLiWXGADdghbBpYBJ5AOooOTsfHN-hWmRT6w@mail.gmail.com>
References: <075c43b7-ffee-937c-03ab-6cf32dba695f@gmail.com>
 <CAPM-O+yajai=wwSLiWXGADdghbBpYBJ5AOooOTsfHN-hWmRT6w@mail.gmail.com>
Message-ID: <5a3f60b1-777c-4842-1dd1-9e940f1e059e@gmail.com>

On 18/5/21 6:12 pm, Joel Goldstick wrote:
> On Tue, May 18, 2021 at 3:23 AM Phil <phillor9 at gmail.com> wrote:
That should have been:

x = math.cos(angle * 6.28 / 360) * radius + x_centre

As you suggested.

-- 

Regards,
Phil


From alan.gauld at yahoo.co.uk  Tue May 18 04:40:59 2021
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Tue, 18 May 2021 09:40:59 +0100
Subject: [Tutor] Using trigonometry to draw a circle
In-Reply-To: <075c43b7-ffee-937c-03ab-6cf32dba695f@gmail.com>
References: <075c43b7-ffee-937c-03ab-6cf32dba695f@gmail.com>
Message-ID: <s7vuit$4eb$1@ciao.gmane.io>

On 18/05/2021 08:21, Phil wrote:
> While this question is not exactly Python related, I'm trying to 
> understand how I can incorporate trig functions into Python code.
> 
...
> 
> Increasing the steps in the range function adds more points to the 
> circle, but still draws a full circle. How would I draw part of a circle 
> by giving a function the starting and ending angles along the circumference?

You already have the general answer but I'd point out that many plotting
and drawing libraries have functions for drawing arcs which are easier
and much faster than drawing individual pixels.

Also some math plotting libraries will plot a function so you
don't have to. But that only helps if you are restricted to drawing
graphs, you still need to use the math functions when manipulating data.

-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos



From phillor9 at gmail.com  Tue May 18 05:33:31 2021
From: phillor9 at gmail.com (Phil)
Date: Tue, 18 May 2021 19:33:31 +1000
Subject: [Tutor] Using trigonometry to draw a circle
In-Reply-To: <s7vuit$4eb$1@ciao.gmane.io>
References: <075c43b7-ffee-937c-03ab-6cf32dba695f@gmail.com>
 <s7vuit$4eb$1@ciao.gmane.io>
Message-ID: <de9d8dcc-5f55-3625-cea8-fe2549a89488@gmail.com>

On 18/5/21 6:40 pm, Alan Gauld via Tutor wrote:
> Also some math plotting libraries will plot a function so you
> don't have to. But that only helps if you are restricted to drawing
> graphs, you still need to use the math functions when manipulating data.

Thanks Alan,

wxPython's addArc function, for example, works well but I cannot see how 
I can set points along the arc. If I plot individual points to generate 
an arc then setting points along the arc is easy.

-- 

Regards,
Phil


From bouncingcats at gmail.com  Tue May 18 06:06:39 2021
From: bouncingcats at gmail.com (David)
Date: Tue, 18 May 2021 20:06:39 +1000
Subject: [Tutor] Using trigonometry to draw a circle
In-Reply-To: <de9d8dcc-5f55-3625-cea8-fe2549a89488@gmail.com>
References: <075c43b7-ffee-937c-03ab-6cf32dba695f@gmail.com>
 <s7vuit$4eb$1@ciao.gmane.io> <de9d8dcc-5f55-3625-cea8-fe2549a89488@gmail.com>
Message-ID: <CAMPXz=q_RYn6Sjb7p2wY1dxTgsOc3VJ7Tusb9_d6NUiaq0C+tg@mail.gmail.com>

On Tue, 18 May 2021 at 19:35, Phil <phillor9 at gmail.com> wrote:
> On 18/5/21 6:40 pm, Alan Gauld via Tutor wrote:

> > Also some math plotting libraries will plot a function so you
> > don't have to. But that only helps if you are restricted to drawing
> > graphs, you still need to use the math functions when manipulating data.

> wxPython's addArc function, for example, works well but I cannot see how
> I can set points along the arc. If I plot individual points to generate
> an arc then setting points along the arc is easy.

Depending on why you are doing this, there are different approaches
that might or might not be a good idea. So you will get better advice
if you describe the bigger picture of what you are doing, not the details.

If you are just playing around, the below code might give you some
useful hints. If you are trying to do sophisticated drawing, this code
is probably not a good way to do it.

#!/usr/bin/python3
import matplotlib.pyplot as plt
import math
radius = 60
x_centre = 100
y_centre = 100
degs = list(range(0, 270, 10))
rads = [math.radians(d) for d in degs]
x = [math.cos(a) * radius + x_centre for a in rads]
y = [math.sin(a) * radius + y_centre for a in rads]
plt.plot(x, y, 'ro', x, y)
plt.gca().axis('scaled')
plt.show()

From roel at roelschroeven.net  Tue May 18 16:43:11 2021
From: roel at roelschroeven.net (Roel Schroeven)
Date: Tue, 18 May 2021 22:43:11 +0200
Subject: [Tutor] Using trigonometry to draw a circle
In-Reply-To: <5a3f60b1-777c-4842-1dd1-9e940f1e059e@gmail.com>
References: <075c43b7-ffee-937c-03ab-6cf32dba695f@gmail.com>
 <CAPM-O+yajai=wwSLiWXGADdghbBpYBJ5AOooOTsfHN-hWmRT6w@mail.gmail.com>
 <5a3f60b1-777c-4842-1dd1-9e940f1e059e@gmail.com>
Message-ID: <s818sv$9p6$1@ciao.gmane.io>

Phil schreef op 18/05/2021 om 10:30:
> On 18/5/21 6:12 pm, Joel Goldstick wrote:
>> On Tue, May 18, 2021 at 3:23 AM Phil <phillor9 at gmail.com> wrote:
> That should have been:
> 
> x = math.cos(angle * 6.28 / 360) * radius + x_centre

Even better: Python has a function for converting degrees to radians:

x = math.cos(math.radians(angle)) * radius + c_centre

There's also math.degrees() for the reverse operation, converting 
radians to degrees.


-- 
"Honest criticism is hard to take, particularly from a relative, a
friend, an acquaintance, or a stranger."
         -- Franklin P. Jones

Roel Schroeven


From phillor9 at gmail.com  Tue May 18 19:16:36 2021
From: phillor9 at gmail.com (Phil)
Date: Wed, 19 May 2021 09:16:36 +1000
Subject: [Tutor] Using trigonometry to draw a circle
In-Reply-To: <s818sv$9p6$1@ciao.gmane.io>
References: <075c43b7-ffee-937c-03ab-6cf32dba695f@gmail.com>
 <CAPM-O+yajai=wwSLiWXGADdghbBpYBJ5AOooOTsfHN-hWmRT6w@mail.gmail.com>
 <5a3f60b1-777c-4842-1dd1-9e940f1e059e@gmail.com> <s818sv$9p6$1@ciao.gmane.io>
Message-ID: <a3f65c46-a5f1-f1e6-6fbd-fb9ce7dd13e7@gmail.com>

On 19/5/21 6:43 am, Roel Schroeven wrote:
> Even better: Python has a function for converting degrees to radians:
>
Thanks Roel,
> x = math.cos(math.radians(angle)) * radius + c_centre
I had replied too quickly and remembered math.radians() during the early 
hours of this morning. Perhaps I shouldn't dash off an e-mail until the 
next morning in future.
>
> There's also math.degrees() for the reverse operation, converting 
> radians to degrees.

This could be useful, I'll file it away for future reference.

-- 

Regards,
Phil


From phillor9 at gmail.com  Tue May 18 20:10:56 2021
From: phillor9 at gmail.com (Phil)
Date: Wed, 19 May 2021 10:10:56 +1000
Subject: [Tutor] Using trigonometry to draw a circle
In-Reply-To: <CAMPXz=q_RYn6Sjb7p2wY1dxTgsOc3VJ7Tusb9_d6NUiaq0C+tg@mail.gmail.com>
References: <075c43b7-ffee-937c-03ab-6cf32dba695f@gmail.com>
 <s7vuit$4eb$1@ciao.gmane.io> <de9d8dcc-5f55-3625-cea8-fe2549a89488@gmail.com>
 <CAMPXz=q_RYn6Sjb7p2wY1dxTgsOc3VJ7Tusb9_d6NUiaq0C+tg@mail.gmail.com>
Message-ID: <296b335c-8329-11b3-e51c-c22a598b7de9@gmail.com>

On 18/5/21 8:06 pm, David wrote:

>> wxPython's addArc function, for example, works well but I cannot see how
>> I can set points along the arc. If I plot individual points to generate
>> an arc then setting points along the arc is easy.

> Depending on why you are doing this, there are different approaches
> that might or might not be a good idea. So you will get better advice
> if you describe the bigger picture of what you are doing, not the details.

Thanks David,

At the moment I'm playing with wxPython and I'm reluctant to go too 
deeply into wxPython code because this is not a wxPython list. I'm 
trying to simulate an analogue meter and the current approach is to use 
the path.AddArc function to draw the meter arc. Now I'd like to add 
ticks along the arc; I cannot see how to do this.

So now I'm experimenting with drawing the arc with a for loop to 
calculate each point and then setting the points on the frame. So far so 
good, now to add the ticks. The ticks should be short lines centred on 
the arc and extending a little on each side of the arc towards the 
centre of the arc. As I see it, this requires more calculations to 
determine the end points of the ticks. I have the x, y coordinates of 
where the ticks should be centred on the arc, I know the length of the 
ticks and I know the distance to the centre of the arc.

Another approach that I've considered is to draw the meter in a drawing 
application, or use the Python pil library. Then I could display the 
meter and rotate the needle about it's pivot point. I haven't looked 
into the finer points of this approach but it would avoid lots of 
calculations every time the meter has to be updated.

Your matplotlib code is very close to what I have in mind and I've saved it.

-- 

Regards,
Phil


From alan.gauld at yahoo.co.uk  Wed May 19 15:41:51 2021
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Wed, 19 May 2021 20:41:51 +0100
Subject: [Tutor] Using trigonometry to draw a circle
In-Reply-To: <296b335c-8329-11b3-e51c-c22a598b7de9@gmail.com>
References: <075c43b7-ffee-937c-03ab-6cf32dba695f@gmail.com>
 <s7vuit$4eb$1@ciao.gmane.io> <de9d8dcc-5f55-3625-cea8-fe2549a89488@gmail.com>
 <CAMPXz=q_RYn6Sjb7p2wY1dxTgsOc3VJ7Tusb9_d6NUiaq0C+tg@mail.gmail.com>
 <296b335c-8329-11b3-e51c-c22a598b7de9@gmail.com>
Message-ID: <s83plv$rm1$1@ciao.gmane.io>

On 19/05/2021 01:10, Phil wrote:

> trying to simulate an analogue meter and the current approach is to use 
> the path.AddArc function to draw the meter arc. Now I'd like to add 
> ticks along the arc; I cannot see how to do this.

The normal way to do this is draw a meter in a drawing package,
save it as a png or gif file and display that. Then use the
graphics library to draw the needle at the appropriate angle
on top of the meter. This is common in photo-realistic GUIs
(as often used in lab tools etc), sometimes even taking a
photo of a real meter as a starting point.


-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos



From phillor9 at gmail.com  Wed May 19 19:43:10 2021
From: phillor9 at gmail.com (Phil)
Date: Thu, 20 May 2021 09:43:10 +1000
Subject: [Tutor] Using trigonometry to draw a circle
In-Reply-To: <s83plv$rm1$1@ciao.gmane.io>
References: <075c43b7-ffee-937c-03ab-6cf32dba695f@gmail.com>
 <s7vuit$4eb$1@ciao.gmane.io> <de9d8dcc-5f55-3625-cea8-fe2549a89488@gmail.com>
 <CAMPXz=q_RYn6Sjb7p2wY1dxTgsOc3VJ7Tusb9_d6NUiaq0C+tg@mail.gmail.com>
 <296b335c-8329-11b3-e51c-c22a598b7de9@gmail.com> <s83plv$rm1$1@ciao.gmane.io>
Message-ID: <6a9cc8f3-1fc9-f20a-bb91-f6315a99b2ab@gmail.com>

On 20/5/21 5:41 am, Alan Gauld via Tutor wrote:

> The normal way to do this is draw a meter in a drawing package,
> save it as a png or gif file and display that. Then use the
> graphics library to draw the needle at the appropriate angle
> on top of the meter. This is common in photo-realistic GUIs
> (as often used in lab tools etc), sometimes even taking a
> photo of a real meter as a starting point.

Thank you Alan and everyone else who offered advice. Simply discussing a 
problem often leads to a solution.

I? started drawing a meter, and a needle, ( I might now see if I can 
find a photo on the Internet) yesterday and while doing that I had a 
thought. I now have a working meter class and a viewer class that 
displays two meters, in different colours, with tick marks. So far the 
meters have a fixed scale of 0 to 5.

I'm not sure what I'll do with it, (probably nothing) perhaps display 
humidity and temperature.

-- 

Regards,
Phil


From robertvstepp at gmail.com  Fri May 21 20:25:29 2021
From: robertvstepp at gmail.com (boB Stepp)
Date: Fri, 21 May 2021 19:25:29 -0500
Subject: [Tutor] Best way to save a D&D-like game's state?
Message-ID: <CANDiX9LSeH8OjEatKf3y0n0XFWy=+9xj=ED92oPA78u0EMmejg@mail.gmail.com>

I am contemplating the design of a D&D-like game where I will
prototype various ideas I have in Python.  Currently I am pondering
how such games typically have their state saved.  I imagine there will
be plenty of custom data types, which represent the state of the game
world when the players save.  I imagine the data involved could reach
sizable proportions, depending on how complex and rich the game
becomes.  The first thing that comes to mind is the pickle module,
which my understanding is that it can save and restore any custom data
types done in Python.  Next that comes to mind is JSON, but my
understanding is that it is limited in what it can save and restore
without additional work by the programmer.  Still staying in the
standard library I suppose an SQLite database could be made to work.

Questions:

1)  First off, am I thinking along the correct lines of doing this, or
is there a better way?

2)  If it does become true that sizable amounts of data need to be
stored, which of the above options is most performant?  Thinking about
this I suppose that in the case of large amounts of world data one
would want to divide up the data into logical units and only load what
is currently needed at any point in the game.

3)  Algorithmically, how would one perform incremental saves?  I know
this is done by many programs, so that only the changes to the
original data are stored, which saves (pun intended) on the amount of
data that needs to be saved.

4)  I am not adverse to considering third party libraries.  If I do
so, YAML also comes to mind.  I have no idea what other formats might
be worth considering.  I hope XML is not a serious option as I have
heard that it can turn into a mess with data files not easily parsable
by human readers.  Though I must add that some of the programs I work
with at work use XML and I have had no difficulty reading and editing
their data files at need in small ways, so perhaps I am unduly
prejudiced against XML?

5)  If this project proceeds to fruition then it is entirely possible
that portions or all of it will need to be rewritten in a more
hardware performant language.  If that proves to become the case will
that alter any of your answers to the above questions?

TIA!
boB Stepp

From cs at cskk.id.au  Fri May 21 21:03:56 2021
From: cs at cskk.id.au (Cameron Simpson)
Date: Sat, 22 May 2021 11:03:56 +1000
Subject: [Tutor] Best way to save a D&D-like game's state?
In-Reply-To: <CANDiX9LSeH8OjEatKf3y0n0XFWy=+9xj=ED92oPA78u0EMmejg@mail.gmail.com>
References: <CANDiX9LSeH8OjEatKf3y0n0XFWy=+9xj=ED92oPA78u0EMmejg@mail.gmail.com>
Message-ID: <YKhYfJ0uS3eC1YR4@cskk.homeip.net>

On 21May2021 19:25, boB Stepp <robertvstepp at gmail.com> wrote:
>I am contemplating the design of a D&D-like game where I will
>prototype various ideas I have in Python.  Currently I am pondering
>how such games typically have their state saved.  I imagine there will
>be plenty of custom data types, which represent the state of the game
>world when the players save.  I imagine the data involved could reach
>sizable proportions, depending on how complex and rich the game
>becomes.  The first thing that comes to mind is the pickle module,
>which my understanding is that it can save and restore any custom data
>types done in Python.

Pretty much. There are things that are not pickleable (I gather) and 
ways to accomodate that, either by adding support to the approriate 
class or by choosing to not save the object (eg a live database 
connection).

>Next that comes to mind is JSON, but my
>understanding is that it is limited in what it can save and restore
>without additional work by the programmer.

Yes, but I would use this as the first cut myself. You just need to make 
sure that things can be serialised to JSON and deserialised. I tend to 
give classes an as_dict() method to return a dict containing only things 
JSONable for that instance's state, and would be inclined to make a 
factory method from_dict(d) to instantiate an instance from a dict.

Then saving becomes f.write(json.dumps(obj.as_dict())) and loading 
becomes ObjClass.from_dict(json.load(f)).

If you've got a "root" object representing the whole game state you 
could have its as_dict() method call the as_dict() methods for the 
subsidiary objects, and so on.

This is ok for small things; it scales less well for large data. But 
might be fin for a D&D game.

>Still staying in the
>standard library I suppose an SQLite database could be made to work.

Aye, or step up to something with an ORM like SQLAlchemy. That requires 
you to cast all your db state as ORM objects - then doing things in the 
game causes writes to the db as you go. You need to define a schema and 
so on; it might be easier to start with JSON, get things right, then 
_if_ JSON becomes too cumbersome, then make an ORM from you mature data 
structures. You might want an import/export for JSON still - if nothing 
else it would aid the transition to a db :-)

Cheers,
Cameron Simpson <cs at cskk.id.au>

From leamhall at gmail.com  Fri May 21 21:07:34 2021
From: leamhall at gmail.com (Leam Hall)
Date: Fri, 21 May 2021 21:07:34 -0400
Subject: [Tutor] Best way to save a D&D-like game's state?
In-Reply-To: <CANDiX9LSeH8OjEatKf3y0n0XFWy=+9xj=ED92oPA78u0EMmejg@mail.gmail.com>
References: <CANDiX9LSeH8OjEatKf3y0n0XFWy=+9xj=ED92oPA78u0EMmejg@mail.gmail.com>
Message-ID: <c1c0109f-de51-1806-c726-8542b1368588@gmail.com>

I'll share my own thoughts, though please keep in mind that I'm not the best programmer out there.

Text files for single item things that will go in short lists.
	https://github.com/makhidkarun/perl_tools/blob/master/data/encounter_people.txt

CSV (colon, actually) for datasets that need a little structure.
	https://github.com/makhidkarun/perl_tools/blob/master/data/ships.csv

JSON is my goto for very structured data storage.
	(From an archived repo)
	$ more resources.json
	{
	  "cash": 250000,
	  "cargo": {
	    "textiles": 3,
	    "spice": 5,
	    "weapons": 9,
	    "medicinals": 30
	  },
	  "location": "Birach"
	}

SQLite if the data needs to be searched, and maybe joined.
	(This is just a simple table DB with for a random item from it)
	https://github.com/makhidkarun/Names/blob/master/getName.py
	https://github.com/makhidkarun/perl_tools/blob/master/data/names.db


I also prefer staying with the Standard Library as much as possible. YAML is nice, and I've recovered from looking at XML, so my choices are based on that. If you need to do incremental saves, it depends on how many processes you're running. If you only have one instance running at a time, dumping a dict to a JSON based file is easy. If you will have multiple instances running, you'll need a database to lock the table/row/cell.

For most of my work I use very simple files and build the objects as needed. Thus a JSON file might be loaded into a dict or a line from a CSV split into a list, and then that data passed to the object creation process.

For the record, I tend to program around Traveller. It's actually much easier to code around, though earlier editions of D&D aren't too bad. If you're talking about the later editions, I would recommend a NoSQL solution like MongoDB. SQLite requires structured data before you build the tables, MongoDB/NoSQL doesn't. You can get on-line classes for both, and usually for free.

Don't worry about performance. Not yet, and likely not ever. Python and any of the above will respond faster than you can type the query.

If you're really hyped, figure out the basics and then get a free AWS account. You can use SQL or DynamoDB, Python, and AWS Lambda for lots of things.

Leam



On 5/21/21 8:25 PM, boB Stepp wrote:
> I am contemplating the design of a D&D-like game where I will
> prototype various ideas I have in Python.  Currently I am pondering
> how such games typically have their state saved.  I imagine there will
> be plenty of custom data types, which represent the state of the game
> world when the players save.  I imagine the data involved could reach
> sizable proportions, depending on how complex and rich the game
> becomes.  The first thing that comes to mind is the pickle module,
> which my understanding is that it can save and restore any custom data
> types done in Python.  Next that comes to mind is JSON, but my
> understanding is that it is limited in what it can save and restore
> without additional work by the programmer.  Still staying in the
> standard library I suppose an SQLite database could be made to work.
> 
> Questions:
> 
> 1)  First off, am I thinking along the correct lines of doing this, or
> is there a better way?
> 
> 2)  If it does become true that sizable amounts of data need to be
> stored, which of the above options is most performant?  Thinking about
> this I suppose that in the case of large amounts of world data one
> would want to divide up the data into logical units and only load what
> is currently needed at any point in the game.
> 
> 3)  Algorithmically, how would one perform incremental saves?  I know
> this is done by many programs, so that only the changes to the
> original data are stored, which saves (pun intended) on the amount of
> data that needs to be saved.
> 
> 4)  I am not adverse to considering third party libraries.  If I do
> so, YAML also comes to mind.  I have no idea what other formats might
> be worth considering.  I hope XML is not a serious option as I have
> heard that it can turn into a mess with data files not easily parsable
> by human readers.  Though I must add that some of the programs I work
> with at work use XML and I have had no difficulty reading and editing
> their data files at need in small ways, so perhaps I am unduly
> prejudiced against XML?
> 
> 5)  If this project proceeds to fruition then it is entirely possible
> that portions or all of it will need to be rewritten in a more
> hardware performant language.  If that proves to become the case will
> that alter any of your answers to the above questions?
> 
> TIA!
> boB Stepp
> _______________________________________________
> Tutor maillist  -  Tutor at python.org
> To unsubscribe or change subscription options:
> https://mail.python.org/mailman/listinfo/tutor
> 

-- 
Site Reliability Engineer  (reuel.net/resume)
Scribe: The Domici War     (domiciwar.net)
General Ne'er-do-well      (github.com/LeamHall)

From leamhall at gmail.com  Fri May 21 21:14:49 2021
From: leamhall at gmail.com (Leam Hall)
Date: Fri, 21 May 2021 21:14:49 -0400
Subject: [Tutor] Best way to save a D&D-like game's state?
In-Reply-To: <CANDiX9LSeH8OjEatKf3y0n0XFWy=+9xj=ED92oPA78u0EMmejg@mail.gmail.com>
References: <CANDiX9LSeH8OjEatKf3y0n0XFWy=+9xj=ED92oPA78u0EMmejg@mail.gmail.com>
Message-ID: <6b7fcee6-a357-8b3e-ee77-482b8799db3a@gmail.com>

Oh, and if you really want to blow your mind, look at Neo4J (https://neo4j.com/). You can get a map of connections with a file like:

	CREATE (sa_mcconnell:Person { name:'Spacer Apprentice Ai McConnell' });
	CREATE (larry_c:Person { name:'Larry Corona' });
	CREATE (el_dad:Person { name:'Sven Jacobs' });
	CREATE (sens_fevre:Person { name:'SubEns Myung Fevre' });
	CREATE (el_mom:Person { name:'Marie Esterhardinge' });
	CREATE (julie:Person { name:'LT Juliette Pike' });
	CREATE (ademola:Person { name:'Ademola Servant' });
	CREATE (alba:Person { name:'SLT Alba Lefron' });
	CREATE (jo_mom:Person { name:'Sulin Hua' });


On 5/21/21 8:25 PM, boB Stepp wrote:
> I am contemplating the design of a D&D-like game where I will
> prototype various ideas I have in Python.  

From leamhall at gmail.com  Fri May 21 21:31:06 2021
From: leamhall at gmail.com (Leam Hall)
Date: Fri, 21 May 2021 21:31:06 -0400
Subject: [Tutor] Best way to save a D&D-like game's state?
In-Reply-To: <CAMU2Sqxy3ZRX+TZYGMWxRO25pPB_RGCtArCvqHUXhFUrU7kxZw@mail.gmail.com>
References: <CANDiX9LSeH8OjEatKf3y0n0XFWy=+9xj=ED92oPA78u0EMmejg@mail.gmail.com>
 <6b7fcee6-a357-8b3e-ee77-482b8799db3a@gmail.com>
 <CAMU2Sqxy3ZRX+TZYGMWxRO25pPB_RGCtArCvqHUXhFUrU7kxZw@mail.gmail.com>
Message-ID: <e9306120-1d32-59cf-af78-be4009547c4f@gmail.com>

Yup, you learn and get useful stuff with every few keystrokes.

Something else to consider; start with CSV and move to JSON if you need complexity. If the structure fits in CSV then it will likely fit in SQLite, when you need a database. If the fluid structure of JSON works better, I'll point out that the internal datastore language for MongoDB looks a lot like JSON.  ;)


On 5/21/21 9:20 PM, Bryan Karsh wrote:
> 
> I absolutely love this thread. Making an rpg is fun and a great way to learn a language.
> 
> 
> On Fri, May 21, 2021 at 6:15 PM Leam Hall <leamhall at gmail.com <mailto:leamhall at gmail.com>> wrote:
> 
>     Oh, and if you really want to blow your mind, look at Neo4J (https://neo4j.com/ <https://neo4j.com/>). You can get a map of connections with a file like:
> 
>      ? ? ? ? CREATE (sa_mcconnell:Person { name:'Spacer Apprentice Ai McConnell' });
>      ? ? ? ? CREATE (larry_c:Person { name:'Larry Corona' });

> 
>     On 5/21/21 8:25 PM, boB Stepp wrote:
>      > I am contemplating the design of a D&D-like game where I will
>      > prototype various ideas I have in Python.

-- 
Site Reliability Engineer  (reuel.net/resume)
Scribe: The Domici War     (domiciwar.net)
General Ne'er-do-well      (github.com/LeamHall)


From robertvstepp at gmail.com  Fri May 21 22:31:26 2021
From: robertvstepp at gmail.com (boB Stepp)
Date: Fri, 21 May 2021 21:31:26 -0500
Subject: [Tutor] Best way to save a D&D-like game's state?
In-Reply-To: <dbmgagthmkoht666ppg2j7hp785aqguofd@4ax.com>
References: <CANDiX9LSeH8OjEatKf3y0n0XFWy=+9xj=ED92oPA78u0EMmejg@mail.gmail.com>
 <dbmgagthmkoht666ppg2j7hp785aqguofd@4ax.com>
Message-ID: <CANDiX9+17FB8Tb0eFi7ibAESKvQT2wVRYt-W1Sbstaw8267RcQ@mail.gmail.com>

On Fri, May 21, 2021 at 8:52 PM Dennis Lee Bieber <wlfraed at ix.netcom.com> wrote:
>
> On Fri, 21 May 2021 19:25:29 -0500, boB Stepp <robertvstepp at gmail.com>
> declaimed the following:
>
> >I am contemplating the design of a D&D-like game where I will
>
>         You may have to expand on what you consider a "D&D-like" game. To me, a
> true (desktop) RPG (AD&D [to date me], RuneQuest 2 [RQ3, and RQ:Roleplaying
> in Glorantha], Traveller) only have whatever statistics the players have on
> their character sheets, and whatever memory the gamemaster retains of the
> sessions. The games themselves are free-format -- anything may be
> encountered, treasures are fully random including artifacts, etc.

You may date me as well!  I started out with "Chainmail" and
"Blackmoor" booklets when I first played as a player, not a DM.

In a well-designed D&D campaign, IMO, most things of any importance
are pre-placed with at least a rough outline of how world events are
to develop time-wise.  This can be taken to as granular a design as
one has patience and inclination.  How free-form the DM makes it can
vary considerably.  Of course in classic paper, pencil and dice D&D
much of the fun comes from the spontaneous role playing by everyone.
Of course this is truly impossible to capture in its entirety with a
program.  But, nonetheless, I would like to explore the truly
difficult problem of allowing the program to be a mediator of the
players' actions and allow their range of activities to be as
unfettered as possible.  I don't know how far I will make it in such a
difficult problem, but its difficulty along with some ideas I wish to
explore are what makes it attractive to me.  Of course the big issue
is interpreting natural language.  If this can be done for at least a
reasonable subset of such language most typical actions that
adventurers might attempt can be resolved rather mechanistically.

The reason I am suspecting the data involved might grow significantly
is that if I allow the players to seriously do whatever they want then
I need to record and be able to restore how they have altered the
state of their environment.  For instance they might scrawl on a
dungeon wall, "Kilroy was here!".  Where and how that was done should
be storable and recreatable if someone revisits that location.  Or as
you say if someone empties the treasure chest then those items need to
be tracked, including if the players make alterations to such items.
Of course common stuff of no real importance need not be scrupulously
tracked *until* a player character acquires such item(s).

The real humdinger is how to manage conversations in a free-form way
that isn't highly constrained from a very limited number of choices
and to make such conversations flow sensibly.  Even creating something
even remotely satisfying to a player would be a huge, possibly
insoluble, challenge.

Anyway this is what the ever foolish boB is interested in exploring.
I may go nowhere, but in the process of exploring I am certain I will
learn much.  And if I am successful to any reasonable degree then what
I learn and create will be useful for other challenges.

Cheers!
boB Stepp

From Richard at Damon-Family.org  Fri May 21 23:10:23 2021
From: Richard at Damon-Family.org (Richard Damon)
Date: Fri, 21 May 2021 23:10:23 -0400
Subject: [Tutor] Best way to save a D&D-like game's state?
In-Reply-To: <CANDiX9LSeH8OjEatKf3y0n0XFWy=+9xj=ED92oPA78u0EMmejg@mail.gmail.com>
References: <CANDiX9LSeH8OjEatKf3y0n0XFWy=+9xj=ED92oPA78u0EMmejg@mail.gmail.com>
Message-ID: <1461404b-5a33-2d84-a882-9260a4ceb394@Damon-Family.org>

On 5/21/21 8:25 PM, boB Stepp wrote:
> I am contemplating the design of a D&D-like game where I will
> prototype various ideas I have in Python.  Currently I am pondering
> how such games typically have their state saved.  I imagine there will
> be plenty of custom data types, which represent the state of the game
> world when the players save.  I imagine the data involved could reach
> sizable proportions, depending on how complex and rich the game
> becomes.  The first thing that comes to mind is the pickle module,
> which my understanding is that it can save and restore any custom data
> types done in Python.  Next that comes to mind is JSON, but my
> understanding is that it is limited in what it can save and restore
> without additional work by the programmer.  Still staying in the
> standard library I suppose an SQLite database could be made to work.
>
> Questions:
>
> 1)  First off, am I thinking along the correct lines of doing this, or
> is there a better way?
>
> 2)  If it does become true that sizable amounts of data need to be
> stored, which of the above options is most performant?  Thinking about
> this I suppose that in the case of large amounts of world data one
> would want to divide up the data into logical units and only load what
> is currently needed at any point in the game.
>
> 3)  Algorithmically, how would one perform incremental saves?  I know
> this is done by many programs, so that only the changes to the
> original data are stored, which saves (pun intended) on the amount of
> data that needs to be saved.
>
> 4)  I am not adverse to considering third party libraries.  If I do
> so, YAML also comes to mind.  I have no idea what other formats might
> be worth considering.  I hope XML is not a serious option as I have
> heard that it can turn into a mess with data files not easily parsable
> by human readers.  Though I must add that some of the programs I work
> with at work use XML and I have had no difficulty reading and editing
> their data files at need in small ways, so perhaps I am unduly
> prejudiced against XML?
>
> 5)  If this project proceeds to fruition then it is entirely possible
> that portions or all of it will need to be rewritten in a more
> hardware performant language.  If that proves to become the case will
> that alter any of your answers to the above questions?
>
> TIA!
> boB Stepp

While not done in Python but C (and the actual source code is a bit of a
terror as its origins pre-date commonly available standard complient
compilers) is Nethack.

It does a sort of incremental save, as each level of the dungeon is
saved seperately (and the levels you aren't on sort of disappear when
you leave and come back when you return). 'Things' (Items, monsters and
you) are a bag of values, and the 'class' that they are part of knows
how to write and read that sort of thing to a save file.

My guess is that this is sort of like what pickling does in Python.


-- 
Richard Damon


From PyTutor at DancesWithMice.info  Sat May 22 02:49:41 2021
From: PyTutor at DancesWithMice.info (dn)
Date: Sat, 22 May 2021 18:49:41 +1200
Subject: [Tutor] Best way to save a D&D-like game's state?
In-Reply-To: <YKhYfJ0uS3eC1YR4@cskk.homeip.net>
References: <CANDiX9LSeH8OjEatKf3y0n0XFWy=+9xj=ED92oPA78u0EMmejg@mail.gmail.com>
 <YKhYfJ0uS3eC1YR4@cskk.homeip.net>
Message-ID: <d434766a-7e42-be35-7b5b-04e8ff55eb96@DancesWithMice.info>

On 22/05/2021 13.03, Cameron Simpson wrote:
> On 21May2021 19:25, boB Stepp <robertvstepp at gmail.com> wrote:
>> I am contemplating the design of a D&D-like game where I will
>> prototype various ideas I have in Python.  Currently I am pondering
>> how such games typically have their state saved.  I imagine there will
>> be plenty of custom data types, which represent the state of the game
>> world when the players save.  I imagine the data involved could reach
>> sizable proportions, depending on how complex and rich the game
>> becomes.  The first thing that comes to mind is the pickle module,
>> which my understanding is that it can save and restore any custom data
>> types done in Python.
> 
> Pretty much. There are things that are not pickleable (I gather) and 
> ways to accomodate that, either by adding support to the approriate 
> class or by choosing to not save the object (eg a live database 
> connection).

This is a key point. Each save-able entity should have a 'save'
subroutine - likely a method. Thus, to save an entire game, each entity
will be saved, in-turn. (so, somewhere you will need a master-list of
objects which comprise the game's data-set)

Question: What do I mean by "save".
Answer: Depends what you know, and what you are able to program, at the
time.

In other words, when you decide to change backing-store, the code within
the method is all that needs to be changed...


>> Next that comes to mind is JSON, but my
>> understanding is that it is limited in what it can save and restore
>> without additional work by the programmer.
> 
> Yes, but I would use this as the first cut myself. You just need to make 
> sure that things can be serialised to JSON and deserialised. I tend to 
> give classes an as_dict() method to return a dict containing only things 
> JSONable for that instance's state, and would be inclined to make a 
> factory method from_dict(d) to instantiate an instance from a dict.

This is the next step in method-ology (you started with the puns!).

Once you realise that there is common functionality within the various
objects' save-methods, this can be factored-out. Each object prepares
its data in a generalised form, eg serialised or dict-ed, so that a
single I/O routine can perform such tasks. With this, moving between
storage techniques/technologies becomes an even smaller code-change!


> Then saving becomes f.write(json.dumps(obj.as_dict())) and loading 
> becomes ObjClass.from_dict(json.load(f)).

Now, it becomes even easier to change between backing-stores.

Modules maketh man!


> If you've got a "root" object representing the whole game state you 
> could have its as_dict() method call the as_dict() methods for the 
> subsidiary objects, and so on.
> 
> This is ok for small things; it scales less well for large data. But 
> might be fin for a D&D game.

+1

As this is (also) a learning experience, by all means start with
pickle-ing. Once you have an appreciation for that, and have realised
its strengths and short-comings for yourself, eg speed and
read/testability, then move to JSON.

As speed is a recognised consideration, may I recommend building-in a
performance statistics-gathering module from the get-go. Assuming you
play the game in one incarnation, but then notice a performance lag (at
save-time), facts will be available. Thereafter, as you refactor/improve
the save mechanism, the improvement will be documented as well as (one
hopes) humanly-noticeable!


>> Still staying in the
>> standard library I suppose an SQLite database could be made to work.
> 
> Aye, or step up to something with an ORM like SQLAlchemy. That requires 
> you to cast all your db state as ORM objects - then doing things in the 
> game causes writes to the db as you go. You need to define a schema and 
> so on; it might be easier to start with JSON, get things right, then 
> _if_ JSON becomes too cumbersome, then make an ORM from you mature data 
> structures. You might want an import/export for JSON still - if nothing 
> else it would aid the transition to a db :-)

+1

I'm not a great fan of SQLite, but that is largely because of its 'lite'
nature, eg single-user access. However, it is a handy learning-tool
requiring little more than an import command/call to get-started!

Continuing as a learning-path, once you have learned the necessary SQL
and have become able to adapt the code, you will?may be able to justify
the effort of installing an RDBMS server, eg MySQL, MariaDB, PostgreSQL, ...

However, the increased installation-effort may also be a consideration -
if you (ever) plan to copy/deliver the code to another machine.


The spec talks about progressive-saving as well as end-of-game?session.
Such "save" routines need to be fast. So fast that they do not interfere
with play!

As a gross generalisation, NoSQL DBs are faster to write than SQL, but
slower to return specific data. The latter is less of an issue to you
(if I have understood correctly), because someone resetting a game is
not going to begrudge (reasonable) delay/latency. Accordingly, (per
@Liam) MongoDB may be a better choice. Whilst there is still an
installation step, the code-change from a JSON-file structure is minimal
and logically-identical.

Personally, I prefer RDBMS. However, that's rooted in my learning SQL so
long ago it was before Oracle and SQL/DS were $available-products. The
MongoDB people have a 'university' and (several years back) I found
their basic course readily-understandable and immediately applicable.

In such a project, where the data-set may be as extensible/in as much
flux as the code-base, the NoSQL/no-(fixed)schema is going to be much
more 'forgiving' and will demand far fewer 'boiler-plate' type
routine-changes, when code and data-sets evolve!
-- 
Regards,
=dn

From bkarsh at gmail.com  Fri May 21 21:20:29 2021
From: bkarsh at gmail.com (Bryan Karsh)
Date: Fri, 21 May 2021 18:20:29 -0700
Subject: [Tutor] Best way to save a D&D-like game's state?
In-Reply-To: <6b7fcee6-a357-8b3e-ee77-482b8799db3a@gmail.com>
References: <CANDiX9LSeH8OjEatKf3y0n0XFWy=+9xj=ED92oPA78u0EMmejg@mail.gmail.com>
 <6b7fcee6-a357-8b3e-ee77-482b8799db3a@gmail.com>
Message-ID: <CAMU2Sqxy3ZRX+TZYGMWxRO25pPB_RGCtArCvqHUXhFUrU7kxZw@mail.gmail.com>

I absolutely love this thread. Making an rpg is fun and a great way to
learn a language.


On Fri, May 21, 2021 at 6:15 PM Leam Hall <leamhall at gmail.com> wrote:

> Oh, and if you really want to blow your mind, look at Neo4J (
> https://neo4j.com/). You can get a map of connections with a file like:
>
>         CREATE (sa_mcconnell:Person { name:'Spacer Apprentice Ai
> McConnell' });
>         CREATE (larry_c:Person { name:'Larry Corona' });
>         CREATE (el_dad:Person { name:'Sven Jacobs' });
>         CREATE (sens_fevre:Person { name:'SubEns Myung Fevre' });
>         CREATE (el_mom:Person { name:'Marie Esterhardinge' });
>         CREATE (julie:Person { name:'LT Juliette Pike' });
>         CREATE (ademola:Person { name:'Ademola Servant' });
>         CREATE (alba:Person { name:'SLT Alba Lefron' });
>         CREATE (jo_mom:Person { name:'Sulin Hua' });
>
>
> On 5/21/21 8:25 PM, boB Stepp wrote:
> > I am contemplating the design of a D&D-like game where I will
> > prototype various ideas I have in Python.
> _______________________________________________
> Tutor maillist  -  Tutor at python.org
> To unsubscribe or change subscription options:
> https://mail.python.org/mailman/listinfo/tutor
>

From leamhall at gmail.com  Sat May 22 05:37:15 2021
From: leamhall at gmail.com (Leam Hall)
Date: Sat, 22 May 2021 05:37:15 -0400
Subject: [Tutor] Best way to save a D&D-like game's state?
In-Reply-To: <CANDiX9LSeH8OjEatKf3y0n0XFWy=+9xj=ED92oPA78u0EMmejg@mail.gmail.com>
References: <CANDiX9LSeH8OjEatKf3y0n0XFWy=+9xj=ED92oPA78u0EMmejg@mail.gmail.com>
Message-ID: <c5bb1a23-6b67-8231-e272-53a55644eee8@gmail.com>

On 5/21/21 8:25 PM, boB Stepp wrote:

> 5)  If this project proceeds to fruition then it is entirely possible
> that portions or all of it will need to be rewritten in a more
> hardware performant language.  If that proves to become the case will
> that alter any of your answers to the above questions?

Not mine, but I would avoid pickling and SQLAlchemy. While they are good things, they are Python specific.

Though, really, if you keep it modular you can replace parts of it with C/Go/Rust and keep the majority of it in Python.

-- 
Site Reliability Engineer  (reuel.net/resume)
Scribe: The Domici War     (domiciwar.net)
General Ne'er-do-well      (github.com/LeamHall)

From manpritsinghece at gmail.com  Sat May 22 05:51:13 2021
From: manpritsinghece at gmail.com (Manprit Singh)
Date: Sat, 22 May 2021 15:21:13 +0530
Subject: [Tutor] infinity
Message-ID: <CAO1OCwZ=MXqvDd+wrXFxfSdG4=d8=j8w4n7ftR1mNGSLrKPuRA@mail.gmail.com>

Dear sir ,

Just need to know if it is valid to use float("inf") for infinity  and
-float("inf")  for negative infinity in python ?

Regards
Manprit Singh

From alan.gauld at yahoo.co.uk  Sat May 22 06:38:57 2021
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Sat, 22 May 2021 11:38:57 +0100
Subject: [Tutor] infinity
In-Reply-To: <CAO1OCwZ=MXqvDd+wrXFxfSdG4=d8=j8w4n7ftR1mNGSLrKPuRA@mail.gmail.com>
References: <CAO1OCwZ=MXqvDd+wrXFxfSdG4=d8=j8w4n7ftR1mNGSLrKPuRA@mail.gmail.com>
Message-ID: <s8an01$il6$1@ciao.gmane.io>

On 22/05/2021 10:51, Manprit Singh wrote:
> Just need to know if it is valid to use float("inf") for infinity  and
> -float("inf")  for negative infinity in python ?

Yes it is valid, that's why it's in the language.
Whether it is wise, depends in what you are trying to do.

Mostly it does what you expect but some operations
will return nan so you need to handle that in addition
to inf itself.

-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos



From leamhall at gmail.com  Sat May 22 06:53:44 2021
From: leamhall at gmail.com (Leam Hall)
Date: Sat, 22 May 2021 06:53:44 -0400
Subject: [Tutor] Best way to save a D&D-like game's state?
In-Reply-To: <CANDiX9+17FB8Tb0eFi7ibAESKvQT2wVRYt-W1Sbstaw8267RcQ@mail.gmail.com>
References: <CANDiX9LSeH8OjEatKf3y0n0XFWy=+9xj=ED92oPA78u0EMmejg@mail.gmail.com>
 <dbmgagthmkoht666ppg2j7hp785aqguofd@4ax.com>
 <CANDiX9+17FB8Tb0eFi7ibAESKvQT2wVRYt-W1Sbstaw8267RcQ@mail.gmail.com>
Message-ID: <8a5e3d9f-dbb0-7b93-8f33-d37edc2b250d@gmail.com>

On 5/21/21 10:31 PM, boB Stepp wrote:

> But, nonetheless, I would like to explore the truly
> difficult problem of allowing the program to be a mediator of the
> players' actions and allow their range of activities to be as
> unfettered as possible. 

If you're looking at NLP, then I recommend finding an NLP specific community. They have likely already worked through the underlying solutions you're asking about.

-- 
Site Reliability Engineer  (reuel.net/resume)
Scribe: The Domici War     (domiciwar.net)
General Ne'er-do-well      (github.com/LeamHall)

From alan.gauld at yahoo.co.uk  Sat May 22 07:04:52 2021
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Sat, 22 May 2021 12:04:52 +0100
Subject: [Tutor] Best way to save a D&D-like game's state?
In-Reply-To: <CANDiX9LSeH8OjEatKf3y0n0XFWy=+9xj=ED92oPA78u0EMmejg@mail.gmail.com>
References: <CANDiX9LSeH8OjEatKf3y0n0XFWy=+9xj=ED92oPA78u0EMmejg@mail.gmail.com>
Message-ID: <s8aogl$i26$1@ciao.gmane.io>

On 22/05/2021 01:25, boB Stepp wrote:
> I am contemplating the design of a D&D-like game where I will
> prototype various ideas I have in Python.  Currently I am pondering
> how such games typically have their state saved. 

In practice its usually in a flat file since they usually load
it all into memory at startup. (the actual volumes of data are
not that big on modern computers - ie. where a few megabytes is
considered normal...

The flat file will usually have some kind of format such as
config file, XML, CSV, JSON or YAML.

Whether there is one big file with different sections
for different data types or separate files for different
types of data(settings, config, player status, etc.) seems
to be an arbitrary choice by the programmer.

> be plenty of custom data types, which represent the state of the game
> world when the players save.

Not usually. These can all be abstracted to a relatively
few data items. weapons for example equate to relative
power, effect, fuel/ammo levels etc. But there might be
many types of weapon, but for data storage it's only a
few common attributes that matter. (You may also have
a separate file for each weapon holding the features
unique to that item but the status data will be small.


> types done in Python.  Next that comes to mind is JSON, but my
> understanding is that it is limited in what it can save and restore
> without additional work by the programmer.  

There will always be extra work required, even with pickle,
because you need to be in control of what gets saved and
when. Almost inevitably you will want to write a save/load
pair of methods for each persistent object. (you could
use a persistence mixin class to simplify this)

> I suppose an SQLite database could be made to work.

Yes, both as a persistence store - although I'd prefer
JSON etc for this - but more importantly for a dynamic
store during the game using sqlite's in-memory mode of
working. That gives very fast access combined with SQL's
searching capability. The downside is having to create
the in-memory database at startup each time.

> 1)  First off, am I thinking along the correct lines of doing this, or
> is there a better way?

Yes, you are on the right lines..

> 2)  If it does become true that sizable amounts of data need to be
> stored, which of the above options is most performant?  Thinking about
> this I suppose that in the case of large amounts of world data one
> would want to divide up the data into logical units and only load what
> is currently needed at any point in the game.

That should rarely be an issue with a D&D type game. If you make it a
large multi player game it might be a problem, although then you'll be
running on a server with, hopefully, bigger RAM/disk capacity. All of
the options discussed will happily scale up to several hundred
megabytes of data.

> 3)  Algorithmically, how would one perform incremental saves?  I know
> this is done by many programs, so that only the changes to the
> original data are stored, which saves (pun intended) on the amount of
> data that needs to be saved.

The standard technique is to use a dirty flag per object then in the
save() method write code like:

def save(self):
   if self.isDirty():
      self.store()

Where self.store() is the function that writes the object state
to storage. self.save() is probably an inherited method of the
persistence mixin while self.store() will be an abstract method
of the mixin implemented in each concrete object class.

self.isDirty() can be a simple getter of an attribute or it can
do a more sophisticated examination of the internal state to
see if changes are necessary. Usually a simply flag attribute
is enough and every write operation sets it to True.

> 4)  I am not adverse to considering third party libraries.  If I do
> so, YAML also comes to mind.  I have no idea what other formats might
> be worth considering.  I hope XML is not a serious option as I have
> heard that it can turn into a mess with data files not easily parsable
> by human readers.

Yes, and also hugely inefficient in storage - often up to
a 3 to one ratio of markup to content! YThis is one reason JSON
has become popular, it has a much lower size when you need to
store or transmit it.

> 5)  If this project proceeds to fruition then it is entirely possible
> that portions or all of it will need to be rewritten in a more
> hardware performant language.  If that proves to become the case will
> that alter any of your answers to the above questions?

Most D&D games do not need high performance computing so Python
should be more than capable. But if you do think its a possibility
choose a portable option such as XML, JSON, or SQLite.

The other thing to consider in that scenario is the overall structure
of the application. Keeping the areas that might need to be rewritten
separate from bits that don;t might reduce the amount of code to be
ported. That's usually a much bigger issue than converting the data storage!

Finally, somebody else suggested a NoSQL database such as Mongo
and while that would indeed be a good choice, it does add a whole
extra layer of learning. (Assuming you are familiar with
regular SQL, or JSON etc. but not with Mongo)

-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos



From robertvstepp at gmail.com  Sat May 22 20:45:18 2021
From: robertvstepp at gmail.com (boB Stepp)
Date: Sat, 22 May 2021 19:45:18 -0500
Subject: [Tutor] Best way to save a D&D-like game's state?
In-Reply-To: <8a5e3d9f-dbb0-7b93-8f33-d37edc2b250d@gmail.com>
References: <CANDiX9LSeH8OjEatKf3y0n0XFWy=+9xj=ED92oPA78u0EMmejg@mail.gmail.com>
 <dbmgagthmkoht666ppg2j7hp785aqguofd@4ax.com>
 <CANDiX9+17FB8Tb0eFi7ibAESKvQT2wVRYt-W1Sbstaw8267RcQ@mail.gmail.com>
 <8a5e3d9f-dbb0-7b93-8f33-d37edc2b250d@gmail.com>
Message-ID: <CANDiX9KsM3Jd+9SPXUyUxf66H1sXg=bx8fKucix5wGimEAcWgA@mail.gmail.com>

On Sat, May 22, 2021 at 5:54 AM Leam Hall <leamhall at gmail.com> wrote:
>
> On 5/21/21 10:31 PM, boB Stepp wrote:
>
> > But, nonetheless, I would like to explore the truly
> > difficult problem of allowing the program to be a mediator of the
> > players' actions and allow their range of activities to be as
> > unfettered as possible.
>
> If you're looking at NLP, then I recommend finding an NLP specific community. They have likely already worked through the underlying solutions you're asking about.

I was just answering Dennis' question.  I am very far away from this
aspect of the project.  In fact it will probably be the very last
thing I tackle.  Right now I am just trying to consider the overall
architecture and anticipate troublesome areas.  My actual effort to
start coding will be *very* iterative.  I already have most of the
game content settled on where I can "control" the game play
environment in a way I don't think it will seem arbitrary or
artificial to a potential player.  That is, I think I have good story
lines planned out that make sense in their own context.  Step 1 will
be to develop a text adventure version of this so I don't have to
worry about a GUI much less art and 3D graphics.  In this I will try
to implement my ideas for allowing free-form play for the players.  I
have an idea to restrict the language issues to a manageable subset
that I think will allow players to do many more things than I am
currently aware of any other game allowing.  This will be challenging
enough for a start.  *If* I make serious inroads on this I will
consider what to tackle next.

But going back to your point I have read a tutorial on NLTK and
explored the project a bit to get a feel of what is currently doable
with language interpretation and processing.

So my original questions were strictly on-topic Python related as I
will have to deal with saving almost immediately once I start coding,
and I don't want to make a stupid decision on file formats that I will
regret and have to go back and fix later.

boB Stepp

From cs at cskk.id.au  Sat May 22 22:49:44 2021
From: cs at cskk.id.au (Cameron Simpson)
Date: Sun, 23 May 2021 12:49:44 +1000
Subject: [Tutor] Best way to save a D&D-like game's state?
In-Reply-To: <CANDiX9KsM3Jd+9SPXUyUxf66H1sXg=bx8fKucix5wGimEAcWgA@mail.gmail.com>
References: <CANDiX9KsM3Jd+9SPXUyUxf66H1sXg=bx8fKucix5wGimEAcWgA@mail.gmail.com>
Message-ID: <YKnCyLCPX4pzrvfG@cskk.homeip.net>

On 22May2021 19:45, boB Stepp <robertvstepp at gmail.com> wrote:
>So my original questions were strictly on-topic Python related as I
>will have to deal with saving almost immediately once I start coding,
>and I don't want to make a stupid decision on file formats that I will
>regret and have to go back and fix later.

One thing not mentioned, I think, (including by me) is that saving to a 
text file eg JSON means you can just visually inspect the file with a 
text editor by eye. That is very useful, and not nearly as convenient 
with a database.

Cheers,
Cameron Simpson <cs at cskk.id.au>

From phillor9 at gmail.com  Sun May 23 03:28:56 2021
From: phillor9 at gmail.com (Phil)
Date: Sun, 23 May 2021 17:28:56 +1000
Subject: [Tutor] Expecting a float but get an int
Message-ID: <9cbb376f-ef4a-e808-5ab3-d4122a4bafc2@gmail.com>

Help please.

This function returns "a" as .7 and "b" as 0 instead of .7. I'm sure the 
reason is obvious but I cannot see what it is.

def slope_intercept(x1, x2, y1, y2):
 ??? a = (y2 - y1) / (x2 - x1) # a = .7 which is correct
 ??? #a = .7

 ??? b = (y1 - (a * x1) # b = 0 where it should be .7
 ??? return a, b

slope, intercept = slope_intercept(9, 0, 7, 0)
print("slope :", slope, "intercept :", intercept)

This is what I've tried:

 ??? a = float((y2 - y1) / (x2 - x1))

 ??? b = float((y1 - (a * x1))

In the function:

x1 = float(x1)

the same for x2, y1, y2

The debugger show "a" and "b" to be floats.

The only way that I can have "b" show the correct answer is if I 
specifically make a = .7.

What have I overlooked?

-- 
Regards,
Phil


From alan.gauld at yahoo.co.uk  Sun May 23 04:21:19 2021
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Sun, 23 May 2021 09:21:19 +0100
Subject: [Tutor] Expecting a float but get an int
In-Reply-To: <9cbb376f-ef4a-e808-5ab3-d4122a4bafc2@gmail.com>
References: <9cbb376f-ef4a-e808-5ab3-d4122a4bafc2@gmail.com>
Message-ID: <s8d39v$sh4$1@ciao.gmane.io>

On 23/05/2021 08:28, Phil wrote:
> Help please.
> 
> This function returns "a" as .7 and "b" as 0 instead of .7. I'm sure the 
> reason is obvious but I cannot see what it is.
> 
> def slope_intercept(x1, x2, y1, y2):
>  ??? a = (y2 - y1) / (x2 - x1) # a = .7 which is correct

It is not correct.
It should be (using your values) 0.7777777....
Or more accurately it is the rational number 7/9

>  ??? b = (y1 - (a * x1) # b = 0 where it should be .7

And this is 7 - (7/9) * 9 = 7-7 = 0

> slope, intercept = slope_intercept(9, 0, 7, 0)

The real mystery is how you get 0.7 for a...

> What have I overlooked?

Math.


-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos



From chris_roysmith at internode.on.net  Sun May 23 04:22:30 2021
From: chris_roysmith at internode.on.net (Chris Roy-Smith)
Date: Sun, 23 May 2021 18:22:30 +1000
Subject: [Tutor] Expecting a float but get an int
In-Reply-To: <9cbb376f-ef4a-e808-5ab3-d4122a4bafc2@gmail.com>
References: <9cbb376f-ef4a-e808-5ab3-d4122a4bafc2@gmail.com>
Message-ID: <ad27554c-f10f-5745-4a77-56c9073c8981@internode.on.net>

On 23/5/21 5:28 pm, Phil wrote:
> Help please.
> 
> This function returns "a" as .7 and "b" as 0 instead of .7. I'm sure the 
> reason is obvious but I cannot see what it is.
> 
> def slope_intercept(x1, x2, y1, y2):
>  ??? a = (y2 - y1) / (x2 - x1) # a = .7 which is correct
>  ??? #a = .7
> 
>  ??? b = (y1 - (a * x1) # b = 0 where it should be .7
>  ??? return a, b
> 
> slope, intercept = slope_intercept(9, 0, 7, 0)
> print("slope :", slope, "intercept :", intercept)
> 
> This is what I've tried:
> 
>  ??? a = float((y2 - y1) / (x2 - x1))
> 
>  ??? b = float((y1 - (a * x1))
> 
> In the function:
> 
> x1 = float(x1)
> 
> the same for x2, y1, y2
> 
> The debugger show "a" and "b" to be floats.
> 
> The only way that I can have "b" show the correct answer is if I 
> specifically make a = .7.
> 
> What have I overlooked?
> 
Hi,
try making the values for x1, x2, y1, y2 floats before calling the 
function. Python does integer math on integers. even making one value in 
each calculation a float will make python to do floating point math.

regards,
Chris

From phillor9 at gmail.com  Sun May 23 04:40:26 2021
From: phillor9 at gmail.com (Phil)
Date: Sun, 23 May 2021 18:40:26 +1000
Subject: [Tutor] Expecting a float but get an int
In-Reply-To: <s8d39v$sh4$1@ciao.gmane.io>
References: <9cbb376f-ef4a-e808-5ab3-d4122a4bafc2@gmail.com>
 <s8d39v$sh4$1@ciao.gmane.io>
Message-ID: <98162fd6-d7ef-47b9-964f-06f06528e754@gmail.com>

On 23/5/21 6:21 pm, Alan Gauld via Tutor wrote:

  ??? a = (y2 - y1) / (x2 - x1) # a = .7 which is correct

> It is not correct.
> It should be (using your values) 0.7777777....

Thanks Alan,

I was chasing an error that didn't exist.

-- 

Regards,
Phil


From PyTutor at DancesWithMice.info  Sun May 23 04:40:33 2021
From: PyTutor at DancesWithMice.info (dn)
Date: Sun, 23 May 2021 20:40:33 +1200
Subject: [Tutor] Expecting a float but get an int
In-Reply-To: <9cbb376f-ef4a-e808-5ab3-d4122a4bafc2@gmail.com>
References: <9cbb376f-ef4a-e808-5ab3-d4122a4bafc2@gmail.com>
Message-ID: <55b061ba-aea0-b913-d2aa-03fb62723f52@DancesWithMice.info>

On 23/05/2021 19.28, Phil wrote:
> This function returns "a" as .7 and "b" as 0 instead of .7. I'm sure the
> reason is obvious but I cannot see what it is.
> 
> def slope_intercept(x1, x2, y1, y2):
> ??? a = (y2 - y1) / (x2 - x1) # a = .7 which is correct
> ??? #a = .7
> 
> ??? b = (y1 - (a * x1) # b = 0 where it should be .7
> ??? return a, b
> 
> slope, intercept = slope_intercept(9, 0, 7, 0)
> print("slope :", slope, "intercept :", intercept)
> 
> This is what I've tried:
> 
> ??? a = float((y2 - y1) / (x2 - x1))
> 
> ??? b = float((y1 - (a * x1))
> 
> In the function:
> 
> x1 = float(x1)
> 
> the same for x2, y1, y2
> 
> The debugger show "a" and "b" to be floats.
> 
> The only way that I can have "b" show the correct answer is if I
> specifically make a = .7.
> 
> What have I overlooked?

Have you confused which parameter corresponds to the Cartesian
coordinates, eg "slope_intercept(9, 0, 7, 0)" is operating on the
coordinates (9, 7) and (0, 0). Doesn't any line mentioning the origin
have zero as its intercept? (it's late here and I'm sleepy)

The way to test is to add more print statements, even "print( a * x1 )"
to be sure that the small component of the calculation is working to spec!

If you are convinced it is a typing problem, then print the type( object
) value to be sure, maybe even adding typing meta-data to the parameters...
-- 
Regards =dn

-- 
Regards,
=dn

From DomainAdmin at DancesWithMice.info  Sun May 23 04:17:36 2021
From: DomainAdmin at DancesWithMice.info (David L Neil)
Date: Sun, 23 May 2021 20:17:36 +1200
Subject: [Tutor] Expecting a float but get an int
In-Reply-To: <9cbb376f-ef4a-e808-5ab3-d4122a4bafc2@gmail.com>
References: <9cbb376f-ef4a-e808-5ab3-d4122a4bafc2@gmail.com>
Message-ID: <c0427680-c24a-15c4-d9b9-65d2ab4d0d9a@DancesWithMice.info>

On 23/05/2021 19.28, Phil wrote:
> This function returns "a" as .7 and "b" as 0 instead of .7. I'm sure the
> reason is obvious but I cannot see what it is.
> 
> def slope_intercept(x1, x2, y1, y2):
> ??? a = (y2 - y1) / (x2 - x1) # a = .7 which is correct
> ??? #a = .7
> 
> ??? b = (y1 - (a * x1) # b = 0 where it should be .7
> ??? return a, b
> 
> slope, intercept = slope_intercept(9, 0, 7, 0)
> print("slope :", slope, "intercept :", intercept)
> 
> This is what I've tried:
> 
> ??? a = float((y2 - y1) / (x2 - x1))
> 
> ??? b = float((y1 - (a * x1))
> 
> In the function:
> 
> x1 = float(x1)
> 
> the same for x2, y1, y2
> 
> The debugger show "a" and "b" to be floats.
> 
> The only way that I can have "b" show the correct answer is if I
> specifically make a = .7.
> 
> What have I overlooked?

Have you confused which parameter corresponds to the Cartesian
coordinates, eg "slope_intercept(9, 0, 7, 0)" is operating on the
coordinates (9, 7) and (0, 0). Doesn't any line mentioning the origin
have zero as its intercept? (it's late here and I'm sleepy)

The way to test is to add more print statements, even "print( a * x1 )"
to be sure that the small component of the calculation is working to spec!

If you are convinced it is a typing problem, then print the type( object
) value to be sure, maybe even adding typing meta-data to the parameters...
-- 
Regards =dn

From avulamahendra at gmail.com  Sun May 23 12:34:28 2021
From: avulamahendra at gmail.com (Mahendra)
Date: Sun, 23 May 2021 22:04:28 +0530
Subject: [Tutor] IP address changes
Message-ID: <CAN-6G3wemHOmnz3S11oLD4tAyMHv=DdAc3Bky0+L=sj+NZ4XSA@mail.gmail.com>

Hi all are being well.I want change IP address in my personal computer
using python How to apply those to pc?

Mahendra Yadav

From raimondhs at gmail.com  Fri May 21 15:46:26 2021
From: raimondhs at gmail.com (=?utf-8?Q?Raimond_Haugom_St=C3=B8mvall?=)
Date: Fri, 21 May 2021 21:46:26 +0200
Subject: [Tutor] Password
Message-ID: <2CA1EB3C-8402-419E-9F2F-1999D8360288@hotmail.com>

Hello.

I installed Python on my Mac today. When I am trying to use it, I get asked for a password. I ?have not set a password. What should I do?

-Raimond

From learn2program at gmail.com  Sun May 23 19:32:57 2021
From: learn2program at gmail.com (Alan Gauld)
Date: Mon, 24 May 2021 00:32:57 +0100
Subject: [Tutor] IP address changes
In-Reply-To: <CAN-6G3wemHOmnz3S11oLD4tAyMHv=DdAc3Bky0+L=sj+NZ4XSA@mail.gmail.com>
References: <CAN-6G3wemHOmnz3S11oLD4tAyMHv=DdAc3Bky0+L=sj+NZ4XSA@mail.gmail.com>
Message-ID: <bb09267e-7cdb-24dc-1240-c4017b9bec94@yahoo.co.uk>


On 23/05/2021 17:34, Mahendra wrote:
> Hi all are being well.I want change IP address in my personal computer
> using python How to apply those to pc?

That depends on many factors, not least your OS.


Also if you are using DHCP then the IP address is
not assigned by your computer but by your network
server (usually your gateway).


Also do you want to change the setting (so that
the PC always has that new value) or is this a
dynamic change that only applies while your program
is running?


Finally, since changing the IP address is a pretty unusual
thing to do it might help if you tell us why you want to
do it. What are you hoping to achieve? Then we might
be able to suggest an alternative strategy that is easier or
more robust.

-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos


From phillor9 at gmail.com  Sun May 23 20:22:06 2021
From: phillor9 at gmail.com (Phil)
Date: Mon, 24 May 2021 10:22:06 +1000
Subject: [Tutor] Expecting a float but get an int
In-Reply-To: <ncpkagh5amltg41vc8m4lba5oaj4quuqk3@4ax.com>
References: <9cbb376f-ef4a-e808-5ab3-d4122a4bafc2@gmail.com>
 <ncpkagh5amltg41vc8m4lba5oaj4quuqk3@4ax.com>
Message-ID: <7fcd3321-72ba-1d22-b6c4-3e554fcf04eb@gmail.com>

On 24/5/21 12:38 am, Dennis Lee Bieber wrote:
> Those lines are computing results using INTEGERS and then converting
> the integer result to a float.
>
> 	You should convert the integers to float BEFORE doing the computations
That's what I was attempting to do Dennis although it doesn't appear to 
make any difference to the result. My original question refereed to an 
error that didn't actually exist.
> if you want to be safe (though recent Python does treat "/" as a float
> division -- which always confuses me as so many other languages treat it as
> integer if both sides are integers), and the "a *" should be a float
> coercing the second equation to float.

> 	"a" and "b" are rather meaningless names
Perhaps not. The idea is to draw a line based on y = mx + b and points 
along that line. At the time of posting my question, "m" was "a" in my 
function. My confusion stems from the fact that the centre of the plane 
is 0, 0 whereas the top left corner on a computer system is 0, 0. I'm 
still working on translating between the two systems. If I simply wanted 
to plot a line then I could use wx.Python's plot library. However, 
that's not the object of this project, I'm just trying to satisfy my 
curiosity with no real aim in mind.
> 	Consider:
>
>>>> def slope_intercept(point1, point2):
> ... 	slope = (point2[1] - point1[1]) / float(point2[0] - point1[0])
> ... 	intercept = (point1[1] - slope * float(point1[0]))
> ... 	return slope, intercept

Point taken, a list of tuples is a good idea.

-- 

Regards,
Phil


From robertvstepp at gmail.com  Sun May 23 20:43:50 2021
From: robertvstepp at gmail.com (boB Stepp)
Date: Sun, 23 May 2021 19:43:50 -0500
Subject: [Tutor] Password
In-Reply-To: <2CA1EB3C-8402-419E-9F2F-1999D8360288@hotmail.com>
References: <2CA1EB3C-8402-419E-9F2F-1999D8360288@hotmail.com>
Message-ID: <CANDiX9J9xm=gb506k2FTzZAztCshUM5RLrB9TVV=-UgWfjkMRA@mail.gmail.com>

On Sun, May 23, 2021 at 5:24 PM Raimond Haugom St?mvall
<raimondhs at gmail.com> wrote:

> I installed Python on my Mac today. When I am trying to use it, I get asked for a password. I ?have not set a password. What should I do?

I don't own a Mac, so I have no direct experience to help.  But I do
know that Python does not require a password to run.  First a link
that might help you solve your own problem:

https://docs.python.org/3/using/mac.html

If this does not help, then you need to provide more information:

1)  How exactly did you install Python and what version did you install?

2)  What is the exact version of your Mac OS?

3)  How did you try to "run" Python?  Normally you can either fire up
IDLE, which should appear in your list of programs, perhaps in a
Python folder?  The other way is to open up a terminal window and type
"python3".  This latter way would put you in the Python interpreter
where you can type in Python commands and see what happens.  The final
way to run Python is to create a file containing Python commands and
then executing that Python program, either from inside IDLE, an IDE or
editor you like, or from the command line, say by typing "python3
<name/path of your program file>.

HTH!
boB Stepp

From robertvstepp at gmail.com  Sun May 23 21:21:42 2021
From: robertvstepp at gmail.com (boB Stepp)
Date: Sun, 23 May 2021 20:21:42 -0500
Subject: [Tutor] Best way to save a D&D-like game's state?
In-Reply-To: <YKnCyLCPX4pzrvfG@cskk.homeip.net>
References: <CANDiX9KsM3Jd+9SPXUyUxf66H1sXg=bx8fKucix5wGimEAcWgA@mail.gmail.com>
 <YKnCyLCPX4pzrvfG@cskk.homeip.net>
Message-ID: <CANDiX9+gtoAzOuyVhUbsVTxrE0nkbk7DuoovDf4SU9_vz2hgDg@mail.gmail.com>

Thank you very much to all who took their time to respond to my
questions.  I now believe I have a much better understanding of my
options and how to go forward.  I am sure once implementation time
comes around, I will have more to ask!

Cheers!
boB Stepp

From bryan.m.obrien at gmail.com  Sun May 23 20:58:32 2021
From: bryan.m.obrien at gmail.com (Bryan O'Brien)
Date: Sun, 23 May 2021 19:58:32 -0500
Subject: [Tutor] Password
In-Reply-To: <2CA1EB3C-8402-419E-9F2F-1999D8360288@hotmail.com>
References: <2CA1EB3C-8402-419E-9F2F-1999D8360288@hotmail.com>
Message-ID: <D48FE000-A0BC-4216-A1D9-443008C2296D@gmail.com>

Thanks to this mailing list, I have a bit of python skill (and use a Mac daily).  

Can you post the exact error message you're seeing and the versions of MacOS AND Python?

> On May 23, 2021, at 17:24, Raimond Haugom St?mvall <raimondhs at gmail.com> wrote:
> 
> ?Hello.
> 
> I installed Python on my Mac today. When I am trying to use it, I get asked for a password. I ?have not set a password. What should I do?
> 
> -Raimond
> _______________________________________________
> Tutor maillist  -  Tutor at python.org
> To unsubscribe or change subscription options:
> https://mail.python.org/mailman/listinfo/tutor

From roel at roelschroeven.net  Mon May 24 11:02:59 2021
From: roel at roelschroeven.net (Roel Schroeven)
Date: Mon, 24 May 2021 17:02:59 +0200
Subject: [Tutor] Expecting a float but get an int
In-Reply-To: <ad27554c-f10f-5745-4a77-56c9073c8981@internode.on.net>
References: <9cbb376f-ef4a-e808-5ab3-d4122a4bafc2@gmail.com>
 <ad27554c-f10f-5745-4a77-56c9073c8981@internode.on.net>
Message-ID: <s8gf73$idu$1@ciao.gmane.io>

Chris Roy-Smith schreef op 23/05/2021 om 10:22:
> try making the values for x1, x2, y1, y2 floats before calling the
> function. Python does integer math on integers. even making one value in
> each calculation a float will make python to do floating point math.

That's not correct anymore. In Python 3 (and optionally in Python 2, if 
you do 'from __future__ import division'), the division operator (/) 
yields a float even for integers. The floor division operator (//) on 
the other hand yields an integer for integer operands, a float if one of 
the operands is a float.


 >>> 4/3
1.3333333333333333
 >>> 4.0/3.0
1.3333333333333333
 >>> 4//3
1
 >>> 4.0//3.0
1.0

-- 
"Honest criticism is hard to take, particularly from a relative, a
friend, an acquaintance, or a stranger."
         -- Franklin P. Jones

Roel Schroeven


From sccdzt at foxmail.com  Tue May 25 08:47:34 2021
From: sccdzt at foxmail.com (=?gb18030?B?Q1BFQ0PVxczO?=)
Date: Tue, 25 May 2021 15:47:34 +0300
Subject: [Tutor] Python Crawl problem help
Message-ID: <tencent_BCE2EEE4D6B6BD0BC30D2FD16CD090561606@qq.com>

Dear sir :
Could you please help solve the below problem that can not run and the result is 
"E:\Python Data Visualization\Scripts\python.exe" "E:/Python Data Visualization/??/wallpaper2.py"
None
Traceback (most recent call last):
&nbsp; File "E:/Python Data Visualization/??/wallpaper2.py", line 52, in <module&gt;
&nbsp; &nbsp; start()
&nbsp; File "E:/Python Data Visualization/??/wallpaper2.py", line 49, in start
&nbsp; &nbsp; imgs=getimgdata(page)
&nbsp; File "E:/Python Data Visualization/??/wallpaper2.py", line 28, in getimgdata
&nbsp; &nbsp; for item in content_list.find_all('figure'):
AttributeError: 'NoneType' object has no attribute 'find_all'


Process finished with exit code 1



import requests
import re
import time
import os
from bs4 import BeautifulSoup
import urllib


def getpage():
    url='https://www.zhihu.com/question/451014453/answer/1797338225'
    headers={'User-Agent': 'Mozilla/5.0 (Windows NT 6.1;'
                       'Win64; x64) AppleWebKit/537.36 (KHTML, like'
                       'Gecko) Chrome/69.0.3497.100'
                       'Safari/537.36','Referer': "https://www.zhihu.com"
                       "/question/37787176"}
    try:
        r = requests.get(url, headers=headers).content
        return r
    except:
        return print('coneection error')

def getimgdata(data):
    soup=BeautifulSoup(data,'lxml')
    content_list=soup.find('div',attrs={'class':'list'})
    print(content_list)
    img_list=[]
    for item in content_list.find_all('figure'):
        img=item.find('img')['src']
        img_list.append(img)
    return img_list
def saveToDir(contents):
    img=40
    try:
        path=r'F:\Python crawler'
        if not os.path.isdir(path):
            os.makedirs(path)
        img=0
        for item in contents:
            paths=path+str(img)+'.jpg'
            time.sleep(1)
            urllib.request.urlretrieve(item,paths)
            img+=1
            print('%sDownloaded'%img)
    except Exception as e:
        print(e)
def start():
    page=getpage()
    imgs=getimgdata(page)
    saveToDir(imgs)

start()

From robertvstepp at gmail.com  Wed May 26 21:49:39 2021
From: robertvstepp at gmail.com (boB Stepp)
Date: Wed, 26 May 2021 20:49:39 -0500
Subject: [Tutor] Why does CPython cache small integers "asymmetrically"?
Message-ID: <CANDiX9+ApCRdmiumW6Z0hbW-LMSj2vr-Ma=Ne1pEK+454XeQHA@mail.gmail.com>

I often wonder how Python design decisions are reached.  I wish there
was a single go-to place for these sorts of questions!

I cannot resist asking why -- if anyone happens to know -- more
positive integers are cached than negative ones:

Python 3.9.5 (tags/v3.9.5:0a7dcbd, May  3 2021, 17:27:52) [MSC v.1928
64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> x = 256
>>> y = 256
>>> id(x)
1176492272016
>>> id(y)
1176492272016
>>> x = 257
>>> y = 257
>>> id(x)
1176503075504
>>> id(y)
1176503075408  # So Python stops caching at 2**16 on the positive side.
>>> x = -4
>>> y = -4
>>> id(x)
1176492075152
>>> id(y)
1176492075152
>>> x = -5
>>> x = -5
>>> id(x)
1176492075120
>>> id(y)
1176492075152  # But strangely (to me) stops at -2**2 on the negative side.
>>> x = 0
>>> y = 0
>>> id(x)
1176492075280  # Just to check.  ~(:>))

I suppose most people tend to stick with whole numbers.  But
nonetheless I find this a bit surprising that the negative numbers are
second class in this regard!

Cheers!
boB

From cs at cskk.id.au  Wed May 26 23:37:52 2021
From: cs at cskk.id.au (Cameron Simpson)
Date: Thu, 27 May 2021 13:37:52 +1000
Subject: [Tutor] Why does CPython cache small integers "asymmetrically"?
In-Reply-To: <CANDiX9+ApCRdmiumW6Z0hbW-LMSj2vr-Ma=Ne1pEK+454XeQHA@mail.gmail.com>
References: <CANDiX9+ApCRdmiumW6Z0hbW-LMSj2vr-Ma=Ne1pEK+454XeQHA@mail.gmail.com>
Message-ID: <YK8UEMYpxZLeZyRi@cskk.homeip.net>

On 26May2021 20:49, boB Stepp <robertvstepp at gmail.com> wrote:
>I often wonder how Python design decisions are reached.  I wish there
>was a single go-to place for these sorts of questions!
>
>I cannot resist asking why -- if anyone happens to know -- more
>positive integers are cached than negative ones:

Probably it has been judged that there are more commonly used small 
positive integers used than negative ones, maybe from some statistics (I 
can imagine that this is benchmarkable if your test cases can be 
considered representative).

The constants themselves seem to be here:

    https://github.com/python/cpython/blob/3e7ee02327db13e4337374597cdc4458ecb9e3ad/Include/internal/pycore_interp.h#L211

I have no insight into how these were chosen though.

Cheers,
Cameron Simpson <cs at cskk.id.au>

From alan.gauld at yahoo.co.uk  Thu May 27 07:44:42 2021
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Thu, 27 May 2021 12:44:42 +0100
Subject: [Tutor] Why does CPython cache small integers "asymmetrically"?
In-Reply-To: <CANDiX9+ApCRdmiumW6Z0hbW-LMSj2vr-Ma=Ne1pEK+454XeQHA@mail.gmail.com>
References: <CANDiX9+ApCRdmiumW6Z0hbW-LMSj2vr-Ma=Ne1pEK+454XeQHA@mail.gmail.com>
Message-ID: <s8o0na$3oj$1@ciao.gmane.io>

On 27/05/2021 02:49, boB Stepp wrote:
> I often wonder how Python design decisions are reached.  I wish there
> was a single go-to place for these sorts of questions!
> 
Technically this is an implementation decision, I don;t think
the Python language requires small ints to be cached, its
a purely CPython design choice and could change.

> I cannot resist asking why -- if anyone happens to know -- more
> positive integers are cached than negative ones:

I'd guess because positive ints are used way more often than
negative ones. I very rarely use a negative number literal
or even perform operations where I expect to get a negative
result. Index searches and limits and slices etc are all
specified by positive numbers except for a very few
negatives used for accessing end points(-1 thru' -5 at most!)

-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos



From patrikfougere at gmail.com  Wed May 26 21:16:37 2021
From: patrikfougere at gmail.com (Patrik Fougere)
Date: Wed, 26 May 2021 21:16:37 -0400
Subject: [Tutor] Python Error
Message-ID: <CAPjie-+iuSj5-uvqaZWzXiLiW4PvdujHCj5sJQj3v+b=xRiZoQ@mail.gmail.com>

Hi,
I'm in the infancy stage of creating a UI app and I'm still a beginner
coder. I'm running into a couple of issues and I would love any input on
how to fix it. The first issue was turning string data into datetime data
(I found an answer on google). The next issue was a value error in regards
to the input of the string data. I've attached the image to this email. If
you have any questions or advice please do not hesitate to reach out to me.
Thank you.

Please see the link below:
https://www.online-python.com/xaytwZFliC

- Patrik Fougere
"Action is the foundational key to all success - Pablo Picasso"

From sccdzt at foxmail.com  Thu May 27 01:38:39 2021
From: sccdzt at foxmail.com (=?gb18030?B?Q1BFQ0PVxczO?=)
Date: Thu, 27 May 2021 08:38:39 +0300
Subject: [Tutor] Python Scraping problem help
Message-ID: <tencent_C9073968BD21324F466C6FBB3CDC2411010A@qq.com>

Dear sir :
Could you please help solve the below problem that can run but no result ,the program is runing,but can noly retrieve one picture ,Could you help tell me how to solve this problem .
import requests
from bs4 import BeautifulSoup
import urllib
import time,os


headers={'User-Agent': 'Mozilla/5.0 (Windows NT 6.1;'
                       'Win64; x64) AppleWebKit/537.36 (KHTML, like'
                       'Gecko) Chrome/69.0.3497.100'
                       'Safari/537.36','Referer': "https://www.douban.com/group/topic/206388806/?type=rec"}
url=r'https://www.douban.com/group/topic/206388806/?type=rec'
wbdata=requests.get(url,headers=headers)
# print(response)
soup=BeautifulSoup(wbdata.content,'lxml')
imgs=soup.select('div.image-wrapper&gt;img')
# print(imgs)
number=1
for item in imgs:
    img=item.get('src')
    print(img)
    path=r'F:\Python crawler'

    if not os.path.isdir(path):
        os.makedirs(path)
    paths=path+str(number)+'.jpg'
    time.sleep(1)
    try:
        urllib.request.urlretrieve(img,paths)
        number+=1
        # print('%sDownloaded'%img)
    except:
        continue

From alan.gauld at yahoo.co.uk  Thu May 27 09:05:14 2021
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Thu, 27 May 2021 14:05:14 +0100
Subject: [Tutor] Python Error
In-Reply-To: <CAPjie-+iuSj5-uvqaZWzXiLiW4PvdujHCj5sJQj3v+b=xRiZoQ@mail.gmail.com>
References: <CAPjie-+iuSj5-uvqaZWzXiLiW4PvdujHCj5sJQj3v+b=xRiZoQ@mail.gmail.com>
Message-ID: <s8o5ea$qif$1@ciao.gmane.io>

On 27/05/2021 02:16, Patrik Fougere wrote:

> coder. I'm running into a couple of issues and I would love any input on
> how to fix it. The first issue was turning string data into datetime data
> (I found an answer on google). The next issue was a value error in regards
> to the input of the string data. I've attached the image to this email. 

Its much easier to respond to if you just copy n paste the code into the
email - as I've done below...

> from datetime import datetime

> full_name = input("Hi my name is Jacko. What is your full name?")
> print ("Hello " + full_name)

> class Jacko:
>     dob = input("Input your birthday, please: ")
>     date_of_birth = datetime.strptime(dob, '%y, %m, %d')
>     current_date = datetime.today()
>     current_age = current_date - date_of_birth

The 4 lines above should be inside the __init__() method, otherwise
you only get one person's birthday for the class not one per person..

Everything unique to an instance should be inside __init__()

>     def __init__(self, name):
>        self.name = name

>     def age (self):

This should probably be called check_age() or similar since age()
suggests that it returns the age. Its just a bit confusing.


>         self.age = self.current_age/365

And here we have a problem because you overwrite your method with data.
self.age is the method you are calling. By doing this you lose the method.

>         if self.age < 21:
>             print ("Sorry we can not create your account at this time")
>         else:
>             print ("Let's move forward with the next steps")

If you are getting a ValueError please include the full error text.
It contains lots of useful data.

-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos



From learn2program at gmail.com  Thu May 27 12:59:51 2021
From: learn2program at gmail.com (Alan Gauld)
Date: Thu, 27 May 2021 17:59:51 +0100
Subject: [Tutor] Python Scraping problem help
In-Reply-To: <s7hvaghph61p0cad8ga791418l9p54v319@4ax.com>
References: <tencent_C9073968BD21324F466C6FBB3CDC2411010A@qq.com>
 <s7hvaghph61p0cad8ga791418l9p54v319@4ax.com>
Message-ID: <8681929f-0dd6-0fe6-1590-ef0a4cfd2c23@yahoo.co.uk>


On 27/05/2021 17:33, Dennis Lee Bieber wrote:
> difference will be that enumerate counts from 0


Unless you give it a different starting number:

===================

class enumerate(object)
?|? enumerate(iterable, start=0)
?|?
?|? Return an enumerate object.
?|?
?|??? iterable
?|????? an object supporting iteration
?|?
?|? The enumerate object yields pairs containing a count (from start, which
?|? defaults to zero) and a value yielded by the iterable argument.

==================

>>> for n,v in enumerate([0,1,2,3],start=5):
	print(n,v)

5 0
6 1
7 2
8 3

-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos


From cs at cskk.id.au  Thu May 27 19:43:42 2021
From: cs at cskk.id.au (Cameron Simpson)
Date: Fri, 28 May 2021 09:43:42 +1000
Subject: [Tutor] Why does CPython cache small integers "asymmetrically"?
In-Reply-To: <YK8UEMYpxZLeZyRi@cskk.homeip.net>
References: <YK8UEMYpxZLeZyRi@cskk.homeip.net>
Message-ID: <YLAurlWosSEbYvp9@cskk.homeip.net>

On 27May2021 13:37, Cameron Simpson <cs at cskk.id.au> wrote:
>The constants themselves seem to be here:
>    https://github.com/python/cpython/blob/3e7ee02327db13e4337374597cdc4458ecb9e3ad/Include/internal/pycore_interp.h#L211

On reflection, these might just be the interned ints: some _precomputed_ 
cached ints :-) The larger range of cached int boB reports would be a 
wider range implemented programmatically at runtime.

Still no deeper insights though.

Cheers,
Cameron Simpson <cs at cskk.id.au>

From robertvstepp at gmail.com  Thu May 27 20:13:37 2021
From: robertvstepp at gmail.com (boB Stepp)
Date: Thu, 27 May 2021 19:13:37 -0500
Subject: [Tutor] Why does CPython cache small integers "asymmetrically"?
In-Reply-To: <YLAurlWosSEbYvp9@cskk.homeip.net>
References: <YK8UEMYpxZLeZyRi@cskk.homeip.net>
 <YLAurlWosSEbYvp9@cskk.homeip.net>
Message-ID: <CANDiX9KVbTcsbPo_2+Fywh2K-xqpxeQA6RGaf-To0g7ebCkfEg@mail.gmail.com>

On Thu, May 27, 2021 at 6:45 PM Cameron Simpson <cs at cskk.id.au> wrote:
>
> On 27May2021 13:37, Cameron Simpson <cs at cskk.id.au> wrote:
> >The constants themselves seem to be here:
> >    https://github.com/python/cpython/blob/3e7ee02327db13e4337374597cdc4458ecb9e3ad/Include/internal/pycore_interp.h#L211
>
> On reflection, these might just be the interned ints: some _precomputed_
> cached ints :-) The larger range of cached int boB reports would be a
> wider range implemented programmatically at runtime.

Actually the link you provide agrees almost exactly with the range I
discovered of -4 to 256.  A bit farther along in the source you link
to is a comment which says:

/* Small integers are preallocated in this array so that they
can be shared.
The integers that are preallocated are those in the range
-_PY_NSMALLNEGINTS (inclusive) to _PY_NSMALLPOSINTS (not inclusive).
*/

Where you linked these constants were set to 5 and 257 respectively.
The upper end I discovered via the interpreter agrees exactly since
257 is not included according to this comment.  However, I am puzzled
by the negative end as -5 was *not* cached, but the comment says it is
inclusively included.  So there is an off-by-one error here with what
I observed in the interpreter and what the comment claims.  I tried to
puzzle out the code, but was unsuccessful, wondering why they
apparently they had two extra slots in the array created to store
these cached integers.

I guess I will never know the answer to how these values were chosen.
<sad face>

boB

> Still no deeper insights though.

From __peter__ at web.de  Sat May 29 04:11:16 2021
From: __peter__ at web.de (Peter Otten)
Date: Sat, 29 May 2021 10:11:16 +0200
Subject: [Tutor] Why does CPython cache small integers "asymmetrically"?
In-Reply-To: <CANDiX9KVbTcsbPo_2+Fywh2K-xqpxeQA6RGaf-To0g7ebCkfEg@mail.gmail.com>
References: <YK8UEMYpxZLeZyRi@cskk.homeip.net>
 <YLAurlWosSEbYvp9@cskk.homeip.net>
 <CANDiX9KVbTcsbPo_2+Fywh2K-xqpxeQA6RGaf-To0g7ebCkfEg@mail.gmail.com>
Message-ID: <s8ssv4$vjf$1@ciao.gmane.io>

On 28/05/2021 02:13, boB Stepp wrote:
> On Thu, May 27, 2021 at 6:45 PM Cameron Simpson <cs at cskk.id.au> wrote:
>>
>> On 27May2021 13:37, Cameron Simpson <cs at cskk.id.au> wrote:
>>> The constants themselves seem to be here:
>>>     https://github.com/python/cpython/blob/3e7ee02327db13e4337374597cdc4458ecb9e3ad/Include/internal/pycore_interp.h#L211
>>
>> On reflection, these might just be the interned ints: some _precomputed_
>> cached ints :-) The larger range of cached int boB reports would be a
>> wider range implemented programmatically at runtime.
> 
> Actually the link you provide agrees almost exactly with the range I
> discovered of -4 to 256.  A bit farther along in the source you link
> to is a comment which says:
> 
> /* Small integers are preallocated in this array so that they
> can be shared.
> The integers that are preallocated are those in the range
> -_PY_NSMALLNEGINTS (inclusive) to _PY_NSMALLPOSINTS (not inclusive).
> */
> 
> Where you linked these constants were set to 5 and 257 respectively.
> The upper end I discovered via the interpreter agrees exactly since
> 257 is not included according to this comment.  However, I am puzzled
> by the negative end as -5 was *not* cached, but the comment says it is
> inclusively included.  So there is an off-by-one error here with what
> I observed in the interpreter and what the comment claims.  I tried to
> puzzle out the code, but was unsuccessful, wondering why they
> apparently they had two extra slots in the array created to store
> these cached integers.

I cannot confirm your findings:

 >>> sys.version
'3.9.1 (tags/v3.9.1:1e5d33e, Dec  7 2020, 16:33:24) [MSC v.1928 32 bit 
(Intel)]'

 >>> x = -5
 >>> y = -5
 >>> x is y
True
 >>> x = -6
 >>> y = -6
 >>> x is y
False

 >>> x = 256
 >>> y = 256
 >>> x is y
True
 >>> x = 257
 >>> y = 257
 >>> x is y
False

i. e. the precomputed integers are in range(-5, 257) as the constants 
suggest. Maybe you are using an older version of the interpreter?

I think I remember that the lower bound used to be -2 in Python 2...



From robertvstepp at gmail.com  Sat May 29 11:10:30 2021
From: robertvstepp at gmail.com (boB Stepp)
Date: Sat, 29 May 2021 10:10:30 -0500
Subject: [Tutor] Why does CPython cache small integers "asymmetrically"?
In-Reply-To: <CANDiX9+ApCRdmiumW6Z0hbW-LMSj2vr-Ma=Ne1pEK+454XeQHA@mail.gmail.com>
References: <CANDiX9+ApCRdmiumW6Z0hbW-LMSj2vr-Ma=Ne1pEK+454XeQHA@mail.gmail.com>
Message-ID: <CANDiX9LmNHxB+zpM9sCJJS-6pLnzophbu8=1w6Y_tMuiF-FShA@mail.gmail.com>

This is in response to Peter's response.  I see that in my original
post I had an error in my terminal session capture (Of course!).

On Wed, May 26, 2021 at 8:49 PM boB Stepp <robertvstepp at gmail.com> wrote:

> >>> x = -4
> >>> y = -4
> >>> id(x)
> 1176492075152
> >>> id(y)
> 1176492075152
> >>> x = -5
> >>> x = -5  # OOPS!  That was supposed to be "y = -5"!
> >>> id(x)
> 1176492075120
> >>> id(y)
So of course y here is referring to the last set value of -4 and is
different from that of -5.

Thanks for catching that Peter!  I spent quite some time trying to
parse the source Cameron cited looking for a problem that was actually
on my end.  I confirm Peter's results:

PS C:\Users\boB> py
Python 3.9.5 (tags/v3.9.5:0a7dcbd, May  3 2021, 17:27:52) [MSC v.1928
64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> x = -4
>>> y = -4
>>> id(x)
2238155155600
>>> id(y)
2238155155600
>>> x = -5
>>> y = -5
>>> id(x)
2238155155568
>>> id(y)
2238155155568
>>> x = -6
>>> y = -6
>>> id(x)
2238164080720
>>> id(y)
2238164080944

boB Stepp

From manpritsinghece at gmail.com  Sun May 30 19:56:23 2021
From: manpritsinghece at gmail.com (Manprit Singh)
Date: Mon, 31 May 2021 05:26:23 +0530
Subject: [Tutor] to place all zeros of an existing list in the starting of a
 new list
Message-ID: <CAO1OCwZOZpq1nx6REmYpemeBy7OiQMipY+o3p3qPSEn___GSfA@mail.gmail.com>

Dear sir ,
Consider a list ls = [2, 5, 0, 9, 0, 8], now i have to generate a new list
from this existing list , new list must contain all zeros in the starting,
all other elements of the existing list must be placed after zeros in new
list . So new list must be :
new = [0, 0, 2, 5, 9, 8]

The way I am doing it is :
>>> ls = [2, 5, 0, 9, 0, 8]
>>> sorted(ls, key=lambda x: x != 0)
[0, 0, 2, 5, 9, 8]
>>>
Is this the correct way ? or is there something better that can be done ?

Regards
Manprit Singh

From alan.gauld at yahoo.co.uk  Sun May 30 20:26:04 2021
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Mon, 31 May 2021 01:26:04 +0100
Subject: [Tutor] to place all zeros of an existing list in the starting
 of a new list
In-Reply-To: <CAO1OCwZOZpq1nx6REmYpemeBy7OiQMipY+o3p3qPSEn___GSfA@mail.gmail.com>
References: <CAO1OCwZOZpq1nx6REmYpemeBy7OiQMipY+o3p3qPSEn___GSfA@mail.gmail.com>
Message-ID: <s91aes$nn0$1@ciao.gmane.io>

On 31/05/2021 00:56, Manprit Singh wrote:

> Consider a list ls = [2, 5, 0, 9, 0, 8], now i have to generate a new list
> from this existing list , new list must contain all zeros in the starting,
> all other elements of the existing list must be placed after zeros in new
> list . So new list must be :
> new = [0, 0, 2, 5, 9, 8]

This is such a specific and unusual requirement that just about any way
of achieving it would be "correct". In particular, the zeros in the
original list and in the new list are all the same object since python
(or CPython) caches small integers, including zero.

In the more general case where we have a list of objects and you
want to create a new list putting some arbitrary group of objects
first followed by the rest, what happens then?

> The way I am doing it is :
>>>> ls = [2, 5, 0, 9, 0, 8]
>>>> sorted(ls, key=lambda x: x != 0)
> [0, 0, 2, 5, 9, 8]

This would seem to meet both the specific and general cases.
You only need to define the key function to identify the
retained cases.

Another, more generalized approach is to create two new lists,
one with the required elements, the other without, then add
these together. Like so:

>>> ls1 = [2,5,0,9,0,8]
>>> ls2 = [n for n in ls1 if n == 0]
>>> ls3 = [n for n in ls1 if n != 0]
>>> ls = ls2+ls3
>>> ls
[0, 0, 2, 5, 9, 8]

I suspect the sorted approach is quicker in this case.

But as you create more and more arcane requirements the
likelihood of there being a definitive or correct answer
or approach diminishes greatly.

-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos



From PyTutor at DancesWithMice.info  Sun May 30 20:39:35 2021
From: PyTutor at DancesWithMice.info (dn)
Date: Mon, 31 May 2021 12:39:35 +1200
Subject: [Tutor] to place all zeros of an existing list in the starting
 of a new list
In-Reply-To: <CAO1OCwZOZpq1nx6REmYpemeBy7OiQMipY+o3p3qPSEn___GSfA@mail.gmail.com>
References: <CAO1OCwZOZpq1nx6REmYpemeBy7OiQMipY+o3p3qPSEn___GSfA@mail.gmail.com>
Message-ID: <3a610417-63e6-3c57-b735-906a976ce394@DancesWithMice.info>



On 31/05/2021 11.56, Manprit Singh wrote:
> Dear sir ,
> Consider a list ls = [2, 5, 0, 9, 0, 8], now i have to generate a new list
> from this existing list , new list must contain all zeros in the starting,
> all other elements of the existing list must be placed after zeros in new
> list . So new list must be :
> new = [0, 0, 2, 5, 9, 8]
> 
> The way I am doing it is :
>>>> ls = [2, 5, 0, 9, 0, 8]
>>>> sorted(ls, key=lambda x: x != 0)
> [0, 0, 2, 5, 9, 8]
>>>>
> Is this the correct way ? or is there something better that can be done ?

+1 @Alan's comment.
These appear highly academic questions with little apparent real-world
application.

A learning opportunity for itertools?
"itertools ? Functions creating iterators for efficient looping"
https://docs.python.org/3/library/itertools.html


import itertools as it

ls = [2, 5, 0, 9, 0, 8]

list( it.repeat( 0,
(len( ls ) - (
length_compressed := len( compressed := list( it.compress( ls, ls )
) ) ) ) ) ) + compressed

# [0, 0, 2, 5, 9, 8]


Is it "correct"?
- yes, in that it answers the question
- no, in that it is a ghastly mess to comprehend

Is it "better"?
- yes, I wrote it
- no, it is convoluted

However, it makes arcanely-amusing use of itertools!
-- 
Regards,
=dn

From robertvstepp at gmail.com  Sun May 30 21:31:01 2021
From: robertvstepp at gmail.com (boB Stepp)
Date: Sun, 30 May 2021 20:31:01 -0500
Subject: [Tutor] to place all zeros of an existing list in the starting
 of a new list
In-Reply-To: <3a610417-63e6-3c57-b735-906a976ce394@DancesWithMice.info>
References: <CAO1OCwZOZpq1nx6REmYpemeBy7OiQMipY+o3p3qPSEn___GSfA@mail.gmail.com>
 <3a610417-63e6-3c57-b735-906a976ce394@DancesWithMice.info>
Message-ID: <CANDiX9KxX3yk2bf=mSb8M3N4tB2FRBrdj2QC40UTTxvbT0dkuQ@mail.gmail.com>

On Sun, May 30, 2021 at 7:40 PM dn via Tutor <tutor at python.org> wrote:
>
>
>
> On 31/05/2021 11.56, Manprit Singh wrote:
> > Dear sir ,
> > Consider a list ls = [2, 5, 0, 9, 0, 8], now i have to generate a new list
> > from this existing list , new list must contain all zeros in the starting,
> > all other elements of the existing list must be placed after zeros in new
> > list . So new list must be :
> > new = [0, 0, 2, 5, 9, 8]
> >
> > The way I am doing it is :
> >>>> ls = [2, 5, 0, 9, 0, 8]
> >>>> sorted(ls, key=lambda x: x != 0)
> > [0, 0, 2, 5, 9, 8]
> >>>>
> > Is this the correct way ? or is there something better that can be done ?
>
> +1 @Alan's comment.
> These appear highly academic questions with little apparent real-world
> application.

Or is Mr. Singh simply trying to understand the fine details of how
Python does things by coming up with these examples and exploring
them? I suspect that much exploration may have occurred (Which we
never get to see) before submitting his question with the intent of
getting validation of his conclusions. In any case, I found his
example quite stimulating.  I realized that I did not understand how
the "key" keyword parameter worked in sorted(),  when I did not see
how he got the result he had.  Of course I have not yet had any use
for that optional parameter.  I finally realized after playing around
in the interpreter and going to the docs multiple times that the key
function mapped each element in the original result to the following:
[2, 5, 0, 9, 0, 8] => [True, True, False, True, False, True], then
sorted this "Boolean" list where I had to keep in mind for sorting
purposes that False = 0 and True = 1.  Then sorted() apparently uses
this new order to reverse the mapping to get the end result of [0, 0,
2, 5, 9, 8].

So Mr. Singh's question caused me to learn multiple things tonight and
I am grateful to him!

Cheers!
boB Stepp

From manpritsinghece at gmail.com  Sun May 30 23:58:16 2021
From: manpritsinghece at gmail.com (Manprit Singh)
Date: Mon, 31 May 2021 09:28:16 +0530
Subject: [Tutor] flatten a python list
Message-ID: <CAO1OCwYHo7o9wCDRGaKRHxqykBABdQqekHzi8-WSyVg9MJu6jg@mail.gmail.com>

Dear sir,

consider a problem to get a flat list for below given list :
lst = [[2, 6], [5, 8], [6, 0]]
the flatten list will be :
ans = [2, 6, 5, 8, 6, 0]

I have seen in several texts around the internet and even in the textbooks,
the approach followed is to use nested for loop.
ans = []
for ele in lst:
  for num in ele:
    ans.append(num)

instead of using this for loop if i write :
ans = []
for ele in lst:
  ans.extend(ele)

Although the answer is correct, I need your comments on this approach.

Just for the sake of healthy discussion, i am putting this question
Although i can do it in a very efficient manner with list comprehension as
given below:
ans = [num for ele in lst for num in ele]

Regards
Manprit Singh

From cs at cskk.id.au  Mon May 31 01:11:32 2021
From: cs at cskk.id.au (Cameron Simpson)
Date: Mon, 31 May 2021 15:11:32 +1000
Subject: [Tutor] flatten a python list
In-Reply-To: <CAO1OCwYHo7o9wCDRGaKRHxqykBABdQqekHzi8-WSyVg9MJu6jg@mail.gmail.com>
References: <CAO1OCwYHo7o9wCDRGaKRHxqykBABdQqekHzi8-WSyVg9MJu6jg@mail.gmail.com>
Message-ID: <YLRwBCdmMnSaiArd@cskk.homeip.net>

On 31May2021 09:28, Manprit Singh <manpritsinghece at gmail.com> wrote:
>consider a problem to get a flat list for below given list :
>lst = [[2, 6], [5, 8], [6, 0]]
>the flatten list will be :
>ans = [2, 6, 5, 8, 6, 0]
>
>I have seen in several texts around the internet and even in the textbooks,
>the approach followed is to use nested for loop.
>ans = []
>for ele in lst:
>  for num in ele:
>    ans.append(num)

That is a direct solution.

>instead of using this for loop if i write :
>ans = []
>for ele in lst:
>  ans.extend(ele)

I would expect this to be faster because the target list gets to 
allocate new slots in batches of the size of "ele". Rather than 
accomodating new elements one at a time. With small lists the like your 
example the different might be small. With large lists (each ele" being 
long) it might be more obvious.

>Just for the sake of healthy discussion, i am putting this question
>Although i can do it in a very efficient manner with list comprehension as
>given below:
>ans = [num for ele in lst for num in ele]

This is concise. Is it more efficient than the nested for-loops 
appending a single element?

Check out the timeit module, which is useful for benchmarking things 
like this (timing very small operations such as your example is 
unreliable because the run time is so small - timeit runs the task many 
times).

Note: the difference between the two may be small. Even when the "ele" 
sublists are very large the internals of the "list" type might be good 
enough to make the difference small.

Often, unless this is a performance bottleneck, you should go with the 
most readable/understandable solution.

Finally: in the case where large "ele" makes a big difference, you might 
be better of _not_ flattening the list at all - it can be expensive.  
instead your use case might one need to _use_ the elements in flattened 
form without the step of constructing a distinct new list.

See the "chain" function in the itertools module.

Cheers,
Cameron Simpson <cs at cskk.id.au>

From alan.gauld at yahoo.co.uk  Mon May 31 05:15:44 2021
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Mon, 31 May 2021 10:15:44 +0100
Subject: [Tutor] flatten a python list
In-Reply-To: <CAO1OCwYHo7o9wCDRGaKRHxqykBABdQqekHzi8-WSyVg9MJu6jg@mail.gmail.com>
References: <CAO1OCwYHo7o9wCDRGaKRHxqykBABdQqekHzi8-WSyVg9MJu6jg@mail.gmail.com>
Message-ID: <s929g0$rbl$1@ciao.gmane.io>

On 31/05/2021 04:58, Manprit Singh wrote:

> I have seen in several texts around the internet and even in the textbooks,
> the approach followed is to use nested for loop.
> ans = []
> for ele in lst:
>   for num in ele:
>     ans.append(num)
> 
> instead of using this for loop if i write :
> ans = []
> for ele in lst:
>   ans.extend(ele)

Both are valid.

Both are flawed if the lists are not homogenous.
For example if lst contained single numbers as
well as sub lists. Or if the sublists can contain
sub lists of their own. To flatten a list in the
real world you'd probably want some type checking
and possibly use a recursive function to process
multiple layers of sublists..

> ans = [num for ele in lst for num in ele]

This also works but loses a lot in readability.
Unless it was proven to be much faster and
that speed was actually needed I'd stick
with either of the more explicit versions above.

-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos



From manpritsinghece at gmail.com  Mon May 31 05:56:21 2021
From: manpritsinghece at gmail.com (Manprit Singh)
Date: Mon, 31 May 2021 15:26:21 +0530
Subject: [Tutor] product of all arguments passed to function call
Message-ID: <CAO1OCwbU6St-1dVT4otz6kdj5CCuxqcT4sX190-8=EvzLd8Mfg@mail.gmail.com>

Dear sir ,
Consider a problem where i have to find the product of all arguments passed
to function call , where the function must be capable of accepting any
number of arguments : My approach will be as follows :

def product(x, *y):
    for ele in y:
        x *= ele
    return x

ans = product(3, 4, 2)
print(ans) gives the right answer = 24

ans = product(3, 4, 2, 5)
print(ans) gives the right answer = 120

The point here is, in both cases, 3 is the first argument which will be
passed to formal parameter x, and rest of the arguments will be received by
y in the form of tuple. Is my understanding correct? is my problem solving
correct in this case ?
Regards
Manprit Singh

From alan.gauld at yahoo.co.uk  Mon May 31 06:19:19 2021
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Mon, 31 May 2021 11:19:19 +0100
Subject: [Tutor] product of all arguments passed to function call
In-Reply-To: <CAO1OCwbU6St-1dVT4otz6kdj5CCuxqcT4sX190-8=EvzLd8Mfg@mail.gmail.com>
References: <CAO1OCwbU6St-1dVT4otz6kdj5CCuxqcT4sX190-8=EvzLd8Mfg@mail.gmail.com>
Message-ID: <s92d77$kob$1@ciao.gmane.io>

On 31/05/2021 10:56, Manprit Singh wrote:
> Dear sir ,
> Consider a problem where i have to find the product of all arguments passed
> to function call , where the function must be capable of accepting any
> number of arguments : My approach will be as follows :
> 
> def product(x, *y):
>     for ele in y:
>         x *= ele
>     return x

You solution works for the case where at least 1 argument is passed.
What if none are passed? A small change suffices:

def product(*x):
    result = 1 if x else 0
    for n in x:
      result *= n
    return result

If you don't like returning zero for an empty list you could
raise an exception instead - ValueError perhaps?.

-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos



From __peter__ at web.de  Mon May 31 09:11:29 2021
From: __peter__ at web.de (Peter Otten)
Date: Mon, 31 May 2021 15:11:29 +0200
Subject: [Tutor] flatten a python list
In-Reply-To: <CAO1OCwYHo7o9wCDRGaKRHxqykBABdQqekHzi8-WSyVg9MJu6jg@mail.gmail.com>
References: <CAO1OCwYHo7o9wCDRGaKRHxqykBABdQqekHzi8-WSyVg9MJu6jg@mail.gmail.com>
Message-ID: <s92na0$rei$1@ciao.gmane.io>

On 31/05/2021 05:58, Manprit Singh wrote:
> Dear sir,
> 
> consider a problem to get a flat list for below given list :
> lst = [[2, 6], [5, 8], [6, 0]]
> the flatten list will be :
> ans = [2, 6, 5, 8, 6, 0]
> 
> I have seen in several texts around the internet and even in the textbooks,
> the approach followed is to use nested for loop.
> ans = []
> for ele in lst:
>    for num in ele:
>      ans.append(num)
> 
> instead of using this for loop if i write :
> ans = []
> for ele in lst:
>    ans.extend(ele)
> 
> Although the answer is correct, I need your comments on this approach.
> 
> Just for the sake of healthy discussion, i am putting this question
> Although i can do it in a very efficient manner with list comprehension as
> given below:
> ans = [num for ele in lst for num in ele]

Here are a few other variants for your collection:

 >>> lst = [[2, 6], [5, 8], [6, 0]]
 >>> from functools import reduce
 >>> from operator import add
 >>> reduce(add, lst)
[2, 6, 5, 8, 6, 0]

This is basically add(add(lst[0], lst[1]), lst[2]) without the nesting.

You might rewrite that as lst[0] + lst[1] + lst[2], which is what sum() 
does if you provide the second argument:

 >>> sum(lst, [])
[2, 6, 5, 8, 6, 0]

reduce() is a little more flexible, you can get it to extend() a list; 
+= (or iadd) is just a different incantation of extend:

 >>> from operator import iadd
 >>> a = []
 >>> reduce(iadd, lst, a)
[2, 6, 5, 8, 6, 0]
 >>> assert a is _
 >>>

Have fun :)


From __peter__ at web.de  Mon May 31 09:20:07 2021
From: __peter__ at web.de (Peter Otten)
Date: Mon, 31 May 2021 15:20:07 +0200
Subject: [Tutor] product of all arguments passed to function call
In-Reply-To: <CAO1OCwbU6St-1dVT4otz6kdj5CCuxqcT4sX190-8=EvzLd8Mfg@mail.gmail.com>
References: <CAO1OCwbU6St-1dVT4otz6kdj5CCuxqcT4sX190-8=EvzLd8Mfg@mail.gmail.com>
Message-ID: <s92nq6$10q3$1@ciao.gmane.io>

On 31/05/2021 11:56, Manprit Singh wrote:

> Consider a problem where i have to find the product of all arguments passed
> to function call , where the function must be capable of accepting any
> number of arguments : My approach will be as follows :
> 
> def product(x, *y):
>      for ele in y:
>          x *= ele
>      return x

You might try to implement that with reduce() ;)


From manpritsinghece at gmail.com  Mon May 31 10:21:36 2021
From: manpritsinghece at gmail.com (Manprit Singh)
Date: Mon, 31 May 2021 19:51:36 +0530
Subject: [Tutor] product of all arguments passed to function call
In-Reply-To: <s92d77$kob$1@ciao.gmane.io>
References: <CAO1OCwbU6St-1dVT4otz6kdj5CCuxqcT4sX190-8=EvzLd8Mfg@mail.gmail.com>
 <s92d77$kob$1@ciao.gmane.io>
Message-ID: <CAO1OCwZxoyc=DZ9mGhEisAN1GXaakcrd0vO71tQHw-OLj3-VCQ@mail.gmail.com>

 Dear sir,

Coming to the same question , of finding the product of all arguments
passed to a function call . Actually I have seen so many times when getting
replies from python mailing list, those replies other than from you are
more focussed on using modules that are part of  python standard library.
My question is, if i had to perform the same task (finding the product of
argument in function call )  in a real world program, what should i choose
? a solution without using those modules or it will be better using those
modules?

Solution without using module (as given by you in previous mail):
def product(*x):
    result = 1 if x else 0
    for n in x:
      result *= n
    return result

Solution using python standard library modules :

>>> from functools import reduce
>>> from operator import mul
>>> def prod_num(*x):
           if not x or 0 in x:
               return 0
          else:
              return reduce(mul, x)

I feel there are overheads while you are importing , so better avoid using
this way...
I raised this question because sometime back, i saw one of my friend using
re module with string for very small problem that was even easy to handle
with string methods, i suggested him not to use re module for it, later on
he agreed. So what is the real picture ? what should i adopt ?

Need your guidance

Regards
Manprit Singh


On Mon, May 31, 2021 at 3:50 PM Alan Gauld via Tutor <tutor at python.org>
wrote:

> On 31/05/2021 10:56, Manprit Singh wrote:
> > Dear sir ,
> > Consider a problem where i have to find the product of all arguments
> passed
> > to function call , where the function must be capable of accepting any
> > number of arguments : My approach will be as follows :
> >
> > def product(x, *y):
> >     for ele in y:
> >         x *= ele
> >     return x
>
> You solution works for the case where at least 1 argument is passed.
> What if none are passed? A small change suffices:
>
> def product(*x):
>     result = 1 if x else 0
>     for n in x:
>       result *= n
>     return result
>
> If you don't like returning zero for an empty list you could
> raise an exception instead - ValueError perhaps?.
>
> --
> Alan G
> Author of the Learn to Program web site
> http://www.alan-g.me.uk/
> http://www.amazon.com/author/alan_gauld
> Follow my photo-blog on Flickr at:
> http://www.flickr.com/photos/alangauldphotos
>
>
> _______________________________________________
> Tutor maillist  -  Tutor at python.org
> To unsubscribe or change subscription options:
> https://mail.python.org/mailman/listinfo/tutor
>

From mats at wichmann.us  Mon May 31 11:15:04 2021
From: mats at wichmann.us (Mats Wichmann)
Date: Mon, 31 May 2021 09:15:04 -0600
Subject: [Tutor] product of all arguments passed to function call
In-Reply-To: <CAO1OCwZxoyc=DZ9mGhEisAN1GXaakcrd0vO71tQHw-OLj3-VCQ@mail.gmail.com>
References: <CAO1OCwbU6St-1dVT4otz6kdj5CCuxqcT4sX190-8=EvzLd8Mfg@mail.gmail.com>
 <s92d77$kob$1@ciao.gmane.io>
 <CAO1OCwZxoyc=DZ9mGhEisAN1GXaakcrd0vO71tQHw-OLj3-VCQ@mail.gmail.com>
Message-ID: <e861e529-91ff-3780-1e2f-f215a397e2e1@wichmann.us>

On 5/31/21 8:21 AM, Manprit Singh wrote:
>   Dear sir,
> 
> Coming to the same question , of finding the product of all arguments
> passed to a function call . Actually I have seen so many times when getting
> replies from python mailing list, those replies other than from you are
> more focussed on using modules that are part of  python standard library.
> My question is, if i had to perform the same task (finding the product of
> argument in function call )  in a real world program, what should i choose
> ? a solution without using those modules or it will be better using those
> modules?
> 
> Solution without using module (as given by you in previous mail):
> def product(*x):
>      result = 1 if x else 0
>      for n in x:
>        result *= n
>      return result
> 
> Solution using python standard library modules :
> 
>>>> from functools import reduce
>>>> from operator import mul
>>>> def prod_num(*x):
>             if not x or 0 in x:
>                 return 0
>            else:
>                return reduce(mul, x)
> 
> I feel there are overheads while you are importing , so better avoid using
> this way...
> I raised this question because sometime back, i saw one of my friend using
> re module with string for very small problem that was even easy to handle
> with string methods, i suggested him not to use re module for it, later on
> he agreed. So what is the real picture ? what should i adopt ?

So as you probably suspect, there's not going to be one overriding answer.

When building complex systems, there's a lot to think about, and if a 
supported part of the Language (which the standard library is) can solve 
your problem, why not?  You get the benefit of code which has been 
developed, tested and maintained by experienced Python developers as 
solutions to common programming situations, and the odds are good that 
they've thought of corner cases that you might not at first.  You'll 
still have plenty to think about building your software, why spend even 
more cycles than you need to?

The overhead of an import is non-zero, but "avoiding imports" just for 
some perceived performance gains is a losing strategy.

Sometimes, though, you have a simple problem to solve and there's no 
reason to reach for a big tool when a few lines of code will do.  Your 
example is quite an apt one - reaching for a regex when one is not 
needed is a formula for frustration.  It's probably been quoted to you 
here already, but there are jokes about this - the famous one (I'm too 
lazy to search it out, hope I've remembered the wording correctly) 'Some 
people, when confronted with a problem, think "I know, I'll use regular 
expressions." Now they have two problems.'  I'd note that it's easier to 
get regular expressions right these ways with the presence of regex 
sites which can evaluate one you've written, and in some cases, help you 
construct one by clicking some buttons.

And of course, sometimes a standard library module doesn't hit close 
enough to the mark of what you're trying to achieve to be worth the 
effort to try and bend it to your need.

Using the right tool for a job is also a skill to develop.



From bkarsh at gmail.com  Mon May 31 14:18:29 2021
From: bkarsh at gmail.com (Bryan Karsh)
Date: Mon, 31 May 2021 11:18:29 -0700
Subject: [Tutor] to place all zeros of an existing list in the starting
 of a new list
In-Reply-To: <CANDiX9KxX3yk2bf=mSb8M3N4tB2FRBrdj2QC40UTTxvbT0dkuQ@mail.gmail.com>
References: <CAO1OCwZOZpq1nx6REmYpemeBy7OiQMipY+o3p3qPSEn___GSfA@mail.gmail.com>
 <3a610417-63e6-3c57-b735-906a976ce394@DancesWithMice.info>
 <CANDiX9KxX3yk2bf=mSb8M3N4tB2FRBrdj2QC40UTTxvbT0dkuQ@mail.gmail.com>
Message-ID: <CAMU2Sqx2miQaZo77S2Gc74vZfeMJh+wvGrvF=Lu-iS=5Wy0joA@mail.gmail.com>

I too enjoy Mr. Singh?s questions. He?s asking what I often ask myself
while I code: ?This approach works? but is it optimal? Am I introducing a
good or bad habit doing it this way??

On Sun, May 30, 2021 at 6:31 PM boB Stepp <robertvstepp at gmail.com> wrote:

> On Sun, May 30, 2021 at 7:40 PM dn via Tutor <tutor at python.org> wrote:
> >
> >
> >
> > On 31/05/2021 11.56, Manprit Singh wrote:
> > > Dear sir ,
> > > Consider a list ls = [2, 5, 0, 9, 0, 8], now i have to generate a new
> list
> > > from this existing list , new list must contain all zeros in the
> starting,
> > > all other elements of the existing list must be placed after zeros in
> new
> > > list . So new list must be :
> > > new = [0, 0, 2, 5, 9, 8]
> > >
> > > The way I am doing it is :
> > >>>> ls = [2, 5, 0, 9, 0, 8]
> > >>>> sorted(ls, key=lambda x: x != 0)
> > > [0, 0, 2, 5, 9, 8]
> > >>>>
> > > Is this the correct way ? or is there something better that can be
> done ?
> >
> > +1 @Alan's comment.
> > These appear highly academic questions with little apparent real-world
> > application.
>
> Or is Mr. Singh simply trying to understand the fine details of how
> Python does things by coming up with these examples and exploring
> them? I suspect that much exploration may have occurred (Which we
> never get to see) before submitting his question with the intent of
> getting validation of his conclusions. In any case, I found his
> example quite stimulating.  I realized that I did not understand how
> the "key" keyword parameter worked in sorted(),  when I did not see
> how he got the result he had.  Of course I have not yet had any use
> for that optional parameter.  I finally realized after playing around
> in the interpreter and going to the docs multiple times that the key
> function mapped each element in the original result to the following:
> [2, 5, 0, 9, 0, 8] => [True, True, False, True, False, True], then
> sorted this "Boolean" list where I had to keep in mind for sorting
> purposes that False = 0 and True = 1.  Then sorted() apparently uses
> this new order to reverse the mapping to get the end result of [0, 0,
> 2, 5, 9, 8].
>
> So Mr. Singh's question caused me to learn multiple things tonight and
> I am grateful to him!
>
> Cheers!
> boB Stepp
> _______________________________________________
> Tutor maillist  -  Tutor at python.org
> To unsubscribe or change subscription options:
> https://mail.python.org/mailman/listinfo/tutor
>

From roel at roelschroeven.net  Mon May 31 17:48:34 2021
From: roel at roelschroeven.net (Roel Schroeven)
Date: Mon, 31 May 2021 23:48:34 +0200
Subject: [Tutor] to place all zeros of an existing list in the starting
 of a new list
In-Reply-To: <CAO1OCwZOZpq1nx6REmYpemeBy7OiQMipY+o3p3qPSEn___GSfA@mail.gmail.com>
References: <CAO1OCwZOZpq1nx6REmYpemeBy7OiQMipY+o3p3qPSEn___GSfA@mail.gmail.com>
Message-ID: <s93ljj$g9m$1@ciao.gmane.io>

Manprit Singh schreef op 31/05/2021 om 1:56:
> Consider a list ls = [2, 5, 0, 9, 0, 8], now i have to generate a new list
> from this existing list , new list must contain all zeros in the starting,
> all other elements of the existing list must be placed after zeros in new
> list . So new list must be :
> new = [0, 0, 2, 5, 9, 8]
> 
> The way I am doing it is :
>>>> ls = [2, 5, 0, 9, 0, 8]
>>>> sorted(ls, key=lambda x: x != 0)
> [0, 0, 2, 5, 9, 8]
>>>>
> Is this the correct way ? or is there something better that can be done ?

First, a note about correctness:

Your approach is fine if the sort function you use is stable, meaning 
that it doesn't change the relative order of elements that compare equal 
(i.e. in this case: keep 2, 5, 9 and  in the correct order). It just so 
happens that Python's sorted() function, and the sort() method on lists, 
are guaranteed to be stable, so your approach works just fine.

Just remember that that doesn't necessarily translate to other 
environments. For example, std::sort() in C++ is *not* guaranteed to 
preserve the order of equal elements (I know because I got bitten by 
that some time ago). When you ever face a similar problem using another 
sort function, be sure to read the documentation to find out if the sort 
function is stable.


Secondly, an alternative approach, with different performance:

Python uses Timsort (so called because it's written by Python dev Tim 
Peters); see https://en.wikipedia.org/wiki/Timsort. Timsort is pretty 
efficient as sorting algorithms go; in fact it is adopted in the sorting 
functions in other programming languages. Even so, it may be that 
another approach may be faster.

You could do two passes over the original list: first to collect the 
zeros, next to collect all the other numbers, and then put them all 
together:

     [n for n in ls if n == 0] + [n for n in ls if n != 0]

Or a variation that prevents building two possibly large temporary list 
through the use of generator expressions and itertools.chain to combine 
them:

     from itertools import chain
     list(chain((n for n in ls if n == 0), (n for n in ls if n != 0)))

The sorting approach has complexity O(n log n), my alternative has 
complexity O(n). O(n) is better all else being equal, but simply 
comparing the complexities isn't the whole story. It's very well 
possible that my alternative has a high constant factor, meaning that is 
slower for small lists and only gets faster than your approach for very 
large lists.

I don't really think it's something to worry about, unless this is 
something you are going to use in a time-sensitive situation with large 
lists, in which case you should benchmark different approaches. Mainly I 
just wanted to show you a possible alternative solution.

-- 
"Honest criticism is hard to take, particularly from a relative, a
friend, an acquaintance, or a stranger."
         -- Franklin P. Jones

Roel Schroeven


From robertvstepp at gmail.com  Mon May 31 23:08:28 2021
From: robertvstepp at gmail.com (boB Stepp)
Date: Mon, 31 May 2021 22:08:28 -0500
Subject: [Tutor] product of all arguments passed to function call
In-Reply-To: <CAO1OCwbU6St-1dVT4otz6kdj5CCuxqcT4sX190-8=EvzLd8Mfg@mail.gmail.com>
References: <CAO1OCwbU6St-1dVT4otz6kdj5CCuxqcT4sX190-8=EvzLd8Mfg@mail.gmail.com>
Message-ID: <CANDiX9+Y=yxmSPgJQ2VCGvAyhAUmDmX_Fk_=LJBC4rSKF0y69w@mail.gmail.com>

On Mon, May 31, 2021 at 4:57 AM Manprit Singh <manpritsinghece at gmail.com> wrote:
>
> Dear sir ,
> Consider a problem where i have to find the product of all arguments passed
> to function call , where the function must be capable of accepting any
> number of arguments : My approach will be as follows :
>
> def product(x, *y):
>     for ele in y:
>         x *= ele
>     return x

I would omit "x" from the parameter list and just do "def product(*y):".

boB Stepp

From cs at cskk.id.au  Mon May 31 23:31:11 2021
From: cs at cskk.id.au (Cameron Simpson)
Date: Tue, 1 Jun 2021 13:31:11 +1000
Subject: [Tutor] product of all arguments passed to function call
In-Reply-To: <s92d77$kob$1@ciao.gmane.io>
References: <s92d77$kob$1@ciao.gmane.io>
Message-ID: <YLWp/+YR1vUwsgWI@cskk.homeip.net>

On 31May2021 11:19, Alan Gauld <alan.gauld at yahoo.co.uk> wrote:
>You solution works for the case where at least 1 argument is passed.
>What if none are passed? A small change suffices:
>
>def product(*x):
>    result = 1 if x else 0
>    for n in x:
>      result *= n
>    return result
>
>If you don't like returning zero for an empty list you could
>raise an exception instead - ValueError perhaps?.

If he doesn't like zero (indeed, I don't either) he can use what he's 
got, because Python will raise a better error when the x parameter isn't 
supplied, with the bonus that linters may well catch it too.

Cheers,
Cameron Simpson <cs at cskk.id.au>