diff --git a/.gitignore b/.gitignore index 659cf51c..7b6cfdd7 100644 --- a/.gitignore +++ b/.gitignore @@ -145,3 +145,4 @@ homepage/static/css/**/*.css translations/codes.json .DS_Store +translations/chunks/ diff --git a/tests/golden_files/zh/test_transcript.json b/tests/golden_files/zh/test_transcript.json index e032ca5d..1ebbd701 100644 --- a/tests/golden_files/zh/test_transcript.json +++ b/tests/golden_files/zh/test_transcript.json @@ -1,11 +1,11 @@ [ { - "page": "Introducing The Shell", + "page": "\u4ecb\u7ecd Shell", "program": [ "'literally anything'" ], "response": { - "message": "
Awesome, you're trying out your own experiments!\nThat's a great sign. Keep it up.\nJust letting you know that you do need to eventually type 1+2
for the book to move forward.
\u5f88\u68d2\uff0c\u4f60\u5728\u5c1d\u8bd5\u81ea\u5df1\u7684\u5b9e\u9a8c\uff01\n\u8fd9\u771f\u662f\u4e2a\u597d\u5146\u5934\u3002\u7ee7\u7eed\u4fdd\u6301\u3002\n\u53ea\u662f\u8ba9\u4f60\u77e5\u9053\uff0c\u4f60\u6700\u7ec8\u9700\u8981\u8f93\u5165 1+2
\u624d\u80fd\u7ee7\u7eed\u8fdb\u884c\u3002
I see an 'x'. If you're trying to multiply, use an asterisk, e.g:
\n3 * 4\n
",
+ "message": "\u6211\u770b\u5230\u4e00\u4e2a 'x'\u3002\u5982\u679c\u4f60\u60f3\u8981\u4e58\u6cd5\uff0c\u8bf7\u4f7f\u7528\u661f\u53f7\uff0c\u4f8b\u5982\uff1a
\n3 * 4\n
",
"passed": false,
"result": [
{
- "text": " 3 x 4\n ^\nSyntaxError: invalid syntax\nat line 1\n\nA `SyntaxError` occurs when Python cannot understand your code.\n\nCurrently, I cannot guess the likely cause of this error.\nTry to examine closely the line indicated as well as the line\nimmediately above to see if you can identify some misspelled\nword, or missing symbols, like (, ), [, ], :, etc.\n\nUnless your code uses type annotations, which are beyond our scope,\nif you think that this is something which should be handled\nby friendly, please report this case to\nhttps://github.com/aroberge/friendly/issues\n\n\n\n",
+ "friendly": "A SyntaxError
occurs when Python cannot understand your code.
Currently, I cannot guess the likely cause of this error.\nTry to examine closely the line indicated as well as the line\nimmediately above to see if you can identify some misspelled\nword, or missing symbols, like (, ), [, ], :, etc.
\nUnless your code uses type annotations, which are beyond our scope,\nif you think that this is something which should be handled\nby friendly, please report this case to\nhttps://github.com/friendly-traceback/friendly-traceback/issues
", + "text": " 3 x 4\n ^\nSyntaxError: invalid syntax\n\u5728\u884c 1\n", "type": "syntax_error" } ] @@ -51,12 +52,12 @@ "step": "more_calculation" }, { - "page": "Introducing The Shell", + "get_solution": "program", + "page": "\u4ecb\u7ecd Shell", "program": [ "5 - 6" ], "response": { - "message": "", "passed": true, "result": [ { @@ -68,12 +69,12 @@ "step": "more_calculation" }, { - "page": "Introducing Strings", + "get_solution": "program", + "page": "\u4ecb\u7ecd\u5b57\u7b26\u4e32", "program": [ "'hello'" ], "response": { - "message": "", "passed": true, "result": [ { @@ -85,12 +86,12 @@ "step": "hello_string" }, { - "page": "Adding Strings", + "get_solution": "program", + "page": "\u6dfb\u52a0\u5b57\u7b26\u4e32", "program": [ "'hello' + 'world'" ], "response": { - "message": "", "passed": true, "result": [ { @@ -102,12 +103,12 @@ "step": "hello_world_concat" }, { - "page": "Adding Strings", + "page": "\u6dfb\u52a0\u5b57\u7b26\u4e32", "program": [ "'hello world'" ], "response": { - "message": "You must still add two or more strings together.
", + "message": "\u4f60\u4ecd\u7136\u5fc5\u987b\u5c06\u4e24\u4e2a\u6216\u66f4\u591a\u5b57\u7b26\u4e32\u76f8\u52a0\u3002
", "passed": false, "result": [ { @@ -119,15 +120,12 @@ "step": "hello_world_space" }, { - "get_solution": [ - "'hello ' + 'world'" - ], - "page": "Adding Strings", + "get_solution": "program", + "page": "\u6dfb\u52a0\u5b57\u7b26\u4e32", "program": [ "'hello ' + 'world'" ], "response": { - "message": "", "passed": true, "result": [ { @@ -139,36 +137,36 @@ "step": "hello_world_space" }, { - "page": "Introducing Variables", + "get_solution": "program", + "page": "\u4ecb\u7ecd\u53d8\u91cf", "program": [ "word = 'Hello'" ], "response": { - "message": "", "passed": true, "result": [] }, "step": "word_assign" }, { - "page": "Introducing Variables", + "page": "\u4ecb\u7ecd\u53d8\u91cf", "program": [ "word = 2" ], "response": { - "message": "Oops, you need to set word = 'Hello'
before we can continue.
\u54ce\u5440\uff0c\u4f60\u9700\u8981\u5148\u8bbe\u7f6e word = 'Hello'
\uff0c\u624d\u80fd\u7ee7\u7eed\u3002
print()
",
+ "page": "\u4f7f\u7528\u53d8\u91cf\u548c print()
",
"program": [
"foo = 3"
],
"response": {
- "message": "Put your_name
before the =
to create a variable called your_name
.
\u5728 =
\u524d\u9762\u653e\u4e0a your_name
\u6765\u521b\u5efa\u4e00\u4e2a\u540d\u4e3a your_name
\u7684\u53d8\u91cf\u3002
print()
",
+ "page": "\u4f7f\u7528\u53d8\u91cf\u548c print()
",
"program": [
"your_name = ''"
],
"response": {
- "message": "For this exercise, choose a non-empty string
", + "message": "\u5bf9\u4e8e\u8fd9\u4e2a\u7ec3\u4e60\uff0c\u9009\u62e9\u4e00\u4e2a\u975e\u7a7a\u5b57\u7b26\u4e32\u3002
", "passed": false, "result": [] }, "step": "name_assign" }, { - "page": "Using Variables andprint()
",
+ "page": "\u4f7f\u7528\u53d8\u91cf\u548c print()
",
"program": [
"your_name = 3"
],
"response": {
- "message": "You've got the your_name =
part right, now put a string (use quotes) on the right of the =
.
\u4f60\u5df2\u7ecf\u628a your_name =
\u90e8\u5206\u5199\u5bf9\u4e86\uff0c\u73b0\u5728\u5728 =
\u7684\u53f3\u8fb9\u653e\u4e00\u4e2a\u5b57\u7b26\u4e32\uff08\u4f7f\u7528\u5f15\u53f7\uff09\u3002
print()
",
+ "page": "\u4f7f\u7528\u53d8\u91cf\u548c print()
",
"program": [
"your_name = ' Alex'"
],
"response": {
- "message": "For this exercise, choose a name that doesn't start with a space.
", + "message": "\u5bf9\u4e8e\u8fd9\u4e2a\u7ec3\u4e60\uff0c\u9009\u62e9\u4e00\u4e2a\u4e0d\u4ee5\u7a7a\u683c\u5f00\u5934\u7684\u540d\u5b57\u3002
", "passed": false, "result": [] }, "step": "name_assign" }, { - "page": "Using Variables andprint()
",
+ "get_solution": "program",
+ "page": "\u4f7f\u7528\u53d8\u91cf\u548c print()
",
"program": [
"your_name = 'Alex'"
],
"response": {
- "message": "",
"passed": true,
"result": []
},
"step": "name_assign"
},
{
- "page": "Using Variables and print()
",
+ "get_solution": "program",
+ "page": "\u4f7f\u7528\u53d8\u91cf\u548c print()
",
"program": [
"'Hello ' + your_name"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -344,24 +344,24 @@
"step": "hello_plus_name"
},
{
- "page": "Using Variables and print()
",
+ "page": "\u4f7f\u7528\u53d8\u91cf\u548c print()
",
"program": [
"word = 2"
],
"response": {
- "message": "Oops, you need to set word = 'Hello'
before we can continue.
\u54ce\u5440\uff0c\u4f60\u9700\u8981\u5148\u8bbe\u7f6e word = 'Hello'
\uff0c\u624d\u80fd\u7ee7\u7eed\u3002
print()
",
+ "get_solution": "program",
+ "page": "\u4f7f\u7528\u53d8\u91cf\u548c print()
",
"program": [
"word + your_name"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -373,27 +373,24 @@
"step": "word_plus_name"
},
{
- "page": "Using Variables and print()
",
+ "page": "\u4f7f\u7528\u53d8\u91cf\u548c print()
",
"program": [
"word = 2"
],
"response": {
- "message": "Oops, you need to set word = 'Hello'
before we can continue.
\u54ce\u5440\uff0c\u4f60\u9700\u8981\u5148\u8bbe\u7f6e word = 'Hello'
\uff0c\u624d\u80fd\u7ee7\u7eed\u3002
print()
",
+ "get_solution": "program",
+ "page": "\u4f7f\u7528\u53d8\u91cf\u548c print()
",
"program": [
"word + ' ' + your_name"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -405,24 +402,24 @@
"step": "word_plus_name_with_space"
},
{
- "page": "Using Variables and print()
",
+ "get_solution": "program",
+ "page": "\u4f7f\u7528\u53d8\u91cf\u548c print()
",
"program": [
"word = 'Goodbye'"
],
"response": {
- "message": "",
"passed": true,
"result": []
},
"step": "word_assign_goodbye"
},
{
- "page": "Using Variables and print()
",
+ "get_solution": "program",
+ "page": "\u4f7f\u7528\u53d8\u91cf\u548c print()
",
"program": [
"word + ' ' + your_name"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -434,12 +431,12 @@
"step": "goodbye_plus_name"
},
{
- "page": "Using Variables and print()
",
+ "get_solution": "program",
+ "page": "\u4f7f\u7528\u53d8\u91cf\u548c print()
",
"program": [
"print(word + ' ' + your_name)"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -451,7 +448,8 @@
"step": "first_print"
},
{
- "page": "Writing Programs",
+ "get_solution": "program",
+ "page": "\u7f16\u5199\u7a0b\u5e8f",
"program": [
"word = 'Hello'",
"name = 'World'",
@@ -460,7 +458,6 @@
"print(word + ' ' + name)"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -472,7 +469,8 @@
"step": "editor_hello_world"
},
{
- "page": "Storing Calculations In Variables",
+ "get_solution": "program",
+ "page": "\u5728\u53d8\u91cf\u4e2d\u5b58\u50a8\u8ba1\u7b97",
"program": [
"word = 'Hello'",
"name = 'World'",
@@ -480,7 +478,6 @@
"print(sentence)"
],
"response": {
- "message": "",
"passed": true,
"prediction": {
"answer": "Hello World",
@@ -491,7 +488,7 @@
"'Hello' + ' ' + 'World'",
"Hello World",
"'Hello World'",
- "Error"
+ "\u9519\u8bef"
]
},
"result": [
@@ -504,7 +501,8 @@
"step": "sentence_equals_word_plus_name"
},
{
- "page": "Storing Calculations In Variables",
+ "get_solution": "program",
+ "page": "\u5728\u53d8\u91cf\u4e2d\u5b58\u50a8\u8ba1\u7b97",
"program": [
"word = 'Hello'",
"name = 'World'",
@@ -514,7 +512,6 @@
"print(sentence)"
],
"response": {
- "message": "",
"passed": true,
"prediction": {
"answer": "Hello World\nHello World",
@@ -522,7 +519,7 @@
"Hello World\nHello World",
"Hello World\nGoodbye World",
"Goodbye World\nGoodbye World",
- "Error"
+ "\u9519\u8bef"
]
},
"result": [
@@ -535,13 +532,13 @@
"step": "sentence_doesnt_change"
},
{
- "page": "Introducing For Loops",
+ "get_solution": "program",
+ "page": "\u5f15\u5165 For \u5faa\u73af",
"program": [
"name = 'World'",
"for character in name: print(character)"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -553,17 +550,18 @@
"step": "first_for_loop"
},
{
- "page": "Indentation",
+ "get_solution": "program",
+ "page": "\u7f29\u8fdb",
"program": [
"for character in name:",
"print(character)"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
- "text": " print(character)\n ^\nIndentationError: expected an indented block\nat line 2\n\nAn `IndentationError` occurs when a given line of code is\nnot indented (aligned vertically with other lines) as expected.\n\nLine `2` identified above was expected to begin a new indented block.\n\n\n",
+ "friendly": "An IndentationError
occurs when a given line of code is\nnot indented (aligned vertically with other lines) as expected.
Line 2
identified above was expected to begin a new indented block.
An IndentationError
occurs when a given line of code is\nnot indented (aligned vertically with other lines) as expected.
Line 3
identified above is less indented than expected.
Almost there! You have one space too many before each letter.\nMake sure that the first time your loop calls print
\nyour variable which will contain the spaces is an empty string.\nCheck the order of your code.
\u5feb\u5230\u4e86\uff01\u6bcf\u4e2a\u5b57\u6bcd\u524d\u9762\u591a\u4e86\u4e00\u4e2a\u7a7a\u683c\u3002\n\u786e\u4fdd\u4f60\u7684\u5faa\u73af\u7b2c\u4e00\u6b21\u8c03\u7528 print
\n\u65f6\uff0c\u5305\u542b\u7a7a\u683c\u7684\u53d8\u91cf\u662f\u4e00\u4e2a\u7a7a\u5b57\u7b26\u4e32\u3002\n\u68c0\u67e5\u4f60\u7684\u4ee3\u7801\u987a\u5e8f\u3002
snoop
",
+ "get_solution": "program",
+ "page": "\u4f7f\u7528 snoop
\u7406\u89e3\u7a0b\u5e8f",
"program": [
"sentence = 'Hello World'",
"",
@@ -1217,7 +1207,6 @@
"print(new_sentence)"
],
"response": {
- "message": "",
"passed": true,
"prediction": {
"answer": "ello World",
@@ -1227,7 +1216,7 @@
"Hello Worl",
"H",
"d",
- "Error"
+ "\u9519\u8bef"
]
},
"result": [
@@ -1240,7 +1229,8 @@
"step": "print_tail"
},
{
- "page": "Understanding Programs With snoop
",
+ "get_solution": "program",
+ "page": "\u4f7f\u7528 snoop
\u7406\u89e3\u7a0b\u5e8f",
"program": [
"sentence = 'Hello World'",
"",
@@ -1254,208 +1244,43 @@
"print(new_sentence)"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
- "text": "",
- "type": "stdout"
- },
- {
- "text": "\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 1\u001b[0m | sentence \u001b[38;5;197m=\u001b[39m \u001b[38;5;186m'\u001b[39m\u001b[38;5;186mHello World\u001b[39m\u001b[38;5;186m'\u001b[39m\n",
- "type": "stdout"
- },
- {
- "text": "\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 3\u001b[0m | include \u001b[38;5;197m=\u001b[39m \u001b[38;5;81mFalse\u001b[39m\n",
- "type": "stdout"
- },
- {
- "text": "\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 4\u001b[0m | new_sentence \u001b[38;5;197m=\u001b[39m \u001b[38;5;186m'\u001b[39m\u001b[38;5;186m'\u001b[39m\n",
- "type": "stdout"
- },
- {
- "text": "\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 5\u001b[0m | \u001b[38;5;81mfor\u001b[39m char \u001b[38;5;197min\u001b[39m sentence:\n",
- "type": "stdout"
- },
- {
- "text": "\u001b[38;5;242m \u001b[0m...... char = \u001b[38;5;186m'\u001b[39m\u001b[38;5;186mH\u001b[39m\u001b[38;5;186m'\u001b[39m\n\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 6\u001b[0m | \u001b[38;5;81mif\u001b[39m include:\n",
- "type": "stdout"
- },
- {
- "text": "\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 8\u001b[0m | include \u001b[38;5;197m=\u001b[39m \u001b[38;5;81mTrue\u001b[39m\n",
- "type": "stdout"
- },
- {
- "text": "\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 5\u001b[0m | \u001b[38;5;81mfor\u001b[39m char \u001b[38;5;197min\u001b[39m sentence:\n",
- "type": "stdout"
- },
- {
- "text": "\u001b[38;5;242m \u001b[0m...... char = \u001b[38;5;186m'\u001b[39m\u001b[38;5;186me\u001b[39m\u001b[38;5;186m'\u001b[39m\n\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 6\u001b[0m | \u001b[38;5;81mif\u001b[39m include:\n",
- "type": "stdout"
- },
- {
- "text": "\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 7\u001b[0m | new_sentence \u001b[38;5;197m+\u001b[39m\u001b[38;5;197m=\u001b[39m char\n",
- "type": "stdout"
- },
- {
- "text": "\u001b[38;5;242m \u001b[0m.............. new_sentence = \u001b[38;5;186m'\u001b[39m\u001b[38;5;186me\u001b[39m\u001b[38;5;186m'\u001b[39m\n\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 8\u001b[0m | include \u001b[38;5;197m=\u001b[39m \u001b[38;5;81mTrue\u001b[39m\n",
- "type": "stdout"
- },
- {
- "text": "\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 5\u001b[0m | \u001b[38;5;81mfor\u001b[39m char \u001b[38;5;197min\u001b[39m sentence:\n",
- "type": "stdout"
- },
- {
- "text": "\u001b[38;5;242m \u001b[0m...... char = \u001b[38;5;186m'\u001b[39m\u001b[38;5;186ml\u001b[39m\u001b[38;5;186m'\u001b[39m\n\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 6\u001b[0m | \u001b[38;5;81mif\u001b[39m include:\n",
- "type": "stdout"
- },
- {
- "text": "\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 7\u001b[0m | new_sentence \u001b[38;5;197m+\u001b[39m\u001b[38;5;197m=\u001b[39m char\n",
- "type": "stdout"
- },
- {
- "text": "\u001b[38;5;242m \u001b[0m.............. new_sentence = \u001b[38;5;186m'\u001b[39m\u001b[38;5;186mel\u001b[39m\u001b[38;5;186m'\u001b[39m\n\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 8\u001b[0m | include \u001b[38;5;197m=\u001b[39m \u001b[38;5;81mTrue\u001b[39m\n",
- "type": "stdout"
- },
- {
- "text": "\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 5\u001b[0m | \u001b[38;5;81mfor\u001b[39m char \u001b[38;5;197min\u001b[39m sentence:\n",
- "type": "stdout"
- },
- {
- "text": "\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 6\u001b[0m | \u001b[38;5;81mif\u001b[39m include:\n",
- "type": "stdout"
- },
- {
- "text": "\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 7\u001b[0m | new_sentence \u001b[38;5;197m+\u001b[39m\u001b[38;5;197m=\u001b[39m char\n",
- "type": "stdout"
- },
- {
- "text": "\u001b[38;5;242m \u001b[0m.............. new_sentence = \u001b[38;5;186m'\u001b[39m\u001b[38;5;186mell\u001b[39m\u001b[38;5;186m'\u001b[39m\n\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 8\u001b[0m | include \u001b[38;5;197m=\u001b[39m \u001b[38;5;81mTrue\u001b[39m\n",
- "type": "stdout"
- },
- {
- "text": "\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 5\u001b[0m | \u001b[38;5;81mfor\u001b[39m char \u001b[38;5;197min\u001b[39m sentence:\n",
- "type": "stdout"
- },
- {
- "text": "\u001b[38;5;242m \u001b[0m...... char = \u001b[38;5;186m'\u001b[39m\u001b[38;5;186mo\u001b[39m\u001b[38;5;186m'\u001b[39m\n\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 6\u001b[0m | \u001b[38;5;81mif\u001b[39m include:\n",
- "type": "stdout"
- },
- {
- "text": "\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 7\u001b[0m | new_sentence \u001b[38;5;197m+\u001b[39m\u001b[38;5;197m=\u001b[39m char\n",
- "type": "stdout"
- },
- {
- "text": "\u001b[38;5;242m \u001b[0m.............. new_sentence = \u001b[38;5;186m'\u001b[39m\u001b[38;5;186mello\u001b[39m\u001b[38;5;186m'\u001b[39m\n\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 8\u001b[0m | include \u001b[38;5;197m=\u001b[39m \u001b[38;5;81mTrue\u001b[39m\n",
- "type": "stdout"
- },
- {
- "text": "\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 5\u001b[0m | \u001b[38;5;81mfor\u001b[39m char \u001b[38;5;197min\u001b[39m sentence:\n",
- "type": "stdout"
- },
- {
- "text": "\u001b[38;5;242m \u001b[0m...... char = \u001b[38;5;186m'\u001b[39m\u001b[38;5;186m \u001b[39m\u001b[38;5;186m'\u001b[39m\n\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 6\u001b[0m | \u001b[38;5;81mif\u001b[39m include:\n",
- "type": "stdout"
- },
- {
- "text": "\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 7\u001b[0m | new_sentence \u001b[38;5;197m+\u001b[39m\u001b[38;5;197m=\u001b[39m char\n",
- "type": "stdout"
- },
- {
- "text": "\u001b[38;5;242m \u001b[0m.............. new_sentence = \u001b[38;5;186m'\u001b[39m\u001b[38;5;186mello \u001b[39m\u001b[38;5;186m'\u001b[39m\n\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 8\u001b[0m | include \u001b[38;5;197m=\u001b[39m \u001b[38;5;81mTrue\u001b[39m\n",
- "type": "stdout"
- },
- {
- "text": "\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 5\u001b[0m | \u001b[38;5;81mfor\u001b[39m char \u001b[38;5;197min\u001b[39m sentence:\n",
- "type": "stdout"
- },
- {
- "text": "\u001b[38;5;242m \u001b[0m...... char = \u001b[38;5;186m'\u001b[39m\u001b[38;5;186mW\u001b[39m\u001b[38;5;186m'\u001b[39m\n\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 6\u001b[0m | \u001b[38;5;81mif\u001b[39m include:\n",
- "type": "stdout"
- },
- {
- "text": "\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 7\u001b[0m | new_sentence \u001b[38;5;197m+\u001b[39m\u001b[38;5;197m=\u001b[39m char\n",
- "type": "stdout"
- },
- {
- "text": "\u001b[38;5;242m \u001b[0m.............. new_sentence = \u001b[38;5;186m'\u001b[39m\u001b[38;5;186mello W\u001b[39m\u001b[38;5;186m'\u001b[39m\n\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 8\u001b[0m | include \u001b[38;5;197m=\u001b[39m \u001b[38;5;81mTrue\u001b[39m\n",
- "type": "stdout"
- },
- {
- "text": "\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 5\u001b[0m | \u001b[38;5;81mfor\u001b[39m char \u001b[38;5;197min\u001b[39m sentence:\n",
- "type": "stdout"
- },
- {
- "text": "\u001b[38;5;242m \u001b[0m...... char = \u001b[38;5;186m'\u001b[39m\u001b[38;5;186mo\u001b[39m\u001b[38;5;186m'\u001b[39m\n\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 6\u001b[0m | \u001b[38;5;81mif\u001b[39m include:\n",
- "type": "stdout"
- },
- {
- "text": "\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 7\u001b[0m | new_sentence \u001b[38;5;197m+\u001b[39m\u001b[38;5;197m=\u001b[39m char\n",
- "type": "stdout"
- },
- {
- "text": "\u001b[38;5;242m \u001b[0m.............. new_sentence = \u001b[38;5;186m'\u001b[39m\u001b[38;5;186mello Wo\u001b[39m\u001b[38;5;186m'\u001b[39m\n\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 8\u001b[0m | include \u001b[38;5;197m=\u001b[39m \u001b[38;5;81mTrue\u001b[39m\n",
- "type": "stdout"
- },
- {
- "text": "\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 5\u001b[0m | \u001b[38;5;81mfor\u001b[39m char \u001b[38;5;197min\u001b[39m sentence:\n",
- "type": "stdout"
- },
- {
- "text": "\u001b[38;5;242m \u001b[0m...... char = \u001b[38;5;186m'\u001b[39m\u001b[38;5;186mr\u001b[39m\u001b[38;5;186m'\u001b[39m\n\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 6\u001b[0m | \u001b[38;5;81mif\u001b[39m include:\n",
- "type": "stdout"
- },
- {
- "text": "\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 7\u001b[0m | new_sentence \u001b[38;5;197m+\u001b[39m\u001b[38;5;197m=\u001b[39m char\n",
- "type": "stdout"
- },
- {
- "text": "\u001b[38;5;242m \u001b[0m.............. new_sentence = \u001b[38;5;186m'\u001b[39m\u001b[38;5;186mello Wor\u001b[39m\u001b[38;5;186m'\u001b[39m\n\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 8\u001b[0m | include \u001b[38;5;197m=\u001b[39m \u001b[38;5;81mTrue\u001b[39m\n",
- "type": "stdout"
- },
- {
- "text": "\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 5\u001b[0m | \u001b[38;5;81mfor\u001b[39m char \u001b[38;5;197min\u001b[39m sentence:\n",
- "type": "stdout"
- },
- {
- "text": "\u001b[38;5;242m \u001b[0m...... char = \u001b[38;5;186m'\u001b[39m\u001b[38;5;186ml\u001b[39m\u001b[38;5;186m'\u001b[39m\n\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 6\u001b[0m | \u001b[38;5;81mif\u001b[39m include:\n",
- "type": "stdout"
- },
- {
- "text": "\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 7\u001b[0m | new_sentence \u001b[38;5;197m+\u001b[39m\u001b[38;5;197m=\u001b[39m char\n",
- "type": "stdout"
+ "text": "\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 1\u001b[0m | sentence \u001b[38;5;204m=\u001b[39m \u001b[38;5;186m'\u001b[39m\u001b[38;5;186mHello World\u001b[39m\u001b[38;5;186m'\u001b[39m\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 3\u001b[0m | include \u001b[38;5;204m=\u001b[39m \u001b[38;5;81mFalse\u001b[39m\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 4\u001b[0m | new_sentence \u001b[38;5;204m=\u001b[39m \u001b[38;5;186m'\u001b[39m\u001b[38;5;186m'\u001b[39m\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 5\u001b[0m | \u001b[38;5;81mfor\u001b[39m char \u001b[38;5;204min\u001b[39m sentence:\n\u001b[38;5;245m \u001b[0m...... char = \u001b[38;5;186m'\u001b[39m\u001b[38;5;186mH\u001b[39m\u001b[38;5;186m'\u001b[39m\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 6\u001b[0m | \u001b[38;5;81mif\u001b[39m include:\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 8\u001b[0m | include \u001b[38;5;204m=\u001b[39m \u001b[38;5;81mTrue\u001b[39m\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 5\u001b[0m | \u001b[38;5;81mfor\u001b[39m char \u001b[38;5;204min\u001b[39m sentence:\n\u001b[38;5;245m \u001b[0m...... char = \u001b[38;5;186m'\u001b[39m\u001b[38;5;186me\u001b[39m\u001b[38;5;186m'\u001b[39m\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 6\u001b[0m | \u001b[38;5;81mif\u001b[39m include:\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 7\u001b[0m | new_sentence \u001b[38;5;204m+\u001b[39m\u001b[38;5;204m=\u001b[39m char\n\u001b[38;5;245m \u001b[0m.............. new_sentence = \u001b[38;5;186m'\u001b[39m\u001b[38;5;186me\u001b[39m\u001b[38;5;186m'\u001b[39m\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 8\u001b[0m | include \u001b[38;5;204m=\u001b[39m \u001b[38;5;81mTrue\u001b[39m\n",
+ "type": "snoop"
},
{
- "text": "\u001b[38;5;242m \u001b[0m.............. new_sentence = \u001b[38;5;186m'\u001b[39m\u001b[38;5;186mello Worl\u001b[39m\u001b[38;5;186m'\u001b[39m\n\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 8\u001b[0m | include \u001b[38;5;197m=\u001b[39m \u001b[38;5;81mTrue\u001b[39m\n",
- "type": "stdout"
+ "text": "\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 5\u001b[0m | \u001b[38;5;81mfor\u001b[39m char \u001b[38;5;204min\u001b[39m sentence:\n\u001b[38;5;245m \u001b[0m...... char = \u001b[38;5;186m'\u001b[39m\u001b[38;5;186ml\u001b[39m\u001b[38;5;186m'\u001b[39m\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 6\u001b[0m | \u001b[38;5;81mif\u001b[39m include:\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 7\u001b[0m | new_sentence \u001b[38;5;204m+\u001b[39m\u001b[38;5;204m=\u001b[39m char\n\u001b[38;5;245m \u001b[0m.............. new_sentence = \u001b[38;5;186m'\u001b[39m\u001b[38;5;186mel\u001b[39m\u001b[38;5;186m'\u001b[39m\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 8\u001b[0m | include \u001b[38;5;204m=\u001b[39m \u001b[38;5;81mTrue\u001b[39m\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 5\u001b[0m | \u001b[38;5;81mfor\u001b[39m char \u001b[38;5;204min\u001b[39m sentence:\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 6\u001b[0m | \u001b[38;5;81mif\u001b[39m include:\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 7\u001b[0m | new_sentence \u001b[38;5;204m+\u001b[39m\u001b[38;5;204m=\u001b[39m char\n\u001b[38;5;245m \u001b[0m.............. new_sentence = \u001b[38;5;186m'\u001b[39m\u001b[38;5;186mell\u001b[39m\u001b[38;5;186m'\u001b[39m\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 8\u001b[0m | include \u001b[38;5;204m=\u001b[39m \u001b[38;5;81mTrue\u001b[39m\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 5\u001b[0m | \u001b[38;5;81mfor\u001b[39m char \u001b[38;5;204min\u001b[39m sentence:\n",
+ "type": "snoop"
},
{
- "text": "\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 5\u001b[0m | \u001b[38;5;81mfor\u001b[39m char \u001b[38;5;197min\u001b[39m sentence:\n",
- "type": "stdout"
+ "text": "\u001b[38;5;245m \u001b[0m...... char = \u001b[38;5;186m'\u001b[39m\u001b[38;5;186mo\u001b[39m\u001b[38;5;186m'\u001b[39m\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 6\u001b[0m | \u001b[38;5;81mif\u001b[39m include:\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 7\u001b[0m | new_sentence \u001b[38;5;204m+\u001b[39m\u001b[38;5;204m=\u001b[39m char\n\u001b[38;5;245m \u001b[0m.............. new_sentence = \u001b[38;5;186m'\u001b[39m\u001b[38;5;186mello\u001b[39m\u001b[38;5;186m'\u001b[39m\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 8\u001b[0m | include \u001b[38;5;204m=\u001b[39m \u001b[38;5;81mTrue\u001b[39m\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 5\u001b[0m | \u001b[38;5;81mfor\u001b[39m char \u001b[38;5;204min\u001b[39m sentence:\n\u001b[38;5;245m \u001b[0m...... char = \u001b[38;5;186m'\u001b[39m\u001b[38;5;186m \u001b[39m\u001b[38;5;186m'\u001b[39m\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 6\u001b[0m | \u001b[38;5;81mif\u001b[39m include:\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 7\u001b[0m | new_sentence \u001b[38;5;204m+\u001b[39m\u001b[38;5;204m=\u001b[39m char\n\u001b[38;5;245m \u001b[0m.............. new_sentence = \u001b[38;5;186m'\u001b[39m\u001b[38;5;186mello \u001b[39m\u001b[38;5;186m'\u001b[39m\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 8\u001b[0m | include \u001b[38;5;204m=\u001b[39m \u001b[38;5;81mTrue\u001b[39m\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 5\u001b[0m | \u001b[38;5;81mfor\u001b[39m char \u001b[38;5;204min\u001b[39m sentence:\n",
+ "type": "snoop"
},
{
- "text": "\u001b[38;5;242m \u001b[0m...... char = \u001b[38;5;186m'\u001b[39m\u001b[38;5;186md\u001b[39m\u001b[38;5;186m'\u001b[39m\n\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 6\u001b[0m | \u001b[38;5;81mif\u001b[39m include:\n",
- "type": "stdout"
+ "text": "\u001b[38;5;245m \u001b[0m...... char = \u001b[38;5;186m'\u001b[39m\u001b[38;5;186mW\u001b[39m\u001b[38;5;186m'\u001b[39m\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 6\u001b[0m | \u001b[38;5;81mif\u001b[39m include:\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 7\u001b[0m | new_sentence \u001b[38;5;204m+\u001b[39m\u001b[38;5;204m=\u001b[39m char\n\u001b[38;5;245m \u001b[0m.............. new_sentence = \u001b[38;5;186m'\u001b[39m\u001b[38;5;186mello W\u001b[39m\u001b[38;5;186m'\u001b[39m\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 8\u001b[0m | include \u001b[38;5;204m=\u001b[39m \u001b[38;5;81mTrue\u001b[39m\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 5\u001b[0m | \u001b[38;5;81mfor\u001b[39m char \u001b[38;5;204min\u001b[39m sentence:\n\u001b[38;5;245m \u001b[0m...... char = \u001b[38;5;186m'\u001b[39m\u001b[38;5;186mo\u001b[39m\u001b[38;5;186m'\u001b[39m\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 6\u001b[0m | \u001b[38;5;81mif\u001b[39m include:\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 7\u001b[0m | new_sentence \u001b[38;5;204m+\u001b[39m\u001b[38;5;204m=\u001b[39m char\n\u001b[38;5;245m \u001b[0m.............. new_sentence = \u001b[38;5;186m'\u001b[39m\u001b[38;5;186mello Wo\u001b[39m\u001b[38;5;186m'\u001b[39m\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 8\u001b[0m | include \u001b[38;5;204m=\u001b[39m \u001b[38;5;81mTrue\u001b[39m\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 5\u001b[0m | \u001b[38;5;81mfor\u001b[39m char \u001b[38;5;204min\u001b[39m sentence:\n",
+ "type": "snoop"
},
{
- "text": "\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 7\u001b[0m | new_sentence \u001b[38;5;197m+\u001b[39m\u001b[38;5;197m=\u001b[39m char\n",
- "type": "stdout"
+ "text": "\u001b[38;5;245m \u001b[0m...... char = \u001b[38;5;186m'\u001b[39m\u001b[38;5;186mr\u001b[39m\u001b[38;5;186m'\u001b[39m\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 6\u001b[0m | \u001b[38;5;81mif\u001b[39m include:\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 7\u001b[0m | new_sentence \u001b[38;5;204m+\u001b[39m\u001b[38;5;204m=\u001b[39m char\n\u001b[38;5;245m \u001b[0m.............. new_sentence = \u001b[38;5;186m'\u001b[39m\u001b[38;5;186mello Wor\u001b[39m\u001b[38;5;186m'\u001b[39m\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 8\u001b[0m | include \u001b[38;5;204m=\u001b[39m \u001b[38;5;81mTrue\u001b[39m\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 5\u001b[0m | \u001b[38;5;81mfor\u001b[39m char \u001b[38;5;204min\u001b[39m sentence:\n\u001b[38;5;245m \u001b[0m...... char = \u001b[38;5;186m'\u001b[39m\u001b[38;5;186ml\u001b[39m\u001b[38;5;186m'\u001b[39m\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 6\u001b[0m | \u001b[38;5;81mif\u001b[39m include:\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 7\u001b[0m | new_sentence \u001b[38;5;204m+\u001b[39m\u001b[38;5;204m=\u001b[39m char\n\u001b[38;5;245m \u001b[0m.............. new_sentence = \u001b[38;5;186m'\u001b[39m\u001b[38;5;186mello Worl\u001b[39m\u001b[38;5;186m'\u001b[39m\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 8\u001b[0m | include \u001b[38;5;204m=\u001b[39m \u001b[38;5;81mTrue\u001b[39m\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 5\u001b[0m | \u001b[38;5;81mfor\u001b[39m char \u001b[38;5;204min\u001b[39m sentence:\n",
+ "type": "snoop"
},
{
- "text": "\u001b[38;5;242m \u001b[0m.............. new_sentence = \u001b[38;5;186m'\u001b[39m\u001b[38;5;186mello World\u001b[39m\u001b[38;5;186m'\u001b[39m\n\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 8\u001b[0m | include \u001b[38;5;197m=\u001b[39m \u001b[38;5;81mTrue\u001b[39m\n",
- "type": "stdout"
+ "text": "\u001b[38;5;245m \u001b[0m...... char = \u001b[38;5;186m'\u001b[39m\u001b[38;5;186md\u001b[39m\u001b[38;5;186m'\u001b[39m\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 6\u001b[0m | \u001b[38;5;81mif\u001b[39m include:\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 7\u001b[0m | new_sentence \u001b[38;5;204m+\u001b[39m\u001b[38;5;204m=\u001b[39m char\n\u001b[38;5;245m \u001b[0m.............. new_sentence = \u001b[38;5;186m'\u001b[39m\u001b[38;5;186mello World\u001b[39m\u001b[38;5;186m'\u001b[39m\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 8\u001b[0m | include \u001b[38;5;204m=\u001b[39m \u001b[38;5;81mTrue\u001b[39m\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 5\u001b[0m | \u001b[38;5;81mfor\u001b[39m char \u001b[38;5;204min\u001b[39m sentence:\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 10\u001b[0m | print(new_sentence)\n",
+ "type": "snoop"
},
{
- "text": "\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 5\u001b[0m | \u001b[38;5;81mfor\u001b[39m char \u001b[38;5;197min\u001b[39m sentence:\n",
+ "text": "ello World",
"type": "stdout"
},
{
- "text": "\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 10\u001b[0m | print(new_sentence)\n",
+ "text": "\n",
"type": "stdout"
},
{
- "text": "ello World\n",
- "type": "stdout"
+ "text": "",
+ "type": "snoop"
}
]
},
@@ -1472,7 +1297,7 @@
"",
"print(new_sentence)"
],
- "page": "Understanding Programs With snoop
",
+ "page": "\u4f7f\u7528 snoop
\u7406\u89e3\u7a0b\u5e8f",
"program": [
"sentence = 'Hello there'",
"include = True",
@@ -1485,7 +1310,6 @@
"print(new_sentence)"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -1497,7 +1321,8 @@
"step": "print_first_character"
},
{
- "page": "if
and else
",
+ "get_solution": "program",
+ "page": "if
\u548c else
",
"program": [
"condition = True",
"if condition:",
@@ -1506,7 +1331,6 @@
" print('No')"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -1518,7 +1342,8 @@
"step": "first_if_else"
},
{
- "page": "if
and else
",
+ "get_solution": "program",
+ "page": "if
\u548c else
",
"program": [
"condition = False",
"if condition:",
@@ -1527,7 +1352,6 @@
" print('No')"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -1539,7 +1363,8 @@
"step": "first_if_else_false"
},
{
- "page": "if
and else
",
+ "get_solution": "program",
+ "page": "if
\u548c else
",
"program": [
"sentence = 'Hello World'",
"excited = True",
@@ -1550,7 +1375,6 @@
"print(sentence)"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -1562,7 +1386,8 @@
"step": "if_upper_else_lower"
},
{
- "page": "if
and else
",
+ "get_solution": "program",
+ "page": "if
\u548c else
",
"program": [
"sentence = 'Hello World'",
"excited = False",
@@ -1573,7 +1398,6 @@
"print(sentence)"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -1585,7 +1409,8 @@
"step": "if_upper_else_lower_false"
},
{
- "page": "if
and else
",
+ "get_solution": "program",
+ "page": "if
\u548c else
",
"program": [
"sentence = 'Hello World'",
"excited = False",
@@ -1597,14 +1422,13 @@
"print(sentence)"
],
"response": {
- "message": "",
"passed": true,
"prediction": {
- "answer": "Error",
+ "answer": "\u9519\u8bef",
"choices": [
"Hello World",
"Hello World!",
- "Error"
+ "\u9519\u8bef"
]
},
"result": [
@@ -1620,11 +1444,13 @@
},
"frames": [
{
+ "filename": "/my_program.py",
+ "lineno": 6,
"lines": [
{
- "content": "sentence += char",
"is_current": true,
"lineno": 6,
+ "text": "sentence += char",
"type": "line"
}
],
@@ -1648,7 +1474,7 @@
],
"text": [
"Traceback (most recent call last):",
- " File \"my_program.py\", line 6, in if
and else
",
+ "get_solution": [
+ "if excited:",
+ " char = '!'",
+ "else:",
+ " char = '.'",
+ "sentence += char",
+ "",
+ "print(sentence)"
+ ],
+ "page": "if
\u548c else
",
"program": [
"sentence = 'Hello there'",
"excited = True",
@@ -1677,7 +1512,6 @@
"print(sentence)"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -1702,7 +1536,7 @@
"",
"print(new_sentence)"
],
- "page": "if
and else
",
+ "page": "if
\u548c else
",
"program": [
"sentence = 'HELLO THERE'",
"upper = True",
@@ -1718,7 +1552,6 @@
"print(new_sentence)"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -1744,7 +1577,7 @@
"",
"print(new_sentence)"
],
- "page": "if
and else
",
+ "page": "if
\u548c else
",
"program": [
"sentence = 'One more exercise, and then you can relax.'",
"upper = True",
@@ -1761,7 +1594,6 @@
"print(new_sentence)"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -1773,14 +1605,14 @@
"step": "spongebob"
},
{
- "page": "The Equality Operator",
+ "get_solution": "program",
+ "page": "\u7b49\u53f7\u8fd0\u7b97\u7b26",
"program": [
"print(1 + 2 == 3)",
"print(4 + 5 == 6)",
"print('ab' + 'c' == 'a' + 'bc')"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -1792,16 +1624,17 @@
"step": "introducing_equality"
},
{
- "page": "The Equality Operator",
+ "get_solution": "program",
+ "page": "\u7b49\u53f7\u8fd0\u7b97\u7b26",
"program": [
"print(1 + 2 = 3)"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
- "text": " print(1 + 2 = 3)\n ^\nSyntaxError: expression cannot contain assignment, perhaps you meant \"==\"?\nat line 1\n\nA `SyntaxError` occurs when Python cannot understand your code.\n\nYou likely called a function with a named argument:\n\n a_function(invalid=something) \n\nwhere `invalid` is not a valid variable name in Python\neither because it starts with a number, or is a string,\nor contains a period, etc.\n\n\n",
+ "friendly": "A SyntaxError
occurs when Python cannot understand your code.
You likely called a function with a named argument:
\na_function(invalid=something)\n
\nwhere invalid
is not a valid variable name in Python\neither because it starts with a number, or is a string,\nor contains a period, etc.
elif
",
+ "get_solution": "program",
+ "page": "\u4ecb\u7ecdelif
",
"program": [
"dna = 'AGTAGCGTC'",
"opposite_dna = ''",
@@ -1892,7 +1725,6 @@
"print(opposite_dna)"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -1921,7 +1753,7 @@
"",
"print(opposite_dna)"
],
- "page": "Introducing elif
",
+ "page": "\u4ecb\u7ecdelif
",
"program": [
"dna = 'AGTAGCGTCCTTAGTTACAGGATGGCTTAT'",
"opposite_dna = ''",
@@ -1941,7 +1773,6 @@
"print(opposite_dna)"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -1953,7 +1784,8 @@
"step": "dna_example_with_else"
},
{
- "page": "Introducing elif
",
+ "get_solution": "program",
+ "page": "\u4ecb\u7ecdelif
",
"program": [
"dna = 'AGTAGCGTC'",
"opposite_dna = ''",
@@ -1971,7 +1803,6 @@
"print(opposite_dna)"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -1983,13 +1814,21 @@
"step": "dna_example_with_elif"
},
{
- "page": "Other Comparison Operators",
+ "get_solution": "program",
+ "page": "\u5176\u4ed6\u6bd4\u8f83\u8fd0\u7b97\u7b26",
"program": [
"1 != 2"
],
"response": {
- "message": "",
"passed": true,
+ "prediction": {
+ "answer": "True",
+ "choices": [
+ "True",
+ "False",
+ "\u9519\u8bef"
+ ]
+ },
"result": [
{
"text": "True\n",
@@ -2000,7 +1839,8 @@
"step": "try_not_equals"
},
{
- "page": "Other Comparison Operators",
+ "get_solution": "program",
+ "page": "\u5176\u4ed6\u6bd4\u8f83\u8fd0\u7b97\u7b26",
"program": [
"sentence = 'The e key on my keyboard is broken'",
"new_sentence = ''",
@@ -2010,7 +1850,6 @@
"print(new_sentence)"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -2022,15 +1861,12 @@
"step": "brokn_kyboard"
},
{
- "get_solution": [
- "1 < 2"
- ],
- "page": "Other Comparison Operators",
+ "get_solution": "program",
+ "page": "\u5176\u4ed6\u6bd4\u8f83\u8fd0\u7b97\u7b26",
"program": [
"1 < 2"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -2042,15 +1878,12 @@
"step": "introducing_less_than"
},
{
- "get_solution": [
- "'1' < '2'"
- ],
- "page": "Other Comparison Operators",
+ "get_solution": "program",
+ "page": "\u5176\u4ed6\u6bd4\u8f83\u8fd0\u7b97\u7b26",
"program": [
"'1' < '2'"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -2062,7 +1895,8 @@
"step": "comparing_strings"
},
{
- "page": "Other Comparison Operators",
+ "get_solution": "program",
+ "page": "\u5176\u4ed6\u6bd4\u8f83\u8fd0\u7b97\u7b26",
"program": [
"percentage = 73",
"",
@@ -2078,7 +1912,6 @@
"print(grade)"
],
"response": {
- "message": "",
"passed": true,
"prediction": {
"answer": "B",
@@ -2087,7 +1920,7 @@
"C",
"B",
"A",
- "Error"
+ "\u9519\u8bef"
]
},
"result": [
@@ -2113,7 +1946,7 @@
" first = x3",
"print(first)"
],
- "page": "Other Comparison Operators",
+ "page": "\u5176\u4ed6\u6bd4\u8f83\u8fd0\u7b97\u7b26",
"program": [
"x1 = 1",
"x2 = 2",
@@ -2131,7 +1964,6 @@
"print(first)"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -2143,7 +1975,8 @@
"step": "min_three_exercise"
},
{
- "page": "Introducing Lists",
+ "get_solution": "program",
+ "page": "\u4ecb\u7ecd\u5217\u8868",
"program": [
"words = ['This', 'is', 'a', 'list']",
"",
@@ -2151,7 +1984,6 @@
" print(word)"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -2163,14 +1995,14 @@
"step": "first_list"
},
{
- "page": "Introducing Lists",
+ "get_solution": "program",
+ "page": "\u4ecb\u7ecd\u5217\u8868",
"program": [
"x = 1",
"things = ['Hello', x, x + 3]",
"print(things)"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -2182,7 +2014,8 @@
"step": "can_contain_anything"
},
{
- "page": "Introducing Lists",
+ "get_solution": "program",
+ "page": "\u4ecb\u7ecd\u5217\u8868",
"program": [
"numbers = [3, 1, 4, 1, 5, 9]",
"",
@@ -2193,7 +2026,6 @@
"print(total)"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -2212,7 +2044,7 @@
"",
"print(total)"
],
- "page": "Introducing Lists",
+ "page": "\u4ecb\u7ecd\u5217\u8868",
"program": [
"words = ['This', 'is', 'a', 'list']",
"total = ''",
@@ -2222,7 +2054,6 @@
"print(total)"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -2246,7 +2077,7 @@
"",
"print(total)"
],
- "page": "Introducing Lists",
+ "page": "\u4ecb\u7ecd\u5217\u8868",
"program": [
"words = ['This', 'is', 'a', 'list']",
"separator = ' - '",
@@ -2262,7 +2093,6 @@
"print(total)"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -2280,7 +2110,7 @@
" double += [number * 2]",
"print(double)"
],
- "page": "Building New Lists",
+ "page": "\u6784\u5efa\u65b0\u5217\u8868",
"program": [
"numbers = [3, 1, 4, 1, 5, 9, 2, 6, 5]",
"double = []",
@@ -2289,7 +2119,6 @@
"print(double)"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -2308,7 +2137,7 @@
" big_numbers.append(number)",
"print(big_numbers)"
],
- "page": "Building New Lists",
+ "page": "\u6784\u5efa\u65b0\u5217\u8868",
"program": [
"numbers = [3, 1, 4, 1, 5, 9, 2, 6, 5]",
"big_numbers = []",
@@ -2318,7 +2147,6 @@
"print(big_numbers)"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -2338,7 +2166,7 @@
"",
"print(found)"
],
- "page": "Using break
to end a loop early",
+ "page": "\u4f7f\u7528 break
\u63d0\u524d\u7ed3\u675f\u5faa\u73af",
"program": [
"things = ['This', 'is', 'a', 'list']",
"thing_to_find = 'is'",
@@ -2350,7 +2178,6 @@
"print(found)"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -2362,7 +2189,8 @@
"step": "list_contains_exercise"
},
{
- "page": "Getting elements at a position, range()
, and len()
",
+ "get_solution": "program",
+ "page": "\u83b7\u53d6\u4f4d\u7f6e\u7684\u5143\u7d20\uff0crange()
\u548c len()
",
"program": [
"words = ['This', 'is', 'a', 'list']",
"",
@@ -2372,7 +2200,6 @@
"print(words[3])"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -2384,12 +2211,12 @@
"step": "introducing_subscripting"
},
{
- "page": "Getting elements at a position, range()
, and len()
",
+ "get_solution": "program",
+ "page": "\u83b7\u53d6\u4f4d\u7f6e\u7684\u5143\u7d20\uff0crange()
\u548c len()
",
"program": [
"words[4]"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -2402,11 +2229,13 @@
},
"frames": [
{
+ "filename": "/my_program.py",
+ "lineno": 1,
"lines": [
{
- "content": "words[4]",
"is_current": true,
"lineno": 1,
+ "text": "words[4]",
"type": "line"
}
],
@@ -2426,7 +2255,7 @@
],
"text": [
"Traceback (most recent call last):",
- " File \"my_program.py\", line 1, in range()
, and len()
",
+ "get_solution": "program",
+ "page": "\u83b7\u53d6\u4f4d\u7f6e\u7684\u5143\u7d20\uff0crange()
\u548c len()
",
"program": [
"words = ['This', 'is', 'a', 'list']",
"indices = [0, 1, 2, 3]",
@@ -2450,7 +2280,6 @@
" print(words[index])"
],
"response": {
- "message": "",
"passed": true,
"prediction": {
"answer": "0\nThis\n1\nis\n2\na\n3\nlist",
@@ -2461,7 +2290,7 @@
"This\n0\nis\n1\na\n2\nlist\n3",
"0\n1\n2\n3\nThis\nis\na\nlist",
"This\nis\na\nlist\n0\n1\n2\n3",
- "Error"
+ "\u9519\u8bef"
]
},
"result": [
@@ -2474,7 +2303,8 @@
"step": "introducing_len_and_range"
},
{
- "page": "Getting elements at a position, range()
, and len()
",
+ "get_solution": "program",
+ "page": "\u83b7\u53d6\u4f4d\u7f6e\u7684\u5143\u7d20\uff0crange()
\u548c len()
",
"program": [
"words = ['This', 'is', 'a', 'list']",
"indices = range(4)",
@@ -2484,7 +2314,6 @@
" print(words[index])"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -2496,7 +2325,8 @@
"step": "range_len"
},
{
- "page": "Getting elements at a position, range()
, and len()
",
+ "get_solution": "program",
+ "page": "\u83b7\u53d6\u4f4d\u7f6e\u7684\u5143\u7d20\uff0crange()
\u548c len()
",
"program": [
"indices = range(4)",
"",
@@ -2506,7 +2336,6 @@
"print(indices[3])"
],
"response": {
- "message": "",
"passed": true,
"prediction": {
"answer": "0\n1\n2\n3",
@@ -2516,7 +2345,7 @@
"[0]\n[1]\n[2]\n[3]",
"[1]\n[2]\n[3]\n[4]",
"This\nis\na\nlist",
- "Error"
+ "\u9519\u8bef"
]
},
"result": [
@@ -2529,22 +2358,22 @@
"step": "printing_the_range"
},
{
- "page": "Getting elements at a position, range()
, and len()
",
+ "get_solution": "program",
+ "page": "\u83b7\u53d6\u4f4d\u7f6e\u7684\u5143\u7d20\uff0crange()
\u548c len()
",
"program": [
"indices[4]"
],
"response": {
- "message": "",
"passed": true,
"prediction": {
- "answer": "Error",
+ "answer": "\u9519\u8bef",
"choices": [
"0",
"1",
"2",
"3",
"4",
- "Error"
+ "\u9519\u8bef"
]
},
"result": [
@@ -2558,11 +2387,13 @@
},
"frames": [
{
+ "filename": "/my_program.py",
+ "lineno": 1,
"lines": [
{
- "content": "indices[4]",
"is_current": true,
"lineno": 1,
+ "text": "indices[4]",
"type": "line"
}
],
@@ -2576,13 +2407,13 @@
]
}
],
- "friendly": "An IndexError
occurs when you try to get an item from a list,\na tuple, or a similar object (sequence), and use an index which\ndoes not exist; typically, this happens because the index you give\nis greater than the length of the sequence.
You have tried to get the item with index 4
of indices
,\nrange object of length 4
.\nThe valid index values of indices
are integers ranging from\n-4
to 3
.
An IndexError
occurs when you try to get an item from a list,\na tuple, or a similar object (sequence), and use an index which\ndoes not exist; typically, this happens because the index you give\nis greater than the length of the sequence.
You have tried to get the item with index 4
of indices
,\nrange object
of length 4
.\nThe valid index values of indices
are integers ranging from\n-4
to 3
.
range()
, and len()
",
+ "get_solution": "program",
+ "page": "\u83b7\u53d6\u4f4d\u7f6e\u7684\u5143\u7d20\uff0crange()
\u548c len()
",
"program": [
"range(4)"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -2613,12 +2444,12 @@
"step": "range_almost_the_same_as_list"
},
{
- "page": "Getting elements at a position, range()
, and len()
",
+ "get_solution": "program",
+ "page": "\u83b7\u53d6\u4f4d\u7f6e\u7684\u5143\u7d20\uff0crange()
\u548c len()
",
"program": [
"list(range(4))"
],
"response": {
- "message": "",
"passed": true,
"prediction": {
"answer": "[0, 1, 2, 3]",
@@ -2630,7 +2461,7 @@
"range(0, 1, 2, 3)",
"(0, 1, 2, 3)",
"[0, 1, 2, 3]",
- "Error"
+ "\u9519\u8bef"
]
},
"result": [
@@ -2643,13 +2474,13 @@
"step": "range_versus_list"
},
{
- "page": "Getting elements at a position, range()
, and len()
",
+ "get_solution": "program",
+ "page": "\u83b7\u53d6\u4f4d\u7f6e\u7684\u5143\u7d20\uff0crange()
\u548c len()
",
"program": [
"words = ['This', 'is', 'a', 'list']",
"print(len(words))"
],
"response": {
- "message": "",
"passed": true,
"prediction": {
"answer": "4",
@@ -2660,7 +2491,7 @@
"3",
"4",
"5",
- "Error"
+ "\u9519\u8bef"
]
},
"result": [
@@ -2676,13 +2507,12 @@
"get_solution": [
"print(words[len(words) - 1])"
],
- "page": "Getting elements at a position, range()
, and len()
",
+ "page": "\u83b7\u53d6\u4f4d\u7f6e\u7684\u5143\u7d20\uff0crange()
\u548c len()
",
"program": [
"words = ['Python']",
"print(words[len(words) - 1])"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -2699,7 +2529,7 @@
" print(index)",
" print(words[index])"
],
- "page": "Getting elements at a position, range()
, and len()
",
+ "page": "\u83b7\u53d6\u4f4d\u7f6e\u7684\u5143\u7d20\uff0crange()
\u548c len()
",
"program": [
"words = ['Python']",
"for index in range(len(words)):",
@@ -2707,7 +2537,6 @@
" print(words[index])"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -2719,7 +2548,7 @@
"step": "print_indices_and_words"
},
{
- "page": "Exercises with range()
and len()
",
+ "page": "\u4f7f\u7528 range()
\u548c len()
\u7684\u7ec3\u4e60",
"program": [
"things = ['on', 'the', 'way', 'to', 'the', 'store']",
"to_find = 'the'",
@@ -2728,7 +2557,7 @@
" print(i)"
],
"response": {
- "message": "You're almost there! However, this prints all the indices,\nnot just the first one.
", + "message": "\u4f60\u5feb\u5230\u4e86\uff01\u4f46\u662f\uff0c\u8fd9\u4f1a\u6253\u5370\u6240\u6709\u7684\u7d22\u5f15\uff0c\n\u800c\u4e0d\u4ec5\u4ec5\u662f\u7b2c\u4e00\u4e2a\u3002
", "passed": false, "result": [ { @@ -2740,7 +2569,7 @@ "step": "index_exercise" }, { - "page": "Exercises withrange()
and len()
",
+ "page": "\u4f7f\u7528 range()
\u548c len()
\u7684\u7ec3\u4e60",
"program": [
"things = ['on', 'the', 'way', 'to', 'the', 'store']",
"to_find = 'the'",
@@ -2751,7 +2580,7 @@
"print(answer)"
],
"response": {
- "message": "You're almost there! However, this prints the last index,\nnot the first one.
", + "message": "\u4f60\u5feb\u5230\u4e86\uff01\u4f46\u662f\uff0c\u8fd9\u4f1a\u6253\u5370 \u6700\u540e \u4e00\u4e2a\u7d22\u5f15\uff0c\n\u800c\u4e0d\u662f\u7b2c\u4e00\u4e2a\u3002
", "passed": false, "result": [ { @@ -2769,7 +2598,7 @@ " print(i)", " break" ], - "page": "Exercises withrange()
and len()
",
+ "page": "\u4f7f\u7528 range()
\u548c len()
\u7684\u7ec3\u4e60",
"program": [
"things = ['on', 'the', 'way', 'to', 'the', 'store']",
"to_find = 'the'",
@@ -2779,7 +2608,6 @@
" break"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -2797,7 +2625,7 @@
" char2 = string2[i]",
" print(char1 + ' ' + char2)"
],
- "page": "Exercises with range()
and len()
",
+ "page": "\u4f7f\u7528 range()
\u548c len()
\u7684\u7ec3\u4e60",
"program": [
"string1 = 'Hello'",
"string2 = 'World'",
@@ -2807,7 +2635,6 @@
" print(char1 + ' ' + char2)"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -2841,7 +2668,7 @@
"",
" print(char1 + ' ' + char2)"
],
- "page": "Exercises with range()
and len()
",
+ "page": "\u4f7f\u7528 range()
\u548c len()
\u7684\u7ec3\u4e60",
"program": [
"string1 = 'Goodbye'",
"string2 = 'World'",
@@ -2867,7 +2694,6 @@
" print(char1 + ' ' + char2)"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -2879,13 +2705,13 @@
"step": "zip_longest_exercise"
},
{
- "page": "Terminology: Calling functions and methods",
+ "get_solution": "program",
+ "page": "\u672f\u8bed\uff1a\u8c03\u7528\u51fd\u6570\u548c\u65b9\u6cd5",
"program": [
"print(len)",
"print(print)"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -2897,12 +2723,12 @@
"step": "print_functions"
},
{
- "page": "Terminology: Calling functions and methods",
+ "get_solution": "program",
+ "page": "\u672f\u8bed\uff1a\u8c03\u7528\u51fd\u6570\u548c\u65b9\u6cd5",
"program": [
"print(callable(len))"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -2914,14 +2740,14 @@
"step": "introducing_callable"
},
{
- "page": "Terminology: Calling functions and methods",
+ "get_solution": "program",
+ "page": "\u672f\u8bed\uff1a\u8c03\u7528\u51fd\u6570\u548c\u65b9\u6cd5",
"program": [
"f = 'a string'",
"print(callable(f))",
"f()"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -2940,11 +2766,13 @@
},
"frames": [
{
+ "filename": "/my_program.py",
+ "lineno": 3,
"lines": [
{
- "content": "f()",
"is_current": true,
"lineno": 3,
+ "text": "f()",
"type": "line"
}
],
@@ -2958,13 +2786,13 @@
]
}
],
- "friendly": "A TypeError
is usually caused by trying\nto combine two incompatible types of objects,\nby calling a function with the wrong type of object,\nor by trying to do an operation not allowed on a given type of object.
The parenthesis ()
following f
are interpreted\nby Python as a function call for f
.\nHowever, f
is not a function but an object of type str
.
A TypeError
is usually caused by trying\nto combine two incompatible types of objects,\nby calling a function with the wrong type of object,\nor by trying to do an operation not allowed on a given type of object.
Because of the surrounding parenthesis, ` \nis interpreted by Python as indicating a function call for
f, which is an object of type
str`\nwhich cannot be called.
==
vs is
, and Having Multiple Names for One Value",
+ "get_solution": "program",
+ "page": "==
\u4e0e is
\uff0c\u4ee5\u53ca\u4e00\u4e2a\u503c\u7684\u591a\u4e2a\u540d\u79f0",
"program": [
"list1 = [1, 2, 3]",
"list2 = [1, 2, 3]",
@@ -3798,7 +3585,6 @@
"print(list2)"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -3810,7 +3596,8 @@
"step": "two_separate_lists"
},
{
- "page": "==
vs is
, and Having Multiple Names for One Value",
+ "get_solution": "program",
+ "page": "==
\u4e0e is
\uff0c\u4ee5\u53ca\u4e00\u4e2a\u503c\u7684\u591a\u4e2a\u540d\u79f0",
"program": [
"list1 = [1, 2, 3]",
"list2 = list1",
@@ -3827,7 +3614,6 @@
"print(list2)"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -3839,7 +3625,8 @@
"step": "same_list"
},
{
- "page": "Modifying While Iterating",
+ "get_solution": "program",
+ "page": "\u8fed\u4ee3\u65f6\u7684\u4fee\u6539",
"program": [
"numbers = [10, 7, 8, 3, 12, 15]",
"for i in range(len(numbers)):",
@@ -3849,7 +3636,6 @@
"print(numbers)"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -3862,11 +3648,13 @@
},
"frames": [
{
+ "filename": "/my_program.py",
+ "lineno": 3,
"lines": [
{
- "content": "number = numbers[i]",
"is_current": true,
"lineno": 3,
+ "text": "number = numbers[i]",
"type": "line"
}
],
@@ -3906,7 +3694,7 @@
],
"text": [
"Traceback (most recent call last):",
- " File \"my_program.py\", line 3, in A SyntaxError
occurs when Python cannot understand your code.
You started writing a string with a single or double quote\nbut never ended the string with another quote on that line.
", + "text": " print('Alice's Diner')\n ^\nSyntaxError: unterminated string literal (detected at line 1)\n\u5728\u884c 1\n", "type": "syntax_error" } ] @@ -4031,12 +3820,12 @@ "step": "single_quotes_apostrophe" }, { - "page": "Single and Double Quotes in Strings", + "get_solution": "program", + "page": "\u5b57\u7b26\u4e32\u4e2d\u7684\u5355\u5f15\u53f7\u548c\u53cc\u5f15\u53f7", "program": [ "print(\"Alice's Diner\")" ], "response": { - "message": "", "passed": true, "result": [ { @@ -4048,19 +3837,19 @@ "step": "double_quotes" }, { - "page": "Single and Double Quotes in Strings", + "get_solution": "program", + "page": "\u5b57\u7b26\u4e32\u4e2d\u7684\u5355\u5f15\u53f7\u548c\u53cc\u5f15\u53f7", "program": [ "'Alice' == \"Alice\"" ], "response": { - "message": "", "passed": true, "prediction": { "answer": "True", "choices": [ "True", "False", - "Error" + "\u9519\u8bef" ] }, "result": [ @@ -4073,15 +3862,12 @@ "step": "single_double_quotes_equal" }, { - "get_solution": [ - "print(\"Special cases aren't special enough to break the rules.\")" - ], - "page": "Single and Double Quotes in Strings", + "get_solution": "program", + "page": "\u5b57\u7b26\u4e32\u4e2d\u7684\u5355\u5f15\u53f7\u548c\u53cc\u5f15\u53f7", "program": [ "print(\"Special cases aren't special enough to break the rules.\")" ], "response": { - "message": "", "passed": true, "result": [ { @@ -4093,15 +3879,12 @@ "step": "double_quote_exercise" }, { - "get_solution": [ - "print('\"Talk is cheap. Show me the code.\" - Linus Torvalds')" - ], - "page": "Single and Double Quotes in Strings", + "get_solution": "program", + "page": "\u5b57\u7b26\u4e32\u4e2d\u7684\u5355\u5f15\u53f7\u548c\u53cc\u5f15\u53f7", "program": [ "print('\"Talk is cheap. Show me the code.\" - Linus Torvalds')" ], "response": { - "message": "", "passed": true, "result": [ { @@ -4113,6 +3896,7 @@ "step": "single_quote_exercise" }, { + "get_solution": "program", "page": "f-strings", "program": [ "name = \"Alice\"", @@ -4121,7 +3905,6 @@ "print(f\"{name} went to {meal} with {friend}.\")" ], "response": { - "message": "", "passed": true, "prediction": { "answer": "Alice went to lunch with Bob.", @@ -4135,7 +3918,7 @@ "'Alice' went to 'lunch' with 'Bob'.", "\"Alice went to lunch with Bob.\"", "Alice went to lunch with Bob.", - "Error" + "\u9519\u8bef" ] }, "result": [ @@ -4148,6 +3931,7 @@ "step": "introduce_f_strings" }, { + "get_solution": "program", "page": "f-strings", "program": [ "name = \"Alice\"", @@ -4155,16 +3939,15 @@ "print(\"Hello \" + name + \". You are \" + age + \" years old.\")" ], "response": { - "message": "", "passed": true, "prediction": { - "answer": "Error", + "answer": "\u9519\u8bef", "choices": [ "\"Hello \" + name + \". You are \" + age + \" years old.\"", "Hello name. You are age years old.", "Hello Alice. You are 20 years old.", "Hello 'Alice'. You are 20 years old.", - "Error" + "\u9519\u8bef" ] }, "result": [ @@ -4178,11 +3961,13 @@ }, "frames": [ { + "filename": "/my_program.py", + "lineno": 3, "lines": [ { - "content": "print("Hello " + name + ". You are " + age + " years old.")", "is_current": true, "lineno": 3, + "text": "print("Hello " + name + ". You are " + age + " years old.")", "type": "line" } ], @@ -4214,7 +3999,7 @@ ], "text": [ "Traceback (most recent call last):", - " File \"my_program.py\", line 3, inYou can't add together strings and numbers. Use an f-string.
", + "message": "\u4f60\u4e0d\u80fd\u5c06\u5b57\u7b26\u4e32\u548c\u6570\u5b57\u76f8\u52a0\u3002\u4f7f\u7528 f-string\u3002
", "passed": false, "result": [ { @@ -4343,11 +4122,13 @@ }, "frames": [ { + "filename": "/my_program.py", + "lineno": 1, "lines": [ { - "content": "print(1 + "x")", "is_current": true, "lineno": 1, + "text": "print(1 + "x")", "type": "line" } ], @@ -4362,7 +4143,7 @@ ], "text": [ "Traceback (most recent call last):", - " File \"my_program.py\", line 1, inYou added 1 to your outer loop variable at the wrong place!\nWhere should you do that instead to fix it?
", + "message": "\u4f60\u5728\u9519\u8bef\u7684\u5730\u65b9\u7ed9\u5916\u90e8\u5faa\u73af\u53d8\u91cf\u52a0\u4e86 1\uff01\n\u4f60\u5e94\u8be5\u5728\u54ea\u91cc\u505a\u8fd9\u4e2a\u4ee5\u4fee\u590d\u5b83\uff1f
", "passed": false, "result": [ { - "text": "1 x 1 = 1\n2 x 2 = 4\n3 x 3 = 9\n4 x 4 = 16\n5 x 5 = 25\n6 x 6 = 36\n7 x 7 = 49\n8 x 8 = 64\n9 x 9 = 81\n10 x 10 = 100\n11 x 11 = 121\n12 x 12 = 144\n----------\n2 x 1 = 2\n3 x 2 = 6\n4 x 3 = 12\n5 x 4 = 20\n6 x 5 = 30\n7 x 6 = 42\n8 x 7 = 56\n9 x 8 = 72\n10 x 9 = 90\n11 x 10 = 110\n12 x 11 = 132\n13 x 12 = 156\n----------\n3 x 1 = 3\n4 x 2 = 8\n5 x 3 = 15\n6 x 4 = 24\n7 x 5 = 35\n8 x 6 = 48\n9 x 7 = 63\n10 x 8 = 80\n11 x 9 = 99\n12 x 10 = 120\n13 x 11 = 143\n14 x 12 = 168\n----------\n4 x 1 = 4\n5 x 2 = 10\n6 x 3 = 18\n7 x 4 = 28\n8 x 5 = 40\n9 x 6 = 54\n10 x 7 = 70\n11 x 8 = 88\n12 x 9 = 108\n13 x 10 = 130\n14 x 11 = 154\n15 x 12 = 180\n----------\n5 x 1 = 5\n6 x 2 = 12\n7 x 3 = 21\n8 x 4 = 32\n9 x 5 = 45\n10 x 6 = 60\n11 x 7 = 77\n12 x 8 = 96\n13 x 9 = 117\n14 x 10 = 140\n15 x 11 = 165\n16 x 12 = 192\n----------\n6 x 1 = 6\n7 x 2 = 14\n8 x 3 = 24\n9 x 4 = 36\n10 x 5 = 50\n11 x 6 = 66\n12 x 7 = 84\n13 x 8 = 104\n14 x 9 = 126\n15 x 10 = 150\n16 x 11 = 176\n17 x 12 = 204\n----------\n7 x 1 = 7\n8 x 2 = 16\n9 x 3 = 27\n10 x 4 = 40\n11 x 5 = 55\n12 x 6 = 72\n13 x 7 = 91", + "text": "1 x 1 = 1\n2 x 2 = 4\n3 x 3 = 9\n4 x 4 = 16\n5 x 5 = 25\n6 x 6 = 36\n7 x 7 = 49\n8 x 8 = 64\n9 x 9 = 81\n10 x 10 = 100\n11 x 11 = 121\n12 x 12 = 144\n---\n2 x 1 = 2\n3 x 2 = 6\n4 x 3 = 12\n5 x 4 = 20\n6 x 5 = 30\n7 x 6 = 42\n8 x 7 = 56\n9 x 8 = 72\n10 x 9 = 90\n11 x 10 = 110\n12 x 11 = 132\n13 x 12 = 156\n---\n3 x 1 = 3\n4 x 2 = 8\n5 x 3 = 15\n6 x 4 = 24\n7 x 5 = 35\n8 x 6 = 48\n9 x 7 = 63\n10 x 8 = 80\n11 x 9 = 99\n12 x 10 = 120\n13 x 11 = 143\n14 x 12 = 168\n---\n4 x 1 = 4\n5 x 2 = 10\n6 x 3 = 18\n7 x 4 = 28\n8 x 5 = 40\n9 x 6 = 54\n10 x 7 = 70\n11 x 8 = 88\n12 x 9 = 108\n13 x 10 = 130\n14 x 11 = 154\n15 x 12 = 180\n---\n5 x 1 = 5\n6 x 2 = 12\n7 x 3 = 21\n8 x 4 = 32\n9 x 5 = 45\n10 x 6 = 60\n11 x 7 = 77\n12 x 8 = 96\n13 x 9 = 117\n14 x 10 = 140\n15 x 11 = 165\n16 x 12 = 192\n---\n6 x 1 = 6\n7 x 2 = 14\n8 x 3 = 24\n9 x 4 = 36\n10 x 5 = 50\n11 x 6 = 66\n12 x 7 = 84\n13 x 8 = 104\n14 x 9 = 126\n15 x 10 = 150\n16 x 11 = 176\n17 x 12 = 204\n---\n7 x 1 = 7\n8 x 2 = 16\n9 x 3 = 27\n10 x 4 = 40\n11 x 5 = 55\n12 x 6 = 72\n13 x 7 = 91\n14 x 8 = 112\n15 x 9 = 135\n16 x 10 = 160\n17 x 11 = 187", "type": "stdout" }, { - "text": "\n14 x 8 = 112\n15 x 9 = 135\n16 x 10 = 160\n17 x 11 = 187\n18 x 12 = 216\n----------\n8 x 1 = 8\n9 x 2 = 18\n10 x 3 = 30\n11 x 4 = 44\n12 x 5 = 60\n13 x 6 = 78\n14 x 7 = 98\n15 x 8 = 120\n16 x 9 = 144\n17 x 10 = 170\n18 x 11 = 198\n19 x 12 = 228\n----------\n9 x 1 = 9\n10 x 2 = 20\n11 x 3 = 33\n12 x 4 = 48\n13 x 5 = 65\n14 x 6 = 84\n15 x 7 = 105\n16 x 8 = 128\n17 x 9 = 153\n18 x 10 = 180\n19 x 11 = 209\n20 x 12 = 240\n----------\n10 x 1 = 10\n11 x 2 = 22\n12 x 3 = 36\n13 x 4 = 52\n14 x 5 = 70\n15 x 6 = 90\n16 x 7 = 112\n17 x 8 = 136\n18 x 9 = 162\n19 x 10 = 190\n20 x 11 = 220\n21 x 12 = 252\n----------\n11 x 1 = 11\n12 x 2 = 24\n13 x 3 = 39\n14 x 4 = 56\n15 x 5 = 75\n16 x 6 = 96\n17 x 7 = 119\n18 x 8 = 144\n19 x 9 = 171\n20 x 10 = 200\n21 x 11 = 231\n22 x 12 = 264\n----------\n12 x 1 = 12\n13 x 2 = 26\n14 x 3 = 42\n15 x 4 = 60\n16 x 5 = 80\n17 x 6 = 102\n18 x 7 = 126\n19 x 8 = 152\n20 x 9 = 180\n21 x 10 = 210\n22 x 11 = 242\n23 x 12 = 276\n----------\n", + "text": "\n18 x 12 = 216\n---\n8 x 1 = 8\n9 x 2 = 18\n10 x 3 = 30\n11 x 4 = 44\n12 x 5 = 60\n13 x 6 = 78\n14 x 7 = 98\n15 x 8 = 120\n16 x 9 = 144\n17 x 10 = 170\n18 x 11 = 198\n19 x 12 = 228\n---\n9 x 1 = 9\n10 x 2 = 20\n11 x 3 = 33\n12 x 4 = 48\n13 x 5 = 65\n14 x 6 = 84\n15 x 7 = 105\n16 x 8 = 128\n17 x 9 = 153\n18 x 10 = 180\n19 x 11 = 209\n20 x 12 = 240\n---\n10 x 1 = 10\n11 x 2 = 22\n12 x 3 = 36\n13 x 4 = 52\n14 x 5 = 70\n15 x 6 = 90\n16 x 7 = 112\n17 x 8 = 136\n18 x 9 = 162\n19 x 10 = 190\n20 x 11 = 220\n21 x 12 = 252\n---\n11 x 1 = 11\n12 x 2 = 24\n13 x 3 = 39\n14 x 4 = 56\n15 x 5 = 75\n16 x 6 = 96\n17 x 7 = 119\n18 x 8 = 144\n19 x 9 = 171\n20 x 10 = 200\n21 x 11 = 231\n22 x 12 = 264\n---\n12 x 1 = 12\n13 x 2 = 26\n14 x 3 = 42\n15 x 4 = 60\n16 x 5 = 80\n17 x 6 = 102\n18 x 7 = 126\n19 x 8 = 152\n20 x 9 = 180\n21 x 10 = 210\n22 x 11 = 242\n23 x 12 = 276\n---\n", "type": "stdout" } ] @@ -4401,7 +4182,7 @@ "step": "times_table_exercise" }, { - "page": "Introducing Nested Loops", + "page": "\u4ecb\u7ecd\u5d4c\u5957\u5faa\u73af", "program": [ "for left in range(12):", " left += 1", @@ -4417,18 +4198,18 @@ " print(left, 'x 10 =', left * 10)", " print(left, 'x 11 =', left * 11)", " print(left, 'x 12 =', left * 12)", - " print('----------')" + " print('---')" ], "response": { - "message": "Your solution is too long. You only need a few lines of code for this problem.\nUse a nested loop so that you don't need to repeat yourself.\nThe computer will do the repetition for you!
", + "message": "\u4f60\u7684\u89e3\u51b3\u65b9\u6848\u592a\u957f\u4e86\u3002\u8fd9\u4e2a\u95ee\u9898\u53ea\u9700\u8981\u51e0\u884c\u4ee3\u7801\u3002\n\u4f7f\u7528\u5d4c\u5957\u5faa\u73af\uff0c\u8fd9\u6837\u4f60\u5c31\u4e0d\u9700\u8981\u91cd\u590d\u81ea\u5df1\u3002\n\u8ba1\u7b97\u673a\u4f1a\u4e3a\u4f60\u5b8c\u6210\u91cd\u590d\u7684\u5de5\u4f5c\uff01
", "passed": false, "result": [ { - "text": "1 x 1 = 1\n1 x 2 = 2\n1 x 3 = 3\n1 x 4 = 4\n1 x 5 = 5\n1 x 6 = 6\n1 x 7 = 7\n1 x 8 = 8\n1 x 9 = 9\n1 x 10 = 10\n1 x 11 = 11\n1 x 12 = 12\n----------\n2 x 1 = 2\n2 x 2 = 4\n2 x 3 = 6\n2 x 4 = 8\n2 x 5 = 10\n2 x 6 = 12\n2 x 7 = 14\n2 x 8 = 16\n2 x 9 = 18\n2 x 10 = 20\n2 x 11 = 22\n2 x 12 = 24\n----------\n3 x 1 = 3\n3 x 2 = 6\n3 x 3 = 9\n3 x 4 = 12\n3 x 5 = 15\n3 x 6 = 18\n3 x 7 = 21\n3 x 8 = 24\n3 x 9 = 27\n3 x 10 = 30\n3 x 11 = 33\n3 x 12 = 36\n----------\n4 x 1 = 4\n4 x 2 = 8\n4 x 3 = 12\n4 x 4 = 16\n4 x 5 = 20\n4 x 6 = 24\n4 x 7 = 28\n4 x 8 = 32\n4 x 9 = 36\n4 x 10 = 40\n4 x 11 = 44\n4 x 12 = 48\n----------\n5 x 1 = 5\n5 x 2 = 10\n5 x 3 = 15\n5 x 4 = 20\n5 x 5 = 25\n5 x 6 = 30\n5 x 7 = 35\n5 x 8 = 40\n5 x 9 = 45\n5 x 10 = 50\n5 x 11 = 55\n5 x 12 = 60\n----------\n6 x 1 = 6\n6 x 2 = 12\n6 x 3 = 18\n6 x 4 = 24\n6 x 5 = 30\n6 x 6 = 36\n6 x 7 = 42\n6 x 8 = 48\n6 x 9 = 54\n6 x 10 = 60\n6 x 11 = 66\n6 x 12 = 72\n----------\n7 x 1 = 7\n7 x 2 = 14\n7 x 3 = 21\n7 x 4 = 28\n7 x 5 = 35\n7 x 6 = 42\n7 x 7 = 49\n7 x 8 = 56\n7 x 9 = 63\n7 x 10 = 70\n7 x 11 = 77\n7 x 12 = 84\n----------", + "text": "1 x 1 = 1\n1 x 2 = 2\n1 x 3 = 3\n1 x 4 = 4\n1 x 5 = 5\n1 x 6 = 6\n1 x 7 = 7\n1 x 8 = 8\n1 x 9 = 9\n1 x 10 = 10\n1 x 11 = 11\n1 x 12 = 12\n---\n2 x 1 = 2\n2 x 2 = 4\n2 x 3 = 6\n2 x 4 = 8\n2 x 5 = 10\n2 x 6 = 12\n2 x 7 = 14\n2 x 8 = 16\n2 x 9 = 18\n2 x 10 = 20\n2 x 11 = 22\n2 x 12 = 24\n---\n3 x 1 = 3\n3 x 2 = 6\n3 x 3 = 9\n3 x 4 = 12\n3 x 5 = 15\n3 x 6 = 18\n3 x 7 = 21\n3 x 8 = 24\n3 x 9 = 27\n3 x 10 = 30\n3 x 11 = 33\n3 x 12 = 36\n---\n4 x 1 = 4\n4 x 2 = 8\n4 x 3 = 12\n4 x 4 = 16\n4 x 5 = 20\n4 x 6 = 24\n4 x 7 = 28\n4 x 8 = 32\n4 x 9 = 36\n4 x 10 = 40\n4 x 11 = 44\n4 x 12 = 48\n---\n5 x 1 = 5\n5 x 2 = 10\n5 x 3 = 15\n5 x 4 = 20\n5 x 5 = 25\n5 x 6 = 30\n5 x 7 = 35\n5 x 8 = 40\n5 x 9 = 45\n5 x 10 = 50\n5 x 11 = 55\n5 x 12 = 60\n---\n6 x 1 = 6\n6 x 2 = 12\n6 x 3 = 18\n6 x 4 = 24\n6 x 5 = 30\n6 x 6 = 36\n6 x 7 = 42\n6 x 8 = 48\n6 x 9 = 54\n6 x 10 = 60\n6 x 11 = 66\n6 x 12 = 72\n---\n7 x 1 = 7\n7 x 2 = 14\n7 x 3 = 21\n7 x 4 = 28\n7 x 5 = 35\n7 x 6 = 42\n7 x 7 = 49\n7 x 8 = 56\n7 x 9 = 63\n7 x 10 = 70\n7 x 11 = 77\n7 x 12 = 84\n---\n8 x 1 = 8\n8 x 2 = 16\n8 x 3 = 24\n8 x 4 = 32\n8 x 5 =", "type": "stdout" }, { - "text": "\n8 x 1 = 8\n8 x 2 = 16\n8 x 3 = 24\n8 x 4 = 32\n8 x 5 = 40\n8 x 6 = 48\n8 x 7 = 56\n8 x 8 = 64\n8 x 9 = 72\n8 x 10 = 80\n8 x 11 = 88\n8 x 12 = 96\n----------\n9 x 1 = 9\n9 x 2 = 18\n9 x 3 = 27\n9 x 4 = 36\n9 x 5 = 45\n9 x 6 = 54\n9 x 7 = 63\n9 x 8 = 72\n9 x 9 = 81\n9 x 10 = 90\n9 x 11 = 99\n9 x 12 = 108\n----------\n10 x 1 = 10\n10 x 2 = 20\n10 x 3 = 30\n10 x 4 = 40\n10 x 5 = 50\n10 x 6 = 60\n10 x 7 = 70\n10 x 8 = 80\n10 x 9 = 90\n10 x 10 = 100\n10 x 11 = 110\n10 x 12 = 120\n----------\n11 x 1 = 11\n11 x 2 = 22\n11 x 3 = 33\n11 x 4 = 44\n11 x 5 = 55\n11 x 6 = 66\n11 x 7 = 77\n11 x 8 = 88\n11 x 9 = 99\n11 x 10 = 110\n11 x 11 = 121\n11 x 12 = 132\n----------\n12 x 1 = 12\n12 x 2 = 24\n12 x 3 = 36\n12 x 4 = 48\n12 x 5 = 60\n12 x 6 = 72\n12 x 7 = 84\n12 x 8 = 96\n12 x 9 = 108\n12 x 10 = 120\n12 x 11 = 132\n12 x 12 = 144\n----------\n", + "text": " 40\n8 x 6 = 48\n8 x 7 = 56\n8 x 8 = 64\n8 x 9 = 72\n8 x 10 = 80\n8 x 11 = 88\n8 x 12 = 96\n---\n9 x 1 = 9\n9 x 2 = 18\n9 x 3 = 27\n9 x 4 = 36\n9 x 5 = 45\n9 x 6 = 54\n9 x 7 = 63\n9 x 8 = 72\n9 x 9 = 81\n9 x 10 = 90\n9 x 11 = 99\n9 x 12 = 108\n---\n10 x 1 = 10\n10 x 2 = 20\n10 x 3 = 30\n10 x 4 = 40\n10 x 5 = 50\n10 x 6 = 60\n10 x 7 = 70\n10 x 8 = 80\n10 x 9 = 90\n10 x 10 = 100\n10 x 11 = 110\n10 x 12 = 120\n---\n11 x 1 = 11\n11 x 2 = 22\n11 x 3 = 33\n11 x 4 = 44\n11 x 5 = 55\n11 x 6 = 66\n11 x 7 = 77\n11 x 8 = 88\n11 x 9 = 99\n11 x 10 = 110\n11 x 11 = 121\n11 x 12 = 132\n---\n12 x 1 = 12\n12 x 2 = 24\n12 x 3 = 36\n12 x 4 = 48\n12 x 5 = 60\n12 x 6 = 72\n12 x 7 = 84\n12 x 8 = 96\n12 x 9 = 108\n12 x 10 = 120\n12 x 11 = 132\n12 x 12 = 144\n---\n", "type": "stdout" } ] @@ -4436,7 +4217,7 @@ "step": "times_table_exercise" }, { - "page": "Introducing Nested Loops", + "page": "\u4ecb\u7ecd\u5d4c\u5957\u5faa\u73af", "program": [ "for left in range(12):", " left += 1", @@ -4444,18 +4225,18 @@ " right += 1", " # for the sake of translation", " print(f'{left} x {right} = {left * right}'.replace('x', '*'))", - " print('----------')" + " print('---')" ], "response": { - "message": "That's almost correct! Make sure to display the right character x
in your table.\nFor example, your solution should display 3 x 4 = 12
and not 3 * 4 = 12
.
\u8fd9\u51e0\u4e4e\u662f\u6b63\u786e\u7684\uff01\u786e\u4fdd\u5728\u4f60\u7684\u8868\u4e2d\u663e\u793a\u6b63\u786e\u7684\u5b57\u7b26 x
\u3002\n\u4f8b\u5982\uff0c\u4f60\u7684\u89e3\u51b3\u65b9\u6848\u5e94\u8be5\u663e\u793a 3 x 4 = 12
\u800c\u4e0d\u662f 3 * 4 = 12
\u3002
To multiply numbers, use *
\u8981\u4e58\u6570\u5b57\uff0c\u4f7f\u7528 *
A SyntaxError
occurs when Python cannot understand your code.
Currently, I cannot guess the likely cause of this error.\nTry to examine closely the line indicated as well as the line\nimmediately above to see if you can identify some misspelled\nword, or missing symbols, like (, ), [, ], :, etc.
\nUnless your code uses type annotations, which are beyond our scope,\nif you think that this is something which should be handled\nby friendly, please report this case to\nhttps://github.com/friendly-traceback/friendly-traceback/issues
", + "text": " 3 x 4\n ^\nSyntaxError: invalid syntax\n\u5728\u884c 2\n", "type": "syntax_error" } ] @@ -4481,33 +4263,25 @@ "step": "times_table_exercise" }, { - "get_solution": [ - "for left in range(12):", - " left += 1", - " for right in range(12):", - " right += 1", - " print(f'{left} x {right} = {left * right}')", - " print('----------')" - ], - "page": "Introducing Nested Loops", + "get_solution": "program", + "page": "\u4ecb\u7ecd\u5d4c\u5957\u5faa\u73af", "program": [ "for left in range(12):", " left += 1", " for right in range(12):", " right += 1", " print(f'{left} x {right} = {left * right}')", - " print('----------')" + " print('---')" ], "response": { - "message": "", "passed": true, "result": [ { - "text": "1 x 1 = 1\n1 x 2 = 2\n1 x 3 = 3\n1 x 4 = 4\n1 x 5 = 5\n1 x 6 = 6\n1 x 7 = 7\n1 x 8 = 8\n1 x 9 = 9\n1 x 10 = 10\n1 x 11 = 11\n1 x 12 = 12\n----------\n2 x 1 = 2\n2 x 2 = 4\n2 x 3 = 6\n2 x 4 = 8\n2 x 5 = 10\n2 x 6 = 12\n2 x 7 = 14\n2 x 8 = 16\n2 x 9 = 18\n2 x 10 = 20\n2 x 11 = 22\n2 x 12 = 24\n----------\n3 x 1 = 3\n3 x 2 = 6\n3 x 3 = 9\n3 x 4 = 12\n3 x 5 = 15\n3 x 6 = 18\n3 x 7 = 21\n3 x 8 = 24\n3 x 9 = 27\n3 x 10 = 30\n3 x 11 = 33\n3 x 12 = 36\n----------\n4 x 1 = 4\n4 x 2 = 8\n4 x 3 = 12\n4 x 4 = 16\n4 x 5 = 20\n4 x 6 = 24\n4 x 7 = 28\n4 x 8 = 32\n4 x 9 = 36\n4 x 10 = 40\n4 x 11 = 44\n4 x 12 = 48\n----------\n5 x 1 = 5\n5 x 2 = 10\n5 x 3 = 15\n5 x 4 = 20\n5 x 5 = 25\n5 x 6 = 30\n5 x 7 = 35\n5 x 8 = 40\n5 x 9 = 45\n5 x 10 = 50\n5 x 11 = 55\n5 x 12 = 60\n----------\n6 x 1 = 6\n6 x 2 = 12\n6 x 3 = 18\n6 x 4 = 24\n6 x 5 = 30\n6 x 6 = 36\n6 x 7 = 42\n6 x 8 = 48\n6 x 9 = 54\n6 x 10 = 60\n6 x 11 = 66\n6 x 12 = 72\n----------\n7 x 1 = 7\n7 x 2 = 14\n7 x 3 = 21\n7 x 4 = 28\n7 x 5 = 35\n7 x 6 = 42\n7 x 7 = 49\n7 x 8 = 56\n7 x 9 = 63\n7 x 10 = 70\n7 x 11 = 77\n7 x 12 = 84\n----------", + "text": "1 x 1 = 1\n1 x 2 = 2\n1 x 3 = 3\n1 x 4 = 4\n1 x 5 = 5\n1 x 6 = 6\n1 x 7 = 7\n1 x 8 = 8\n1 x 9 = 9\n1 x 10 = 10\n1 x 11 = 11\n1 x 12 = 12\n---\n2 x 1 = 2\n2 x 2 = 4\n2 x 3 = 6\n2 x 4 = 8\n2 x 5 = 10\n2 x 6 = 12\n2 x 7 = 14\n2 x 8 = 16\n2 x 9 = 18\n2 x 10 = 20\n2 x 11 = 22\n2 x 12 = 24\n---\n3 x 1 = 3\n3 x 2 = 6\n3 x 3 = 9\n3 x 4 = 12\n3 x 5 = 15\n3 x 6 = 18\n3 x 7 = 21\n3 x 8 = 24\n3 x 9 = 27\n3 x 10 = 30\n3 x 11 = 33\n3 x 12 = 36\n---\n4 x 1 = 4\n4 x 2 = 8\n4 x 3 = 12\n4 x 4 = 16\n4 x 5 = 20\n4 x 6 = 24\n4 x 7 = 28\n4 x 8 = 32\n4 x 9 = 36\n4 x 10 = 40\n4 x 11 = 44\n4 x 12 = 48\n---\n5 x 1 = 5\n5 x 2 = 10\n5 x 3 = 15\n5 x 4 = 20\n5 x 5 = 25\n5 x 6 = 30\n5 x 7 = 35\n5 x 8 = 40\n5 x 9 = 45\n5 x 10 = 50\n5 x 11 = 55\n5 x 12 = 60\n---\n6 x 1 = 6\n6 x 2 = 12\n6 x 3 = 18\n6 x 4 = 24\n6 x 5 = 30\n6 x 6 = 36\n6 x 7 = 42\n6 x 8 = 48\n6 x 9 = 54\n6 x 10 = 60\n6 x 11 = 66\n6 x 12 = 72\n---\n7 x 1 = 7\n7 x 2 = 14\n7 x 3 = 21\n7 x 4 = 28\n7 x 5 = 35\n7 x 6 = 42\n7 x 7 = 49\n7 x 8 = 56\n7 x 9 = 63\n7 x 10 = 70\n7 x 11 = 77\n7 x 12 = 84\n---\n8 x 1 = 8\n8 x 2 = 16\n8 x 3 = 24\n8 x 4 = 32\n8 x 5 = 40", "type": "stdout" }, { - "text": "\n8 x 1 = 8\n8 x 2 = 16\n8 x 3 = 24\n8 x 4 = 32\n8 x 5 = 40\n8 x 6 = 48\n8 x 7 = 56\n8 x 8 = 64\n8 x 9 = 72\n8 x 10 = 80\n8 x 11 = 88\n8 x 12 = 96\n----------\n9 x 1 = 9\n9 x 2 = 18\n9 x 3 = 27\n9 x 4 = 36\n9 x 5 = 45\n9 x 6 = 54\n9 x 7 = 63\n9 x 8 = 72\n9 x 9 = 81\n9 x 10 = 90\n9 x 11 = 99\n9 x 12 = 108\n----------\n10 x 1 = 10\n10 x 2 = 20\n10 x 3 = 30\n10 x 4 = 40\n10 x 5 = 50\n10 x 6 = 60\n10 x 7 = 70\n10 x 8 = 80\n10 x 9 = 90\n10 x 10 = 100\n10 x 11 = 110\n10 x 12 = 120\n----------\n11 x 1 = 11\n11 x 2 = 22\n11 x 3 = 33\n11 x 4 = 44\n11 x 5 = 55\n11 x 6 = 66\n11 x 7 = 77\n11 x 8 = 88\n11 x 9 = 99\n11 x 10 = 110\n11 x 11 = 121\n11 x 12 = 132\n----------\n12 x 1 = 12\n12 x 2 = 24\n12 x 3 = 36\n12 x 4 = 48\n12 x 5 = 60\n12 x 6 = 72\n12 x 7 = 84\n12 x 8 = 96\n12 x 9 = 108\n12 x 10 = 120\n12 x 11 = 132\n12 x 12 = 144\n----------\n", + "text": "\n8 x 6 = 48\n8 x 7 = 56\n8 x 8 = 64\n8 x 9 = 72\n8 x 10 = 80\n8 x 11 = 88\n8 x 12 = 96\n---\n9 x 1 = 9\n9 x 2 = 18\n9 x 3 = 27\n9 x 4 = 36\n9 x 5 = 45\n9 x 6 = 54\n9 x 7 = 63\n9 x 8 = 72\n9 x 9 = 81\n9 x 10 = 90\n9 x 11 = 99\n9 x 12 = 108\n---\n10 x 1 = 10\n10 x 2 = 20\n10 x 3 = 30\n10 x 4 = 40\n10 x 5 = 50\n10 x 6 = 60\n10 x 7 = 70\n10 x 8 = 80\n10 x 9 = 90\n10 x 10 = 100\n10 x 11 = 110\n10 x 12 = 120\n---\n11 x 1 = 11\n11 x 2 = 22\n11 x 3 = 33\n11 x 4 = 44\n11 x 5 = 55\n11 x 6 = 66\n11 x 7 = 77\n11 x 8 = 88\n11 x 9 = 99\n11 x 10 = 110\n11 x 11 = 121\n11 x 12 = 132\n---\n12 x 1 = 12\n12 x 2 = 24\n12 x 3 = 36\n12 x 4 = 48\n12 x 5 = 60\n12 x 6 = 72\n12 x 7 = 84\n12 x 8 = 96\n12 x 9 = 108\n12 x 10 = 120\n12 x 11 = 132\n12 x 12 = 144\n---\n", "type": "stdout" } ] @@ -4521,7 +4295,7 @@ " if player1 != player2:", " print(f'{player1} vs {player2}')" ], - "page": "Introducing Nested Loops", + "page": "\u4ecb\u7ecd\u5d4c\u5957\u5faa\u73af", "program": [ "players = ['Alice', 'Bob', 'Charlie']", "for player1 in players:", @@ -4530,7 +4304,6 @@ " print(f'{player1} vs {player2}')" ], "response": { - "message": "", "passed": true, "result": [ { @@ -4549,7 +4322,7 @@ " for c4 in letters:", " print(c1 + c2 + c3 + c4)" ], - "page": "Introducing Nested Loops", + "page": "\u4ecb\u7ecd\u5d4c\u5957\u5faa\u73af", "program": [ "letters = 'AB'", "for c1 in letters:", @@ -4559,7 +4332,6 @@ " print(c1 + c2 + c3 + c4)" ], "response": { - "message": "", "passed": true, "result": [ { @@ -4579,7 +4351,7 @@ " line += '+'", " print(line)" ], - "page": "Introducing Nested Loops", + "page": "\u4ecb\u7ecd\u5d4c\u5957\u5faa\u73af", "program": [ "size = 3", "for i in range(size):", @@ -4590,7 +4362,6 @@ " print(line)" ], "response": { - "message": "", "passed": true, "result": [ { @@ -4608,7 +4379,7 @@ " if i < j:", " print(f'{players[i]} vs {players[j]}')" ], - "page": "Introducing Nested Loops", + "page": "\u4ecb\u7ecd\u5d4c\u5957\u5faa\u73af", "program": [ "players = ['Alice', 'Bob', 'Charlie']", "for i in range(len(players)):", @@ -4617,7 +4388,6 @@ " print(f'{players[i]} vs {players[j]}')" ], "response": { - "message": "", "passed": true, "result": [ { @@ -4629,7 +4399,8 @@ "step": "player_vs_player_bonus" }, { - "page": "Understanding Programs withbirdseye
",
+ "get_solution": "program",
+ "page": "\u4f7f\u7528 birdseye
\u7406\u89e3\u7a0b\u5e8f",
"program": [
"a = 2",
"b = 3",
@@ -4638,7 +4409,6 @@
"print(a * b + c * d)"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -4650,7 +4420,8 @@
"step": "first_birdseye_example"
},
{
- "page": "Understanding Programs with birdseye
",
+ "get_solution": "program",
+ "page": "\u4f7f\u7528 birdseye
\u7406\u89e3\u7a0b\u5e8f",
"program": [
"word = 'Amazing'",
"vowels = []",
@@ -4664,7 +4435,6 @@
"print(consonants)"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -4680,14 +4450,13 @@
"string = strings[1]",
"print(string[0])"
],
- "page": "Introducing Nested Lists",
+ "page": "\u4ecb\u7ecd\u5d4c\u5957\u5217\u8868",
"program": [
"strings = ['abc', 'def', 'ghi']",
"string = strings[1]",
"print(string[0])"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -4699,13 +4468,13 @@
"step": "string_list_exercise"
},
{
- "page": "Introducing Nested Lists",
+ "get_solution": "program",
+ "page": "\u4ecb\u7ecd\u5d4c\u5957\u5217\u8868",
"program": [
"strings = [\"abc\", \"def\", \"ghi\"]",
"print(strings[1][0])"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -4720,13 +4489,12 @@
"get_solution": [
"print(strings[-2][-1])"
],
- "page": "Introducing Nested Lists",
+ "page": "\u4ecb\u7ecd\u5d4c\u5957\u5217\u8868",
"program": [
"strings = ['abc', 'de', 'fghi', 'jklmn', 'o']",
"print(strings[-2][-1])"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -4738,13 +4506,13 @@
"step": "double_subscripting_exercise"
},
{
- "page": "Introducing Nested Lists",
+ "get_solution": "program",
+ "page": "\u4ecb\u7ecd\u5d4c\u5957\u5217\u8868",
"program": [
"strings = [['hello', 'there'], ['how', 'are', 'you']]",
"print(strings[1][0])"
],
"response": {
- "message": "",
"passed": true,
"prediction": {
"answer": "how",
@@ -4760,7 +4528,7 @@
"t",
"e",
"a",
- "Error"
+ "\u9519\u8bef"
]
},
"result": [
@@ -4776,13 +4544,12 @@
"get_solution": [
"print(strings[1][2][0])"
],
- "page": "Introducing Nested Lists",
+ "page": "\u4ecb\u7ecd\u5d4c\u5957\u5217\u8868",
"program": [
"strings = [['hello', 'there'], ['how', 'are', 'you']]",
"print(strings[1][2][0])"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -4794,7 +4561,8 @@
"step": "triple_subscripting"
},
{
- "page": "Looping Over Nested Lists",
+ "get_solution": "program",
+ "page": "\u904d\u5386\u5d4c\u5957\u5217\u8868",
"program": [
"numbers = [[1, 2, 3], [4, 5], [6], []]",
"for sublist in numbers:",
@@ -4803,7 +4571,6 @@
" print('---')"
],
"response": {
- "message": "",
"passed": true,
"prediction": {
"answer": "1\n2\n3\n---\n4\n5\n---\n6\n---\n---",
@@ -4813,7 +4580,7 @@
"1\n2\n3\n---\n4\n5\n---\n6\n---",
"1 2 3\n---\n4 5\n---\n6\n---\n---",
"1 2 3\n---\n4 5\n---\n6\n---",
- "Error"
+ "\u9519\u8bef"
]
},
"result": [
@@ -4826,7 +4593,8 @@
"step": "nested_list_nested_loop_example"
},
{
- "page": "Looping Over Nested Lists",
+ "get_solution": "program",
+ "page": "\u904d\u5386\u5d4c\u5957\u5217\u8868",
"program": [
"numbers = [[1, 2, 3], [4, 5], [6], []]",
"for sublist in numbers:",
@@ -4835,7 +4603,6 @@
" print('---')"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -4853,7 +4620,7 @@
" if word in string:",
" print(string)"
],
- "page": "Looping Over Nested Lists",
+ "page": "\u904d\u5386\u5d4c\u5957\u5217\u8868",
"program": [
"strings = [['hello there', 'how are you'], ['goodbye world', 'hello world']]",
"word = 'hello'",
@@ -4863,7 +4630,6 @@
" print(string)"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -4883,7 +4649,7 @@
" present = True",
" print(present)"
],
- "page": "Looping Over Nested Lists",
+ "page": "\u904d\u5386\u5d4c\u5957\u5217\u8868",
"program": [
"strings = [['hello there', 'how are you'], ['goodbye world', 'hello world']]",
"word = 'goodbye'",
@@ -4895,7 +4661,6 @@
" print(present)"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -4915,7 +4680,7 @@
" present = True",
"print(present)"
],
- "page": "Looping Over Nested Lists",
+ "page": "\u904d\u5386\u5d4c\u5957\u5217\u8868",
"program": [
"strings = [['hello there', 'how are you'], ['goodbye world', 'hello world']]",
"word = 'are'",
@@ -4927,7 +4692,6 @@
"print(present)"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -4946,7 +4710,7 @@
" line += string[i]",
" print(line)"
],
- "page": "Looping Over Nested Lists",
+ "page": "\u904d\u5386\u5d4c\u5957\u5217\u8868",
"program": [
"strings = ['abc', 'def', 'ghi']",
"for i in range(len(strings[0])):",
@@ -4956,7 +4720,6 @@
" print(line)"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -4983,7 +4746,7 @@
" line += string[i]",
" print(line)"
],
- "page": "Looping Over Nested Lists",
+ "page": "\u904d\u5386\u5d4c\u5957\u5217\u8868",
"program": [
"strings = ['abcqwe', 'def', 'ghiq']",
"lengths = []",
@@ -5001,7 +4764,6 @@
" print(line)"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -5013,7 +4775,8 @@
"step": "zip_longest_strings_exercise"
},
{
- "page": "Defining Functions",
+ "get_solution": "program",
+ "page": "\u5b9a\u4e49\u51fd\u6570",
"program": [
"def greet(name):",
" print(f\"Hello {name}!\")",
@@ -5022,7 +4785,6 @@
"greet(\"Bob\")"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -5034,7 +4796,8 @@
"step": "define_greet"
},
{
- "page": "Defining Functions",
+ "get_solution": "program",
+ "page": "\u5b9a\u4e49\u51fd\u6570",
"program": [
"def greet(name):",
" print(f\"Hello {name}!\")",
@@ -5044,7 +4807,6 @@
"greet(\"Bob\")"
],
"response": {
- "message": "",
"passed": true,
"prediction": {
"answer": "Hello Alice!\nHow are you?\nHello Bob!\nHow are you?",
@@ -5052,7 +4814,7 @@
"Hello Alice!\nHow are you?\nHello Bob!\nHow are you?",
"Hello Alice!\nHello Bob!\nHow are you?",
"Hello Alice!\nHow are you?\nHello Bob!",
- "Error"
+ "\u9519\u8bef"
]
},
"result": [
@@ -5065,15 +4827,8 @@
"step": "how_are_you"
},
{
- "get_solution": [
- "def say_hello(name):",
- " print(f\"Hello {name}!\")",
- " print(\"How are you?\")",
- "",
- "say_hello(\"Alice\")",
- "say_hello(\"Bob\")"
- ],
- "page": "Defining Functions",
+ "get_solution": "program",
+ "page": "\u5b9a\u4e49\u51fd\u6570",
"program": [
"def say_hello(name):",
" print(f\"Hello {name}!\")",
@@ -5083,7 +4838,6 @@
"say_hello(\"Bob\")"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -5095,15 +4849,8 @@
"step": "change_function_name"
},
{
- "get_solution": [
- "def say_hello(person_name):",
- " print(f\"Hello {person_name}!\")",
- " print(\"How are you?\")",
- "",
- "say_hello(\"Alice\")",
- "say_hello(\"Bob\")"
- ],
- "page": "Defining Functions",
+ "get_solution": "program",
+ "page": "\u5b9a\u4e49\u51fd\u6570",
"program": [
"def say_hello(person_name):",
" print(f\"Hello {person_name}!\")",
@@ -5113,7 +4860,6 @@
"say_hello(\"Bob\")"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -5125,26 +4871,22 @@
"step": "change_parameter_name"
},
{
- "get_solution": [
- "def print_twice(x):",
- " print(x)",
- " print(x)"
- ],
- "page": "Defining Functions",
+ "get_solution": "program",
+ "page": "\u5b9a\u4e49\u51fd\u6570",
"program": [
"def print_twice(x):",
" print(x)",
" print(x)"
],
"response": {
- "message": "",
"passed": true,
"result": []
},
"step": "print_twice_exercise"
},
{
- "page": "Defining Functions",
+ "get_solution": "program",
+ "page": "\u5b9a\u4e49\u51fd\u6570",
"program": [
"def print_many(thing, n):",
" for _ in range(n):",
@@ -5153,7 +4895,6 @@
"print_many(\"Hello\", 3)"
],
"response": {
- "message": "",
"passed": true,
"prediction": {
"answer": "Hello\nHello\nHello",
@@ -5163,7 +4904,7 @@
"Hello\nHello\nHello",
"Hello",
"H\ne\nl\nl\no",
- "Error"
+ "\u9519\u8bef"
]
},
"result": [
@@ -5176,15 +4917,9 @@
"step": "print_many"
},
{
- "get_solution": [
- "def print_many(n, thing):",
- " for _ in range(n):",
- " print(thing)",
- "",
- "print_many(3, \"Hello\")"
- ],
- "page": "Defining Functions",
- "program": [
+ "get_solution": "program",
+ "page": "\u5b9a\u4e49\u51fd\u6570",
+ "program": [
"def print_many(n, thing):",
" for _ in range(n):",
" print(thing)",
@@ -5192,7 +4927,6 @@
"print_many(3, \"Hello\")"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -5204,7 +4938,8 @@
"step": "swap_parameters"
},
{
- "page": "Calling Functions Within Functions",
+ "get_solution": "program",
+ "page": "\u5728\u51fd\u6570\u4e2d\u8c03\u7528\u51fd\u6570",
"program": [
"def print_many(n, thing):",
" for _ in range(n):",
@@ -5216,7 +4951,6 @@
"print_twice(\"Hello\")"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -5228,7 +4962,8 @@
"step": "print_twice_call_print_many"
},
{
- "page": "Calling Functions Within Functions",
+ "get_solution": "program",
+ "page": "\u5728\u51fd\u6570\u4e2d\u8c03\u7528\u51fd\u6570",
"program": [
"def print_many(n, thing):",
" for _ in range(n):",
@@ -5240,83 +4975,55 @@
"print_twice(\"Hello\")"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
- "text": "",
- "type": "stdout"
- },
- {
- "text": "\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 1\u001b[0m | \u001b[38;5;81mdef\u001b[39m \u001b[38;5;148mprint_many\u001b[39m(n, thing):\n",
- "type": "stdout"
+ "text": "\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 1\u001b[0m | \u001b[38;5;81mdef\u001b[39m \u001b[38;5;148mprint_many\u001b[39m(n, thing):\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 5\u001b[0m | \u001b[38;5;81mdef\u001b[39m \u001b[38;5;148mprint_twice\u001b[39m(x):\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 8\u001b[0m | print_twice(\u001b[38;5;186m\"\u001b[39m\u001b[38;5;186mHello\u001b[39m\u001b[38;5;186m\"\u001b[39m)\n\u001b[38;5;245m \u001b[0m\u001b[36m\u001b[1m>>> Call to print_twice in File \"/my_program.py\", line 5\u001b[0m\n\u001b[38;5;245m \u001b[0m...... x = \u001b[38;5;186m'\u001b[39m\u001b[38;5;186mHello\u001b[39m\u001b[38;5;186m'\u001b[39m\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 5\u001b[0m | \u001b[38;5;81mdef\u001b[39m \u001b[38;5;148mprint_twice\u001b[39m(x):\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 6\u001b[0m | print_many(\u001b[38;5;141m2\u001b[39m, x)\n\u001b[38;5;245m \u001b[0m\u001b[36m\u001b[1m>>> Call to print_many in File \"/my_program.py\", line 1\u001b[0m\n\u001b[38;5;245m \u001b[0m...... n = \u001b[38;5;141m2\u001b[39m\n\u001b[38;5;245m \u001b[0m...... thing = \u001b[38;5;186m'\u001b[39m\u001b[38;5;186mHello\u001b[39m\u001b[38;5;186m'\u001b[39m\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 1\u001b[0m | \u001b[38;5;81mdef\u001b[39m \u001b[38;5;148mprint_many\u001b[39m(n, thing):\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 2\u001b[0m | \u001b[38;5;81mfor\u001b[39m _ \u001b[38;5;204min\u001b[39m range(n):\n",
+ "type": "snoop"
},
{
- "text": "\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 5\u001b[0m | \u001b[38;5;81mdef\u001b[39m \u001b[38;5;148mprint_twice\u001b[39m(x):\n",
- "type": "stdout"
+ "text": "\u001b[38;5;245m \u001b[0m.......... _ = \u001b[38;5;141m0\u001b[39m\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 3\u001b[0m | print(thing)\n",
+ "type": "snoop"
},
{
- "text": "\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 8\u001b[0m | print_twice(\u001b[38;5;186m\"\u001b[39m\u001b[38;5;186mHello\u001b[39m\u001b[38;5;186m\"\u001b[39m)\n",
+ "text": "Hello",
"type": "stdout"
},
{
- "text": "\u001b[38;5;242m \u001b[0m\u001b[36m\u001b[1m>>> Call to print_twice in File \"my_program.py\", line 5\u001b[0m\n\u001b[38;5;242m \u001b[0m...... x = \u001b[38;5;186m'\u001b[39m\u001b[38;5;186mHello\u001b[39m\u001b[38;5;186m'\u001b[39m\n\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 5\u001b[0m | \u001b[38;5;81mdef\u001b[39m \u001b[38;5;148mprint_twice\u001b[39m(x):\n",
+ "text": "\n",
"type": "stdout"
},
{
- "text": "\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 6\u001b[0m | print_many(\u001b[38;5;141m2\u001b[39m, x)\n",
- "type": "stdout"
+ "text": "\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 2\u001b[0m | \u001b[38;5;81mfor\u001b[39m _ \u001b[38;5;204min\u001b[39m range(n):\n",
+ "type": "snoop"
},
{
- "text": "\u001b[38;5;242m \u001b[0m\u001b[36m\u001b[1m>>> Call to print_many in File \"my_program.py\", line 1\u001b[0m\n\u001b[38;5;242m \u001b[0m...... n = \u001b[38;5;141m2\u001b[39m\n\u001b[38;5;242m \u001b[0m...... thing = \u001b[38;5;186m'\u001b[39m\u001b[38;5;186mHello\u001b[39m\u001b[38;5;186m'\u001b[39m\n\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 1\u001b[0m | \u001b[38;5;81mdef\u001b[39m \u001b[38;5;148mprint_many\u001b[39m(n, thing):\n",
- "type": "stdout"
+ "text": "\u001b[38;5;245m \u001b[0m.......... _ = \u001b[38;5;141m1\u001b[39m\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 3\u001b[0m | print(thing)\n",
+ "type": "snoop"
},
{
- "text": "\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 2\u001b[0m | \u001b[38;5;81mfor\u001b[39m _ \u001b[38;5;197min\u001b[39m range(n):\n",
+ "text": "Hello",
"type": "stdout"
},
{
- "text": "\u001b[38;5;242m \u001b[0m.......... _ = \u001b[38;5;141m0\u001b[39m\n\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 3\u001b[0m | print(thing)\n",
+ "text": "\n",
"type": "stdout"
},
{
- "text": "Hello\n\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 2\u001b[0m | \u001b[38;5;81mfor\u001b[39m _ \u001b[38;5;197min\u001b[39m range(n):\n",
- "type": "stdout"
+ "text": "\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 2\u001b[0m | \u001b[38;5;81mfor\u001b[39m _ \u001b[38;5;204min\u001b[39m range(n):\n",
+ "type": "snoop"
},
{
- "text": "\u001b[38;5;242m \u001b[0m.......... _ = \u001b[38;5;141m1\u001b[39m\n\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 3\u001b[0m | print(thing)\n",
- "type": "stdout"
- },
- {
- "text": "Hello\n\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 2\u001b[0m | \u001b[38;5;81mfor\u001b[39m _ \u001b[38;5;197min\u001b[39m range(n):\n",
- "type": "stdout"
- },
- {
- "text": "\u001b[38;5;242m \u001b[0m\u001b[32m\u001b[1m<<< Return value from print_many: \u001b[0m\u001b[38;5;81mNone\u001b[39m\n",
- "type": "stdout"
- },
- {
- "text": "\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 6\u001b[0m | print_many(\u001b[38;5;141m2\u001b[39m, x)\n",
- "type": "stdout"
- },
- {
- "text": "\u001b[38;5;242m \u001b[0m\u001b[32m\u001b[1m<<< Return value from print_twice: \u001b[0m\u001b[38;5;81mNone\u001b[39m\n",
- "type": "stdout"
- },
- {
- "text": "\u001b[38;5;242m \u001b[0m\u001b[38;5;242m 8\u001b[0m | print_twice(\u001b[38;5;186m\"\u001b[39m\u001b[38;5;186mHello\u001b[39m\u001b[38;5;186m\"\u001b[39m)\n",
- "type": "stdout"
- },
- {
- "text": "",
- "type": "stdout"
+ "text": "\u001b[38;5;245m \u001b[0m\u001b[32m\u001b[1m<<< Return value from print_many: \u001b[0m\u001b[38;5;81mNone\u001b[39m\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 6\u001b[0m | print_many(\u001b[38;5;141m2\u001b[39m, x)\n\u001b[38;5;245m \u001b[0m\u001b[32m\u001b[1m<<< Return value from print_twice: \u001b[0m\u001b[38;5;81mNone\u001b[39m\n\u001b[38;5;245m \u001b[0m\u001b[38;5;245m 8\u001b[0m | print_twice(\u001b[38;5;186m\"\u001b[39m\u001b[38;5;186mHello\u001b[39m\u001b[38;5;186m\"\u001b[39m)\n",
+ "type": "snoop"
}
]
},
"step": "see_stack_in_snoop"
},
{
- "page": "Calling Functions Within Functions",
+ "get_solution": "program",
+ "page": "\u5728\u51fd\u6570\u4e2d\u8c03\u7528\u51fd\u6570",
"program": [
"def print_many(n, thing):",
" for _ in range(n):",
@@ -5328,7 +5035,6 @@
"print_twice(\"Hello\")"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -5340,7 +5046,8 @@
"step": "see_stack_in_pythontutor"
},
{
- "page": "Calling Functions Within Functions",
+ "get_solution": "program",
+ "page": "\u5728\u51fd\u6570\u4e2d\u8c03\u7528\u51fd\u6570",
"program": [
"def print_many(n, thing):",
" for _ in range(n):",
@@ -5352,7 +5059,6 @@
"print_twice(\"Hello\")"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -5364,7 +5070,8 @@
"step": "see_stack_in_birdseye"
},
{
- "page": "Returning Values From Functions",
+ "get_solution": "program",
+ "page": "\u4ece\u51fd\u6570\u8fd4\u56de\u503c",
"program": [
"def double(x):",
" return x * 2",
@@ -5375,7 +5082,6 @@
"print(twice)"
],
"response": {
- "message": "",
"passed": true,
"prediction": {
"answer": "5\n10",
@@ -5383,7 +5089,7 @@
"5\n5",
"5\n10",
"10\n10",
- "Error"
+ "\u9519\u8bef"
]
},
"result": [
@@ -5396,7 +5102,8 @@
"step": "first_return"
},
{
- "page": "Returning Values From Functions",
+ "get_solution": "program",
+ "page": "\u4ece\u51fd\u6570\u8fd4\u56de\u503c",
"program": [
"def double(x):",
" return x * 2",
@@ -5406,14 +5113,13 @@
"print(number)"
],
"response": {
- "message": "",
"passed": true,
"prediction": {
"answer": "5",
"choices": [
"5",
"10",
- "Error"
+ "\u9519\u8bef"
]
},
"result": [
@@ -5426,13 +5132,13 @@
"step": "losing_return_value"
},
{
- "page": "Returning Values From Functions",
+ "page": "\u4ece\u51fd\u6570\u8fd4\u56de\u503c",
"program": [
"def quadruple(x):",
" return x * 4"
],
"response": {
- "message": "You cannot use *
, +
, or even any numbers inside quadruple
.\nYou must call double
to solve the problem.
\u4f60\u4e0d\u80fd\u5728 quadruple
\u5185\u90e8\u4f7f\u7528 *
\u3001+
\uff0c\u751a\u81f3\u4efb\u4f55\u6570\u5b57\u3002\n\u4f60\u5fc5\u987b\u8c03\u7528 double
\u6765\u89e3\u51b3\u8fd9\u4e2a\u95ee\u9898\u3002
In the alert
function, you placed your return
statement at the wrong place!\nPay attention to your indentations in alert
. You might be ending a loop too early with return
.
\u5728 alert
\u51fd\u6570\u4e2d\uff0c\u4f60\u628a return
\u8bed\u53e5\u653e\u9519\u4e86\u5730\u65b9\uff01\n\u6ce8\u610f\u4f60\u5728 alert
\u4e2d\u7684\u7f29\u8fdb\u3002\u4f60\u53ef\u80fd\u8fc7\u65e9\u5730\u7528 return
\u7ed3\u675f\u4e86\u4e00\u4e2a\u5faa\u73af\u3002
You cannot use string concatenation/formatting/interpolation/multiplication or f-strings in alert
.\nYou must call surround
to solve the problem.
\u4f60\u4e0d\u80fd\u5728 alert
\u4e2d\u4f7f\u7528\u5b57\u7b26\u4e32\u8fde\u63a5/\u683c\u5f0f\u5316/\u63d2\u503c/\u4e58\u6cd5\u6216 f-strings\u3002\n\u4f60\u5fc5\u987b\u8c03\u7528 surround
\u6765\u89e3\u51b3\u8fd9\u4e2a\u95ee\u9898\u3002
return
ends the function call",
+ "get_solution": "program",
+ "page": "return
\u7ed3\u675f\u51fd\u6570\u8c03\u7528",
"program": [
"def foo():",
" return 1",
@@ -5631,7 +5332,6 @@
"print(foo())"
],
"response": {
- "message": "",
"passed": true,
"prediction": {
"answer": "1",
@@ -5641,7 +5341,7 @@
"[1, 2]",
"1\n2",
"1 2",
- "Error"
+ "\u9519\u8bef"
]
},
"result": [
@@ -5654,7 +5354,8 @@
"step": "double_return_in_one_function"
},
{
- "page": "return
ends the function call",
+ "get_solution": "program",
+ "page": "return
\u7ed3\u675f\u51fd\u6570\u8c03\u7528",
"program": [
"def double_numbers(numbers):",
" for x in numbers:",
@@ -5663,7 +5364,6 @@
"assert_equal(double_numbers([1, 2, 3]), [2, 4, 6])"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -5675,7 +5375,8 @@
"step": "cannot_return_multiple_values"
},
{
- "page": "return
ends the function call",
+ "get_solution": "program",
+ "page": "return
\u7ed3\u675f\u51fd\u6570\u8c03\u7528",
"program": [
"def foo():",
" for letter in 'abc':",
@@ -5687,7 +5388,6 @@
"foo()"
],
"response": {
- "message": "",
"passed": true,
"prediction": {
"answer": "a 0\na 1\na 2\nb 0",
@@ -5697,7 +5397,7 @@
"a 0\na 1\na 2\nb 0\nb 1\nb 2",
"a 0\na 1\na 2\nb 0\nc 0\nc 1\nc 2",
"a 0\na 1\na 2\nb 0\nb 1\nb 2\nc 0\nc 1\nc 2",
- "Error"
+ "\u9519\u8bef"
]
},
"result": [
@@ -5710,7 +5410,8 @@
"step": "return_ends_whole_function"
},
{
- "page": "return
ends the function call",
+ "get_solution": "program",
+ "page": "return
\u7ed3\u675f\u51fd\u6570\u8c03\u7528",
"program": [
"def foo():",
" for letter in 'abc':",
@@ -5722,7 +5423,6 @@
"foo()"
],
"response": {
- "message": "",
"passed": true,
"prediction": {
"answer": "a 0\na 1\na 2\nb 0\nc 0\nc 1\nc 2",
@@ -5732,7 +5432,7 @@
"a 0\na 1\na 2\nb 0\nb 1\nb 2",
"a 0\na 1\na 2\nb 0\nc 0\nc 1\nc 2",
"a 0\na 1\na 2\nb 0\nb 1\nb 2\nc 0\nc 1\nc 2",
- "Error"
+ "\u9519\u8bef"
]
},
"result": [
@@ -5745,7 +5445,8 @@
"step": "break_vs_return"
},
{
- "page": "Introducing or
",
+ "get_solution": "program",
+ "page": "\u4ecb\u7ecd or
",
"program": [
"def is_friend(name):",
" if name == \"Alice\":",
@@ -5760,7 +5461,6 @@
"assert_equal(is_friend(\"Charlie\"), False)"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -5772,19 +5472,19 @@
"step": "InputAliceBob"
},
{
- "page": "Introducing or
",
+ "get_solution": "program",
+ "page": "\u4ecb\u7ecd or
",
"program": [
"True or True"
],
"response": {
- "message": "",
"passed": true,
"prediction": {
"answer": "True",
"choices": [
"True",
"False",
- "Error"
+ "\u9519\u8bef"
]
},
"result": [
@@ -5797,19 +5497,19 @@
"step": "TrueOrTrue"
},
{
- "page": "Introducing or
",
+ "get_solution": "program",
+ "page": "\u4ecb\u7ecd or
",
"program": [
"True or False"
],
"response": {
- "message": "",
"passed": true,
"prediction": {
"answer": "True",
"choices": [
"True",
"False",
- "Error"
+ "\u9519\u8bef"
]
},
"result": [
@@ -5822,19 +5522,19 @@
"step": "TrueOrFalse"
},
{
- "page": "Introducing or
",
+ "get_solution": "program",
+ "page": "\u4ecb\u7ecd or
",
"program": [
"False or False"
],
"response": {
- "message": "",
"passed": true,
"prediction": {
"answer": "False",
"choices": [
"True",
"False",
- "Error"
+ "\u9519\u8bef"
]
},
"result": [
@@ -5847,7 +5547,8 @@
"step": "FalseOrFalse"
},
{
- "page": "Introducing or
",
+ "get_solution": "program",
+ "page": "\u4ecb\u7ecd or
",
"program": [
"def is_friend(name):",
" if name == \"Alice\" or name == \"Bob\":",
@@ -5860,7 +5561,6 @@
"assert_equal(is_friend(\"Charlie\"), False)"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -5872,7 +5572,8 @@
"step": "ImprovingWithOr"
},
{
- "page": "Introducing or
",
+ "get_solution": "program",
+ "page": "\u4ecb\u7ecd or
",
"program": [
"def is_friend(name):",
" return name == \"Alice\" or name == \"Bob\"",
@@ -5882,7 +5583,6 @@
"assert_equal(is_friend(\"Charlie\"), False)"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -5894,7 +5594,8 @@
"step": "FurtherImprovement"
},
{
- "page": "Introducing or
",
+ "get_solution": "program",
+ "page": "\u4ecb\u7ecd or
",
"program": [
"def is_friend(name):",
" return name == \"Alice\" or \"Bob\"",
@@ -5904,7 +5605,6 @@
"assert_equal(is_friend(\"Charlie\"), False)"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -5916,7 +5616,8 @@
"step": "ACommonMistake"
},
{
- "page": "Introducing or
",
+ "get_solution": "program",
+ "page": "\u4ecb\u7ecd or
",
"program": [
"def is_friend(name):",
" return name == \"Alice\" or \"Bob\"",
@@ -5926,7 +5627,6 @@
"assert_equal(is_friend(\"Charlie\"), False)"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -5938,14 +5638,8 @@
"step": "InspectWithBirdseye"
},
{
- "get_solution": [
- "def is_valid_percentage(x):",
- " if x < 0 or x > 100:",
- " return False",
- " else:",
- " return True"
- ],
- "page": "Introducing or
",
+ "get_solution": "program",
+ "page": "\u4ecb\u7ecd or
",
"program": [
"def is_valid_percentage(x):",
" if x < 0 or x > 100:",
@@ -5954,26 +5648,25 @@
" return True"
],
"response": {
- "message": "",
"passed": true,
"result": []
},
"step": "AnExercise"
},
{
- "page": "Introducing and
",
+ "get_solution": "program",
+ "page": "\u4ecb\u7ecd and
",
"program": [
"True and True"
],
"response": {
- "message": "",
"passed": true,
"prediction": {
"answer": "True",
"choices": [
"True",
"False",
- "Error"
+ "\u9519\u8bef"
]
},
"result": [
@@ -5986,19 +5679,19 @@
"step": "TrueAndTrue"
},
{
- "page": "Introducing and
",
+ "get_solution": "program",
+ "page": "\u4ecb\u7ecd and
",
"program": [
"True and False"
],
"response": {
- "message": "",
"passed": true,
"prediction": {
"answer": "False",
"choices": [
"True",
"False",
- "Error"
+ "\u9519\u8bef"
]
},
"result": [
@@ -6011,19 +5704,19 @@
"step": "TrueAndFalse"
},
{
- "page": "Introducing and
",
+ "get_solution": "program",
+ "page": "\u4ecb\u7ecd and
",
"program": [
"False and False"
],
"response": {
- "message": "",
"passed": true,
"prediction": {
"answer": "False",
"choices": [
"True",
"False",
- "Error"
+ "\u9519\u8bef"
]
},
"result": [
@@ -6036,14 +5729,8 @@
"step": "FalseAndFalse"
},
{
- "get_solution": [
- "def is_valid_percentage(x):",
- " if 0 <= x and x <= 100:",
- " return True",
- " else:",
- " return False"
- ],
- "page": "Introducing and
",
+ "get_solution": "program",
+ "page": "\u4ecb\u7ecd and
",
"program": [
"def is_valid_percentage(x):",
" if 0 <= x and x <= 100:",
@@ -6052,41 +5739,37 @@
" return False"
],
"response": {
- "message": "",
"passed": true,
"result": []
},
"step": "AndExercise"
},
{
- "get_solution": [
- "def all_equal(row):",
- " return row[0] == row[1] and row[0] == row[2]"
- ],
- "page": "Introducing and
",
+ "get_solution": "program",
+ "page": "\u4ecb\u7ecd and
",
"program": [
"def all_equal(row):",
" return row[0] == row[1] and row[0] == row[2]"
],
"response": {
- "message": "",
"passed": true,
"result": []
},
"step": "TicTacToeWinningRow"
},
{
- "page": "Multi-line statements",
+ "get_solution": "program",
+ "page": "\u591a\u884c\u8bed\u53e5",
"program": [
"is_friend = name == \"Alice\" or",
" name == \"Bob\""
],
"response": {
- "message": "",
"passed": true,
"result": [
{
- "text": " is_friend = name == \"Alice\" or\n ^\nSyntaxError: invalid syntax\nat line 1\n\nA `SyntaxError` occurs when Python cannot understand your code.\n\nThe Python keyword `or` can only be used for boolean expressions.\nPerhaps you meant to write\n\n`is_friend = name == \"Alice\" ,`\n\n\n",
+ "friendly": "A SyntaxError
occurs when Python cannot understand your code.
The Python keyword or
can only be used for boolean expressions.\nPerhaps you meant to write
is_friend = name == \"Alice\" ,
and
and or
",
+ "get_solution": "program",
+ "page": "\u7ec4\u5408 and
\u548c or
",
"program": [
"True or False and False"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -6143,15 +5826,8 @@
"step": "CombiningAndOr"
},
{
- "get_solution": [
- "def diagonal_winner(board):",
- " middle = board[1][1]",
- " return (",
- " (middle == board[0][0] and middle == board[2][2]) or",
- " (middle == board[0][2] and middle == board[2][0])",
- " )"
- ],
- "page": "Combining and
and or
",
+ "get_solution": "program",
+ "page": "\u7ec4\u5408 and
\u548c or
",
"program": [
"def diagonal_winner(board):",
" middle = board[1][1]",
@@ -6161,26 +5837,25 @@
" )"
],
"response": {
- "message": "",
"passed": true,
"result": []
},
"step": "AndHasHigherPriority"
},
{
- "page": "Introducing not
",
+ "get_solution": "program",
+ "page": "\u4ecb\u7ecd not
",
"program": [
"not True"
],
"response": {
- "message": "",
"passed": true,
"prediction": {
"answer": "False",
"choices": [
"True",
"False",
- "Error"
+ "\u9519\u8bef"
]
},
"result": [
@@ -6193,19 +5868,19 @@
"step": "IntroducingNot"
},
{
- "page": "Introducing not
",
+ "get_solution": "program",
+ "page": "\u4ecb\u7ecd not
",
"program": [
"not False"
],
"response": {
- "message": "",
"passed": true,
"prediction": {
"answer": "True",
"choices": [
"True",
"False",
- "Error"
+ "\u9519\u8bef"
]
},
"result": [
@@ -6218,13 +5893,13 @@
"step": "NotFalse"
},
{
- "page": "Introducing not
",
+ "get_solution": "program",
+ "page": "\u4ecb\u7ecd not
",
"program": [
"b = True",
"print(not b or b)"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -6236,24 +5911,20 @@
"step": "NotTrueOrTrue"
},
{
- "get_solution": [
- "def invalid_image(filename):",
- " return not (filename.endswith(\".png\") or filename.endswith(\".jpg\"))"
- ],
- "page": "Introducing not
",
+ "get_solution": "program",
+ "page": "\u4ecb\u7ecd not
",
"program": [
"def invalid_image(filename):",
" return not (filename.endswith(\".png\") or filename.endswith(\".jpg\"))"
],
"response": {
- "message": "",
"passed": true,
"result": []
},
"step": "NotPriority"
},
{
- "page": "Checking the board for winners",
+ "page": "\u68c0\u67e5\u68cb\u76d8\u4e0a\u7684\u83b7\u80dc\u8005",
"program": [
"def row_winner(board):",
" for row in board:",
@@ -6268,27 +5939,15 @@
" return False"
],
"response": {
- "message": "Keep in mind that some entries might be ' '
. An empty row is not a winning row.
\u8bf7\u8bb0\u4f4f\uff0c\u6709\u4e9b\u6761\u76ee\u53ef\u80fd\u662f ' '
\u3002\u7a7a\u884c\u4e0d\u662f\u83b7\u80dc\u884c\u3002
format_board
",
+ "get_solution": "program",
+ "page": "\u6362\u884c\u7b26\uff0cformat_board
",
"program": [
"def print_board(board):",
" for row in board:",
@@ -6442,7 +6074,6 @@
"])"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -6454,7 +6085,8 @@
"step": "one_way_to_print_board"
},
{
- "page": "The newline character, format_board
",
+ "get_solution": "program",
+ "page": "\u6362\u884c\u7b26\uff0cformat_board
",
"program": [
"assert_equal(",
" format_board([",
@@ -6468,11 +6100,11 @@
")"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
- "text": " \"XOX\n ^\nSyntaxError: EOL while scanning string literal\nat line 7\n\nA `SyntaxError` occurs when Python cannot understand your code.\n\nYou started writing a string with a single or double quote\nbut never ended the string with another quote on that line.\n\n\n",
+ "friendly": "A SyntaxError
occurs when Python cannot understand your code.
You started writing a string with a single or double quote\nbut never ended the string with another quote on that line.
", + "text": " \"XOX\n ^\nSyntaxError: unterminated string literal (detected at line 7)\n\u5728\u884c 7\n", "type": "syntax_error" } ] @@ -6480,14 +6112,14 @@ "step": "invalid_multi_line_string" }, { - "page": "The newline character,format_board
",
+ "get_solution": "program",
+ "page": "\u6362\u884c\u7b26\uff0cformat_board
",
"program": [
"string = \"\"\"First line",
"Second line\"\"\"",
"print(string)"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -6499,24 +6131,24 @@
"step": "multi_line_strings_triple_quotes"
},
{
- "page": "The newline character, format_board
",
+ "page": "\u6362\u884c\u7b26\uff0cformat_board
",
"program": [
"string = 'a'"
],
"response": {
- "message": "Oops, string
doesn't have the right value. Run the program from the previous step again.
\u54ce\u5440\uff0cstring
\u7684\u503c\u4e0d\u6b63\u786e\u3002\u8bf7\u518d\u6b21\u8fd0\u884c\u4e0a\u4e00\u6b65\u7684\u7a0b\u5e8f\u3002
format_board
",
+ "get_solution": "program",
+ "page": "\u6362\u884c\u7b26\uff0cformat_board
",
"program": [
"string"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -6528,19 +6160,19 @@
"step": "discovering_newline"
},
{
- "page": "The newline character, format_board
",
+ "get_solution": "program",
+ "page": "\u6362\u884c\u7b26\uff0cformat_board
",
"program": [
"len('\\n')"
],
"response": {
- "message": "",
"passed": true,
"prediction": {
"answer": "1",
"choices": [
"1",
"2",
- "Error"
+ "\u9519\u8bef"
]
},
"result": [
@@ -6553,17 +6185,8 @@
"step": "introducing_newline"
},
{
- "get_solution": [
- "def format_board(board):",
- " result = ''",
- " for i in range(len(board)):",
- " for char in board[i]:",
- " result += char",
- " if i != len(board) - 1:",
- " result += '\\n'",
- " return result"
- ],
- "page": "The newline character, format_board
",
+ "get_solution": "program",
+ "page": "\u6362\u884c\u7b26\uff0cformat_board
",
"program": [
"def format_board(board):",
" result = ''",
@@ -6575,25 +6198,14 @@
" return result"
],
"response": {
- "message": "",
"passed": true,
"result": []
},
"step": "format_board_simple"
},
{
- "get_solution": [
- "def format_board(board):",
- " joined_rows = []",
- " for row in board:",
- " joined_rows.append(\"|\".join(row))",
- " lines = []",
- " for _ in board[0]:",
- " lines.append(\"-\")",
- " line = f'\\n{\"+\".join(lines)}\\n'",
- " return line.join(joined_rows)"
- ],
- "page": "The newline character, format_board
",
+ "get_solution": "program",
+ "page": "\u6362\u884c\u7b26\uff0cformat_board
",
"program": [
"def format_board(board):",
" joined_rows = []",
@@ -6606,14 +6218,14 @@
" return line.join(joined_rows)"
],
"response": {
- "message": "",
"passed": true,
"result": []
},
"step": "format_board_bonus_challenge"
},
{
- "page": "Types",
+ "get_solution": "program",
+ "page": "\u7c7b\u578b",
"program": [
"print(type('Hello World'))",
"print(type(23))",
@@ -6622,7 +6234,6 @@
"print(type(4.56))"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -6634,12 +6245,12 @@
"step": "five_different_types"
},
{
- "page": "Types",
+ "get_solution": "program",
+ "page": "\u7c7b\u578b",
"program": [
"type(3) == int"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -6651,14 +6262,14 @@
"step": "check_type_manually"
},
{
- "page": "Types",
+ "get_solution": "program",
+ "page": "\u7c7b\u578b",
"program": [
"print('123')",
"print(123)",
"print(123 == '123')"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -6670,13 +6281,13 @@
"step": "different_types_look_same"
},
{
- "page": "Types",
+ "get_solution": "program",
+ "page": "\u7c7b\u578b",
"program": [
"print(123 + 456)",
"print('123' + '456')"
],
"response": {
- "message": "",
"passed": true,
"prediction": {
"answer": "579\n123456",
@@ -6687,7 +6298,7 @@
"123456\n'123456'",
"579\n123456",
"579\n'123456'",
- "Error"
+ "\u9519\u8bef"
]
},
"result": [
@@ -6700,13 +6311,13 @@
"step": "plus_has_two_meanings"
},
{
- "page": "Types",
+ "get_solution": "program",
+ "page": "\u7c7b\u578b",
"program": [
"print(13 < 120)",
"print('13' < '120')"
],
"response": {
- "message": "",
"passed": true,
"prediction": {
"answer": "True\nFalse",
@@ -6715,7 +6326,7 @@
"True\nFalse",
"False\nTrue",
"False\nFalse",
- "Error"
+ "\u9519\u8bef"
]
},
"result": [
@@ -6728,13 +6339,13 @@
"step": "less_than_has_two_meanings"
},
{
- "page": "Types",
+ "get_solution": "program",
+ "page": "\u7c7b\u578b",
"program": [
"print(sorted([120, 13, 0]))",
"print(sorted(['120', '13', '0']))"
],
"response": {
- "message": "",
"passed": true,
"prediction": {
"answer": "[0, 13, 120]\n['0', '120', '13']",
@@ -6745,7 +6356,7 @@
"[120, 13, 0]\n['0', '120', '13']",
"[120, 13, 0]\n['13', '120', '0']",
"[120, 13, 0]\n['120', '13', '0']",
- "Error"
+ "\u9519\u8bef"
]
},
"result": [
@@ -6758,21 +6369,21 @@
"step": "less_than_sorting_strings"
},
{
- "page": "Types",
+ "get_solution": "program",
+ "page": "\u7c7b\u578b",
"program": [
"12 + '34'"
],
"response": {
- "message": "",
"passed": true,
"prediction": {
- "answer": "Error",
+ "answer": "\u9519\u8bef",
"choices": [
"46",
"'46'",
"1234",
"'1234'",
- "Error"
+ "\u9519\u8bef"
]
},
"result": [
@@ -6786,11 +6397,13 @@
},
"frames": [
{
+ "filename": "/my_program.py",
+ "lineno": 1,
"lines": [
{
- "content": "12 + '34'",
"is_current": true,
"lineno": 1,
+ "text": "12 + '34'",
"type": "line"
}
],
@@ -6805,7 +6418,7 @@
],
"text": [
"Traceback (most recent call last):",
- " File \"my_program.py\", line 1, in input()
",
+ "get_solution": "program",
+ "page": "\u4f7f\u7528 input()
\u7684\u4ea4\u4e92\u5f0f\u7a0b\u5e8f",
"program": [
"print('Type your name, then press Enter:')",
"name = input()",
"print(f'Hello {name}!')"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -6906,7 +6507,6 @@
},
{
"get_solution": [
- "super_secret_number = 7",
"print(\"What number am I thinking of?\")",
"guess = input()",
"if int(guess) == super_secret_number:",
@@ -6914,7 +6514,7 @@
"else:",
" print(\"Nope!\")"
],
- "page": "Interactive Programs with input()
",
+ "page": "\u4f7f\u7528 input()
\u7684\u4ea4\u4e92\u5f0f\u7a0b\u5e8f",
"program": [
"super_secret_number = 7",
"print(\"What number am I thinking of?\")",
@@ -6925,7 +6525,6 @@
" print(\"Nope!\")"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -6949,7 +6548,8 @@
"step": "convert_input_to_int"
},
{
- "page": "Nested List Assignment: Playing Moves on the Board",
+ "get_solution": "program",
+ "page": "\u5d4c\u5957\u5217\u8868\u4f5c\u4e1a\uff1a\u5728\u68cb\u76d8\u4e0a\u8fdb\u884c\u79fb\u52a8",
"program": [
"def play_move(board, player):",
" board[1] = player",
@@ -6962,7 +6562,6 @@
"play_game()"
],
"response": {
- "message": "",
"passed": true,
"prediction": {
"answer": "[' ', 'X', ' ']",
@@ -6976,7 +6575,7 @@
"['X', ' ', ' ']",
"[' ', 'X', ' ']",
"[' ', ' ', 'X']",
- "Error"
+ "\u9519\u8bef"
]
},
"result": [
@@ -6989,7 +6588,8 @@
"step": "modify_list_in_function"
},
{
- "page": "Nested List Assignment: Playing Moves on the Board",
+ "get_solution": "program",
+ "page": "\u5d4c\u5957\u5217\u8868\u4f5c\u4e1a\uff1a\u5728\u68cb\u76d8\u4e0a\u8fdb\u884c\u79fb\u52a8",
"program": [
"def play_move(board, player):",
" row = board[1]",
@@ -7007,7 +6607,6 @@
"play_game()"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -7019,13 +6618,8 @@
"step": "nested_assignment_two_lines"
},
{
- "get_solution": [
- "def play_move(board, player):",
- " row = int(input()) - 1",
- " col = int(input()) - 1",
- " board[row][col] = player"
- ],
- "page": "Nested List Assignment: Playing Moves on the Board",
+ "get_solution": "program",
+ "page": "\u5d4c\u5957\u5217\u8868\u4f5c\u4e1a\uff1a\u5728\u68cb\u76d8\u4e0a\u8fdb\u884c\u79fb\u52a8",
"program": [
"def play_move(board, player):",
" row = int(input()) - 1",
@@ -7033,14 +6627,14 @@
" board[row][col] = player"
],
"response": {
- "message": "",
"passed": true,
"result": []
},
"step": "nested_assignment_input"
},
{
- "page": "Making the Board",
+ "get_solution": "program",
+ "page": "\u5236\u4f5c\u68cb\u76d8",
"program": [
"def make_board(size):",
" row = []",
@@ -7068,7 +6662,6 @@
"test()"
],
"response": {
- "message": "",
"passed": true,
"result": [
{
@@ -7080,30 +6673,21 @@
"step": "naive_make_board"
},
{
- "page": "Making the Board",
+ "page": "\u5236\u4f5c\u68cb\u76d8",
"program": [
"pass",
"def make_board(size): return [[' '] * size] * size"
],
"response": {
- "message": "The sublists in the result are not all separate objects.
", + "message": "\u7ed9\u5b9a\u8fd9\u4e9b\u503c\uff1a
\nsize = 2\n
\n\u4f60\u7684\u4ee3\u7801\u8f93\u51fa\uff1a
\n[[' ', ' '], [' ', ' ']]\n
\n\u54ea\u4e00\u4e2a\u662f\u6b63\u786e\u7684\uff01
\n\u7136\u800c\uff0c\u7ed3\u679c\u4e2d\u7684\u5b50\u5217\u8868\u5e76\u4e0d\u662f\u6240\u6709\u72ec\u7acb\u7684\u5bf9\u8c61\u3002
", "passed": false, "result": [] }, "step": "fix_make_board" }, { - "get_solution": [ - "def make_board(size):", - " board = []", - " for _ in range(size):", - " row = []", - " for _ in range(size):", - " row.append(' ')", - " board.append(row)", - " return board" - ], - "page": "Making the Board", + "get_solution": "program", + "page": "\u5236\u4f5c\u68cb\u76d8", "program": [ "def make_board(size):", " board = []", @@ -7115,7 +6699,6 @@ " return board" ], "response": { - "message": "", "passed": true, "result": [] }, @@ -7142,7 +6725,7 @@ "", " print_draw()" ], - "page": "The Full Tic-Tac-Toe Game", + "page": "\u5b8c\u6574\u7684\u4e95\u5b57\u68cb\u6e38\u620f", "program": [ "def winning_line(strings):", " strings = set(strings)", @@ -7205,10 +6788,445 @@ " print_draw()" ], "response": { - "message": "", "passed": true, "result": [] }, "step": "the_full_game" + }, + { + "get_solution": "program", + "page": "\u4ecb\u7ecd\u5b57\u5178", + "program": [ + "french = {'apple': 'pomme', 'box': 'boite'}" + ], + "response": { + "passed": true, + "result": [] + }, + "step": "first_dict" + }, + { + "page": "\u4ecb\u7ecd\u5b57\u5178", + "program": [ + "french = {}" + ], + "response": { + "message": "\u54ce\u5440\uff0c\u4f60\u9700\u8981\u5148\u8bbe\u7f6e french = {'apple': 'pomme', 'box': 'boite'}
\uff0c\u624d\u80fd\u7ee7\u7eed\u3002
A KeyError
is raised when a value is not found as a\nkey in a Python dict or in a similar object.
The key 0
cannot be found in the dict french
.
\u54ce\u5440\uff0c\u4f60\u9700\u8981\u5148\u8bbe\u7f6e french = {'apple': 'pomme', 'box': 'boite'}
\uff0c\u624d\u80fd\u7ee7\u7eed\u3002
\u54ce\u5440\uff0c\u4f60\u9700\u8981\u5148\u8bbe\u7f6e french = {'apple': 'pomme', 'box': 'boite'}
\uff0c\u624d\u80fd\u7ee7\u7eed\u3002
\u54ce\u5440\uff0c\u4f60\u9700\u8981\u5148\u8bbe\u7f6e french = {'apple': 'pomme', 'box': 'boite'}
\uff0c\u624d\u80fd\u7ee7\u7eed\u3002
A KeyError
is raised when a value is not found as a\nkey in a Python dict or in a similar object.
The key 'pomme'
cannot be found in the dict french
.
')
+ msgstr = msgstr.replace('[', '')
+ msgstr = msgstr.replace(']', '')
+ msgstr = msgstr.replace('(', '')
+ msgstr = msgstr.replace(')', '')
+ else:
+ # For regular entries, just preserve newlines
+ msgstr = msgstr.replace('\n', '')
+
+ # Mark special strings
+ msgstr = re.sub(r'(__\w+__)', r'\1 ', msgstr)
+ entry_text += f"msgstr: {msgstr}\n"
+ if entry.msgid_plural:
+ entry_text += f"msgid_plural: {entry.msgid_plural}\n"
+ for i, msgstr in enumerate(entry.msgstr_plural.values()):
+ # Mark newlines and special strings in plural forms too
+ msgstr = msgstr.replace('\n', '')
+ msgstr = re.sub(r'(__\w+__)', r'\1 ', msgstr)
+ entry_text += f"msgstr[{i}]: {msgstr}\n"
+ entries_text.append(entry_text)
+
+ # Combine all entries
+ text_to_translate = "\n\n".join(entries_text)
+ self.logger.debug(f"Prepared text to translate (first 100 chars): {text_to_translate[:100]}")
+
+ # Prepare the system message with rules
+ system_message = f"""You are a professional translator. Your task is to translate the following PO file entries from English to {self.rules.language_name}.
+
+{self.rules.context}
+
+The input will be in PO file format with msgid (English) and msgstr (translation) pairs.
+Only translate the text in the msgstr fields, keeping all other formatting, markers, and structure exactly as is.
+
+Special formatting rules:
+1. Special strings marked with tags must be preserved exactly as they are
+2. Newlines marked with must be preserved exactly as they are, including their position and count
+3. For misc_terms entries (starting with "misc_terms."):
+ - Preserve all newlines exactly as they appear in the original
+ - Preserve all markdown formatting:
+ * for italics (*)
+ * for bold (**)
+ * for code blocks (`)
+ * and for links ([ and ])
+ * and for URLs (( and ))
+ - Keep all URLs and links unchanged
+ - Maintain the exact same number of newlines as the original
+
+Return the translated text in the same PO file format."""
+
+ return {
+ "model": self.config.model,
+ "messages": [
+ {"role": "system", "content": system_message},
+ {"role": "user", "content": text_to_translate}
+ ],
+ "temperature": 0.3
+ }
+
+ def translate_chunk(self, en_chunk_file: str, target_chunk_file: str) -> Optional[polib.POFile]:
+ """Translate a chunk from English to target language."""
+ try:
+ # Check if target chunk already exists and is translated
+ if os.path.exists(target_chunk_file) and self.is_chunk_translated(target_chunk_file):
+ self.logger.info(f"Skipping already translated chunk: {os.path.basename(target_chunk_file)}")
+ return polib.pofile(target_chunk_file)
+
+ self.logger.info(f"Translating {os.path.basename(en_chunk_file)} → {os.path.basename(target_chunk_file)}")
+
+ # Load the English chunk
+ self.logger.debug(f"Loading English chunk: {en_chunk_file}")
+ chunk = polib.pofile(en_chunk_file)
+ self.logger.debug(f"Loaded chunk with {len(chunk)} entries")
+
+ # Prepare translation request
+ payload = self.prepare_translation_request(chunk)
+ self.logger.debug("Prepared translation request")
+
+ # Make API call
+ self.logger.debug(f"Making API call to {self.config.base_url}")
+ response = self.session.post(self.config.base_url, json=payload)
+
+ if response.status_code == 200:
+ result = response.json()
+ translated_text = result['choices'][0]['message']['content']
+ self.logger.debug(f"Received translation (first 100 chars): {translated_text[:100]}")
+
+ # Parse the translated text and update the chunk
+ updated_chunk = self.parse_translated_text(translated_text, chunk)
+
+ if updated_chunk:
+ # Ensure target directory exists
+ os.makedirs(os.path.dirname(target_chunk_file), exist_ok=True)
+ # Save to target language directory
+ updated_chunk.save(target_chunk_file)
+ self.logger.info(f"Successfully translated and saved: {os.path.basename(target_chunk_file)}")
+ return updated_chunk
+ else:
+ self.logger.error(f"Failed to parse translated text for {en_chunk_file}")
+ return None
+ else:
+ self.logger.error(f"API error {response.status_code}: {response.text}")
+ return None
+
+ except Exception as e:
+ self.logger.error(f"Error translating chunk {en_chunk_file}: {str(e)}")
+ return None
+
+ def parse_translated_text(self, translated_text: str, original_chunk: polib.POFile) -> Optional[polib.POFile]:
+ """Parse the translated text and update the original chunk with translations."""
+ try:
+ self.logger.debug("Parsing translated text")
+ translated_lines = translated_text.split('\n')
+ current_entry = None
+ current_key = None
+
+ for line in translated_lines:
+ line = line.strip()
+ if not line:
+ continue
+
+ if line.startswith('msgid: '):
+ current_key = 'msgid'
+ msgid = line[7:].strip()
+ # Find the entry in the original chunk
+ current_entry = original_chunk.find(msgid)
+ if current_entry:
+ self.logger.debug(f"Found entry for msgid: {msgid[:50]}...")
+ else:
+ self.logger.warning(f"Could not find entry for msgid: {msgid[:50]}...")
+
+ elif line.startswith('msgid_plural: '):
+ current_key = 'msgid_plural'
+ msgid_plural = line[14:].strip()
+ if current_entry and current_entry.msgid_plural == msgid_plural:
+ self.logger.debug(f"Found entry for msgid_plural: {msgid_plural[:50]}...")
+
+ elif line.startswith('msgstr: '):
+ if current_entry and current_key == 'msgid':
+ translation = line[8:].strip()
+
+ # Special handling for misc terms
+ if current_entry.msgid.startswith("misc_terms."):
+ # Restore markdown formatting
+ translation = translation.replace('', '*')
+ translation = translation.replace('', '**')
+ translation = translation.replace('', '`')
+ translation = translation.replace('', '[')
+ translation = translation.replace('', ']')
+ translation = translation.replace('', '(')
+ translation = translation.replace('', ')')
+
+ # Restore newlines and special strings
+ translation = translation.replace('', '\n')
+ translation = re.sub(r'(__\w+__) ', r'\1', translation)
+
+ if translation and translation != current_entry.msgid: # Only update if actually translated
+ current_entry.msgstr = translation
+ self.logger.debug(f"Updated msgstr for entry: {current_entry.msgid[:50]}...")
+
+ elif line.startswith('msgstr[0]: '):
+ if current_entry and current_key == 'msgid_plural':
+ translation = line[11:].strip()
+ # Restore newlines and special strings
+ translation = translation.replace('', '\n')
+ translation = re.sub(r'(__\w+__) ', r'\1', translation)
+ if translation:
+ current_entry.msgstr_plural[0] = translation
+ self.logger.debug(f"Updated msgstr[0] for plural entry")
+
+ elif line.startswith('msgstr[1]: '):
+ if current_entry and current_key == 'msgid_plural':
+ translation = line[11:].strip()
+ # Restore newlines and special strings
+ translation = translation.replace('', '\n')
+ translation = re.sub(r'(__\w+__) ', r'\1', translation)
+ if translation:
+ current_entry.msgstr_plural[1] = translation
+ self.logger.debug(f"Updated msgstr[1] for plural entry")
+
+ self.logger.debug(f"Successfully parsed translated text")
+ return original_chunk
+
+ except Exception as e:
+ self.logger.error(f"Error parsing translated text: {str(e)}")
+ return None
+
+class TranslationMerger:
+ def __init__(self, chunks_dir: str, output_file: str, language_code: str):
+ self.chunks_dir = chunks_dir
+ self.output_file = output_file
+ self.language_code = language_code
+ self.logger = logging.getLogger(__name__)
+ # Define the locales directory path
+ self.locales_dir = Path(os.path.dirname(output_file)) / "locales" / language_code / "LC_MESSAGES"
+ self.locales_dir.mkdir(parents=True, exist_ok=True)
+ # Load English PO file for reference
+ self.english_po = polib.pofile(os.path.join(os.path.dirname(output_file), "english.po"))
+
+ def validate_special_strings(self, entry: polib.POEntry, original_entry: polib.POEntry) -> bool:
+ """Validate that all special strings from the original entry are preserved in the translation."""
+ try:
+ # Extract special strings from original entry with their positions
+ original_special_strings = []
+ for match in re.finditer(r'(__\w+__)', original_entry.msgstr):
+ original_special_strings.append((match.group(1), match.start()))
+
+ # Extract special strings from translated entry with their positions
+ translated_special_strings = []
+ for match in re.finditer(r'(__\w+__)', entry.msgstr):
+ translated_special_strings.append((match.group(1), match.start()))
+
+ # Check if we have the same number of special strings
+ if len(original_special_strings) != len(translated_special_strings):
+ self.logger.warning(f"Mismatched special strings count for {entry.msgid[:50]}...")
+ self.logger.warning(f"Original has {len(original_special_strings)} special strings: {[s[0] for s in original_special_strings]}")
+ self.logger.warning(f"Translation has {len(translated_special_strings)} special strings: {[s[0] for s in translated_special_strings]}")
+ return False
+
+ # Check if each special string matches and is in a similar relative position
+ for (orig_str, orig_pos), (trans_str, trans_pos) in zip(original_special_strings, translated_special_strings):
+ if orig_str != trans_str:
+ self.logger.warning(f"Mismatched special string in {entry.msgid[:50]}...")
+ self.logger.warning(f"Original: {orig_str} at position {orig_pos}")
+ self.logger.warning(f"Translation: {trans_str} at position {trans_pos}")
+ return False
+
+ # Calculate relative positions (as percentage of total length)
+ orig_rel_pos = orig_pos / len(original_entry.msgstr)
+ trans_rel_pos = trans_pos / len(entry.msgstr)
+
+ # Allow some flexibility in position (within 20% of the text length)
+ if abs(orig_rel_pos - trans_rel_pos) > 0.2:
+ self.logger.warning(f"Special string {orig_str} is too far from expected position in {entry.msgid[:50]}...")
+ self.logger.warning(f"Original relative position: {orig_rel_pos:.2f}")
+ self.logger.warning(f"Translation relative position: {trans_rel_pos:.2f}")
+ return False
+
+ return True
+
+ except Exception as e:
+ self.logger.error(f"Error validating special strings: {str(e)}")
+ return False
+
+ def fix_special_strings(self, entry: polib.POEntry, original_entry: polib.POEntry) -> polib.POEntry:
+ """Fix missing or misplaced special strings in the translation by copying them from the original entry."""
+ try:
+ # Extract special strings from original entry with their context
+ original_special_strings = []
+ original_text = original_entry.msgstr
+ translated_text = entry.msgstr
+
+ # Find all special strings and their surrounding context
+ for match in re.finditer(r'(__\w+__)', original_text):
+ special_str = match.group(1)
+ start = max(0, match.start() - 20) # Get 20 chars before
+ end = min(len(original_text), match.end() + 20) # Get 20 chars after
+ context = original_text[start:end]
+ original_special_strings.append((special_str, context, match.start()))
+
+ # For each special string in the original, ensure it exists in the translation
+ fixed_text = translated_text
+ for special_str, context, orig_pos in original_special_strings:
+ # Check if the special string exists in the translation
+ if special_str not in fixed_text:
+ # Find a good position to insert the special string
+ # Try to find similar context in the translation
+ context_words = set(re.findall(r'\w+', context))
+ best_pos = 0
+ best_match = 0
+
+ # Look for similar context in the translation
+ for i in range(len(fixed_text) - len(context) + 1):
+ trans_context = fixed_text[i:i + len(context)]
+ trans_words = set(re.findall(r'\w+', trans_context))
+ common_words = len(context_words & trans_words)
+ if common_words > best_match:
+ best_match = common_words
+ best_pos = i
+
+ # Insert the special string at the best position
+ if best_match > 0:
+ fixed_text = fixed_text[:best_pos] + special_str + fixed_text[best_pos:]
+ else:
+ # If no good context found, append at the end
+ fixed_text += f"\n{special_str}\n"
+
+ self.logger.info(f"Added missing special string {special_str} to translation")
+
+ # Create a new entry with the fixed translation
+ fixed_entry = polib.POEntry(
+ msgid=entry.msgid,
+ msgstr=fixed_text,
+ msgid_plural=entry.msgid_plural,
+ msgstr_plural=entry.msgstr_plural,
+ comment=entry.comment,
+ tcomment=entry.tcomment,
+ occurrences=entry.occurrences,
+ flags=entry.flags,
+ previous_msgid=entry.previous_msgid,
+ previous_msgid_plural=entry.previous_msgid_plural,
+ encoding=entry.encoding
+ )
+
+ # Validate the fix
+ if not self.validate_special_strings(fixed_entry, original_entry):
+ self.logger.warning(f"Failed to fix special strings for {entry.msgid[:50]}...")
+ # If validation fails, return the original entry's msgstr
+ fixed_entry.msgstr = original_entry.msgstr
+ self.logger.info(f"Using original English text for {entry.msgid[:50]}...")
+
+ return fixed_entry
+
+ except Exception as e:
+ self.logger.error(f"Error fixing special strings: {str(e)}")
+ return entry
+
+ def normalize_po_file(self, po_file: str) -> bool:
+ """Normalize line endings and validate PO file format."""
+ try:
+ # Read the PO file
+ with open(po_file, 'r', encoding='utf-8') as f:
+ content = f.read()
+
+ # Normalize line endings to \n
+ content = content.replace('\r\n', '\n').replace('\r', '\n')
+
+ # Parse the PO file using polib first to get proper structure
+ po = polib.pofile(po_file)
+
+ # Create a new PO file with normalized entries
+ normalized_po = polib.POFile()
+ normalized_po.metadata = po.metadata.copy()
+
+ for entry in po:
+ # Create a new entry
+ new_entry = polib.POEntry(
+ msgid=entry.msgid.strip(),
+ msgstr=entry.msgstr.strip(),
+ msgid_plural=entry.msgid_plural.strip() if entry.msgid_plural else None,
+ msgstr_plural=entry.msgstr_plural if entry.msgstr_plural else None,
+ comment=entry.comment,
+ tcomment=entry.tcomment,
+ occurrences=entry.occurrences,
+ flags=entry.flags,
+ previous_msgid=entry.previous_msgid,
+ previous_msgid_plural=entry.previous_msgid_plural,
+ encoding=entry.encoding
+ )
+ normalized_po.append(new_entry)
+
+ # Write back the normalized content
+ normalized_po.save(po_file)
+
+ # Validate the normalized file
+ try:
+ polib.pofile(po_file)
+ self.logger.info(f"Successfully normalized and validated {po_file}")
+ return True
+ except Exception as e:
+ self.logger.error(f"PO file validation failed: {str(e)}")
+ return False
+
+ except Exception as e:
+ self.logger.error(f"Error normalizing PO file: {str(e)}")
+ return False
+
+ def compile_mo_file(self, po_file: str) -> bool:
+ """Compile PO file to MO file using msgfmt."""
+ try:
+ # First normalize the PO file
+ if not self.normalize_po_file(po_file):
+ self.logger.error(f"Failed to normalize {po_file}")
+ return False
+
+ # Always use futurecoder.mo as the output filename
+ mo_file = self.locales_dir / "futurecoder.mo"
+
+ # Use msgfmt to compile the PO file to MO
+ result = subprocess.run(
+ ["msgfmt", "-o", str(mo_file), po_file],
+ capture_output=True,
+ text=True
+ )
+
+ if result.returncode == 0:
+ self.logger.info(f"Successfully compiled {po_file} to {mo_file}")
+ return True
+ else:
+ self.logger.error(f"Failed to compile {po_file}: {result.stderr}")
+ return False
+
+ except Exception as e:
+ self.logger.error(f"Error compiling MO file: {str(e)}")
+ return False
+
+ def merge_translations(self) -> None:
+ """Merge translated chunks into a single PO file and compile to MO."""
+ self.logger.info(f"Starting merge process for {self.language_code}")
+ self.logger.info(f"Looking for chunks in: {self.chunks_dir}")
+
+ # Create output directory if it doesn't exist
+ os.makedirs(os.path.dirname(os.path.abspath(self.output_file)), exist_ok=True)
+
+ # Get all chunk files
+ chunk_files = sorted(glob.glob(os.path.join(self.chunks_dir, "*.po")))
+ if not chunk_files:
+ self.logger.error(f"No chunk files found in {self.chunks_dir}")
+ all_files = glob.glob(os.path.join(self.chunks_dir, "*"))
+ self.logger.info(f"All files found: {all_files}")
+ raise FileNotFoundError(f"No chunk files found in {self.chunks_dir}")
+
+ self.logger.info(f"Found {len(chunk_files)} chapter-based chunk files to merge")
+ for f in chunk_files:
+ self.logger.info(f" - {os.path.basename(f)}")
+
+ # Create new PO file with metadata from english.po
+ try:
+ merged_po = polib.POFile()
+ merged_po.metadata = self.english_po.metadata.copy()
+ merged_po.metadata['Language'] = self.language_code
+
+ # Get language rules for plural forms
+ language_rules = Language.get_rules(self.language_code)
+ merged_po.metadata['Plural-Forms'] = language_rules.plural_forms
+ except Exception as e:
+ self.logger.error(f"Failed to read english.po: {str(e)}")
+ raise
+
+ # Track statistics
+ total_entries = 0
+ translated_entries = 0
+ skipped_entries = 0
+ code_bits_kept = 0
+ program_entries_kept = 0
+ prediction_choices_kept = 0
+
+ # Process each translated chunk
+ for chunk_file in chunk_files:
+ self.logger.info(f"Processing translated chunk: {chunk_file}")
+ try:
+ chunk_po = polib.pofile(chunk_file)
+ total_entries += len(chunk_po)
+
+ for entry in chunk_po:
+ if entry.msgstr and entry.msgstr.strip(): # Only include translated entries
+ # Find the corresponding English entry
+ original_entry = self.english_po.find(entry.msgid)
+ if original_entry:
+ # For Chinese and Tamil, keep certain entries in English
+ if self.language_code in ["zh", "ta"] and (
+ entry.msgid.startswith("code_bits.") or
+ entry.msgid.endswith(".program") or
+ "output_prediction_choices" in entry.msgid
+ ):
+ entry.msgstr = original_entry.msgstr # Use English version
+ if entry.msgid.startswith("code_bits."):
+ code_bits_kept += 1
+ self.logger.info(f"Keeping English code bit: {entry.msgid[:50]}...")
+ elif entry.msgid.endswith(".program"):
+ program_entries_kept += 1
+ self.logger.info(f"Keeping English program entry: {entry.msgid[:50]}...")
+ else:
+ prediction_choices_kept += 1
+ self.logger.info(f"Keeping English prediction choice: {entry.msgid[:50]}...")
+
+ # Create a new entry with stripped content
+ new_entry = polib.POEntry(
+ msgid=entry.msgid.strip(),
+ msgstr=entry.msgstr.strip(),
+ msgid_plural=entry.msgid_plural.strip() if entry.msgid_plural else None,
+ msgstr_plural=entry.msgstr_plural if entry.msgstr_plural else None,
+ comment=entry.comment,
+ tcomment=entry.tcomment,
+ occurrences=entry.occurrences,
+ flags=entry.flags,
+ previous_msgid=entry.previous_msgid,
+ previous_msgid_plural=entry.previous_msgid_plural,
+ encoding=entry.encoding
+ )
+ merged_po.append(new_entry)
+ translated_entries += 1
+ else:
+ self.logger.warning(f"Skipping untranslated entry in {chunk_file}: {entry.msgid[:50]}...")
+ skipped_entries += 1
+
+ except Exception as e:
+ self.logger.error(f"Error processing chunk {chunk_file}: {str(e)}")
+ raise
+
+ # Save the merged PO file
+ try:
+ # Save with proper formatting
+ merged_po.save(self.output_file)
+ self.logger.info(f"Successfully merged translations to {self.output_file}")
+
+ # Normalize and compile the merged PO file to MO
+ if self.compile_mo_file(self.output_file):
+ self.logger.info(f"Successfully compiled MO file to {self.locales_dir}")
+ else:
+ self.logger.error("Failed to compile MO file")
+
+ self.logger.info(f"Statistics:")
+ self.logger.info(f" Total entries: {total_entries}")
+ self.logger.info(f" Translated entries: {translated_entries}")
+ if self.language_code in ["zh", "ta"]:
+ self.logger.info(f" Code bits kept in English: {code_bits_kept}")
+ self.logger.info(f" Program entries kept in English: {program_entries_kept}")
+ self.logger.info(f" Prediction choices kept in English: {prediction_choices_kept}")
+ self.logger.info(f" Skipped entries: {skipped_entries}")
+ if total_entries > 0:
+ self.logger.info(f" Translation coverage: {(translated_entries/total_entries)*100:.1f}%")
+ except Exception as e:
+ self.logger.error(f"Failed to save merged file: {str(e)}")
+ raise
+
+def validate_language_code(language_code: str) -> bool:
+ """Validate if the language code is supported"""
+ try:
+ Language(language_code)
+ return True
+ except ValueError:
+ return False
+
+def translate_all_chunks(translator: Translator, base_chunks_dir: str, language_code: str, max_workers: int = 3):
+ """Translate all chunks from chunks/en/ to chunks/{lang}/, skipping already translated ones."""
+ logger = logging.getLogger(__name__)
+
+ en_chunks_dir = os.path.join(base_chunks_dir, "chunks", "en")
+ target_chunks_dir = os.path.join(base_chunks_dir, "chunks", language_code)
+
+ # Get all English chunk files
+ en_chunk_files = sorted(glob.glob(os.path.join(en_chunks_dir, "*.po")))
+ if not en_chunk_files:
+ logger.error(f"No English chunk files found in {en_chunks_dir}")
+ return
+
+ logger.info(f"Found {len(en_chunk_files)} English chunk files in {en_chunks_dir}")
+ logger.info(f"Will translate to {target_chunks_dir}")
+
+ # Create target directory
+ os.makedirs(target_chunks_dir, exist_ok=True)
+
+ # Check which chunks need translation
+ chunks_to_translate = []
+ already_translated = []
+
+ for en_chunk_file in en_chunk_files:
+ chunk_name = os.path.basename(en_chunk_file)
+ target_chunk_file = os.path.join(target_chunks_dir, chunk_name)
+
+ if os.path.exists(target_chunk_file) and translator.is_chunk_translated(target_chunk_file):
+ already_translated.append((en_chunk_file, target_chunk_file))
+ else:
+ chunks_to_translate.append((en_chunk_file, target_chunk_file))
+
+ logger.info(f"Translation status:")
+ logger.info(f" - Already translated: {len(already_translated)} chunks")
+ logger.info(f" - Need translation: {len(chunks_to_translate)} chunks")
+
+ if already_translated:
+ logger.info("Already translated chunks:")
+ for en_file, target_file in already_translated:
+ logger.info(f" ✓ {os.path.basename(target_file)}")
+
+ if not chunks_to_translate:
+ logger.info("All chunks are already translated! Skipping translation phase.")
+ return
+
+ logger.info("Chunks to translate:")
+ for en_file, target_file in chunks_to_translate:
+ logger.info(f" → {os.path.basename(en_file)} → {os.path.basename(target_file)}")
+
+ # Translate only the chunks that need translation
+ logger.info(f"Starting translation of {len(chunks_to_translate)} chunks using {max_workers} workers...")
+
+ with ThreadPoolExecutor(max_workers=max_workers) as executor:
+ # Submit translation tasks
+ future_to_chunk = {
+ executor.submit(translator.translate_chunk, en_file, target_file): (en_file, target_file)
+ for en_file, target_file in chunks_to_translate
+ }
+
+ completed = 0
+ failed = 0
+
+ # Process completed tasks
+ for future in as_completed(future_to_chunk):
+ en_file, target_file = future_to_chunk[future]
+ try:
+ result = future.result()
+ if result is not None:
+ completed += 1
+ logger.info(f"Progress: {completed + failed}/{len(chunks_to_translate)} - Completed: {os.path.basename(target_file)}")
+ else:
+ failed += 1
+ logger.error(f"Progress: {completed + failed}/{len(chunks_to_translate)} - Failed: {os.path.basename(target_file)}")
+ except Exception as e:
+ failed += 1
+ logger.error(f"Progress: {completed + failed}/{len(chunks_to_translate)} - Error: {str(e)}")
+
+ logger.info(f"Translation completed: {completed} successful, {failed} failed")
+
+def main():
+ parser = argparse.ArgumentParser(description="Translate Futurecoder PO files")
+ parser.add_argument("-l", "--language", required=True, help="Language code (e.g., zh, fr, es)")
+ parser.add_argument("-k", "--api-key", required=True, help="API key for translation service")
+ parser.add_argument("--base-url", default="https://api.openai.com/v1/chat/completions",
+ help="Base URL for the translation API")
+ parser.add_argument("-m", "--model", default="gpt-3.5-turbo",
+ help="Model to use for translation")
+ parser.add_argument("-i", "--input", default="./english.po",
+ help="Input PO file to translate")
+ parser.add_argument("-o", "--output-dir", default="./",
+ help="Output directory for translated files")
+ parser.add_argument("--max-workers", type=int, default=5,
+ help="Maximum number of parallel workers")
+ parser.add_argument("--chunk-size", type=int, default=50,
+ help="Number of entries per chunk")
+ parser.add_argument("--skip-mo", action="store_true",
+ help="Skip MO file compilation")
+ args = parser.parse_args()
+
+ # Configure logging
+ logging.basicConfig(
+ level=logging.INFO,
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
+ handlers=[
+ logging.FileHandler(f"translation_{args.language}.log"),
+ logging.StreamHandler(sys.stdout)
+ ]
+ )
+ logger = logging.getLogger(__name__)
+
+ try:
+ # Validate language code
+ try:
+ rules = Language.get_rules(args.language)
+ logger.info(f"Using translation rules for {rules.language_name}")
+ except ValueError as e:
+ logger.error(str(e))
+ logger.info("Supported languages: " + ", ".join(lang.value.language_name for lang in Language))
+ sys.exit(1)
+
+ # Create base chunks directory structure
+ base_chunks_dir = args.output_dir
+ en_chunks_dir = os.path.join(base_chunks_dir, "chunks", "en")
+ target_chunks_dir = os.path.join(base_chunks_dir, "chunks", args.language)
+
+ logger.info(f"Directory structure:")
+ logger.info(f" - English chunks: {en_chunks_dir}")
+ logger.info(f" - Target chunks: {target_chunks_dir}")
+
+ # Initialize components
+ config = TranslationConfig(
+ api_key=args.api_key,
+ base_url=args.base_url,
+ model=args.model
+ )
+
+ # Initialize splitter with base output directory
+ splitter = POFileSplitter(
+ input_file=args.input,
+ base_output_dir=base_chunks_dir,
+ chunk_size=args.chunk_size
+ )
+ translator = Translator(config, args.language)
+ merger = TranslationMerger(
+ chunks_dir=target_chunks_dir,
+ output_file=os.path.join(args.output_dir, f"{args.language}.po"),
+ language_code=args.language
+ )
+
+ # Split the file into English chunks
+ logger.info(f"Splitting PO file from: {args.input}")
+ splitter.split_entries()
+
+ # Translate chunks from en/ to {lang}/
+ logger.info("Starting translation of chunks...")
+ translate_all_chunks(translator, base_chunks_dir, args.language, args.max_workers)
+
+ # Merge translations and compile MO file
+ logger.info(f"Merging translated chunks to: {merger.output_file}")
+ merger.merge_translations()
+
+ logger.info("Translation process completed successfully!")
+ logger.info(f"Final output files:")
+ logger.info(f" - PO file: {os.path.abspath(merger.output_file)}")
+ logger.info(f" - MO file: {os.path.abspath(merger.locales_dir / 'futurecoder.mo')}")
+
+ except Exception as e:
+ logger.error(f"Translation process failed: {str(e)}", exc_info=True)
+ sys.exit(1)
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file