<div dir="ltr">A couple of points:<div><br></div><div>- strings are immutable</div><div>- every str.__add__ creates copies of strings</div><div>- str1 += str2 is equivalwnt to str3 = str1 + str2<br></div><div><br></div><div> So, if, for example, we have a 1KB string and we keep += adding 1KB strings, the allocated memory looks like:</div><div> str1 # 1KB</div><div> str2 # 1KB</div><div> str_n # 1KB</div><div> str1 += str2 # 1KB (str1), 1KB (str2), 2KB (str1` = str1 + str2) = 4 KB</div><div> str1 += str_n # 1KB (str1), 1KB (str2), 2KB (str1` = str1 + str2), 3KB (str1`` = str1` + str_n) = 7 KB</div><div><br></div><div>There's StringIO. StringIO supports .write() and doesn't require copying.</div><div><br></div><div>AFAICT, there's not any user supplied input in the example you've shared here.</div><div>If there was (e.g. "include the player name"), we would need to **escape** it in order to prevent XSS ("Cross-Site Scripting"); so that users couldn't add arbitrary HTML, JS, CSS to the page.</div><div><br></div><div>Methods for escaping user-supplied input:</div><div>HTML:</div><div>- cgi.escape * (see: bleach)<br></div><div>- <a href="https://pypi.python.org/pypi/bleach">https://pypi.python.org/pypi/bleach</a></div><div>- Use a templating language and configure it to "autoescape" (e.g. Jinja2)</div><div> - <a href="http://jinja.pocoo.org/docs/dev/api/#autoescaping">http://jinja.pocoo.org/docs/dev/api/#autoescaping</a> is *off* by default.</div><div> - <a href="https://pypi.python.org/pypi/MarkupSafe">https://pypi.python.org/pypi/MarkupSafe</a> Markup(str) // __html__</div><div> - <a href="https://github.com/pallets/jinja/issues/528">https://github.com/pallets/jinja/issues/528</a></div><div> - Django Templates have autoescaping on by default</div><div> - (Jinja2 is very similar to Django Templates)</div><div> - <a href="https://docs.djangoproject.com/en/1.10/ref/templates/language/#automatic-html-escaping">https://docs.djangoproject.com/en/1.10/ref/templates/language/#automatic-html-escaping</a></div><div><br></div><div>JS:</div><div>- json.dumps</div><div><br></div><div>CSS:</div><div>- </div><div><br></div><div>... "XSS"</div><div><br></div><div>- <a href="https://cwe.mitre.org/top25/#CWE-79">https://cwe.mitre.org/top25/#CWE-79</a> </div><div>- <a href="https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)">https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)</a></div><div>- <a href="https://en.wikipedia.org/wiki/Cross-site_scripting#Preventive_measures">https://en.wikipedia.org/wiki/Cross-site_scripting#Preventive_measures</a></div><div><br></div><div><br>On Tuesday, November 22, 2016, kirby urner <<a href="mailto:kirby.urner@gmail.com" target="_blank">kirby.urner@gmail.com</a>> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><br></div>Wow, thank you Kevin and Wes for some<br></div>eye-opening contributions! <br><br>I really welcome their mind-expanding <br>potential and have been diving into demos <br>and docs all morning. [1]<br></div></div><br></div>In my course last night we looked at that <br>Jupyter Notebook comparing ES6 and <br>Python scripts [2] and I also showed them <br>how Python may be used to write <br>HTML + CSS for browser rendering.[3]<br></div></div></div></div><br>Output: <a href="https://flic.kr/p/PjQ6Bg" target="_blank">https://flic.kr/p/PjQ6Bg</a> (screen<br></div><div>shot).<br><br></div><div>Some of my students are beginner programmers, <br>with little to no programming background <br>so we're really just going over the basics, but at <br></div><div>the same time we need to tune in the <br></div><div>ecosystem with is typically a combination of <br><br>Python + HTML + CSS + JS + SQL + regex <br><br>at least. <br><br>I use sqlite3 module for the SQL part, re module <br>for regex.<br></div><div><br></div>What we have in these resources though is <br>something even more ambitious, including<br></div></div>the ability to compile Python to JS! Wow.<br><br>You know what they say: JS is the <br>assembly language of the web. <br><br>Even developers using JS full stack use <br></div><div>transpilers to go from future JS -> past<br></div><div>JS (using Babel mostly). <br><br>Future JS (from where we stand now) is <br>what looks more Python-like than ever.<br></div></div><br></div><div>My current mode of teaching is to have<br></div><div>students install the Anaconda distro and<br></div><div>then to extend the library with the requests<br></div><div>and flask modules for exploring web stuff.<br></div><div>Anaconda includes command line conda<br></div><div>for using in place of pip, to get packages<br></div><div>from a large web of repositories.<br><br></div><div>Now I see conda lets me install mpld3 to<br></div><div>my Mac with no issues.<br><br>mackurner:~ kurner$ conda install mpld3<br></div><div><br>My teaching application is here:<br></div><div><a href="http://thekirbster.pythonanywhere.com" target="_blank">thekirbster.pythonanywhere.com</a><br></div><div><br></div>Kirby<br><br></div>[1] Kevin, <a href="http://pyeverywhere.org/docs/" target="_blank">http://pyeverywhere.org/docs/</a> 404s<br><div><br>[2] <a href="https://github.com/4dsolutions/Python5/blob/master/Comparing%20JavaScript%20with%20Python.ipynb" target="_blank">https://github.com/4dsolutions<wbr>/Python5/blob/master/<wbr>Comparing%20JavaScript%20with%<wbr>20Python.ipynb</a><br></div><div>(that's direct to Github -- nbviewer is having problems<br></div><div>right now, no wait it's working again) <br><a href="https://goo.gl/nj9RPO" target="_blank">https://goo.gl/nj9RPO</a> (using nbviewer) renders the <br>JS output whereas Github does not.<br> </div><div><br>[3] a chess board generator, just uses string <br>substitution ala str.format( ) method, helps <br>beginners see how HTML + CSS might be <br>string output from a Python script on the server:<br><br></div><div># -*- coding: utf-8 -*-<br>"""<br>Created on Thu Nov 17 09:02:27 2016<br><a href="https://flic.kr/p/PjQ6Bg" target="_blank">https://flic.kr/p/PjQ6Bg</a> (screen shot).<br>@author: Kirby Urner<br><br></div><div>Run the script and open the output .html file<br></div><div>in any browser.<br></div><div>"""<br>from collections import namedtuple<br><br>Piece = namedtuple('Piece', 'type color position unicode')<br><br>black = [ <br> Piece("Rook" , "black", [7,0], "♜"),<br> Piece("Knight" , "black", [7,1], "♞"),<br> Piece("Bishop" , "black", [7,2], "♝"),<br> Piece("Queen" , "black", [7,3], "♛"),<br> Piece("King" , "black", [7,4], "♚"),<br> Piece("Bishop" , "black", [7,5], "♝"),<br> Piece("Knight" , "black", [7,6], "♞"),<br> Piece("Rook" , "black", [7,7], "♜") ]<br><br>for c in range(8):<br> black.append(Piece("Pawn", "black", [6,c], "♟"))<br><br>white = [ <br> Piece("Rook" , "white", [0,0], "♖"),<br> Piece("Knight" , "white", [0,1], "♘"),<br> Piece("Bishop" , "white", [0,2], "♗"),<br> Piece("Queen" , "white", [0,3], "♕"),<br> Piece("King" , "white", [0,4], "♔"),<br> Piece("Bishop" , "white", [0,5], "♗"),<br> Piece("Knight" , "white", [0,6], "♘"),<br> Piece("Rook" , "white", [0,7], "♖") ]<br><br>for c in range(8): <br> white.append(Piece("Pawn", "white", [1,c], "♙"))<br><br>the_board = \<br>"""<br><table><br>{white_royals}<br>{white_pawns}<br>{empty_cells}<br>{black_pawns}<br>{black_royals}<br></table>"""<br><br>white_royals = "<tr>{}</tr>".format("".join(<br> ["<td>{}</td>".format(piece.un<wbr>icode) for piece in white[:8]]))<br>white_pawns = "<tr>{}</tr>".format("".join(<br> ["<td>{}</td>".format(piece.un<wbr>icode) for piece in white[8:]]))<br>black_royals = "<tr>{}</tr>".format("".join(<br> ["<td>{}</td>".format(piece.un<wbr>icode) for piece in black[:8]]))<br>black_pawns = "<tr>{}</tr>".format("".join(<br> ["<td>{}</td>".format(piece.un<wbr>icode) for piece in black[8:]]))<br><br>empty_cells = ""<br>for row in range(4):<br> empty_cells += "<tr>{}</tr>".format("".join(<br> ["<td></td>" for _ in range(8)]))<br><br>chess_board = the_board.format(white_royals = white_royals, <br> white_pawns = white_pawns, <br> empty_cells = empty_cells,<br> black_royals = black_royals, <br> black_pawns = black_pawns)<br><br>the_page = \<br>"""<!DOCTYPE html><br><html><br><head><br><style><br>body {<br> margin-left: 30px;<br> font-size: 20px;<br>}<br><br>table {<br> border: 1px solid black;<br> border-collapse: collapse;<br> border-color: black;<br>}<br><br>td {<br> padding: 15px;<br> border: 1px solid black;<br> height: 20px;<br> vertical-align: bottom;<br>}<br><br>tr:nth-child(even) td:nth-child(odd){<br> background-color: #FF8040;<br>}<br><br>tr:nth-child(odd) td:nth-child(even){<br> background-color: #FF8040;<br>} <br><br>td:hover {<br> background-color: #FF0000 !important;<br> border-color: blue;<br>}<br></style><br></head><br><body><br>""" + \<br>chess_board \<br>+ \<br>"""<br></body><br></html><br>"""<br><br>with open("chessboard02.html", "w") as f:<br> f.write(the_page)<br><br>print("Done!")<br></div></div>
</blockquote></div>
</div>