近年来,Python 已成为最广泛使用的编程语言之一。然而,直到现在,Python 在 Web 开发领域才真正发挥了重要作用。PyScript 的出现改变了这一现状。它是一个全新的框架,允许您仅使用 HTML 和 Python 代码即可在 Web 浏览器上直接运行 Python 代码。无论您的经验水平如何,使用 PyScript 开发交互式 Web 应用都非常便捷,无需了解 JavaScript。在本教程中,您将了解 PyScript 的概念、工作原理以及如何使用它创建您的第一个基于浏览器的 Python 应用。
什么是PyScript
PyScript 是一个开源框架,它弥合了 Python 和 Web 之间的差距。它允许您直接在 Web 浏览器中运行 Python 代码。它允许您编写完全在客户端运行的交互式 Python 应用程序,而无需后端服务器。使用 PyScript 就像使用 Python 而不是 JavaScript 编写 Web 应用一样。您可以使用 Python 构建简单的交互式 Web 工具、仪表盘等。
PyScript 的主要功能
- 浏览器中的 Python:您可以在 HTML 文件中的
<py-script>
标签内编写 Python 代码 - 无需环境设置:无需安装任何其他库或工具。它在浏览器中运行。
- 与 HTML 交互:轻松将 Python 与 HTML、CSS 和 JavaScript 集成。
- 基于 WebAssembly:使用 Pyodide(将 Python 编译为 WebAssembly)在浏览器中运行 Python。
如何在Web应用中使用PyScript?
步骤 1:访问官方网站
访问官方网站。在这里,您可以浏览演示、文档并亲自尝试。
Source: PyScript
步骤 2:设置基本HTML文件
要运行 PyScript,您需要一个包含所需框架的简单 HTML 文件。
示例代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>My First PyScript App</title> <link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" /> <script defer src="https://pyscript.net/latest/pyscript.js"></script> </head> <body> <h1>Hello from PyScript!</h1> <py-script> name = "PyScript" print(f"Hello, {name}! You are running Python in the browser.") </py-script> </body> </html>
步骤 3:在浏览器中打开HTML文件
默认情况下,该文件包含 3 个文件:
main.py:
Your Python code.
Index.html:
The main web page that includes PyScript.
pyscript.toml:
A configuration file listing any extra Python packages youwant to use.
使用适当的代码更新代码文件并开始实验:
您可以在 PyScript 示例中尝试 PyScript Playground 以直接在浏览器中测试代码片段。
PyScript动手实践
现在您已经熟悉了 PyScript 接口的工作原理,让我们来实际操作一下。
我们将构建一个双人井字棋游戏。
步骤 1:更新main.py
在 main.py 文件中添加 TicTacToe
类,该类包含游戏逻辑、用户交互和 UI 更新。它将使用 PyWeb 将 Python 与 HTML 连接起来,使游戏在浏览器中完全可交互。
代码:
from pyweb import pydom class TicTacToe: def __init__(self): self.board = pydom["table#board"] self.status = pydom["h2#status"] self.console = pydom["script#console"][0] self.init_cells() self.init_winning_combos() self.new_game(...) def set_status(self, text): self.status.html = text def init_cells(self): self.cells = [] for i in (0, 1, 2): row = [] for j in (0, 1, 2): cell = pydom[f"div#cell{i}{j}"][0] assert cell row.append(cell) self.cells.append(row) def init_winning_combos(self): self.winning_combos = [] # winning columns for i in (0, 1, 2): combo = [] for j in (0, 1, 2): combo.append((i, j)) self.winning_combos.append(combo) # winning rows for j in (0, 1, 2): combo = [] for i in (0, 1, 2): combo.append((i, j)) self.winning_combos.append(combo) # winning diagonals self.winning_combos.append([(0, 0), (1, 1), (2, 2)]) self.winning_combos.append([(0, 2), (1, 1), (2, 0)]) def new_game(self, event): self.clear_terminal() print('=================') print('NEW GAME STARTING') print() for i in (0, 1, 2): for j in (0, 1, 2): self.set_cell(i, j, "") self.current_player = "x" experimenting self.set_status(f'{self.current_player} playing...') def next_turn(self): winner = self.check_winner() if winner == "tie": self.set_status("It's a tie!") self.current_player = "" # i.e., game ended return elif winner is not None: self.set_status(f'{winner} wins') self.current_player = "" # i.e., game ended return if self.current_player == "x": self.current_player = "o" else: self.current_player = "x" self.set_status(f'{self.current_player} playing...') def check_winner(self): """ Check whether the game as any winner. Return "x", "o", "tie" or None. None means that the game is still playing. """ # check whether we have a winner for combo in self.winning_combos: winner = self.get_winner(combo) if winner: # highlight the winning cells for i, j in combo: self.cells[i][j].add_class("win") return winner # check whether it's a tie for i in (0, 1, 2): for j in (0, 1, 2): if self.get_cell(i, j) == "": # there is at least an empty cell, it's not a tie return None # game still playing return "tie" def get_winner(self, combo): """ If all the cells at the given points have the same value, return it. Else return "". Each point is a tuple of (i, j) coordinates. Example: self.get_winner([(0, 0), (1, 1), (2, 2)]) """ assert len(combo) == 3 values = [self.get_cell(i, j) for i, j in combo] if values[0] == values[1] == values[2] and values[0] != "": return values[0] return "" def set_cell(self, i, j, value): assert value in ("", "x", "o") cell = self.cells[i][j] cell.html = value if "x" in cell.classes: cell.remove_class("x") if "o" in cell.classes: cell.remove_class("o") if "win" in cell.classes: cell.remove_class("win") if value != "": cell.add_class(value) def get_cell(self, i, j): cell = self.cells[i][j] value = cell.html assert value in ("", "x", "o") return value def click(self, event): i = int(event.target.getAttribute('data-x')) j = int(event.target.getAttribute('data-y')) print(f'Cell {i}, {j} clicked: ', end='') if self.current_player == "": print('game ended, nothing to do') return # value = self.get_cell(i, j) if value == "": print('cell empty, setting it') self.set_cell(i, j, self.current_player) self.next_turn() else: print(f'cell already full, cannot set it') def clear_terminal(self): self.console._js.terminal.clear() def toggle_terminal(self, event): hidden = self.console.parent._js.getAttribute("hidden") if hidden: self.console.parent._js.removeAttribute("hidden") else: self.console.parent._js.setAttribute("hidden", "hidden") GAME = TicTacToe()
步骤 2:创建CSS文件
在新建的 assets 文件夹中创建一个 style.css 文件,用于定义井字游戏的布局和样式。这将处理棋盘、单元格以及所有状态消息的样式。
代码:
h1, h2 { font-family: 'Indie Flower', 'Comic Sans', cursive; text-align: center; } #board { font-family: 'Indie Flower', 'Comic Sans', cursive; position: relative; font-size: 120px; margin: 1% auto; border-collapse: collapse; } #board td { border: 4px solid rgb(60, 60, 60); width: 90px; height: 90px; vertical-align: middle; text-align: center; cursor: pointer; } #board td div { width: 90px; height: 90px; line-height: 90px; display: block; overflow: hidden; cursor: pointer; } .x { color: darksalmon; position: relative; font-size: 1.2em; cursor: default; } .o { color: aquamarine; position: relative; font-size: 1.0em; cursor: default; } .win { background-color: beige; }
步骤 3:更新index.html
修改 index.html 文件,使其引用 PyScript 设置,加载 main.py 文件,定义游戏棋盘结构,并指向 style.css 文件(位于 assets 文件夹中)进行样式设置。
代码:
<!doctype html> <html> <head> <!-- Recommended meta tags --> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1.0"> <!-- PyScript CSS --> <link rel="stylesheet" href="https://pyscript.net/releases/2024.1.1/core.css"> <!-- CSS for examples --> <link rel="stylesheet" href="./assets/css/examples.css" /> <!-- This script tag bootstraps PyScript --> <script type="module" src="https://pyscript.net/releases/2024.1.1/core.js"></script> <!-- Custom CSS --> <link href="https://fonts.googleapis.com/css?family=Indie+Flower" rel="stylesheet"> <link rel="stylesheet" href="./assets/css/tictactoe.css" /> <!-- for splashscreen --> <style> #loading { outline: none; border: none; background: transparent } </style> <script type="module"> const loading = document.getElementById('loading'); addEventListener('py:ready', () => loading.close()); loading.showModal(); </script> <title>Tic Tac Toe</title> <link rel="icon" type="image/png" href="./assets/favicon.png" /> </head> <body> <dialog id="loading"> <h1>Loading...</h1> </dialog> <nav class="navbar" style="background-color: #000000"> <div class="app-header"> <a href="/"> <img src="./assets/logo.png" class="logo" /> </a> <a class="title" href="" style="color: #f0ab3c">Tic Tac Toe</a> </div> </nav> <section class="pyscript"> <h1>Tic-Tac-Toe</h1> <script type="py" src="./main.py" config="./pyscript.toml"></script> <table id="board"> <tr> <td><div id="cell00" data-x="0" data-y="0" class="cell" py-click="GAME.click"></div></td> <td><div id="cell01" data-x="0" data-y="1" class="cell" py-click="GAME.click"></div></td> <td><div id="cell02" data-x="0" data-y="2" class="cell" py-click="GAME.click"></div></td> <tr> <td><div id="cell10" data-x="1" data-y="0" class="cell" py-click="GAME.click"></div></td> <td><div id="cell11" data-x="1" data-y="1" class="cell" py-click="GAME.click"></div></td> <td><div id="cell12" data-x="1" data-y="2" class="cell" py-click="GAME.click"></div></td> </tr> <tr> <td><div id="cell20" data-x="2" data-y="0" class="cell" py-click="GAME.click"></div></td> <td><div id="cell21" data-x="2" data-y="1" class="cell" py-click="GAME.click"></div></td> <td><div id="cell22" data-x="2" data-y="2" class="cell" py-click="GAME.click"></div></td> </tr> </table> <h2 id="status"></h2> <button id="btn-new-game" py-click="GAME.new_game">New game</button> <button id="btn-toggle-terminal" py-click="GAME.toggle_terminal">Hide/show terminal</button> <div id="terminal" hidden="hidden"> <script id="console" type="py" terminal></script> </div> </section> </body> </html>
步骤 4:更新pyscript.toml
使用应用所需的必要配置(包括依赖项、文件路径等)更新 pyscript.toml 文件。这可确保 PyScript 知道如何正确加载和运行 Python 代码。以下是我们的井字游戏应用的 pyscript.toml 文件内容:
配置:
name = "Tic Tac Toe" description = "A Tic-Tac-Toe game written in PyScript that allows people to take turns."
输出:
这是您在 PScript 上的第一个项目。
小结
Python 在数据科学、人工智能、自动化和教育领域的应用前所未有。然而,迄今为止,Python 在 Web 上尚无原生平台。PyScript 应运而生,它将 Python 的简洁性与 Web 的易用性完美融合。它仍在不断完善,但已经为开发者、教育工作者和学习者创造了大量机会。
评论留言