詳解如何在JavaScript中無(wú)縫地集成和使用Python代碼
在當(dāng)前的軟件開(kāi)發(fā)領(lǐng)域,Python和JavaScript是兩個(gè)非常重要的編程語(yǔ)言。Python是一種功能強(qiáng)大、易于學(xué)習(xí)和使用的解釋型腳本語(yǔ)言,而JavaScript是一種廣泛應(yīng)用于Web開(kāi)發(fā)的腳本語(yǔ)言。在某些情況下,我們可能需要在JavaScript項(xiàng)目中使用Python代碼,以利用Python的特定功能或庫(kù)。本指南將介紹在JavaScript中使用Python代碼的完整過(guò)程。
目標(biāo)和用途
本文的目標(biāo)是幫助諸位理解如何在JavaScript中無(wú)縫地集成和使用Python代碼。通過(guò)使用Python代碼,我們可以利用Python生態(tài)系統(tǒng)中的豐富資源和庫(kù)來(lái)增強(qiáng)我們的JavaScript應(yīng)用程序。例如,我們可以使用Python的數(shù)據(jù)處理庫(kù)來(lái)進(jìn)行復(fù)雜的數(shù)據(jù)分析,或者使用Python的機(jī)器學(xué)習(xí)庫(kù)來(lái)實(shí)現(xiàn)智能功能。
Python與JavaScript的互操作性
在開(kāi)始之前,讓我們先了解Python和JavaScript之間的互操作性。
客戶端與服務(wù)器端技術(shù)棧
通常情況下,Python在與服務(wù)器端的開(kāi)發(fā)中更為常見(jiàn),而JavaScript則主要應(yīng)用于客戶端開(kāi)發(fā)。在服務(wù)器端技術(shù)棧中,我們可以通過(guò)將Python和JavaScript代碼分別在后端和前端運(yùn)行來(lái)實(shí)現(xiàn)兩者之間的互操作性。
Python解釋器與JavaScript引擎的不同
Python解釋器和JavaScript引擎具有不同的工作原理和語(yǔ)法。Python解釋器將Python代碼解釋為機(jī)器碼并執(zhí)行,而JavaScript引擎將JavaScript代碼解釋為字節(jié)碼并執(zhí)行。這意味著直接在JavaScript中運(yùn)行Python代碼是不可能的。
基于Web的Python解決方案
為了在JavaScript中使用Python代碼,我們可以通過(guò)以下幾種方法實(shí)現(xiàn)。
服務(wù)器端集成
在服務(wù)器端集成中,我們可以使用以下方法將Python代碼與JavaScript集成。
1. 使用Node.js作為中介
我們可以使用Node.js作為中介來(lái)執(zhí)行Python代碼。Node.js是一個(gè)JavaScript運(yùn)行時(shí)環(huán)境,它允許我們?cè)贘avaScript中調(diào)用Python解釋器并獲取結(jié)果。
例如,我們可以使用child_process模塊來(lái)調(diào)用Python腳本文件:
const { exec } = require('child_process');
exec('python script.py', (error, stdout, stderr) => {
if (error) {
console.error(`執(zhí)行出錯(cuò): ${error}`);
return;
}
console.log(`腳本輸出: ${stdout}`);
});在上面的代碼中,我們使用child_process模塊的exec函數(shù)來(lái)執(zhí)行Python腳本文件(script.py),并獲取輸出結(jié)果。
2. 通過(guò)子進(jìn)程調(diào)用Python代碼
在JavaScript中,我們可以通過(guò)child_process模塊將Python代碼作為子進(jìn)程來(lái)執(zhí)行。
const { spawn } = require('child_process');
const pythonProcess = spawn('python', ['script.py']);
pythonProcess.stdout.on('data', (data) => {
console.log(`腳本輸出: ${data}`);
});
pythonProcess.stderr.on('data', (data) => {
console.error(`執(zhí)行出錯(cuò): ${data}`);
});
pythonProcess.on('close', (code) => {
console.log(`子進(jìn)程退出,退出碼 $[code]`);
});在上面的代碼中,我們使用child_process模塊的spawn函數(shù)來(lái)創(chuàng)建一個(gè)Python子進(jìn)程,并通過(guò)stdout事件監(jiān)聽(tīng)子進(jìn)程的輸出。我們還可以通過(guò)stderr事件來(lái)監(jiān)聽(tīng)子進(jìn)程的錯(cuò)誤輸出。
3. 通過(guò)HTTP請(qǐng)求與Python API通信
我們可以使用HTTP請(qǐng)求來(lái)與Python API進(jìn)行通信。這種方法非常適合將Python代碼封裝成API,以便在JavaScript中進(jìn)行訪問(wèn)。
const fetch = require('node-fetch');
fetch('http://localhost:5000/api', {
method: 'POST',
body: JSON.stringify({ param1: 'value1', param2: 'value2' }),headers: {
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then(data => {
console.log(data);
})
.catch(error => {
console.error('請(qǐng)求出錯(cuò):', error);
});上面的代碼中,我們使用node-fetch庫(kù)發(fā)送一個(gè)POST請(qǐng)求到Python APIhttp://localhost:5000/api,并將參數(shù)作為JSON數(shù)據(jù)傳遞。然后,我們使用response.json()方法解析響應(yīng)的JSON數(shù)據(jù),并處理返回的數(shù)據(jù)。
客戶端集成
在客戶端集成中,我們可以使用以下方法將Python代碼與JavaScript集成。
1. 使用WebAssembly執(zhí)行Python代碼
WebAssembly是一種可在Web瀏覽器中運(yùn)行高性能編譯語(yǔ)言的二進(jìn)制格式。我們可以使用Python的WebAssembly版本(如Pyodide)來(lái)在JavaScript中執(zhí)行Python代碼。
// 加載Pyodide
languagePluginLoader.then(() => {
// 加載Python代碼
pyodide.runPython(`
import requests
response = requests.get('https://api.example.com/data')
print(response.json())
`);
});上面的代碼中,我們首先使用languagePluginLoader來(lái)加載Pyodide(Python的WebAssembly版本)。然后,我們使用pyodide.runPython()方法來(lái)執(zhí)行Python代碼。
2. 使用JavaScript庫(kù)與Python互動(dòng)
有一些JavaScript庫(kù)(如Brython和Skulpt)可以在瀏覽器中解釋和執(zhí)行Python代碼。我們可以使用這些庫(kù)來(lái)在JavaScript中編寫(xiě)Python代碼,并與JavaScript進(jìn)行交互。
<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/brython/3.10.2/brython.min.js"></script>
</head>
<body>
<script type="text/python">
import js
def greet(name):
js.alert(f'Hello, {name}!')
greet('John')
</script>
</body>
</html>在上面的代碼中,我們?cè)贖TML文件中引入了Brython庫(kù),并使用<script type="text/python">標(biāo)簽將Python代碼嵌入到頁(yè)面中。在Python代碼中,我們使用js模塊來(lái)與JavaScript進(jìn)行交互,例如在JavaScript中彈出一個(gè)警告框。
3. 通過(guò)WebSockets進(jìn)行實(shí)時(shí)通信
我們可以使用WebSockets來(lái)實(shí)現(xiàn)JavaScript和Python之間的實(shí)時(shí)通信。通過(guò)在服務(wù)器上創(chuàng)建一個(gè)WebSocket服務(wù)器,JavaScript客戶端可以與Python代碼進(jìn)行雙向通信。
在Python中,我們可以使用WebSocket庫(kù)(如websockets)創(chuàng)建一個(gè)WebSocket服務(wù)器:
import asyncio
import websockets
async def communicate(websocket, path):
message = await websocket.recv()
print(f'Received message: {message}')
response = 'Hello from Python!'
await websocket.send(response)
start_server = websockets.serve(communicate, 'localhost', 8765)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()在JavaScript中,我們可以使用WebSocket API來(lái)與Python WebSocket服務(wù)器進(jìn)行通信:
const socket = new WebSocket('ws://localhost:8765/');
socket.onopen = () => {
console.log('WebSocket已連接');
const message = 'Hello from JavaScript!';
socket.send(message);
};
socket.onmessage = (event) => {
const response = event.data;
console.log(`Received response: ${response}`);
};
socket.onclose = () => {
console.log('WebSocket已關(guān)閉');
};在上面的代碼中,我們首先使用WebSocket API連接到Python WebSocket服務(wù)器。然后,我們使用socket.send()方法將消息發(fā)送到服務(wù)器,并通過(guò)socket.onmessage事件監(jiān)聽(tīng)服務(wù)器的響應(yīng)。
數(shù)據(jù)交換和處理
在JavaScript中使用Python代碼時(shí),我們經(jīng)常需要進(jìn)行數(shù)據(jù)交換和處理。以下是一些常見(jiàn)的數(shù)據(jù)交換和處理方法。
1. JSON格式的數(shù)據(jù)傳輸
JSON是一種常用的數(shù)據(jù)格式,在JavaScript和Python之間進(jìn)行數(shù)據(jù)交換時(shí)非常方便。JavaScript提供了JSON.stringify()和JSON.parse()方法將數(shù)據(jù)轉(zhuǎn)換為JSON字符串和對(duì)象,而Python提供了json庫(kù)來(lái)處理JSON數(shù)據(jù)。
在JavaScript中:
// JavaScript中將數(shù)據(jù)轉(zhuǎn)換為JSON字符串
const data = {
name: 'John',
age: 25,
};
const jsonStr = JSON.stringify(data);
console.log(jsonStr); // 輸出: {"name":"John","age":25}
// JavaScript中將JSON字符串轉(zhuǎn)換為對(duì)象
const jsonStr = '{"name":"John","age":25}';
const obj = JSON.parse(jsonStr);
console.log(obj.name); // 輸出: John
console.log(obj.age); // 輸出: 25在上面的代碼中,我們使用JSON.stringify()方法將JavaScript對(duì)象轉(zhuǎn)換為JSON字符串,以便發(fā)送到Python。然后,在Python代碼中,我們可以使用json庫(kù)的loads()函數(shù)將接收到的JSON字符串轉(zhuǎn)換為Python對(duì)象。
2. 使用RESTful API進(jìn)行數(shù)據(jù)交互
RESTful API是一種常用的網(wǎng)絡(luò)架構(gòu)風(fēng)格,它使用HTTP協(xié)議進(jìn)行數(shù)據(jù)交換。我們可以使用Python來(lái)構(gòu)建RESTful API,并使用JavaScript來(lái)發(fā)送HTTP請(qǐng)求以與Python代碼進(jìn)行交互。
在JavaScript中發(fā)送GET請(qǐng)求:
const endpoint = 'http://localhost:5000/api/data';
fetch(endpoint)
.then(response => response.json())
.then(data => {
console.log(data);
})
.catch(error => {
console.error('請(qǐng)求出錯(cuò):', error);
});在上面的代碼中,我們使用fetch()函數(shù)發(fā)送一個(gè)GET請(qǐng)求到Python的API端點(diǎn)(例如http://localhost:5000/api/data)。然后,我們使用.json()方法解析響應(yīng)的JSON數(shù)據(jù),并處理返回的數(shù)據(jù)。
3. 通過(guò)數(shù)據(jù)流進(jìn)行批量處理
對(duì)于大規(guī)模的數(shù)據(jù)處理任務(wù),我們可以使用數(shù)據(jù)流來(lái)批量處理數(shù)據(jù)。在JavaScript中,我們可以使用流處理庫(kù)(如stream模塊)來(lái)生成數(shù)據(jù)流。而在Python中,我們可以使用流處理庫(kù)(如io模塊)來(lái)處理輸入和輸出流。
在JavaScript中生成數(shù)據(jù)流并發(fā)送到Python:
const { Readable } = require('stream');
const fetch = require('node-fetch');
const FormData = require('form-data');
async function sendDataToPython() {
const readableStream = new Readable();
readableStream._read = () => {}; // 必須實(shí)現(xiàn)_read方法
// 生成數(shù)據(jù)流
const data = 'Hello from JavaScript!\n';
readableStream.push(data);
readableStream.push(null); // 表示流的結(jié)束
// 發(fā)送數(shù)據(jù)流
const form = new FormData();
form.append('file', readableStream);
const response = await fetch('http://localhost:5000/api/upload', {
method: 'POST',
body: form,
});
console.log(response.statusText);
}
sendDataToPython().catch(error => {
console.error('請(qǐng)求出錯(cuò):', error);
});上面的代碼中,我們首先使用stream模塊的Readable類(lèi)創(chuàng)建一個(gè)可讀數(shù)據(jù)流,并通過(guò)_read方法來(lái)定義數(shù)據(jù)流的讀取邏輯。然后,我們生成數(shù)據(jù)流并使用FormData將其附加到HTTP請(qǐng)求中。最后,我們使用fetch()函數(shù)發(fā)送帶有數(shù)據(jù)流的POST請(qǐng)求到Python的上傳API端點(diǎn)。
示例項(xiàng)目: 創(chuàng)建一個(gè)完整的應(yīng)用程序
項(xiàng)目結(jié)構(gòu)和依賴
在開(kāi)始編寫(xiě)示例項(xiàng)目之前,讓我們首先定義一下項(xiàng)目的結(jié)構(gòu)和所需的依賴。我們將使用以下結(jié)構(gòu):
myapp/
├── backend/
│ ├── app.py
│ ├── requirements.txt
└── frontend/
├── index.html
├── main.js
在這個(gè)示例項(xiàng)目中,我們將創(chuàng)建一個(gè)簡(jiǎn)單的待辦事項(xiàng)的應(yīng)用程序。后端將使用Python來(lái)處理數(shù)據(jù)和邏輯,前端將使用JavaScript來(lái)處理用戶界面。
在backend文件夾中,我們有一個(gè)app.py文件,它是我們的后端應(yīng)用程序的入口點(diǎn)此外,還有一個(gè)requirements.txt文件,列出了我們后端所依賴的Python包,我們將在后面詳細(xì)討論。
在frontend文件夾中,我們有一個(gè)index.html文件作為前端應(yīng)用程序的入口點(diǎn)。main.js文件包含了我們的JavaScript代碼。
后端實(shí)現(xiàn)(Python)
在backend/app.py中,我們將編寫(xiě)后端的邏輯和數(shù)據(jù)處理代碼。首先,讓我們安裝需要的Python包。在命令行中運(yùn)行以下命令:
pip install -r backend/requirements.txt
接下來(lái),我們將使用Flask框架創(chuàng)建一個(gè)簡(jiǎn)單的API來(lái)處理待辦事項(xiàng)。
# backend/app.py
from flask import Flask, request, jsonify
app = Flask(__name__)
todos = []
@app.route("/")
def hello():
return "Hello, World!"
@app.route("/todos", methods=["GET"])
def get_todos():
return jsonify(todos)
@app.route("/todos", methods=["POST"])
def add_todo():
todo = request.json
todos.append(todo)
return jsonify(todo), 201
@app.route("/todos/<int:index>", methods=["DELETE"])
def delete_todo(index):
if index < len(todos):
deleted_todo = todos.pop(index)
return jsonify(deleted_todo)
return "", 404
if __name__ == "__main__":
app.run()在這個(gè)簡(jiǎn)單的應(yīng)用程序中,我們定義了幾個(gè)路由來(lái)處理待辦事項(xiàng)的操作。/todos路由用于獲取所有的待辦事項(xiàng)(GET請(qǐng)求),添加新的待辦事項(xiàng)(POST請(qǐng)求),以及刪除特定索引的待辦事項(xiàng)(DELETE請(qǐng)求)。我們使用Python列表來(lái)存儲(chǔ)待辦事項(xiàng)。
前端實(shí)現(xiàn)(JavaScript)
在frontend/index.html中,我們將編寫(xiě)前端用戶界面的代碼。
<!-- frontend/index.html -->
<!DOCTYPE html>
<html>
<head>
<title>Todo App</title>
<script src="main.js" type="text/javascript"></script>
</head>
<body>
<h1>Todo App</h1>
<input type="text" id="todoInput" placeholder="Enter a todo">
<button onclick="addTodo()">Add</button>
<ul id="todoList"></ul>
<script>
const todoList = document.getElementById('todoList');
const todoInput = document.getElementById('todoInput');
function addTodo() {
const todoText = todoInput.value;
fetch('/todos', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ text: todoText })
})
.then(response => response.json())
.then(newTodo => {
const todoItem = document.createElement('li');
todoItem.textContent = newTodo.text;
todoList.appendChild(todoItem);
todoInput.value = '';
});
}
fetch('/todos')
.then(response => response.json())
.then(todos => {
todos.forEach(todo => {
const todoItem = document.createElement('li');
todoItem.textContent = todo.text;
todoList.appendChild(todoItem);
});
});
</script>
</body>
</html>我們創(chuàng)建了一個(gè)簡(jiǎn)單的用戶界面,用戶可以在輸入框中輸入待辦事項(xiàng),并點(diǎn)擊添加按鈕來(lái)添加新的待辦事項(xiàng)。我們使用了fetch函數(shù)發(fā)起HTTP請(qǐng)求來(lái)與后端API進(jìn)行通信,并將待辦事項(xiàng)在用戶界面上動(dòng)態(tài)更新。
集成和通信
現(xiàn)在我們已經(jīng)完成了后端和前端的實(shí)現(xiàn),接下來(lái)我們將介紹如何進(jìn)行后端和前端的集成和通信。
首先,確保你已經(jīng)正確地啟動(dòng)了后端應(yīng)用程序。在命令行中導(dǎo)航到backend文件夾,并運(yùn)行以下命令來(lái)啟動(dòng)后端服務(wù)器:
python app.py
一旦服務(wù)器啟動(dòng)成功,你應(yīng)該能夠在瀏覽器中訪問(wèn)http:http://localhost:5000/并看到“Hello, World!”的輸出。
現(xiàn)在,讓我們將前端應(yīng)用程序與后端進(jìn)行集成。
在frontend/main.js中,我們需要對(duì)代碼進(jìn)行一些修改以與后端API進(jìn)行通信。在addTodo函數(shù)中,我們使用fetch函數(shù)來(lái)發(fā)送POST請(qǐng)求,向后端的/todos路由添加待辦事項(xiàng),并在成功響應(yīng)后更新用戶界面。同樣地,在頁(yè)面加載時(shí),我們使用fetch函數(shù)發(fā)送GET請(qǐng)求,獲取所有的待辦事項(xiàng),并在成功響應(yīng)后將它們渲染到用戶界面中。
// frontend/main.js
const todoList = document.getElementById('todoList');
const todoInput = document.getElementById('todoInput');
function addTodo() {
const todoText = todoInput.value;
fetch('/todos', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ text: todoText })
})
.then(response => response.json())
.then(newTodo => {
const todoItem = document.createElement('li');
todoItem.textContent = newTodo.text;
todoList.appendChild(todoItem);
todoInput.value = '';
});
}
fetch('/todos')
.then(response => response.json())
.then(todos => {
todos.forEach(todo => {
const todoItem = document.createElement('li');
todoItem.textContent = todo.text;
todoList.appendChild(todoItem);
});
});我們使用fetch函數(shù)來(lái)發(fā)送GET和POST請(qǐng)求,對(duì)于POST請(qǐng)求,我們將請(qǐng)求的內(nèi)容以JSON格式發(fā)送,并在成功響應(yīng)后將新的待辦事項(xiàng)添加到用戶界面中,對(duì)于GET請(qǐng)求,我們將所有的待辦事項(xiàng)按順序添加到用戶界面中。
現(xiàn)在,我們已經(jīng)成功地集成了后端和前端。當(dāng)你在瀏覽器中訪問(wèn)http:http://localhost:5000/并添加待辦事項(xiàng)時(shí),你應(yīng)該能夠看到待辦事項(xiàng)動(dòng)態(tài)地顯示在界面上。
這就是在JavaScript中使用Python代碼的完整指南。通過(guò)正確地集成和通信,你可以在JavaScript應(yīng)用程序中使用Python來(lái)處理數(shù)據(jù)和邏輯。
最佳實(shí)踐和注意事項(xiàng)
在使用JavaScript中使用Python代碼時(shí),有幾個(gè)最佳實(shí)踐和注意事項(xiàng)需要考慮:
安全性考慮
在集成過(guò)程中,確保你在與Python代碼進(jìn)行交互時(shí)采取必要的安全防護(hù)措施,例如輸入驗(yàn)證和輸入過(guò)濾,以防止?jié)撛诘陌踩┒矗缈缯灸_本攻擊(XSS)和SQL注入。
性能優(yōu)化建議
JavaScript和Python在性能上有所不同,因此在集成過(guò)程中需要注意性能問(wèn)題。避免不必要的數(shù)據(jù)傳輸和處理,優(yōu)化代碼以提高響應(yīng)時(shí)間和資源利用率。
跨平臺(tái)兼容性
在集成過(guò)程中,要注意平臺(tái)兼容性。確保你的Python代碼和JavaScript代碼在不同的操作系統(tǒng)和瀏覽器中都能正常工作,避免依賴特定于平臺(tái)的功能或行為。
以上是一些關(guān)于在JavaScript中使用Python代碼的最佳實(shí)踐和注意事項(xiàng)。通過(guò)遵循這些指導(dǎo)原則,你可以確保集成過(guò)程的安全性、性能和可移植性。
總結(jié)
在服務(wù)器端,我們可以使用Node.js作為中介、通過(guò)子進(jìn)程調(diào)用Python代碼,或者通過(guò)HTTP請(qǐng)求與Python API通信。
在客戶端,我們可以使用WebAssembly執(zhí)行Python代碼、使用JavaScript庫(kù)與Python互動(dòng),或者通過(guò)WebSockets進(jìn)行實(shí)時(shí)通信。
未來(lái),隨著技術(shù)的不斷發(fā)展,對(duì)于在JavaScript中使用Python代碼的需求可能會(huì)繼續(xù)增長(zhǎng)。同時(shí),也可能會(huì)出現(xiàn)更多的工具和庫(kù)來(lái)簡(jiǎn)化和加強(qiáng)Python和JavaScript之間的集成能力,掘友們加油,說(shuō)不定下一個(gè)劃時(shí)代的工具,就是出自各位之手。
以上就是詳解如何在JavaScript中無(wú)縫地集成和使用Python代碼的詳細(xì)內(nèi)容,更多關(guān)于JavaScript使用Python代碼的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
JS實(shí)現(xiàn)可用滑塊滑動(dòng)的緩動(dòng)圖代碼
這篇文章主要介紹了JS實(shí)現(xiàn)可用滑塊滑動(dòng)的緩動(dòng)圖代碼,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-09-09
JavaScript使用performance實(shí)現(xiàn)查看內(nèi)存
這篇文章主要為大家詳細(xì)介紹了JavaScript如何使用performance實(shí)現(xiàn)查看內(nèi)存,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-03-03
JS輕松實(shí)現(xiàn)CSS設(shè)置,DIV+CSS常用CSS設(shè)置
JS輕松實(shí)現(xiàn)CSS設(shè)置,DIV+CSS常用CSS設(shè)置...2007-02-02
關(guān)于事件mouseover ,mouseout ,mouseenter,mouseleave的區(qū)別
mouseover ,mouseout ,mouseenter,mouseleave,都是鼠標(biāo)點(diǎn)擊而觸發(fā)的事件,各自代表什么意思,有哪些區(qū)別呢?下面跟著腳本之家小編一起看看吧2015-10-10
JS代碼屏蔽F12,右鍵,粘貼,復(fù)制,剪切,選中,操作實(shí)例
在本篇文章里小編給大家分享的是關(guān)于利用JS代碼屏蔽F12,右鍵,粘貼,復(fù)制,剪切,選中,操作,需要的朋友們學(xué)習(xí)下。2019-09-09
JS記錄用戶登錄次數(shù)實(shí)現(xiàn)代碼
當(dāng)?shù)卿洿螖?shù)達(dá)到三次,就自動(dòng)調(diào)用函數(shù),隱藏彈出框。下面是具體的實(shí)現(xiàn),感興趣的朋友可以參考下2014-01-01
js 巧妙去除數(shù)組中的重復(fù)項(xiàng)
最近, 我在看YAHOO.util.YUILoader類(lèi)的源碼, 其中有個(gè)排除數(shù)組重復(fù)項(xiàng)的方法, 讓我覺(jué)得甚為巧妙, 這里分享下…2010-01-01

