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: 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 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: References: Message-ID: On 01May2021 12:07, Msd De 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 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 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: 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: References: Message-ID: 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 wrote: > On 01May2021 12:07, Msd De 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 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 > _______________________________________________ > 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: 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: References: 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: References: 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: References: 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: 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 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: References: Message-ID: 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 wrote: > >> On 01May2021 12:07, Msd De 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 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 >> _______________________________________________ >> 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: References: Message-ID: 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: 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: References: Message-ID: 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: 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: References: Message-ID: 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: References: 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: References: 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: 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: 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: References: Message-ID: 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 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: References: 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: References: 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: References: 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: References: 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: <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: References: Message-ID: 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: References: Message-ID: 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: 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: References: Message-ID: 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: References: Message-ID: 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: References: , Message-ID: 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 on behalf of Alan Gauld via Tutor Sent: May 4, 2021 6:19 AM To: 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&data=04%7C01%7C%7C21773837b7914c3f347408d90ee63852%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C637557204210358462%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&sdata=NxRj61z2bFU%2B2BIhADhAt%2BiPBPEcW%2Fm7Ge9xc%2BvvtP0%3D&reserved=0 https://na01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.amazon.com%2Fauthor%2Falan_gauld&data=04%7C01%7C%7C21773837b7914c3f347408d90ee63852%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C637557204210358462%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&sdata=jyBj68gHiQxw1buFAwLU%2F8UUlUbIIWdv0d2Sm4yraaI%3D&reserved=0 Follow my photo-blog on Flickr at: https://na01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.flickr.com%2Fphotos%2Falangauldphotos&data=04%7C01%7C%7C21773837b7914c3f347408d90ee63852%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C637557204210358462%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&sdata=K2MWegIG0nT54eqG1GsJ3R%2BdolXPvX3ia2gRfIyOWGs%3D&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&data=04%7C01%7C%7C21773837b7914c3f347408d90ee63852%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C637557204210358462%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&sdata=M%2FCR4dRjA2Vi2RCKEfjf1iGt%2BYZE5Ep0ZDYBmUZ1gJ0%3D&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: References: Message-ID: 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: References: Message-ID: 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: References: Message-ID: 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: References: , Message-ID: 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 on behalf of Alan Gauld via Tutor Sent: May 4, 2021 8:10 AM To: 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&data=04%7C01%7C%7Cfbb38651382f4becda0608d90ef5b9b3%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C637557270802984314%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&sdata=9IDEpuBENHsQwVHbT9JueHZYUz72IQVKF%2Fa1W2tdTLw%3D&reserved=0 https://na01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.amazon.com%2Fauthor%2Falan_gauld&data=04%7C01%7C%7Cfbb38651382f4becda0608d90ef5b9b3%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C637557270802984314%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&sdata=vVt6M63k%2B6FDHlW9Cq5i1DTy%2FitC36oxDG9tT2y7rKE%3D&reserved=0 Follow my photo-blog on Flickr at: https://na01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.flickr.com%2Fphotos%2Falangauldphotos&data=04%7C01%7C%7Cfbb38651382f4becda0608d90ef5b9b3%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C637557270802984314%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&sdata=FXFxPEgAcZuqnV5WWM5pSY41rDqnzdBEUNk2Fq4cTPI%3D&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&data=04%7C01%7C%7Cfbb38651382f4becda0608d90ef5b9b3%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C637557270802984314%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&sdata=YGtdZCSXkGNjGNVdRoN1g4aFxbhyLf%2FvkrobB9QKFy4%3D&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: References: Message-ID: 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: References: 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: References: 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: References: 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 on behalf of Alan Gauld via Tutor > Sent: May 4, 2021 8:10 AM > To: 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&data=04%7C01%7C%7Cfbb38651382f4becda0608d90ef5b9b3%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C637557270802984314%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&sdata=9IDEpuBENHsQwVHbT9JueHZYUz72IQVKF%2Fa1W2tdTLw%3D&reserved=0 > https://na01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.amazon.com%2Fauthor%2Falan_gauld&data=04%7C01%7C%7Cfbb38651382f4becda0608d90ef5b9b3%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C637557270802984314%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&sdata=vVt6M63k%2B6FDHlW9Cq5i1DTy%2FitC36oxDG9tT2y7rKE%3D&reserved=0 > Follow my photo-blog on Flickr at: > https://na01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.flickr.com%2Fphotos%2Falangauldphotos&data=04%7C01%7C%7Cfbb38651382f4becda0608d90ef5b9b3%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C637557270802984314%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&sdata=FXFxPEgAcZuqnV5WWM5pSY41rDqnzdBEUNk2Fq4cTPI%3D&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&data=04%7C01%7C%7Cfbb38651382f4becda0608d90ef5b9b3%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C637557270802984314%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&sdata=YGtdZCSXkGNjGNVdRoN1g4aFxbhyLf%2FvkrobB9QKFy4%3D&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: References: Message-ID: 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: , <733b3005-1736-bb44-5756-92b0f316c9a5@web.de> Message-ID: 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 on behalf of Peter Otten <__peter__ at web.de> Sent: May 4, 2021 9:59 AM To: 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&data=04%7C01%7C%7Cddad8692c30a49d9ea4f08d90f04e069%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C637557335875222875%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&sdata=EeNpJMadBfNkQnN7%2FcIWc4iVuAiZ8gCD10bXzgKFrB4%3D&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: On 04May2021 12:09, Phil 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: (? 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: References: <4352d14d-3d68-1839-e15d-44ebf3a73088@gmail.com> Message-ID: <758a38da-2ce1-fdd6-b89c-65541fdb4724@gmail.com> On 5/5/21 8:02 am, Cameron Simpson wrote: > On 04May2021 12:09, Phil 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: 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: 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: References: Message-ID: 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: 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: References: Message-ID: 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: References: 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: References: Message-ID: 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: References: Message-ID: 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: <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: References: Message-ID: 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: References: Message-ID: 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: References: Message-ID: 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: References: Message-ID: 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: 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: References: Message-ID: 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: References: 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: References: Message-ID: 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: References: Message-ID: 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: 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: References: Message-ID: 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: References: Message-ID: 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: 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: References: Message-ID: 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: References: Message-ID: 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: References: Message-ID: 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: 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: References: Message-ID: 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: 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: References: 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: 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: References: Message-ID: 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 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 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: References: Message-ID: 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: References: 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 ??? 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: References: Message-ID: 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: References: Message-ID: 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: <3ffb6770-00cc-2095-d978-04e95db22e65@gmail.com> Message-ID: 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: References: 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: <6dc95b8b-2723-02e6-0a99-7ec26c4747f4@gmail.com> Message-ID: 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: 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: References: Message-ID: 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: In "15. Floating Point Arithmetic: Issues and Limitations" at https://docs.python.org/3/tutorial/floatingpoint.html it says: 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. 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: References: <6dc95b8b-2723-02e6-0a99-7ec26c4747f4@gmail.com> 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: References: <6dc95b8b-2723-02e6-0a99-7ec26c4747f4@gmail.com> 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: References: Message-ID: 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: <6dc95b8b-2723-02e6-0a99-7ec26c4747f4@gmail.com> <10c81fd4-72d4-4a12-472e-381bff4f92cc@gmail.com> Message-ID: 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: References: Message-ID: 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: 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: ---------------- #!/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() ---------------- and this is the error message: Traceback (most recent call last): File "test.py", line 24, in 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: References: Message-ID: 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: References: Message-ID: 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: 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: > ---------------- > #!/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: References: <2356938.TbpgK9xzaQ@django019> 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: >> ---------------- >> #!/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: References: <6dc95b8b-2723-02e6-0a99-7ec26c4747f4@gmail.com> <10c81fd4-72d4-4a12-472e-381bff4f92cc@gmail.com> 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> <77f91ed0-2ba1-f852-3551-4077edbd4eac@wichmann.us> Message-ID: 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: References: Message-ID: 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: References: Message-ID: 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: <0ag2agd71l4o1nrn6ubkj3tefjqupqgsn6@4ax.com> Message-ID: On Sun, May 16, 2021 at 11:12 AM Dennis Lee Bieber wrote: > > On Sat, 15 May 2021 13:45:17 -0500, boB Stepp > 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: References: <0ag2agd71l4o1nrn6ubkj3tefjqupqgsn6@4ax.com> Message-ID: 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: References: Message-ID: 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: References: Message-ID: 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 > declaimed the following: > > >On Sat, 15 May 2021 14:58:04 -0300, Joao Carlos Silva de Oliveira Matos > via > >Tutor 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: References: Message-ID: 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: References: <0ag2agd71l4o1nrn6ubkj3tefjqupqgsn6@4ax.com> Message-ID: On 16/05/2021 21:01, Dennis Lee Bieber wrote: > On Sun, 16 May 2021 19:54:56 +0100, Alan Gauld via Tutor > 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: References: Message-ID: On 16May2021 19:59, Alan Gauld 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 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: On Tue, May 18, 2021 at 3:23 AM Phil 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: References: <075c43b7-ffee-937c-03ab-6cf32dba695f@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: References: <075c43b7-ffee-937c-03ab-6cf32dba695f@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 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: 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: References: <075c43b7-ffee-937c-03ab-6cf32dba695f@gmail.com> Message-ID: 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: References: <075c43b7-ffee-937c-03ab-6cf32dba695f@gmail.com> Message-ID: On Tue, 18 May 2021 at 19:35, Phil 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> <5a3f60b1-777c-4842-1dd1-9e940f1e059e@gmail.com> Message-ID: 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 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: References: <075c43b7-ffee-937c-03ab-6cf32dba695f@gmail.com> <5a3f60b1-777c-4842-1dd1-9e940f1e059e@gmail.com> Message-ID: 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: References: <075c43b7-ffee-937c-03ab-6cf32dba695f@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> <296b335c-8329-11b3-e51c-c22a598b7de9@gmail.com> Message-ID: 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: References: <075c43b7-ffee-937c-03ab-6cf32dba695f@gmail.com> <296b335c-8329-11b3-e51c-c22a598b7de9@gmail.com> 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: 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: References: Message-ID: On 21May2021 19: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. 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 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: References: Message-ID: 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: References: 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: References: <6b7fcee6-a357-8b3e-ee77-482b8799db3a@gmail.com> Message-ID: 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 > 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' }); > > 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: References: Message-ID: On Fri, May 21, 2021 at 8:52 PM Dennis Lee Bieber wrote: > > On Fri, 21 May 2021 19:25:29 -0500, boB Stepp > 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: References: 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: References: Message-ID: On 22/05/2021 13.03, Cameron Simpson wrote: > On 21May2021 19: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. 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: <6b7fcee6-a357-8b3e-ee77-482b8799db3a@gmail.com> Message-ID: 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 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: References: Message-ID: 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: 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: References: Message-ID: 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: References: 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: References: Message-ID: 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: <8a5e3d9f-dbb0-7b93-8f33-d37edc2b250d@gmail.com> Message-ID: On Sat, May 22, 2021 at 5:54 AM Leam Hall 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: References: Message-ID: On 22May2021 19:45, boB Stepp 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 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: 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: 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: References: <9cbb376f-ef4a-e808-5ab3-d4122a4bafc2@gmail.com> 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: 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: 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: References: Message-ID: 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: References: <9cbb376f-ef4a-e808-5ab3-d4122a4bafc2@gmail.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: On Sun, May 23, 2021 at 5:24 PM Raimond Haugom St?mvall 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 . 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: References: Message-ID: 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: 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 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: References: <9cbb376f-ef4a-e808-5ab3-d4122a4bafc2@gmail.com> Message-ID: 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: 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):   File "E:/Python Data Visualization/??/wallpaper2.py", line 52, in 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: References: Message-ID: On 26May2021 20: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! > >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 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: References: Message-ID: 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: 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: 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>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: References: Message-ID: 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: References: 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: References: Message-ID: On 27May2021 13:37, Cameron Simpson 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 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: References: Message-ID: On Thu, May 27, 2021 at 6:45 PM Cameron Simpson wrote: > > On 27May2021 13:37, Cameron Simpson 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. 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: References: Message-ID: On 28/05/2021 02:13, boB Stepp wrote: > On Thu, May 27, 2021 at 6:45 PM Cameron Simpson wrote: >> >> On 27May2021 13:37, Cameron Simpson 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: References: Message-ID: 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 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: 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: References: Message-ID: 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: References: 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: <3a610417-63e6-3c57-b735-906a976ce394@DancesWithMice.info> Message-ID: On Sun, May 30, 2021 at 7:40 PM dn via Tutor 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: 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: References: Message-ID: On 31May2021 09:28, Manprit Singh 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 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: References: Message-ID: 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: 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: References: Message-ID: 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: References: Message-ID: 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: References: Message-ID: 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: References: Message-ID: 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 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: References: Message-ID: 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: References: <3a610417-63e6-3c57-b735-906a976ce394@DancesWithMice.info> Message-ID: 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 wrote: > On Sun, May 30, 2021 at 7:40 PM dn via Tutor 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: References: Message-ID: 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: References: Message-ID: On Mon, May 31, 2021 at 4:57 AM 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 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: References: Message-ID: On 31May2021 11:19, Alan Gauld 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