diff --git a/extending/extending.po b/extending/extending.po index 5d61182de3..d6584b1939 100644 --- a/extending/extending.po +++ b/extending/extending.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-05-27 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2018-05-23 14:34+0000\n" "Last-Translator: Adrian Liaw \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -71,6 +71,12 @@ msgid "" "this function to be callable from Python as follows:" msgstr "" +#: ../../extending/extending.rst:48 +msgid "" +">>> import spam\n" +">>> status = spam.system(\"ls -l\")" +msgstr "" + #: ../../extending/extending.rst:53 msgid "" "Begin by creating a file :file:`spammodule.c`. (Historically, if a module " @@ -83,6 +89,12 @@ msgstr "" msgid "The first two lines of our file can be::" msgstr "" +#: ../../extending/extending.rst:60 +msgid "" +"#define PY_SSIZE_T_CLEAN\n" +"#include " +msgstr "" + #: ../../extending/extending.rst:63 msgid "" "which pulls in the Python API (you can add a comment describing the purpose " @@ -120,6 +132,21 @@ msgid "" "(we'll see shortly how it ends up being called)::" msgstr "" +#: ../../extending/extending.rst:87 +msgid "" +"static PyObject *\n" +"spam_system(PyObject *self, PyObject *args)\n" +"{\n" +" const char *command;\n" +" int sts;\n" +"\n" +" if (!PyArg_ParseTuple(args, \"s\", &command))\n" +" return NULL;\n" +" sts = system(command);\n" +" return PyLong_FromLong(sts);\n" +"}" +msgstr "" + #: ../../extending/extending.rst:99 msgid "" "There is a straightforward translation from the argument list in Python (for " @@ -280,12 +307,40 @@ msgid "" "you usually declare a static object variable at the beginning of your file::" msgstr "" +#: ../../extending/extending.rst:207 +msgid "static PyObject *SpamError;" +msgstr "" + #: ../../extending/extending.rst:209 msgid "" "and initialize it in your module's initialization function (:c:func:`!" "PyInit_spam`) with an exception object::" msgstr "" +#: ../../extending/extending.rst:212 +msgid "" +"PyMODINIT_FUNC\n" +"PyInit_spam(void)\n" +"{\n" +" PyObject *m;\n" +"\n" +" m = PyModule_Create(&spammodule);\n" +" if (m == NULL)\n" +" return NULL;\n" +"\n" +" SpamError = PyErr_NewException(\"spam.error\", NULL, NULL);\n" +" Py_XINCREF(SpamError);\n" +" if (PyModule_AddObject(m, \"error\", SpamError) < 0) {\n" +" Py_XDECREF(SpamError);\n" +" Py_CLEAR(SpamError);\n" +" Py_DECREF(m);\n" +" return NULL;\n" +" }\n" +"\n" +" return m;\n" +"}" +msgstr "" + #: ../../extending/extending.rst:233 msgid "" "Note that the Python name for the exception object is :exc:`!spam.error`. " @@ -317,6 +372,25 @@ msgid "" "using a call to :c:func:`PyErr_SetString` as shown below::" msgstr "" +#: ../../extending/extending.rst:251 +msgid "" +"static PyObject *\n" +"spam_system(PyObject *self, PyObject *args)\n" +"{\n" +" const char *command;\n" +" int sts;\n" +"\n" +" if (!PyArg_ParseTuple(args, \"s\", &command))\n" +" return NULL;\n" +" sts = system(command);\n" +" if (sts < 0) {\n" +" PyErr_SetString(SpamError, \"System command failed\");\n" +" return NULL;\n" +" }\n" +" return PyLong_FromLong(sts);\n" +"}" +msgstr "" + #: ../../extending/extending.rst:271 msgid "Back to the Example" msgstr "回到範例" @@ -327,6 +401,12 @@ msgid "" "this statement::" msgstr "" +#: ../../extending/extending.rst:276 +msgid "" +"if (!PyArg_ParseTuple(args, \"s\", &command))\n" +" return NULL;" +msgstr "" + #: ../../extending/extending.rst:279 msgid "" "It returns ``NULL`` (the error indicator for functions returning object " @@ -344,6 +424,10 @@ msgid "" "it the string we just got from :c:func:`PyArg_ParseTuple`::" msgstr "" +#: ../../extending/extending.rst:290 +msgid "sts = system(command);" +msgstr "" + #: ../../extending/extending.rst:292 msgid "" "Our :func:`!spam.system` function must return the value of :c:data:`!sts` as " @@ -351,6 +435,10 @@ msgid "" "`PyLong_FromLong`. ::" msgstr "" +#: ../../extending/extending.rst:295 +msgid "return PyLong_FromLong(sts);" +msgstr "" + #: ../../extending/extending.rst:297 msgid "" "In this case, it will return an integer object. (Yes, even integers are " @@ -365,6 +453,12 @@ msgid "" "macro:`Py_RETURN_NONE` macro)::" msgstr "" +#: ../../extending/extending.rst:305 +msgid "" +"Py_INCREF(Py_None);\n" +"return Py_None;" +msgstr "" + #: ../../extending/extending.rst:308 msgid "" ":c:data:`Py_None` is the C name for the special Python object ``None``. It " @@ -382,6 +476,17 @@ msgid "" "programs. First, we need to list its name and address in a \"method table\"::" msgstr "" +#: ../../extending/extending.rst:321 +msgid "" +"static PyMethodDef SpamMethods[] = {\n" +" ...\n" +" {\"system\", spam_system, METH_VARARGS,\n" +" \"Execute a shell command.\"},\n" +" ...\n" +" {NULL, NULL, 0, NULL} /* Sentinel */\n" +"};" +msgstr "" + #: ../../extending/extending.rst:329 msgid "" "Note the third entry (``METH_VARARGS``). This is a flag telling the " @@ -412,6 +517,18 @@ msgid "" "The method table must be referenced in the module definition structure::" msgstr "" +#: ../../extending/extending.rst:346 +msgid "" +"static struct PyModuleDef spammodule = {\n" +" PyModuleDef_HEAD_INIT,\n" +" \"spam\", /* name of module */\n" +" spam_doc, /* module documentation, may be NULL */\n" +" -1, /* size of per-interpreter state of the module,\n" +" or -1 if the module keeps state in global variables. */\n" +" SpamMethods\n" +"};" +msgstr "" + #: ../../extending/extending.rst:355 msgid "" "This structure, in turn, must be passed to the interpreter in the module's " @@ -420,6 +537,15 @@ msgid "" "only non-\\ ``static`` item defined in the module file::" msgstr "" +#: ../../extending/extending.rst:360 +msgid "" +"PyMODINIT_FUNC\n" +"PyInit_spam(void)\n" +"{\n" +" return PyModule_Create(&spammodule);\n" +"}" +msgstr "" + #: ../../extending/extending.rst:366 msgid "" "Note that :c:macro:`PyMODINIT_FUNC` declares the function as ``PyObject *`` " @@ -449,6 +575,47 @@ msgid "" "`PyImport_AppendInittab`, optionally followed by an import of the module::" msgstr "" +#: ../../extending/extending.rst:386 +msgid "" +"int\n" +"main(int argc, char *argv[])\n" +"{\n" +" wchar_t *program = Py_DecodeLocale(argv[0], NULL);\n" +" if (program == NULL) {\n" +" fprintf(stderr, \"Fatal error: cannot decode argv[0]\\n\");\n" +" exit(1);\n" +" }\n" +"\n" +" /* Add a built-in module, before Py_Initialize */\n" +" if (PyImport_AppendInittab(\"spam\", PyInit_spam) == -1) {\n" +" fprintf(stderr, \"Error: could not extend in-built modules " +"table\\n\");\n" +" exit(1);\n" +" }\n" +"\n" +" /* Pass argv[0] to the Python interpreter */\n" +" Py_SetProgramName(program);\n" +"\n" +" /* Initialize the Python interpreter. Required.\n" +" If this step fails, it will be a fatal error. */\n" +" Py_Initialize();\n" +"\n" +" /* Optionally import the module; alternatively,\n" +" import can be deferred until the embedded script\n" +" imports it. */\n" +" PyObject *pmodule = PyImport_ImportModule(\"spam\");\n" +" if (!pmodule) {\n" +" PyErr_Print();\n" +" fprintf(stderr, \"Error: could not import module 'spam'\\n\");\n" +" }\n" +"\n" +" ...\n" +"\n" +" PyMem_RawFree(program);\n" +" return 0;\n" +"}" +msgstr "" + #: ../../extending/extending.rst:425 msgid "" "Removing entries from ``sys.modules`` or importing compiled modules into " @@ -497,6 +664,10 @@ msgid "" "line to the file :file:`Modules/Setup.local` describing your file:" msgstr "" +#: ../../extending/extending.rst:462 +msgid "spam spammodule.o" +msgstr "" + #: ../../extending/extending.rst:466 msgid "" "and rebuild the interpreter by running :program:`make` in the toplevel " @@ -512,6 +683,10 @@ msgid "" "listed on the line in the configuration file as well, for instance:" msgstr "" +#: ../../extending/extending.rst:475 +msgid "spam spammodule.o -lX11" +msgstr "" + #: ../../extending/extending.rst:483 msgid "Calling Python Functions from C" msgstr "" @@ -546,6 +721,33 @@ msgid "" "function might be part of a module definition::" msgstr "" +#: ../../extending/extending.rst:506 +msgid "" +"static PyObject *my_callback = NULL;\n" +"\n" +"static PyObject *\n" +"my_set_callback(PyObject *dummy, PyObject *args)\n" +"{\n" +" PyObject *result = NULL;\n" +" PyObject *temp;\n" +"\n" +" if (PyArg_ParseTuple(args, \"O:set_callback\", &temp)) {\n" +" if (!PyCallable_Check(temp)) {\n" +" PyErr_SetString(PyExc_TypeError, \"parameter must be " +"callable\");\n" +" return NULL;\n" +" }\n" +" Py_XINCREF(temp); /* Add a reference to new callback */\n" +" Py_XDECREF(my_callback); /* Dispose of previous callback */\n" +" my_callback = temp; /* Remember new callback */\n" +" /* Boilerplate to return \"None\" */\n" +" Py_INCREF(Py_None);\n" +" result = Py_None;\n" +" }\n" +" return result;\n" +"}" +msgstr "" + #: ../../extending/extending.rst:529 msgid "" "This function must be registered with the interpreter using the :c:macro:" @@ -574,6 +776,20 @@ msgid "" "or more format codes between parentheses. For example::" msgstr "" +#: ../../extending/extending.rst:550 +msgid "" +"int arg;\n" +"PyObject *arglist;\n" +"PyObject *result;\n" +"...\n" +"arg = 123;\n" +"...\n" +"/* Time to call the callback */\n" +"arglist = Py_BuildValue(\"(i)\", arg);\n" +"result = PyObject_CallObject(my_callback, arglist);\n" +"Py_DECREF(arglist);" +msgstr "" + #: ../../extending/extending.rst:561 msgid "" ":c:func:`PyObject_CallObject` returns a Python object pointer: this is the " @@ -603,6 +819,14 @@ msgid "" "should be cleared by calling :c:func:`PyErr_Clear`. For example::" msgstr "" +#: ../../extending/extending.rst:582 +msgid "" +"if (result == NULL)\n" +" return NULL; /* Pass error back */\n" +"...use result...\n" +"Py_DECREF(result);" +msgstr "" + #: ../../extending/extending.rst:587 msgid "" "Depending on the desired interface to the Python callback function, you may " @@ -615,6 +839,19 @@ msgid "" "you want to pass an integral event code, you might use the following code::" msgstr "" +#: ../../extending/extending.rst:596 +msgid "" +"PyObject *arglist;\n" +"...\n" +"arglist = Py_BuildValue(\"(l)\", eventcode);\n" +"result = PyObject_CallObject(my_callback, arglist);\n" +"Py_DECREF(arglist);\n" +"if (result == NULL)\n" +" return NULL; /* Pass error back */\n" +"/* Here maybe use the result */\n" +"Py_DECREF(result);" +msgstr "" + #: ../../extending/extending.rst:606 msgid "" "Note the placement of ``Py_DECREF(arglist)`` immediately after the call, " @@ -630,6 +867,19 @@ msgid "" "above example, we use :c:func:`Py_BuildValue` to construct the dictionary. ::" msgstr "" +#: ../../extending/extending.rst:614 +msgid "" +"PyObject *dict;\n" +"...\n" +"dict = Py_BuildValue(\"{s:i}\", \"name\", val);\n" +"result = PyObject_Call(my_callback, NULL, dict);\n" +"Py_DECREF(dict);\n" +"if (result == NULL)\n" +" return NULL; /* Pass error back */\n" +"/* Here maybe use the result */\n" +"Py_DECREF(result);" +msgstr "" + #: ../../extending/extending.rst:628 msgid "Extracting Parameters in Extension Functions" msgstr "" @@ -638,6 +888,10 @@ msgstr "" msgid "The :c:func:`PyArg_ParseTuple` function is declared as follows::" msgstr "" +#: ../../extending/extending.rst:634 +msgid "int PyArg_ParseTuple(PyObject *arg, const char *format, ...);" +msgstr "" + #: ../../extending/extending.rst:636 msgid "" "The *arg* argument must be a tuple object containing an argument list passed " @@ -665,6 +919,81 @@ msgstr "" msgid "Some example calls::" msgstr "一些呼叫範例: ::" +#: ../../extending/extending.rst:652 +msgid "" +"#define PY_SSIZE_T_CLEAN /* Make \"s#\" use Py_ssize_t rather than int. */\n" +"#include " +msgstr "" + +#: ../../extending/extending.rst:657 +msgid "" +"int ok;\n" +"int i, j;\n" +"long k, l;\n" +"const char *s;\n" +"Py_ssize_t size;\n" +"\n" +"ok = PyArg_ParseTuple(args, \"\"); /* No arguments */\n" +" /* Python call: f() */" +msgstr "" + +#: ../../extending/extending.rst:668 +msgid "" +"ok = PyArg_ParseTuple(args, \"s\", &s); /* A string */\n" +" /* Possible Python call: f('whoops!') */" +msgstr "" + +#: ../../extending/extending.rst:673 +msgid "" +"ok = PyArg_ParseTuple(args, \"lls\", &k, &l, &s); /* Two longs and a string " +"*/\n" +" /* Possible Python call: f(1, 2, 'three') */" +msgstr "" + +#: ../../extending/extending.rst:678 +msgid "" +"ok = PyArg_ParseTuple(args, \"(ii)s#\", &i, &j, &s, &size);\n" +" /* A pair of ints and a string, whose size is also returned */\n" +" /* Possible Python call: f((1, 2), 'three') */" +msgstr "" + +#: ../../extending/extending.rst:684 +msgid "" +"{\n" +" const char *file;\n" +" const char *mode = \"r\";\n" +" int bufsize = 0;\n" +" ok = PyArg_ParseTuple(args, \"s|si\", &file, &mode, &bufsize);\n" +" /* A string, and optionally another string and an integer */\n" +" /* Possible Python calls:\n" +" f('spam')\n" +" f('spam', 'w')\n" +" f('spam', 'wb', 100000) */\n" +"}" +msgstr "" + +#: ../../extending/extending.rst:698 +msgid "" +"{\n" +" int left, top, right, bottom, h, v;\n" +" ok = PyArg_ParseTuple(args, \"((ii)(ii))(ii)\",\n" +" &left, &top, &right, &bottom, &h, &v);\n" +" /* A rectangle and a point */\n" +" /* Possible Python call:\n" +" f(((0, 0), (400, 300)), (10, 10)) */\n" +"}" +msgstr "" + +#: ../../extending/extending.rst:709 +msgid "" +"{\n" +" Py_complex c;\n" +" ok = PyArg_ParseTuple(args, \"D:myfunction\", &c);\n" +" /* a complex, also providing a function name for errors */\n" +" /* Possible Python call: myfunction(1+2j) */\n" +"}" +msgstr "" + #: ../../extending/extending.rst:720 msgid "Keyword Parameters for Extension Functions" msgstr "" @@ -674,6 +1003,12 @@ msgid "" "The :c:func:`PyArg_ParseTupleAndKeywords` function is declared as follows::" msgstr "" +#: ../../extending/extending.rst:726 +msgid "" +"int PyArg_ParseTupleAndKeywords(PyObject *arg, PyObject *kwdict,\n" +" const char *format, char *kwlist[], ...);" +msgstr "" + #: ../../extending/extending.rst:729 msgid "" "The *arg* and *format* parameters are identical to those of the :c:func:" @@ -699,6 +1034,60 @@ msgid "" "Philbrick (philbrick@hks.com)::" msgstr "" +#: ../../extending/extending.rst:748 +msgid "" +"#define PY_SSIZE_T_CLEAN /* Make \"s#\" use Py_ssize_t rather than int. */\n" +"#include \n" +"\n" +"static PyObject *\n" +"keywdarg_parrot(PyObject *self, PyObject *args, PyObject *keywds)\n" +"{\n" +" int voltage;\n" +" const char *state = \"a stiff\";\n" +" const char *action = \"voom\";\n" +" const char *type = \"Norwegian Blue\";\n" +"\n" +" static char *kwlist[] = {\"voltage\", \"state\", \"action\", \"type\", " +"NULL};\n" +"\n" +" if (!PyArg_ParseTupleAndKeywords(args, keywds, \"i|sss\", kwlist,\n" +" &voltage, &state, &action, &type))\n" +" return NULL;\n" +"\n" +" printf(\"-- This parrot wouldn't %s if you put %i Volts through it." +"\\n\",\n" +" action, voltage);\n" +" printf(\"-- Lovely plumage, the %s -- It's %s!\\n\", type, state);\n" +"\n" +" Py_RETURN_NONE;\n" +"}\n" +"\n" +"static PyMethodDef keywdarg_methods[] = {\n" +" /* The cast of the function is necessary since PyCFunction values\n" +" * only take two PyObject* parameters, and keywdarg_parrot() takes\n" +" * three.\n" +" */\n" +" {\"parrot\", (PyCFunction)(void(*)(void))keywdarg_parrot, METH_VARARGS | " +"METH_KEYWORDS,\n" +" \"Print a lovely skit to standard output.\"},\n" +" {NULL, NULL, 0, NULL} /* sentinel */\n" +"};\n" +"\n" +"static struct PyModuleDef keywdargmodule = {\n" +" PyModuleDef_HEAD_INIT,\n" +" \"keywdarg\",\n" +" NULL,\n" +" -1,\n" +" keywdarg_methods\n" +"};\n" +"\n" +"PyMODINIT_FUNC\n" +"PyInit_keywdarg(void)\n" +"{\n" +" return PyModule_Create(&keywdargmodule);\n" +"}" +msgstr "" + #: ../../extending/extending.rst:800 msgid "Building Arbitrary Values" msgstr "" @@ -709,6 +1098,10 @@ msgid "" "declared as follows::" msgstr "" +#: ../../extending/extending.rst:805 +msgid "PyObject *Py_BuildValue(const char *format, ...);" +msgstr "" + #: ../../extending/extending.rst:807 msgid "" "It recognizes a set of format units similar to the ones recognized by :c:" @@ -734,6 +1127,27 @@ msgid "" "Examples (to the left the call, to the right the resulting Python value):" msgstr "" +#: ../../extending/extending.rst:822 +msgid "" +"Py_BuildValue(\"\") None\n" +"Py_BuildValue(\"i\", 123) 123\n" +"Py_BuildValue(\"iii\", 123, 456, 789) (123, 456, 789)\n" +"Py_BuildValue(\"s\", \"hello\") 'hello'\n" +"Py_BuildValue(\"y\", \"hello\") b'hello'\n" +"Py_BuildValue(\"ss\", \"hello\", \"world\") ('hello', 'world')\n" +"Py_BuildValue(\"s#\", \"hello\", 4) 'hell'\n" +"Py_BuildValue(\"y#\", \"hello\", 4) b'hell'\n" +"Py_BuildValue(\"()\") ()\n" +"Py_BuildValue(\"(i)\", 123) (123,)\n" +"Py_BuildValue(\"(ii)\", 123, 456) (123, 456)\n" +"Py_BuildValue(\"(i,i)\", 123, 456) (123, 456)\n" +"Py_BuildValue(\"[i,i]\", 123, 456) [123, 456]\n" +"Py_BuildValue(\"{s:i,s:i}\",\n" +" \"abc\", 123, \"def\", 456) {'abc': 123, 'def': 456}\n" +"Py_BuildValue(\"((ii)(ii)) (ii)\",\n" +" 1, 2, 3, 4, 5, 6) (((1, 2), (3, 4)), (5, 6))" +msgstr "" + #: ../../extending/extending.rst:846 msgid "Reference Counts" msgstr "" @@ -971,6 +1385,18 @@ msgid "" "instance::" msgstr "" +#: ../../extending/extending.rst:1016 +msgid "" +"void\n" +"bug(PyObject *list)\n" +"{\n" +" PyObject *item = PyList_GetItem(list, 0);\n" +"\n" +" PyList_SetItem(list, 1, PyLong_FromLong(0L));\n" +" PyObject_Print(item, stdout, 0); /* BUG! */\n" +"}" +msgstr "" + #: ../../extending/extending.rst:1025 msgid "" "This function first borrows a reference to ``list[0]``, then replaces " @@ -1005,6 +1431,20 @@ msgid "" "increment the reference count. The correct version of the function reads::" msgstr "" +#: ../../extending/extending.rst:1047 +msgid "" +"void\n" +"no_bug(PyObject *list)\n" +"{\n" +" PyObject *item = PyList_GetItem(list, 0);\n" +"\n" +" Py_INCREF(item);\n" +" PyList_SetItem(list, 1, PyLong_FromLong(0L));\n" +" PyObject_Print(item, stdout, 0);\n" +" Py_DECREF(item);\n" +"}" +msgstr "" + #: ../../extending/extending.rst:1058 msgid "" "This is a true story. An older version of Python contained variants of this " @@ -1025,6 +1465,19 @@ msgid "" "previous one::" msgstr "" +#: ../../extending/extending.rst:1071 +msgid "" +"void\n" +"bug(PyObject *list)\n" +"{\n" +" PyObject *item = PyList_GetItem(list, 0);\n" +" Py_BEGIN_ALLOW_THREADS\n" +" ...some blocking I/O call...\n" +" Py_END_ALLOW_THREADS\n" +" PyObject_Print(item, stdout, 0); /* BUG! */\n" +"}" +msgstr "" + #: ../../extending/extending.rst:1085 msgid "NULL Pointers" msgstr "" @@ -1173,6 +1626,10 @@ msgid "" "following this convention::" msgstr "" +#: ../../extending/extending.rst:1196 +msgid "modulename.attributename" +msgstr "" + #: ../../extending/extending.rst:1198 msgid "" "The convenience function :c:func:`PyCapsule_Import` makes it easy to load a " @@ -1209,18 +1666,52 @@ msgid "" "``static`` like everything else::" msgstr "" +#: ../../extending/extending.rst:1221 +msgid "" +"static int\n" +"PySpam_System(const char *command)\n" +"{\n" +" return system(command);\n" +"}" +msgstr "" + #: ../../extending/extending.rst:1227 msgid "The function :c:func:`!spam_system` is modified in a trivial way::" msgstr "" +#: ../../extending/extending.rst:1229 +msgid "" +"static PyObject *\n" +"spam_system(PyObject *self, PyObject *args)\n" +"{\n" +" const char *command;\n" +" int sts;\n" +"\n" +" if (!PyArg_ParseTuple(args, \"s\", &command))\n" +" return NULL;\n" +" sts = PySpam_System(command);\n" +" return PyLong_FromLong(sts);\n" +"}" +msgstr "" + #: ../../extending/extending.rst:1241 msgid "In the beginning of the module, right after the line ::" msgstr "" +#: ../../extending/extending.rst:1243 +msgid "#include " +msgstr "" + #: ../../extending/extending.rst:1245 msgid "two more lines must be added::" msgstr "" +#: ../../extending/extending.rst:1247 +msgid "" +"#define SPAM_MODULE\n" +"#include \"spammodule.h\"" +msgstr "" + #: ../../extending/extending.rst:1250 msgid "" "The ``#define`` is used to tell the header file that it is being included in " @@ -1229,6 +1720,36 @@ msgid "" "array::" msgstr "" +#: ../../extending/extending.rst:1254 +msgid "" +"PyMODINIT_FUNC\n" +"PyInit_spam(void)\n" +"{\n" +" PyObject *m;\n" +" static void *PySpam_API[PySpam_API_pointers];\n" +" PyObject *c_api_object;\n" +"\n" +" m = PyModule_Create(&spammodule);\n" +" if (m == NULL)\n" +" return NULL;\n" +"\n" +" /* Initialize the C API pointer array */\n" +" PySpam_API[PySpam_System_NUM] = (void *)PySpam_System;\n" +"\n" +" /* Create a Capsule containing the API pointer array's address */\n" +" c_api_object = PyCapsule_New((void *)PySpam_API, \"spam._C_API\", " +"NULL);\n" +"\n" +" if (PyModule_AddObject(m, \"_C_API\", c_api_object) < 0) {\n" +" Py_XDECREF(c_api_object);\n" +" Py_DECREF(m);\n" +" return NULL;\n" +" }\n" +"\n" +" return m;\n" +"}" +msgstr "" + #: ../../extending/extending.rst:1280 msgid "" "Note that ``PySpam_API`` is declared ``static``; otherwise the pointer array " @@ -1241,6 +1762,58 @@ msgid "" "like this::" msgstr "" +#: ../../extending/extending.rst:1286 +msgid "" +"#ifndef Py_SPAMMODULE_H\n" +"#define Py_SPAMMODULE_H\n" +"#ifdef __cplusplus\n" +"extern \"C\" {\n" +"#endif\n" +"\n" +"/* Header file for spammodule */\n" +"\n" +"/* C API functions */\n" +"#define PySpam_System_NUM 0\n" +"#define PySpam_System_RETURN int\n" +"#define PySpam_System_PROTO (const char *command)\n" +"\n" +"/* Total number of C API pointers */\n" +"#define PySpam_API_pointers 1\n" +"\n" +"\n" +"#ifdef SPAM_MODULE\n" +"/* This section is used when compiling spammodule.c */\n" +"\n" +"static PySpam_System_RETURN PySpam_System PySpam_System_PROTO;\n" +"\n" +"#else\n" +"/* This section is used in modules that use spammodule's API */\n" +"\n" +"static void **PySpam_API;\n" +"\n" +"#define PySpam_System \\\n" +" (*(PySpam_System_RETURN (*)PySpam_System_PROTO) " +"PySpam_API[PySpam_System_NUM])\n" +"\n" +"/* Return -1 on error, 0 on success.\n" +" * PyCapsule_Import will set an exception if there's an error.\n" +" */\n" +"static int\n" +"import_spam(void)\n" +"{\n" +" PySpam_API = (void **)PyCapsule_Import(\"spam._C_API\", 0);\n" +" return (PySpam_API != NULL) ? 0 : -1;\n" +"}\n" +"\n" +"#endif\n" +"\n" +"#ifdef __cplusplus\n" +"}\n" +"#endif\n" +"\n" +"#endif /* !defined(Py_SPAMMODULE_H) */" +msgstr "" + #: ../../extending/extending.rst:1334 msgid "" "All that a client module must do in order to have access to the function :c:" @@ -1248,6 +1821,23 @@ msgid "" "import_spam` in its initialization function::" msgstr "" +#: ../../extending/extending.rst:1338 +msgid "" +"PyMODINIT_FUNC\n" +"PyInit_client(void)\n" +"{\n" +" PyObject *m;\n" +"\n" +" m = PyModule_Create(&clientmodule);\n" +" if (m == NULL)\n" +" return NULL;\n" +" if (import_spam() < 0)\n" +" return NULL;\n" +" /* additional initialization can happen here */\n" +" return m;\n" +"}" +msgstr "" + #: ../../extending/extending.rst:1352 msgid "" "The main disadvantage of this approach is that the file :file:`spammodule.h` " diff --git a/extending/newtypes.po b/extending/newtypes.po index 2b2971580d..50e4953d55 100644 --- a/extending/newtypes.po +++ b/extending/newtypes.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-05-27 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2018-05-23 14:34+0000\n" "Last-Translator: Adrian Liaw \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -35,6 +35,96 @@ msgid "" "in :ref:`debug builds ` omitted:" msgstr "" +#: ../../extending/newtypes.rst:17 +msgid "" +"typedef struct _typeobject {\n" +" PyObject_VAR_HEAD\n" +" const char *tp_name; /* For printing, in format \".\" */\n" +" Py_ssize_t tp_basicsize, tp_itemsize; /* For allocation */\n" +"\n" +" /* Methods to implement standard operations */\n" +"\n" +" destructor tp_dealloc;\n" +" Py_ssize_t tp_vectorcall_offset;\n" +" getattrfunc tp_getattr;\n" +" setattrfunc tp_setattr;\n" +" PyAsyncMethods *tp_as_async; /* formerly known as tp_compare (Python 2)\n" +" or tp_reserved (Python 3) */\n" +" reprfunc tp_repr;\n" +"\n" +" /* Method suites for standard classes */\n" +"\n" +" PyNumberMethods *tp_as_number;\n" +" PySequenceMethods *tp_as_sequence;\n" +" PyMappingMethods *tp_as_mapping;\n" +"\n" +" /* More standard operations (here for binary compatibility) */\n" +"\n" +" hashfunc tp_hash;\n" +" ternaryfunc tp_call;\n" +" reprfunc tp_str;\n" +" getattrofunc tp_getattro;\n" +" setattrofunc tp_setattro;\n" +"\n" +" /* Functions to access object as input/output buffer */\n" +" PyBufferProcs *tp_as_buffer;\n" +"\n" +" /* Flags to define presence of optional/expanded features */\n" +" unsigned long tp_flags;\n" +"\n" +" const char *tp_doc; /* Documentation string */\n" +"\n" +" /* Assigned meaning in release 2.0 */\n" +" /* call function for all accessible objects */\n" +" traverseproc tp_traverse;\n" +"\n" +" /* delete references to contained objects */\n" +" inquiry tp_clear;\n" +"\n" +" /* Assigned meaning in release 2.1 */\n" +" /* rich comparisons */\n" +" richcmpfunc tp_richcompare;\n" +"\n" +" /* weak reference enabler */\n" +" Py_ssize_t tp_weaklistoffset;\n" +"\n" +" /* Iterators */\n" +" getiterfunc tp_iter;\n" +" iternextfunc tp_iternext;\n" +"\n" +" /* Attribute descriptor and subclassing stuff */\n" +" struct PyMethodDef *tp_methods;\n" +" struct PyMemberDef *tp_members;\n" +" struct PyGetSetDef *tp_getset;\n" +" // Strong reference on a heap type, borrowed reference on a static type\n" +" struct _typeobject *tp_base;\n" +" PyObject *tp_dict;\n" +" descrgetfunc tp_descr_get;\n" +" descrsetfunc tp_descr_set;\n" +" Py_ssize_t tp_dictoffset;\n" +" initproc tp_init;\n" +" allocfunc tp_alloc;\n" +" newfunc tp_new;\n" +" freefunc tp_free; /* Low-level free-memory routine */\n" +" inquiry tp_is_gc; /* For PyObject_IS_GC */\n" +" PyObject *tp_bases;\n" +" PyObject *tp_mro; /* method resolution order */\n" +" PyObject *tp_cache;\n" +" PyObject *tp_subclasses;\n" +" PyObject *tp_weaklist;\n" +" destructor tp_del;\n" +"\n" +" /* Type attribute cache version tag. Added in version 2.6 */\n" +" unsigned int tp_version_tag;\n" +"\n" +" destructor tp_finalize;\n" +" vectorcallfunc tp_vectorcall;\n" +"\n" +" /* bitset of which type-watchers care about this type */\n" +" unsigned char tp_watched;\n" +"} PyTypeObject;\n" +msgstr "" + #: ../../extending/newtypes.rst:20 msgid "" "Now that's a *lot* of methods. Don't worry too much though -- if you have a " @@ -52,6 +142,10 @@ msgid "" "new type. ::" msgstr "" +#: ../../extending/newtypes.rst:31 +msgid "const char *tp_name; /* For printing */" +msgstr "" + #: ../../extending/newtypes.rst:33 msgid "" "The name of the type -- as mentioned in the previous chapter, this will " @@ -59,6 +153,10 @@ msgid "" "choose something that will be helpful in such a situation! ::" msgstr "" +#: ../../extending/newtypes.rst:37 +msgid "Py_ssize_t tp_basicsize, tp_itemsize; /* For allocation */" +msgstr "" + #: ../../extending/newtypes.rst:39 msgid "" "These fields tell the runtime how much memory to allocate when new objects " @@ -68,6 +166,10 @@ msgid "" "later. ::" msgstr "" +#: ../../extending/newtypes.rst:44 +msgid "const char *tp_doc;" +msgstr "" + #: ../../extending/newtypes.rst:46 msgid "" "Here you can put a string (or its address) that you want returned when the " @@ -84,6 +186,10 @@ msgstr "" msgid "Finalization and De-allocation" msgstr "" +#: ../../extending/newtypes.rst:64 +msgid "destructor tp_dealloc;" +msgstr "" + #: ../../extending/newtypes.rst:66 msgid "" "This function is called when the reference count of the instance of your " @@ -93,12 +199,34 @@ msgid "" "of this function::" msgstr "" +#: ../../extending/newtypes.rst:72 +msgid "" +"static void\n" +"newdatatype_dealloc(newdatatypeobject *obj)\n" +"{\n" +" free(obj->obj_UnderlyingDatatypePtr);\n" +" Py_TYPE(obj)->tp_free((PyObject *)obj);\n" +"}" +msgstr "" + #: ../../extending/newtypes.rst:79 msgid "" "If your type supports garbage collection, the destructor should call :c:func:" "`PyObject_GC_UnTrack` before clearing any member fields::" msgstr "" +#: ../../extending/newtypes.rst:82 +msgid "" +"static void\n" +"newdatatype_dealloc(newdatatypeobject *obj)\n" +"{\n" +" PyObject_GC_UnTrack(obj);\n" +" Py_CLEAR(obj->other_obj);\n" +" ...\n" +" Py_TYPE(obj)->tp_free((PyObject *)obj);\n" +"}" +msgstr "" + #: ../../extending/newtypes.rst:95 msgid "" "One important requirement of the deallocator function is that it leaves any " @@ -114,6 +242,35 @@ msgid "" "c:func:`PyErr_Fetch` and :c:func:`PyErr_Restore` functions::" msgstr "" +#: ../../extending/newtypes.rst:107 +msgid "" +"static void\n" +"my_dealloc(PyObject *obj)\n" +"{\n" +" MyObject *self = (MyObject *) obj;\n" +" PyObject *cbresult;\n" +"\n" +" if (self->my_callback != NULL) {\n" +" PyObject *err_type, *err_value, *err_traceback;\n" +"\n" +" /* This saves the current exception state */\n" +" PyErr_Fetch(&err_type, &err_value, &err_traceback);\n" +"\n" +" cbresult = PyObject_CallNoArgs(self->my_callback);\n" +" if (cbresult == NULL)\n" +" PyErr_WriteUnraisable(self->my_callback);\n" +" else\n" +" Py_DECREF(cbresult);\n" +"\n" +" /* This restores the saved exception state */\n" +" PyErr_Restore(err_type, err_value, err_traceback);\n" +"\n" +" Py_DECREF(self->my_callback);\n" +" }\n" +" Py_TYPE(obj)->tp_free((PyObject*)self);\n" +"}" +msgstr "" + #: ../../extending/newtypes.rst:134 msgid "" "There are limitations to what you can safely do in a deallocator function. " @@ -149,6 +306,12 @@ msgid "" "`print` function just calls :func:`str`.) These handlers are both optional." msgstr "" +#: ../../extending/newtypes.rst:163 +msgid "" +"reprfunc tp_repr;\n" +"reprfunc tp_str;" +msgstr "" + #: ../../extending/newtypes.rst:166 msgid "" "The :c:member:`~PyTypeObject.tp_repr` handler should return a string object " @@ -156,6 +319,16 @@ msgid "" "a simple example::" msgstr "" +#: ../../extending/newtypes.rst:170 +msgid "" +"static PyObject *\n" +"newdatatype_repr(newdatatypeobject *obj)\n" +"{\n" +" return PyUnicode_FromFormat(\"Repr-ified_newdatatype{{size:%d}}\",\n" +" obj->obj_UnderlyingDatatypePtr->size);\n" +"}" +msgstr "" + #: ../../extending/newtypes.rst:177 msgid "" "If no :c:member:`~PyTypeObject.tp_repr` handler is specified, the " @@ -178,6 +351,16 @@ msgstr "" msgid "Here is a simple example::" msgstr "以下是個簡單的範例: ::" +#: ../../extending/newtypes.rst:190 +msgid "" +"static PyObject *\n" +"newdatatype_str(newdatatypeobject *obj)\n" +"{\n" +" return PyUnicode_FromFormat(\"Stringified_newdatatype{{size:%d}}\",\n" +" obj->obj_UnderlyingDatatypePtr->size);\n" +"}" +msgstr "" + #: ../../extending/newtypes.rst:200 msgid "Attribute Management" msgstr "" @@ -201,6 +384,15 @@ msgid "" "whichever pair makes more sense for the implementation's convenience. ::" msgstr "" +#: ../../extending/newtypes.rst:214 +msgid "" +"getattrfunc tp_getattr; /* char * version */\n" +"setattrfunc tp_setattr;\n" +"/* ... */\n" +"getattrofunc tp_getattro; /* PyObject * version */\n" +"setattrofunc tp_setattro;" +msgstr "" + #: ../../extending/newtypes.rst:220 msgid "" "If accessing attributes of an object is always a simple operation (this will " @@ -256,6 +448,13 @@ msgstr "" msgid "The tables are declared as three fields of the type object::" msgstr "" +#: ../../extending/newtypes.rst:255 +msgid "" +"struct PyMethodDef *tp_methods;\n" +"struct PyMemberDef *tp_members;\n" +"struct PyGetSetDef *tp_getset;" +msgstr "" + #: ../../extending/newtypes.rst:259 msgid "" "If :c:member:`~PyTypeObject.tp_methods` is not ``NULL``, it must refer to an " @@ -263,6 +462,16 @@ msgid "" "instance of this structure::" msgstr "" +#: ../../extending/newtypes.rst:263 +msgid "" +"typedef struct PyMethodDef {\n" +" const char *ml_name; /* method name */\n" +" PyCFunction ml_meth; /* implementation function */\n" +" int ml_flags; /* flags */\n" +" const char *ml_doc; /* docstring */\n" +"} PyMethodDef;" +msgstr "" + #: ../../extending/newtypes.rst:270 msgid "" "One entry should be defined for each method provided by the type; no entries " @@ -279,6 +488,17 @@ msgid "" "defined as::" msgstr "" +#: ../../extending/newtypes.rst:279 +msgid "" +"typedef struct PyMemberDef {\n" +" const char *name;\n" +" int type;\n" +" int offset;\n" +" int flags;\n" +" const char *doc;\n" +"} PyMemberDef;" +msgstr "" + #: ../../extending/newtypes.rst:287 msgid "" "For each entry in the table, a :term:`descriptor` will be constructed and " @@ -333,6 +553,23 @@ msgstr "" msgid "Here is an example::" msgstr "舉例來說: ::" +#: ../../extending/newtypes.rst:331 +msgid "" +"static PyObject *\n" +"newdatatype_getattr(newdatatypeobject *obj, char *name)\n" +"{\n" +" if (strcmp(name, \"data\") == 0)\n" +" {\n" +" return PyLong_FromLong(obj->data);\n" +" }\n" +"\n" +" PyErr_Format(PyExc_AttributeError,\n" +" \"'%.100s' object has no attribute '%.400s'\",\n" +" Py_TYPE(obj)->tp_name, name);\n" +" return NULL;\n" +"}" +msgstr "" + #: ../../extending/newtypes.rst:345 msgid "" "The :c:member:`~PyTypeObject.tp_setattr` handler is called when the :meth:" @@ -343,10 +580,24 @@ msgid "" "tp_setattr` handler should be set to ``NULL``. ::" msgstr "" +#: ../../extending/newtypes.rst:351 +msgid "" +"static int\n" +"newdatatype_setattr(newdatatypeobject *obj, char *name, PyObject *v)\n" +"{\n" +" PyErr_Format(PyExc_RuntimeError, \"Read-only attribute: %s\", name);\n" +" return -1;\n" +"}" +msgstr "" + #: ../../extending/newtypes.rst:359 msgid "Object Comparison" msgstr "" +#: ../../extending/newtypes.rst:363 +msgid "richcmpfunc tp_richcompare;" +msgstr "" + #: ../../extending/newtypes.rst:365 msgid "" "The :c:member:`~PyTypeObject.tp_richcompare` handler is called when " @@ -372,6 +623,35 @@ msgid "" "the size of an internal pointer is equal::" msgstr "" +#: ../../extending/newtypes.rst:381 +msgid "" +"static PyObject *\n" +"newdatatype_richcmp(newdatatypeobject *obj1, newdatatypeobject *obj2, int " +"op)\n" +"{\n" +" PyObject *result;\n" +" int c, size1, size2;\n" +"\n" +" /* code to make sure that both arguments are of type\n" +" newdatatype omitted */\n" +"\n" +" size1 = obj1->obj_UnderlyingDatatypePtr->size;\n" +" size2 = obj2->obj_UnderlyingDatatypePtr->size;\n" +"\n" +" switch (op) {\n" +" case Py_LT: c = size1 < size2; break;\n" +" case Py_LE: c = size1 <= size2; break;\n" +" case Py_EQ: c = size1 == size2; break;\n" +" case Py_NE: c = size1 != size2; break;\n" +" case Py_GT: c = size1 > size2; break;\n" +" case Py_GE: c = size1 >= size2; break;\n" +" }\n" +" result = c ? Py_True : Py_False;\n" +" Py_INCREF(result);\n" +" return result;\n" +" }" +msgstr "" + #: ../../extending/newtypes.rst:408 msgid "Abstract Protocol Support" msgstr "" @@ -397,6 +677,13 @@ msgid "" "slot, but a slot may still be unfilled.) ::" msgstr "" +#: ../../extending/newtypes.rst:425 +msgid "" +"PyNumberMethods *tp_as_number;\n" +"PySequenceMethods *tp_as_sequence;\n" +"PyMappingMethods *tp_as_mapping;" +msgstr "" + #: ../../extending/newtypes.rst:429 msgid "" "If you wish your object to be able to act like a number, a sequence, or a " @@ -408,12 +695,29 @@ msgid "" "distribution. ::" msgstr "" +#: ../../extending/newtypes.rst:436 +msgid "hashfunc tp_hash;" +msgstr "" + #: ../../extending/newtypes.rst:438 msgid "" "This function, if you choose to provide it, should return a hash number for " "an instance of your data type. Here is a simple example::" msgstr "" +#: ../../extending/newtypes.rst:441 +msgid "" +"static Py_hash_t\n" +"newdatatype_hash(newdatatypeobject *obj)\n" +"{\n" +" Py_hash_t result;\n" +" result = obj->some_size + 32767 * obj->some_number;\n" +" if (result == -1)\n" +" result = -2;\n" +" return result;\n" +"}" +msgstr "" + #: ../../extending/newtypes.rst:451 msgid "" ":c:type:`!Py_hash_t` is a signed integer type with a platform-varying width. " @@ -422,6 +726,10 @@ msgid "" "computation is successful, as seen above." msgstr "" +#: ../../extending/newtypes.rst:458 +msgid "ternaryfunc tp_call;" +msgstr "" + #: ../../extending/newtypes.rst:460 msgid "" "This function is called when an instance of your data type is \"called\", " @@ -459,6 +767,34 @@ msgstr "" msgid "Here is a toy ``tp_call`` implementation::" msgstr "" +#: ../../extending/newtypes.rst:480 +msgid "" +"static PyObject *\n" +"newdatatype_call(newdatatypeobject *obj, PyObject *args, PyObject *kwds)\n" +"{\n" +" PyObject *result;\n" +" const char *arg1;\n" +" const char *arg2;\n" +" const char *arg3;\n" +"\n" +" if (!PyArg_ParseTuple(args, \"sss:call\", &arg1, &arg2, &arg3)) {\n" +" return NULL;\n" +" }\n" +" result = PyUnicode_FromFormat(\n" +" \"Returning -- value: [%d] arg1: [%s] arg2: [%s] arg3: [%s]\\n\",\n" +" obj->obj_UnderlyingDatatypePtr->size,\n" +" arg1, arg2, arg3);\n" +" return result;\n" +"}" +msgstr "" + +#: ../../extending/newtypes.rst:500 +msgid "" +"/* Iterators */\n" +"getiterfunc tp_iter;\n" +"iternextfunc tp_iternext;" +msgstr "" + #: ../../extending/newtypes.rst:504 msgid "" "These functions provide support for the iterator protocol. Both handlers " @@ -535,12 +871,33 @@ msgid "" "Concretely, here is how the statically declared type object would look::" msgstr "" +#: ../../extending/newtypes.rst:555 +msgid "" +"static PyTypeObject TrivialType = {\n" +" PyVarObject_HEAD_INIT(NULL, 0)\n" +" /* ... other members omitted for brevity ... */\n" +" .tp_flags = Py_TPFLAGS_MANAGED_WEAKREF | ...,\n" +"};" +msgstr "" + #: ../../extending/newtypes.rst:562 msgid "" "The only further addition is that ``tp_dealloc`` needs to clear any weak " "references (by calling :c:func:`PyObject_ClearWeakRefs`)::" msgstr "" +#: ../../extending/newtypes.rst:565 +msgid "" +"static void\n" +"Trivial_dealloc(TrivialObject *self)\n" +"{\n" +" /* Clear weakrefs first before calling any destructors */\n" +" PyObject_ClearWeakRefs((PyObject *) self);\n" +" /* ... remainder of destruction code omitted for brevity ... */\n" +" Py_TYPE(self)->tp_free((PyObject *) self);\n" +"}" +msgstr "" + #: ../../extending/newtypes.rst:576 msgid "More Suggestions" msgstr "" @@ -561,6 +918,14 @@ msgid "" "sample of its use might be something like the following::" msgstr "" +#: ../../extending/newtypes.rst:588 +msgid "" +"if (!PyObject_TypeCheck(some_object, &MyType)) {\n" +" PyErr_SetString(PyExc_TypeError, \"arg #1 not a mything\");\n" +" return NULL;\n" +"}" +msgstr "" + #: ../../extending/newtypes.rst:594 msgid "Download CPython source releases." msgstr "" diff --git a/faq/design.po b/faq/design.po index 09ffc22728..0a63ffa609 100644 --- a/faq/design.po +++ b/faq/design.po @@ -10,7 +10,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-07-20 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2023-08-31 11:34+0800\n" "Last-Translator: Steven Hsu \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -53,6 +53,14 @@ msgstr "" "因為沒有開始/結束括號,因此剖析器和人類讀者感知到的分組就不存在分歧。偶爾 C " "語言的程式設計師會遇到這樣的程式碼片段: ::" +#: ../../faq/design.rst:21 +msgid "" +"if (x <= y)\n" +" x++;\n" +" y--;\n" +"z++;" +msgstr "" + #: ../../faq/design.rst:26 msgid "" "Only the ``x++`` statement is executed if the condition is true, but the " @@ -108,6 +116,12 @@ msgstr "為何浮點數運算如此不精確?" msgid "Users are often surprised by results like this::" msgstr "使用者時常對這樣的結果感到驚訝: ::" +#: ../../faq/design.rst:58 +msgid "" +">>> 1.2 - 1.0\n" +"0.19999999999999996" +msgstr "" + #: ../../faq/design.rst:61 msgid "" "and think it is a bug in Python. It's not. This has little to do with " @@ -139,6 +153,10 @@ msgstr "" "很多數字可以簡單地寫成十進位表示,但卻無法簡單地以二進制浮點數表示。比方說," "在以下程式碼執行後: ::" +#: ../../faq/design.rst:75 +msgid ">>> x = 1.2" +msgstr "" + #: ../../faq/design.rst:77 msgid "" "the value stored for ``x`` is a (very good) approximation to the decimal " @@ -148,10 +166,18 @@ msgstr "" "``x`` 裡的值是一個(很接近)1.2 的估計值,但並非精確地等於 1.2。以一般的電腦" "來說,他實際儲存的值是: ::" +#: ../../faq/design.rst:81 +msgid "1.0011001100110011001100110011001100110011001100110011 (binary)" +msgstr "" + #: ../../faq/design.rst:83 msgid "which is exactly::" msgstr "而這個值正是: ::" +#: ../../faq/design.rst:85 +msgid "1.1999999999999999555910790149937383830547332763671875 (decimal)" +msgstr "" + #: ../../faq/design.rst:87 msgid "" "The typical precision of 53 bits provides Python floats with 15--16 decimal " @@ -281,6 +307,12 @@ msgid "" "an expression::" msgstr "指派運算式使用海象運算子 ``:=`` 來在運算式中指派變數值: ::" +#: ../../faq/design.rst:161 +msgid "" +"while chunk := fp.read(200):\n" +" print(chunk)" +msgstr "" + #: ../../faq/design.rst:164 msgid "See :pep:`572` for more information." msgstr "更多資訊請見 :pep:`572`。" @@ -348,10 +380,18 @@ msgstr "" "的函式有相同功能的方法也被加入。大多數的新方法都被廣泛接受,但有一個方法似乎" "讓一些程式人員不舒服: ::" +#: ../../faq/design.rst:201 +msgid "\", \".join(['1', '2', '4', '8', '16'])" +msgstr "" + #: ../../faq/design.rst:203 msgid "which gives the result::" msgstr "結果是: ::" +#: ../../faq/design.rst:205 +msgid "\"1, 2, 4, 8, 16\"" +msgstr "" + #: ../../faq/design.rst:207 msgid "There are two common arguments against this usage." msgstr "通常有兩個反對這個用法的論點。" @@ -379,6 +419,10 @@ msgstr "" "但很遺憾地,你並不是在這樣做。因為某種原因,把 :meth:`~str.split` 當成字串方" "法比較簡單,因為這樣我們可以輕易地看到: ::" +#: ../../faq/design.rst:220 +msgid "\"1, 2, 4, 8, 16\".split(\", \")" +msgstr "" + #: ../../faq/design.rst:222 msgid "" "is an instruction to a string literal to return the substrings delimited by " @@ -413,6 +457,15 @@ msgstr "" "的。事實上,抓捕例外要付出昂貴的代價。在 Python 2.0 以前,這樣使用是相當常見" "的: ::" +#: ../../faq/design.rst:240 +msgid "" +"try:\n" +" value = mydict[key]\n" +"except KeyError:\n" +" mydict[key] = getvalue(key)\n" +" value = mydict[key]" +msgstr "" + #: ../../faq/design.rst:246 msgid "" "This only made sense when you expected the dict to have the key almost all " @@ -421,6 +474,14 @@ msgstr "" "這只有在你預料這個字典大多數時候都有鍵的時候才合理。如果並非如此,你應該寫" "成: ::" +#: ../../faq/design.rst:249 +msgid "" +"if key in mydict:\n" +" value = mydict[key]\n" +"else:\n" +" value = mydict[key] = getvalue(key)" +msgstr "" + #: ../../faq/design.rst:254 msgid "" "For this specific case, you could also use ``value = dict.setdefault(key, " @@ -451,6 +512,16 @@ msgid "" "to call. For example::" msgstr "如果可能性很多,你可以用字典去映射要呼叫的函式。舉例來說: ::" +#: ../../faq/design.rst:272 +msgid "" +"functions = {'a': function_1,\n" +" 'b': function_2,\n" +" 'c': self.method_1}\n" +"\n" +"func = functions[value]\n" +"func()" +msgstr "" + #: ../../faq/design.rst:279 msgid "" "For calling methods on objects, you can simplify yet further by using the :" @@ -459,6 +530,18 @@ msgstr "" "對於呼叫物件裡的方法,你可以利用內建用來找尋特定方法的函式 :func:`getattr` 來" "做進一步的簡化: ::" +#: ../../faq/design.rst:282 +msgid "" +"class MyVisitor:\n" +" def visit_a(self):\n" +" ...\n" +"\n" +" def dispatch(self, value):\n" +" method_name = 'visit_' + str(value)\n" +" method = getattr(self, method_name)\n" +" method()" +msgstr "" + #: ../../faq/design.rst:291 msgid "" "It's suggested that you use a prefix for the method names, such as " @@ -586,6 +669,13 @@ msgstr "" "在一些 Python 實作中,下面這段程式碼(在 CPython 可以正常運作)可能會把檔案描" "述子 (file descriptor) 用盡: ::" +#: ../../faq/design.rst:356 +msgid "" +"for file in very_long_list_of_files:\n" +" f = open(file)\n" +" c = f.read(1)" +msgstr "" + #: ../../faq/design.rst:360 msgid "" "Indeed, using CPython's reference counting and destructor scheme, each new " @@ -607,6 +697,13 @@ msgstr "" "案或是使用 :keyword:`with` 陳述式,如此一來,不用管記憶體管理的方法,他也會正" "常運作: ::" +#: ../../faq/design.rst:369 +msgid "" +"for file in very_long_list_of_files:\n" +" with open(file) as f:\n" +" c = f.read(1)" +msgstr "" + #: ../../faq/design.rst:375 msgid "Why doesn't CPython use a more traditional garbage collection scheme?" msgstr "為何 CPython 不使用更多傳統的垃圾回收機制?" @@ -817,6 +914,12 @@ msgstr "" "用串列的記憶體位址(物件 id)來雜湊。這不會成功,因為你如果用同樣的值建立一個" "新的串列,是找不到的。舉例來說: ::" +#: ../../faq/design.rst:483 +msgid "" +"mydict = {[1, 2]: '12'}\n" +"print(mydict[[1, 2]])" +msgstr "" + #: ../../faq/design.rst:486 msgid "" "would raise a :exc:`KeyError` exception because the id of the ``[1, 2]`` " @@ -876,6 +979,26 @@ msgstr "" "\n" "::" +#: ../../faq/design.rst:513 +msgid "" +"class ListWrapper:\n" +" def __init__(self, the_list):\n" +" self.the_list = the_list\n" +"\n" +" def __eq__(self, other):\n" +" return self.the_list == other.the_list\n" +"\n" +" def __hash__(self):\n" +" l = self.the_list\n" +" result = 98767 - len(l)*555\n" +" for i, el in enumerate(l):\n" +" try:\n" +" result = result + (hash(el) % 9999999) * 1001 + i\n" +" except Exception:\n" +" result = (result % 7777777) + i * 333\n" +" return result" +msgstr "" + #: ../../faq/design.rst:530 msgid "" "Note that the hash computation is complicated by the possibility that some " @@ -937,6 +1060,12 @@ msgstr "" "物件 (iterable) 來排序建立新串列,並回傳之。例如,以下這個範例會說明如何有序" "地疊代字典的鍵: ::" +#: ../../faq/design.rst:559 +msgid "" +"for key in sorted(mydict):\n" +" ... # do whatever with mydict[key]..." +msgstr "" + #: ../../faq/design.rst:564 msgid "How do you specify and enforce an interface spec in Python?" msgstr "如何在 Python 中指定和強制使用一個介面規範 (interface spec)?" @@ -1050,6 +1179,19 @@ msgstr "" "以方便地模擬在 C、Fortran 和其他語言裡各種合理使用的 ``go`` 和 ``goto``。例" "如: ::" +#: ../../faq/design.rst:620 +msgid "" +"class label(Exception): pass # declare a label\n" +"\n" +"try:\n" +" ...\n" +" if condition: raise label() # goto label\n" +" ...\n" +"except label: # where to goto\n" +" pass\n" +"..." +msgstr "" + #: ../../faq/design.rst:630 msgid "" "This doesn't allow you to jump into the middle of a loop, but that's usually " @@ -1091,11 +1233,22 @@ msgid "" msgstr "" "如果你嘗試建立 Windows 的路徑名稱,請注意 Windows 系統指令也接受一般斜線: ::" +#: ../../faq/design.rst:651 +msgid "f = open(\"/mydir/file.txt\") # works fine!" +msgstr "" + #: ../../faq/design.rst:653 msgid "" "If you're trying to build a pathname for a DOS command, try e.g. one of ::" msgstr "如果你嘗試建立 DOS 指令的路徑名稱,試試看使用以下的範例: ::" +#: ../../faq/design.rst:655 +msgid "" +"dir = r\"\\this\\is\\my\\dos\\dir\" \"\\\\\"\n" +"dir = r\"\\this\\is\\my\\dos\\dir\\ \"[:-1]\n" +"dir = \"\\\\this\\\\is\\\\my\\\\dos\\\\dir\\\\\"" +msgstr "" + #: ../../faq/design.rst:661 msgid "Why doesn't Python have a \"with\" statement for attribute assignments?" msgstr "為何 Python 沒有屬性賦值的 with 陳述式?" @@ -1109,6 +1262,13 @@ msgstr "" "Python 的 :keyword:`with` 陳述式包裝了一區塊程式的執行,在進入和離開該區塊時" "執行程式碼。一些語言會有像如下的結構: ::" +#: ../../faq/design.rst:667 +msgid "" +"with obj:\n" +" a = 1 # equivalent to obj.a = 1\n" +" total = total + 1 # obj.total = obj.total + 1" +msgstr "" + #: ../../faq/design.rst:671 msgid "In Python, such a construct would be ambiguous." msgstr "但在 Python,這種結構是模糊的。" @@ -1140,6 +1300,13 @@ msgstr "" msgid "For instance, take the following incomplete snippet::" msgstr "以下列不完整的程式碼為例: ::" +#: ../../faq/design.rst:686 +msgid "" +"def foo(a):\n" +" with a:\n" +" print(x)" +msgstr "" + #: ../../faq/design.rst:690 msgid "" "The snippet assumes that ``a`` must have a member attribute called ``x``. " @@ -1162,10 +1329,25 @@ msgstr "" "然而 :keyword:`with` 陳述式或類似的語言特性(減少程式碼量)的主要好處可以透過" "賦值來達成。相較於這樣寫: ::" +#: ../../faq/design.rst:699 +msgid "" +"function(args).mydict[index][index].a = 21\n" +"function(args).mydict[index][index].b = 42\n" +"function(args).mydict[index][index].c = 63" +msgstr "" + #: ../../faq/design.rst:703 msgid "write this::" msgstr "應該寫成這樣: ::" +#: ../../faq/design.rst:705 +msgid "" +"ref = function(args).mydict[index][index]\n" +"ref.a = 21\n" +"ref.b = 42\n" +"ref.c = 63" +msgstr "" + #: ../../faq/design.rst:710 msgid "" "This also has the side-effect of increasing execution speed because name " @@ -1213,10 +1395,22 @@ msgid "" msgstr "" "需要冒號主要是為了增加可讀性(由 ABC 語言的實驗得知)。試想如下範例: ::" +#: ../../faq/design.rst:735 +msgid "" +"if a == b\n" +" print(a)" +msgstr "" + #: ../../faq/design.rst:738 msgid "versus ::" msgstr "以及: ::" +#: ../../faq/design.rst:740 +msgid "" +"if a == b:\n" +" print(a)" +msgstr "" + #: ../../faq/design.rst:743 msgid "" "Notice how the second one is slightly easier to read. Notice further how a " @@ -1246,6 +1440,16 @@ msgid "" "dictionaries::" msgstr "Python 允許你在串列、元組和字典的結尾加上逗號: ::" +#: ../../faq/design.rst:757 +msgid "" +"[1, 2, 3,]\n" +"('a', 'b', 'c',)\n" +"d = {\n" +" \"A\": [1, 5],\n" +" \"B\": [6, 7], # last trailing comma is optional but good style\n" +"}" +msgstr "" + #: ../../faq/design.rst:765 msgid "There are several reasons to allow this." msgstr "這有許多原因可被允許。" @@ -1266,6 +1470,16 @@ msgid "" "diagnose. For example::" msgstr "不小心遺漏了逗號會導致難以發現的錯誤,例如: ::" +#: ../../faq/design.rst:775 +msgid "" +"x = [\n" +" \"fee\",\n" +" \"fie\"\n" +" \"foo\",\n" +" \"fum\"\n" +"]" +msgstr "" + #: ../../faq/design.rst:782 msgid "" "This list looks like it has four elements, but it actually contains three: " diff --git a/faq/general.po b/faq/general.po index 2b07fdbcf0..725b5a7cb8 100644 --- a/faq/general.po +++ b/faq/general.po @@ -10,7 +10,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-05-26 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2023-06-23 16:56+0800\n" "Last-Translator: Matt Wang \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -807,6 +807,34 @@ msgstr "" "行直譯器的視窗,同時在另一個視窗中輸入他們的程式原始碼。如果他們不記得 list" "(串列)的 method(方法),他們可以像這樣做: ::" +#: ../../faq/general.rst:412 +msgid "" +">>> L = []\n" +">>> dir(L) \n" +"['__add__', '__class__', '__contains__', '__delattr__', '__delitem__',\n" +"'__dir__', '__doc__', '__eq__', '__format__', '__ge__',\n" +"'__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__',\n" +"'__imul__', '__init__', '__iter__', '__le__', '__len__', '__lt__',\n" +"'__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__',\n" +"'__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__',\n" +"'__sizeof__', '__str__', '__subclasshook__', 'append', 'clear',\n" +"'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove',\n" +"'reverse', 'sort']\n" +">>> [d for d in dir(L) if '__' not in d]\n" +"['append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', " +"'remove', 'reverse', 'sort']\n" +"\n" +">>> help(L.append)\n" +"Help on built-in function append:\n" +"\n" +"append(...)\n" +" L.append(object) -> None -- append object to end\n" +"\n" +">>> L.append(1)\n" +">>> L\n" +"[1]" +msgstr "" + #: ../../faq/general.rst:436 msgid "" "With the interpreter, documentation is never far from the student as they " diff --git a/faq/library.po b/faq/library.po index 1d43b77073..aadf4ca902 100644 --- a/faq/library.po +++ b/faq/library.po @@ -9,7 +9,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-07-20 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2023-02-18 13:22+0800\n" "Last-Translator: Adrian Liaw \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -95,6 +95,12 @@ msgid "" "these, type::" msgstr "用 C 編寫並與直譯器鏈接的模組;要獲得這些 list,請輸入: ::" +#: ../../faq/library.rst:42 +msgid "" +"import sys\n" +"print(sys.builtin_module_names)" +msgstr "" + #: ../../faq/library.rst:47 msgid "How do I make a Python script executable on Unix?" msgstr "我如何使 Python script 執行在 Unix?" @@ -125,6 +131,10 @@ msgid "" "to write ::" msgstr "第二個可以通過多種方式完成。最直接的方法是寫: ::" +#: ../../faq/library.rst:59 +msgid "#!/usr/local/bin/python" +msgstr "" + #: ../../faq/library.rst:61 #, fuzzy msgid "" @@ -144,6 +154,10 @@ msgstr "" "式。幾乎所有 Unix 變體都支援以下內容,假設 Python 直譯器位於使用者的 :envvar:" "`PATH` 上的目錄中: ::" +#: ../../faq/library.rst:69 +msgid "#!/usr/bin/env python" +msgstr "" + #: ../../faq/library.rst:71 #, fuzzy msgid "" @@ -164,6 +178,14 @@ msgstr "" "有時,使用者的環境太滿以至於:program:`/usr/bin/env` 程式失敗;或者根本就沒有 " "env 程式。在這種情況下,你可以嘗試以下 hack(由於 Alex Rezinsky):" +#: ../../faq/library.rst:79 +msgid "" +"#! /bin/sh\n" +"\"\"\":\"\n" +"exec python $0 ${1+\"$@\"}\n" +"\"\"\"" +msgstr "" + #: ../../faq/library.rst:86 #, fuzzy msgid "" @@ -173,6 +195,10 @@ msgstr "" "次要缺點是這定義了腳本的 __doc__ 字串。但是,你可以通過新增來解決這個問" "題: ::" +#: ../../faq/library.rst:89 +msgid "__doc__ = \"\"\"...Whatever...\"\"\"" +msgstr "" + #: ../../faq/library.rst:94 msgid "Is there a curses/termcap package for Python?" msgstr "是否有適用於 Python 的 curses/termcap 套件?" @@ -228,11 +254,21 @@ msgid "" "wrong argument list. It is called as ::" msgstr "最常見的問題是信號處理程式是用錯誤的引數列表聲明的。它被稱為: ::" +#: ../../faq/library.rst:123 +msgid "handler(signum, frame)" +msgstr "" + #: ../../faq/library.rst:125 #, fuzzy msgid "so it should be declared with two parameters::" msgstr "所以它應該用兩個參數聲明: ::" +#: ../../faq/library.rst:127 +msgid "" +"def handler(signum, frame):\n" +" ..." +msgstr "" + #: ../../faq/library.rst:132 msgid "Common tasks" msgstr "常見課題" @@ -281,6 +317,12 @@ msgstr "" msgid "The \"global main logic\" of your program may be as simple as ::" msgstr "你程式的「全局主邏輯」可能像一樣簡單: ::" +#: ../../faq/library.rst:154 +msgid "" +"if __name__ == \"__main__\":\n" +" main_logic()" +msgstr "" + #: ../../faq/library.rst:157 #, fuzzy msgid "at the bottom of the main module of your program." @@ -311,6 +353,12 @@ msgid "" "may include a self-test of the module. ::" msgstr "不打算成為程式主要模組的 \"支援模組\" 可能包括模組的自檢: ::" +#: ../../faq/library.rst:170 +msgid "" +"if __name__ == \"__main__\":\n" +" self_test()" +msgstr "" + #: ../../faq/library.rst:173 #, fuzzy msgid "" @@ -391,6 +439,21 @@ msgid "" msgstr "" "一個簡單的修復方法是在程式末尾新增一個足夠長的睡眠,讓所有執行緒都完成: ::" +#: ../../faq/library.rst:253 +msgid "" +"import threading, time\n" +"\n" +"def thread_task(name, n):\n" +" for i in range(n):\n" +" print(name, i)\n" +"\n" +"for i in range(10):\n" +" T = threading.Thread(target=thread_task, args=(str(i), i))\n" +" T.start()\n" +"\n" +"time.sleep(10) # <---------------------------!" +msgstr "" + #: ../../faq/library.rst:265 #, fuzzy msgid "" @@ -407,6 +470,20 @@ msgstr "" msgid "A simple fix is to add a tiny sleep to the start of the run function::" msgstr "一個簡單的修復方法是在運行函式的開頭新增一個小睡眠: ::" +#: ../../faq/library.rst:271 +msgid "" +"def thread_task(name, n):\n" +" time.sleep(0.001) # <--------------------!\n" +" for i in range(n):\n" +" print(name, i)\n" +"\n" +"for i in range(10):\n" +" T = threading.Thread(target=thread_task, args=(str(i), i))\n" +" T.start()\n" +"\n" +"time.sleep(10)" +msgstr "" + #: ../../faq/library.rst:282 #, fuzzy msgid "" @@ -454,11 +531,67 @@ msgstr "" msgid "Here's a trivial example::" msgstr "這是一個簡單的例子: ::" +#: ../../faq/library.rst:304 +msgid "" +"import threading, queue, time\n" +"\n" +"# The worker thread gets jobs off the queue. When the queue is empty, it\n" +"# assumes there will be no more work and exits.\n" +"# (Realistically workers will run until terminated.)\n" +"def worker():\n" +" print('Running worker')\n" +" time.sleep(0.1)\n" +" while True:\n" +" try:\n" +" arg = q.get(block=False)\n" +" except queue.Empty:\n" +" print('Worker', threading.current_thread(), end=' ')\n" +" print('queue empty')\n" +" break\n" +" else:\n" +" print('Worker', threading.current_thread(), end=' ')\n" +" print('running with argument', arg)\n" +" time.sleep(0.5)\n" +"\n" +"# Create queue\n" +"q = queue.Queue()\n" +"\n" +"# Start a pool of 5 workers\n" +"for i in range(5):\n" +" t = threading.Thread(target=worker, name='worker %i' % (i+1))\n" +" t.start()\n" +"\n" +"# Begin adding work to the queue\n" +"for i in range(50):\n" +" q.put(i)\n" +"\n" +"# Give threads time to run\n" +"print('Main thread sleeping')\n" +"time.sleep(5)" +msgstr "" + #: ../../faq/library.rst:340 #, fuzzy msgid "When run, this will produce the following output:" msgstr "運行時,這將產生以下輸出:" +#: ../../faq/library.rst:342 +msgid "" +"Running worker\n" +"Running worker\n" +"Running worker\n" +"Running worker\n" +"Running worker\n" +"Main thread sleeping\n" +"Worker running with argument 0\n" +"Worker running with argument 1\n" +"Worker running with argument 2\n" +"Worker running with argument 3\n" +"Worker running with argument 4\n" +"Worker running with argument 5\n" +"..." +msgstr "" + #: ../../faq/library.rst:358 #, fuzzy msgid "" @@ -510,11 +643,34 @@ msgstr "" "例如,以下操作都是原子的(L、L1、L2 是列表,D、D1、D2 是字典,x、y 是物件," "i、j 是整數): ::" +#: ../../faq/library.rst:380 +msgid "" +"L.append(x)\n" +"L1.extend(L2)\n" +"x = L[i]\n" +"x = L.pop()\n" +"L1[i:j] = L2\n" +"L.sort()\n" +"x = y\n" +"x.field = y\n" +"D[x] = y\n" +"D1.update(D2)\n" +"D.keys()" +msgstr "" + #: ../../faq/library.rst:392 #, fuzzy msgid "These aren't::" msgstr "這些不是: ::" +#: ../../faq/library.rst:394 +msgid "" +"i = i+1\n" +"L.append(L[-1])\n" +"L[i] = L[j]\n" +"D[x] = D[x] + 1" +msgstr "" + #: ../../faq/library.rst:399 #, fuzzy msgid "" @@ -734,6 +890,15 @@ msgstr "" "例如,以下程式碼從一個檔案中以大端格式讀取兩個 2 位元組整數和一個 4 位元組整" "數: ::" +#: ../../faq/library.rst:506 +msgid "" +"import struct\n" +"\n" +"with open(filename, \"rb\") as f:\n" +" s = f.read(8)\n" +" x, y, z = struct.unpack(\">hhl\", s)" +msgstr "" + #: ../../faq/library.rst:512 #, fuzzy msgid "" @@ -851,6 +1016,13 @@ msgstr "" "要關閉這三個之一的底層 C 檔案描述器,你應該首先確定這是你真正想要做的(例如," "你可能會混淆試圖執行 I/O 的擴充模組)。如果是,使用 :func:`os.close`: ::" +#: ../../faq/library.rst:649 +msgid "" +"os.close(stdin.fileno())\n" +"os.close(stdout.fileno())\n" +"os.close(stderr.fileno())" +msgstr "" + #: ../../faq/library.rst:653 msgid "Or you can use the numeric constants 0, 1 and 2, respectively." msgstr "或者你可以分別使用數字常數 0、1 和 2。" @@ -909,6 +1081,22 @@ msgstr "" msgid "Yes. Here's a simple example that uses :mod:`urllib.request`::" msgstr "是的,這是一個 :mod:`urllib.request` 的簡單範例: ::" +#: ../../faq/library.rst:683 +msgid "" +"#!/usr/local/bin/python\n" +"\n" +"import urllib.request\n" +"\n" +"# build the query string\n" +"qs = \"First=Josephine&MI=Q&Last=Public\"\n" +"\n" +"# connect and send the server a path\n" +"req = urllib.request.urlopen('http://www.some-server.out-there'\n" +" '/cgi-bin/some-cgi-script', data=qs)\n" +"with req:\n" +" msg, hdrs = req.read(), req.info()" +msgstr "" + #: ../../faq/library.rst:696 #, fuzzy msgid "" @@ -919,6 +1107,13 @@ msgstr "" "請注意,通常對於百分比編碼的 POST 操作,查詢字串必須使用 :func:`urllib.parse." "urlencode` 引用。例如,發送 ``name=Guy Steele, Jr.``: ::" +#: ../../faq/library.rst:700 +msgid "" +">>> import urllib.parse\n" +">>> urllib.parse.urlencode({'name': 'Guy Steele, Jr.'})\n" +"'name=Guy+Steele%2C+Jr.'" +msgstr "" + #: ../../faq/library.rst:704 msgid ":ref:`urllib-howto` for extensive examples." msgstr ":ref:`urllib-howto` 內有大量範例。" @@ -953,6 +1148,26 @@ msgstr "" "這是一個使用它的非常簡單的交互式郵件發件人。此方法適用於任何支援 SMTP 偵聽器" "的主機。: ::" +#: ../../faq/library.rst:724 +msgid "" +"import sys, smtplib\n" +"\n" +"fromaddr = input(\"From: \")\n" +"toaddrs = input(\"To: \").split(',')\n" +"print(\"Enter message, end with ^D:\")\n" +"msg = ''\n" +"while True:\n" +" line = sys.stdin.readline()\n" +" if not line:\n" +" break\n" +" msg += line\n" +"\n" +"# The actual mail send\n" +"server = smtplib.SMTP('localhost')\n" +"server.sendmail(fromaddr, toaddrs, msg)\n" +"server.quit()" +msgstr "" + #: ../../faq/library.rst:741 #, fuzzy msgid "" @@ -965,6 +1180,22 @@ msgstr "" "時是 \"/usr/lib/sendmail\" ,有時是 \"/usr/sbin/sendmail\" 。 sendmail 手冊頁" "將幫助你。這是一些示例程式碼: ::" +#: ../../faq/library.rst:746 +msgid "" +"import os\n" +"\n" +"SENDMAIL = \"/usr/sbin/sendmail\" # sendmail location\n" +"p = os.popen(\"%s -t -i\" % SENDMAIL, \"w\")\n" +"p.write(\"To: receiver@example.com\\n\")\n" +"p.write(\"Subject: test\\n\")\n" +"p.write(\"\\n\") # blank line separating headers from body\n" +"p.write(\"Some text\\n\")\n" +"p.write(\"some more text\\n\")\n" +"sts = p.close()\n" +"if sts != 0:\n" +" print(\"Sendmail exit status\", sts)" +msgstr "" + #: ../../faq/library.rst:761 #, fuzzy msgid "How do I avoid blocking in the connect() method of a socket?" @@ -1082,6 +1313,12 @@ msgid "" "Usage is simple::" msgstr "標準模組 :mod:`random` 實作了一個隨機數生成器。用法很簡單: ::" +#: ../../faq/library.rst:825 +msgid "" +"import random\n" +"random.random()" +msgstr "" + #: ../../faq/library.rst:828 msgid "This returns a random floating-point number in the range [0, 1)." msgstr "這將回傳 [0, 1) 範圍內的隨機浮點數。" diff --git a/faq/programming.po b/faq/programming.po index 25f6c6964d..4ea04d4a38 100644 --- a/faq/programming.po +++ b/faq/programming.po @@ -10,7 +10,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-07-20 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2024-04-25 14:17+0800\n" "Last-Translator: KNChiu \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -361,6 +361,13 @@ msgid "" msgstr "" "假設你使用 for 循環來定義幾個不同的 lambda(甚至是普通函式),例如: ::" +#: ../../faq/programming.rst:213 +msgid "" +">>> squares = []\n" +">>> for x in range(5):\n" +"... squares.append(lambda: x**2)" +msgstr "" + #: ../../faq/programming.rst:217 #, fuzzy msgid "" @@ -373,6 +380,14 @@ msgstr "" "時,它們會分別回傳 ``0``、``1``、``4``、``9`` 和 ``16``。然而,當你實際嘗試" "時,你會發現它們都回傳 ``16``: ::" +#: ../../faq/programming.rst:222 +msgid "" +">>> squares[2]()\n" +"16\n" +">>> squares[4]()\n" +"16" +msgstr "" + #: ../../faq/programming.rst:227 #, fuzzy msgid "" @@ -387,6 +402,13 @@ msgstr "" "``4``,因此所有函式現在都回傳 ``4**2``,即 ``16``。你還可以透過更改 ``x`` 的" "值來驗證這一點,並查看 lambda 運算式的結果如何變化: ::" +#: ../../faq/programming.rst:233 +msgid "" +">>> x = 8\n" +">>> squares[2]()\n" +"64" +msgstr "" + #: ../../faq/programming.rst:237 #, fuzzy msgid "" @@ -396,6 +418,13 @@ msgstr "" "為了避免這種情況,你需要將值保存在 lambda 的局部變數中,這樣它們就不會依賴於" "全域 ``x`` 的值: ::" +#: ../../faq/programming.rst:240 +msgid "" +">>> squares = []\n" +">>> for x in range(5):\n" +"... squares.append(lambda n=x: n**2)" +msgstr "" + #: ../../faq/programming.rst:244 #, fuzzy msgid "" @@ -410,6 +439,14 @@ msgstr "" "lambda 中為 ``0`` ,在第二個中為 ``1`` ,在第三個中為 ``2`` ,依此類推。因此" "每個 lambda 現在將回傳正確的結果: ::" +#: ../../faq/programming.rst:250 +msgid "" +">>> squares[2]()\n" +"4\n" +">>> squares[4]()\n" +"16" +msgstr "" + #: ../../faq/programming.rst:255 msgid "" "Note that this behaviour is not peculiar to lambdas, but applies to regular " @@ -439,14 +476,31 @@ msgstr "" msgid "config.py::" msgstr "config.py: ::" +#: ../../faq/programming.rst:270 +msgid "x = 0 # Default value of the 'x' configuration setting" +msgstr "" + #: ../../faq/programming.rst:272 msgid "mod.py::" msgstr "mod.py: ::" +#: ../../faq/programming.rst:274 +msgid "" +"import config\n" +"config.x = 1" +msgstr "" + #: ../../faq/programming.rst:277 msgid "main.py::" msgstr "main.py: ::" +#: ../../faq/programming.rst:279 +msgid "" +"import config\n" +"import mod\n" +"print(config.x)" +msgstr "" + #: ../../faq/programming.rst:283 #, fuzzy msgid "" @@ -585,6 +639,14 @@ msgid "" "function::" msgstr "這種型別的錯誤通常會困擾新手程式員。考慮這個功能: ::" +#: ../../faq/programming.rst:342 +msgid "" +"def foo(mydict={}): # Danger: shared reference to one dict for all calls\n" +" ... compute something ...\n" +" mydict[key] = value\n" +" return mydict" +msgstr "" + #: ../../faq/programming.rst:347 #, fuzzy msgid "" @@ -630,10 +692,23 @@ msgstr "" "``None`` 作為預設值並在函式內部檢查參數是否為 ``None`` 並建立一個新的list/字" "典/無論是否是。例如,不要寫: ::" +#: ../../faq/programming.rst:365 +msgid "" +"def foo(mydict={}):\n" +" ..." +msgstr "" + #: ../../faq/programming.rst:368 msgid "but::" msgstr "但是: ::" +#: ../../faq/programming.rst:370 +msgid "" +"def foo(mydict=None):\n" +" if mydict is None:\n" +" mydict = {} # create a new dict for local namespace" +msgstr "" + #: ../../faq/programming.rst:374 #, fuzzy msgid "" @@ -647,6 +722,20 @@ msgstr "" "和每次呼叫該函式的結果值,並在再次請求相同的值時回傳快取的值。這稱為「記憶" "化」,可以像這樣實作: ::" +#: ../../faq/programming.rst:379 +msgid "" +"# Callers can only provide two parameters and optionally pass _cache by " +"keyword\n" +"def expensive(arg1, arg2, *, _cache={}):\n" +" if (arg1, arg2) in _cache:\n" +" return _cache[(arg1, arg2)]\n" +"\n" +" # Calculate the value\n" +" result = ... expensive computation ...\n" +" _cache[(arg1, arg2)] = result # Store result in the cache\n" +" return result" +msgstr "" + #: ../../faq/programming.rst:389 #, fuzzy msgid "" @@ -672,6 +761,15 @@ msgstr "" "置引數和作為字典的關鍵字引數。然後,你可以在使用 ``*`` 和 ``**`` 呼叫另一個函" "式時傳遞這些引數: ::" +#: ../../faq/programming.rst:401 +msgid "" +"def f(x, *args, **kwargs):\n" +" ...\n" +" kwargs['width'] = '14.3c'\n" +" ...\n" +" g(x, *args, **kwargs)" +msgstr "" + #: ../../faq/programming.rst:415 msgid "What is the difference between arguments and parameters?" msgstr "引數 (arguments) 和參數 (parameters) 有什麼區別?" @@ -689,6 +787,12 @@ msgstr "" "`\\ 是呼叫函式時實際傳遞給函式的值。參數定義函式可以接受的\\ :term:" "引數種類 `。例如,給定函式定義: ::" +#: ../../faq/programming.rst:423 +msgid "" +"def func(foo, bar=None, **kwargs):\n" +" pass" +msgstr "" + #: ../../faq/programming.rst:426 msgid "" "*foo*, *bar* and *kwargs* are parameters of ``func``. However, when calling " @@ -697,6 +801,10 @@ msgstr "" "*foo*、*bar* 和 *kwargs* 是 ``func`` 的參數。然而,當呼叫 ``func`` 時,例" "如: ::" +#: ../../faq/programming.rst:429 +msgid "func(42, bar=314, extra=somevar)" +msgstr "" + #: ../../faq/programming.rst:431 msgid "the values ``42``, ``314``, and ``somevar`` are arguments." msgstr "``42`` 、 ``314`` 和 ``somevar`` 是引數。" @@ -709,6 +817,17 @@ msgstr "為什麼更改 list 'y' 也會更改 list 'x'?" msgid "If you wrote code like::" msgstr "如果你寫了像這樣的程式碼: ::" +#: ../../faq/programming.rst:439 +msgid "" +">>> x = []\n" +">>> y = x\n" +">>> y.append(10)\n" +">>> y\n" +"[10]\n" +">>> x\n" +"[10]" +msgstr "" + #: ../../faq/programming.rst:447 msgid "" "you might be wondering why appending an element to ``y`` changed ``x`` too." @@ -750,6 +869,17 @@ msgstr "" msgid "If we instead assign an immutable object to ``x``::" msgstr "如果我們改為將不可變物件分配給 ``x``: ::" +#: ../../faq/programming.rst:463 +msgid "" +">>> x = 5 # ints are immutable\n" +">>> y = x\n" +">>> x = x + 1 # 5 can't be mutated, we are creating a new object here\n" +">>> x\n" +"6\n" +">>> y\n" +"5" +msgstr "" + #: ../../faq/programming.rst:471 #, fuzzy msgid "" @@ -858,6 +988,18 @@ msgstr "" msgid "By returning a tuple of the results::" msgstr "透過回傳結果的元組: ::" +#: ../../faq/programming.rst:519 +msgid "" +">>> def func1(a, b):\n" +"... a = 'new-value' # a and b are local names\n" +"... b = b + 1 # assigned to new objects\n" +"... return a, b # return new values\n" +"...\n" +">>> x, y = 'old-value', 99\n" +">>> func1(x, y)\n" +"('new-value', 100)" +msgstr "" + #: ../../faq/programming.rst:528 #, fuzzy msgid "This is almost always the clearest solution." @@ -874,16 +1016,57 @@ msgstr "透過使用全域變數。這不是執行緒安全的,不推薦。" msgid "By passing a mutable (changeable in-place) object::" msgstr "透過傳遞一個可變的(原地可變的)物件: ::" +#: ../../faq/programming.rst:534 +msgid "" +">>> def func2(a):\n" +"... a[0] = 'new-value' # 'a' references a mutable list\n" +"... a[1] = a[1] + 1 # changes a shared object\n" +"...\n" +">>> args = ['old-value', 99]\n" +">>> func2(args)\n" +">>> args\n" +"['new-value', 100]" +msgstr "" + #: ../../faq/programming.rst:543 #, fuzzy msgid "By passing in a dictionary that gets mutated::" msgstr "透過傳入一個發生變異的字典: ::" +#: ../../faq/programming.rst:545 +msgid "" +">>> def func3(args):\n" +"... args['a'] = 'new-value' # args is a mutable dictionary\n" +"... args['b'] = args['b'] + 1 # change it in-place\n" +"...\n" +">>> args = {'a': 'old-value', 'b': 99}\n" +">>> func3(args)\n" +">>> args\n" +"{'a': 'new-value', 'b': 100}" +msgstr "" + #: ../../faq/programming.rst:554 #, fuzzy msgid "Or bundle up values in a class instance::" msgstr "或者在類別實例中捆綁值: ::" +#: ../../faq/programming.rst:556 +msgid "" +">>> class Namespace:\n" +"... def __init__(self, /, **args):\n" +"... for key, value in args.items():\n" +"... setattr(self, key, value)\n" +"...\n" +">>> def func4(args):\n" +"... args.a = 'new-value' # args is a mutable Namespace\n" +"... args.b = args.b + 1 # change object in-place\n" +"...\n" +">>> args = Namespace(a='old-value', b=99)\n" +">>> func4(args)\n" +">>> vars(args)\n" +"{'a': 'new-value', 'b': 100}" +msgstr "" + #: ../../faq/programming.rst:571 #, fuzzy msgid "There's almost never a good reason to get this complicated." @@ -910,15 +1093,38 @@ msgstr "" "你有兩種選擇:可以使用巢狀作用域,也可以使用可呼叫物件。例如,假設你想定義 " "linear(a,b) ,它回傳一個計算值 a*x+b 的函式 f(x) 。使用嵌套範圍: ::" +#: ../../faq/programming.rst:583 +msgid "" +"def linear(a, b):\n" +" def result(x):\n" +" return a * x + b\n" +" return result" +msgstr "" + #: ../../faq/programming.rst:588 msgid "Or using a callable object::" msgstr "或者使用可呼叫物件: ::" +#: ../../faq/programming.rst:590 +msgid "" +"class linear:\n" +"\n" +" def __init__(self, a, b):\n" +" self.a, self.b = a, b\n" +"\n" +" def __call__(self, x):\n" +" return self.a * x + self.b" +msgstr "" + #: ../../faq/programming.rst:598 #, fuzzy msgid "In both cases, ::" msgstr "在這兩種情況下: ::" +#: ../../faq/programming.rst:600 +msgid "taxes = linear(0.3, 2)" +msgstr "" + #: ../../faq/programming.rst:602 #, fuzzy msgid "gives a callable object where ``taxes(10e6) == 0.3 * 10e6 + 2``." @@ -934,10 +1140,37 @@ msgstr "" "可呼叫物件方法的缺點是它有點慢並且導致程式碼稍長。但是,請注意,可呼叫集合可" "以透過繼承共享它們的簽名: ::" +#: ../../faq/programming.rst:608 +msgid "" +"class exponential(linear):\n" +" # __init__ inherited\n" +" def __call__(self, x):\n" +" return self.a * (x ** self.b)" +msgstr "" + #: ../../faq/programming.rst:613 msgid "Object can encapsulate state for several methods::" msgstr "物件可以封裝多個方法的狀態: ::" +#: ../../faq/programming.rst:615 +msgid "" +"class counter:\n" +"\n" +" value = 0\n" +"\n" +" def set(self, x):\n" +" self.value = x\n" +"\n" +" def up(self):\n" +" self.value = self.value + 1\n" +"\n" +" def down(self):\n" +" self.value = self.value - 1\n" +"\n" +"count = counter()\n" +"inc, dec, reset = count.up, count.down, count.set" +msgstr "" + #: ../../faq/programming.rst:631 msgid "" "Here ``inc()``, ``dec()`` and ``reset()`` act like functions which share the " @@ -965,10 +1198,18 @@ msgid "" "copy` method::" msgstr "可以更輕鬆地複製某些物件。字典有一個 :meth:`~dict.copy` 方法: ::" +#: ../../faq/programming.rst:644 +msgid "newdict = olddict.copy()" +msgstr "" + #: ../../faq/programming.rst:646 msgid "Sequences can be copied by slicing::" msgstr "序列可以透過切片 (slicing) 複製: ::" +#: ../../faq/programming.rst:648 +msgid "new_l = l[:]" +msgstr "" + #: ../../faq/programming.rst:652 msgid "How can I find the methods or attributes of an object?" msgstr "如何找到物件的方法或屬性?" @@ -999,6 +1240,20 @@ msgstr "" "``def`` 和 ``class`` 陳述式也是如此,但在那種情況下,值是可呼叫的。考慮以下程" "式碼: ::" +#: ../../faq/programming.rst:667 +msgid "" +">>> class A:\n" +"... pass\n" +"...\n" +">>> B = A\n" +">>> a = B()\n" +">>> b = a\n" +">>> print(b)\n" +"<__main__.A object at 0x16D07CC>\n" +">>> print(a)\n" +"<__main__.A object at 0x16D07CC>" +msgstr "" + #: ../../faq/programming.rst:678 #, fuzzy msgid "" @@ -1057,6 +1312,12 @@ msgstr "逗號運算子的優先級是怎麼回事?" msgid "Comma is not an operator in Python. Consider this session::" msgstr "逗號不是 Python 中的運算子。考慮這個會話: ::" +#: ../../faq/programming.rst:705 +msgid "" +">>> \"a\" in \"b\", \"a\"\n" +"(False, 'a')" +msgstr "" + #: ../../faq/programming.rst:708 #, fuzzy msgid "" @@ -1066,11 +1327,19 @@ msgstr "" "由於逗號不是運算子,而是運算式之間的分隔符,因此上面的計算就像你輸入的那" "樣: ::" +#: ../../faq/programming.rst:711 +msgid "(\"a\" in \"b\"), \"a\"" +msgstr "" + #: ../../faq/programming.rst:713 #, fuzzy msgid "not::" msgstr "不是: ::" +#: ../../faq/programming.rst:715 +msgid "\"a\" in (\"b\", \"a\")" +msgstr "" + #: ../../faq/programming.rst:717 #, fuzzy msgid "" @@ -1089,6 +1358,14 @@ msgstr "是否有等效於 C 的 \"?:\" 三元運算子?" msgid "Yes, there is. The syntax is as follows::" msgstr "有的,語法如下: ::" +#: ../../faq/programming.rst:726 +msgid "" +"[on_true] if [expression] else [on_false]\n" +"\n" +"x, y = 50, 25\n" +"small = x if x < y else y" +msgstr "" + #: ../../faq/programming.rst:731 #, fuzzy msgid "" @@ -1097,6 +1374,10 @@ msgid "" msgstr "" "在 Python 2.5 中引入此語法之前,一個常見的習慣用法是使用邏輯運算子: ::" +#: ../../faq/programming.rst:734 +msgid "[expression] and [on_true] or [on_false]" +msgstr "" + #: ../../faq/programming.rst:736 #, fuzzy msgid "" @@ -1122,6 +1403,34 @@ msgstr "" "是的。通常這是透過在 :keyword:`!lambda` 中嵌套 :keyword:`lambda` 來完成的。請" "參閱以下三個示例,稍微改編自 Ulf Bartelt: ::" +#: ../../faq/programming.rst:747 +msgid "" +"from functools import reduce\n" +"\n" +"# Primes < 1000\n" +"print(list(filter(None,map(lambda y:y*reduce(lambda x,y:x*y!=0,\n" +"map(lambda x,y=y:y%x,range(2,int(pow(y,0.5)+1))),1),range(2,1000)))))\n" +"\n" +"# First 10 Fibonacci numbers\n" +"print(list(map(lambda x,f=lambda x,f:(f(x-1,f)+f(x-2,f)) if x>1 else 1:\n" +"f(x,f), range(10))))\n" +"\n" +"# Mandelbrot set\n" +"print((lambda Ru,Ro,Iu,Io,IM,Sx,Sy:reduce(lambda x,y:x+'\\n'+y,map(lambda " +"y,\n" +"Iu=Iu,Io=Io,Ru=Ru,Ro=Ro,Sy=Sy,L=lambda yc,Iu=Iu,Io=Io,Ru=Ru,Ro=Ro,i=IM,\n" +"Sx=Sx,Sy=Sy:reduce(lambda x,y:x+y,map(lambda x,xc=Ru,yc=yc,Ru=Ru,Ro=Ro,\n" +"i=i,Sx=Sx,F=lambda xc,yc,x,y,k,f=lambda xc,yc,x,y,k,f:(k<=0)or (x*x+y*y\n" +">=4.0) or 1+f(xc,yc,x*x-y*y+xc,2.0*x*y+yc,k-1,f):f(xc,yc,x,y,k,f):chr(\n" +"64+F(Ru+x*(Ro-Ru)/Sx,yc,0,0,i)),range(Sx))):L(Iu+y*(Io-Iu)/Sy),range(Sy\n" +"))))(-2.1, 0.7, -1.2, 1.2, 30, 80, 24))\n" +"# \\___ ___/ \\___ ___/ | | |__ lines on screen\n" +"# V V | |______ columns on screen\n" +"# | | |__________ maximum of \"iterations\"\n" +"# | |_________________ range on y axis\n" +"# |____________________________ range on x axis" +msgstr "" + #: ../../faq/programming.rst:771 msgid "Don't try this at home, kids!" msgstr "孩子們,不要在家裡嘗試這個!" @@ -1145,6 +1454,15 @@ msgstr "" "的參數。在呼叫接受僅位置參數的函式時,參數僅根據其位置映射到參數。例如,:" "func:`divmod` 是一個只接受位置參數的函式。它的文檔看起來像這樣: ::" +#: ../../faq/programming.rst:786 +msgid "" +">>> help(divmod)\n" +"Help on built-in function divmod in module builtins:\n" +"\n" +"divmod(x, y, /)\n" +" Return the tuple (x//y, x%y). Invariant: div*y + mod == x." +msgstr "" + #: ../../faq/programming.rst:792 #, fuzzy msgid "" @@ -1155,6 +1473,14 @@ msgstr "" "參數list末尾的斜杠表示兩個參數都是位置參數。因此,使用關鍵字引數呼叫 :func:" "`divmod` 會導致錯誤: ::" +#: ../../faq/programming.rst:796 +msgid "" +">>> divmod(x=3, y=4)\n" +"Traceback (most recent call last):\n" +" File \"\", line 1, in \n" +"TypeError: divmod() takes no keyword arguments" +msgstr "" + #: ../../faq/programming.rst:803 msgid "Numbers and strings" msgstr "數字和字串" @@ -1173,6 +1499,13 @@ msgstr "" "要指定八進位數字,請在八進位值前面加上零,然後是小寫或大寫的 \"o\" 。例如,要" "將變數 \"a\" 設定為八進位值 \"10\" (十進位為 8),請鍵入: ::" +#: ../../faq/programming.rst:812 +msgid "" +">>> a = 0o10\n" +">>> a\n" +"8" +msgstr "" + #: ../../faq/programming.rst:816 #, fuzzy msgid "" @@ -1183,6 +1516,16 @@ msgstr "" "十六進位也很容易。只需在十六進位數前面加上一個零,然後是一個小寫或大寫的 " "\"x\" 。可以用小寫或大寫形式指定十六進位數字。例如,在 Python 直譯器中: ::" +#: ../../faq/programming.rst:820 +msgid "" +">>> a = 0xa5\n" +">>> a\n" +"165\n" +">>> b = 0XB2\n" +">>> b\n" +"178" +msgstr "" + #: ../../faq/programming.rst:829 msgid "Why does -22 // 10 return -3?" msgstr "為什麼 -22 // 10 回傳 -3?" @@ -1196,6 +1539,10 @@ msgstr "" "它主要是由希望 ``i % j`` 與 ``j`` 具有相同的符號驅動的。如果你想要那個,也想" "要: ::" +#: ../../faq/programming.rst:834 +msgid "i == (i // j) * j + (i % j)" +msgstr "" + #: ../../faq/programming.rst:836 msgid "" "then integer division has to return the floor. C also requires that " @@ -1233,6 +1580,15 @@ msgstr "" "嘗試以正常方式查詢 ``int`` 文字屬性會給出一個 SyntaxError ,因為句點被視為小" "數點: ::" +#: ../../faq/programming.rst:853 +msgid "" +">>> 1.__class__\n" +" File \"\", line 1\n" +" 1.__class__\n" +" ^\n" +"SyntaxError: invalid decimal literal" +msgstr "" + #: ../../faq/programming.rst:859 #, fuzzy msgid "" @@ -1333,6 +1689,31 @@ msgstr "" "造一個新字串。但是,如果你需要一個能夠修改原地 unicode 資料的物件,請嘗試使" "用 :class:`io.StringIO` 物件或 :mod:`array` 模組: ::" +#: ../../faq/programming.rst:914 +msgid "" +">>> import io\n" +">>> s = \"Hello, world\"\n" +">>> sio = io.StringIO(s)\n" +">>> sio.getvalue()\n" +"'Hello, world'\n" +">>> sio.seek(7)\n" +"7\n" +">>> sio.write(\"there!\")\n" +"6\n" +">>> sio.getvalue()\n" +"'Hello, there!'\n" +"\n" +">>> import array\n" +">>> a = array.array('u', s)\n" +">>> print(a)\n" +"array('u', 'Hello, world')\n" +">>> a[0] = 'y'\n" +">>> print(a)\n" +"array('u', 'yello, world')\n" +">>> a.tounicode()\n" +"'yello, world'" +msgstr "" + #: ../../faq/programming.rst:938 #, fuzzy msgid "How do I use strings to call functions/methods?" @@ -1354,11 +1735,30 @@ msgstr "" "最好的方法是使用將字串映射到函式的字典。這種技術的主要優點是字串不需要與函式" "名稱相匹配。這也是用於模擬案例構造的主要技術: ::" +#: ../../faq/programming.rst:947 +msgid "" +"def a():\n" +" pass\n" +"\n" +"def b():\n" +" pass\n" +"\n" +"dispatch = {'go': a, 'stop': b} # Note lack of parens for funcs\n" +"\n" +"dispatch[get_input()]() # Note trailing parens to call function" +msgstr "" + #: ../../faq/programming.rst:957 #, fuzzy msgid "Use the built-in function :func:`getattr`::" msgstr "使用內置函式 :func:`getattr`: ::" +#: ../../faq/programming.rst:959 +msgid "" +"import foo\n" +"getattr(foo, 'bar')()" +msgstr "" + #: ../../faq/programming.rst:962 #, fuzzy msgid "" @@ -1371,11 +1771,35 @@ msgstr "請注意:func:`getattr` 適用於任何物件,包括類別、類別 msgid "This is used in several places in the standard library, like this::" msgstr "這在標準函式庫中的幾個地方使用,如下所示: ::" +#: ../../faq/programming.rst:967 +msgid "" +"class Foo:\n" +" def do_foo(self):\n" +" ...\n" +"\n" +" def do_bar(self):\n" +" ...\n" +"\n" +"f = getattr(foo_instance, 'do_' + opname)\n" +"f()" +msgstr "" + #: ../../faq/programming.rst:978 #, fuzzy msgid "Use :func:`locals` to resolve the function name::" msgstr "使用 :func:`locals` 解析函式名: ::" +#: ../../faq/programming.rst:980 +msgid "" +"def myFunc():\n" +" print(\"hello\")\n" +"\n" +"fname = \"myFunc\"\n" +"\n" +"f = locals()[fname]\n" +"f()" +msgstr "" + #: ../../faq/programming.rst:990 #, fuzzy msgid "" @@ -1392,6 +1816,15 @@ msgid "" "removed::" msgstr "" +#: ../../faq/programming.rst:998 +msgid "" +">>> lines = (\"line 1 \\r\\n\"\n" +"... \"\\r\\n\"\n" +"... \"\\r\\n\")\n" +">>> lines.rstrip(\"\\n\\r\")\n" +"'line 1 '" +msgstr "" + #: ../../faq/programming.rst:1004 #, fuzzy msgid "" @@ -1454,6 +1887,15 @@ msgid "" "string's quote::" msgstr "以奇數個反斜杠結尾的原始字串將轉義字串的引號: ::" +#: ../../faq/programming.rst:1036 +msgid "" +">>> r'C:\\this\\will\\not\\work\\'\n" +" File \"\", line 1\n" +" r'C:\\this\\will\\not\\work\\'\n" +" ^\n" +"SyntaxError: unterminated string literal (detected at line 1)" +msgstr "" + #: ../../faq/programming.rst:1042 #, fuzzy msgid "" @@ -1461,6 +1903,12 @@ msgid "" "double the backslashes::" msgstr "有幾種解決方法。一種是使用常規字串並加倍反斜杠: ::" +#: ../../faq/programming.rst:1045 +msgid "" +">>> 'C:\\\\this\\\\will\\\\work\\\\'\n" +"'C:\\\\this\\\\will\\\\work\\\\'" +msgstr "" + #: ../../faq/programming.rst:1048 #, fuzzy msgid "" @@ -1468,6 +1916,12 @@ msgid "" "to the raw string::" msgstr "另一種方法是將包含轉義反斜杠的常規字串連接到原始字串: ::" +#: ../../faq/programming.rst:1051 +msgid "" +">>> r'C:\\this\\will\\work' '\\\\'\n" +"'C:\\\\this\\\\will\\\\work\\\\'" +msgstr "" + #: ../../faq/programming.rst:1054 #, fuzzy msgid "" @@ -1475,6 +1929,12 @@ msgid "" "Windows::" msgstr "也可以使用 :func:`os.path.join` 在 Windows 上附加反斜杠: ::" +#: ../../faq/programming.rst:1056 +msgid "" +">>> os.path.join(r'C:\\this\\will\\work', '')\n" +"'C:\\\\this\\\\will\\\\work\\\\'" +msgstr "" + #: ../../faq/programming.rst:1059 #, fuzzy msgid "" @@ -1486,6 +1946,12 @@ msgstr "" "請注意,雖然為了確定原始字串的結束位置而使用反斜杠「跳脫」引號,但在解釋原始" "字串的值時不會發生轉義。也就是說,反斜杠仍然存在於原始字串的值中: ::" +#: ../../faq/programming.rst:1064 +msgid "" +">>> r'backslash\\'preserved'\n" +"\"backslash\\\\'preserved\"" +msgstr "" + #: ../../faq/programming.rst:1067 #, fuzzy msgid "Also see the specification in the :ref:`language reference `." @@ -1660,6 +2126,14 @@ msgstr "" "要累積許多 :class:`str` 物件,推薦的習慣用法是將它們放入list中並在末尾呼叫 :" "meth:`str.join`: ::" +#: ../../faq/programming.rst:1141 +msgid "" +"chunks = []\n" +"for s in my_strings:\n" +" chunks.append(s)\n" +"result = ''.join(chunks)" +msgstr "" + #: ../../faq/programming.rst:1146 #, fuzzy msgid "(another reasonably efficient idiom is to use :class:`io.StringIO`)" @@ -1675,6 +2149,13 @@ msgstr "" "要累積許多 :class:`bytes` 物件,推薦的習慣用法是使用原地連接(``+=`` 運算子)" "擴充一個 :class:`bytearray` 物件: ::" +#: ../../faq/programming.rst:1151 +msgid "" +"result = bytearray()\n" +"for b in my_bytes_objects:\n" +" result += b" +msgstr "" + #: ../../faq/programming.rst:1157 #, fuzzy msgid "Sequences (Tuples/Lists)" @@ -1757,6 +2238,12 @@ msgstr "如何以相反的順序疊代序列?" msgid "Use the :func:`reversed` built-in function::" msgstr "使用 :func:`reversed` 內置函式: ::" +#: ../../faq/programming.rst:1194 +msgid "" +"for x in reversed(sequence):\n" +" ... # do something with x ..." +msgstr "" + #: ../../faq/programming.rst:1197 #, fuzzy msgid "" @@ -1787,6 +2274,18 @@ msgstr "" "如果你不介意重新排序list,請對其進行排序,然後從list末尾開始掃描,同時刪除重" "複項: ::" +#: ../../faq/programming.rst:1211 +msgid "" +"if mylist:\n" +" mylist.sort()\n" +" last = mylist[-1]\n" +" for i in range(len(mylist)-2, -1, -1):\n" +" if last == mylist[i]:\n" +" del mylist[i]\n" +" else:\n" +" last = mylist[i]" +msgstr "" + #: ../../faq/programming.rst:1220 #, fuzzy msgid "" @@ -1796,6 +2295,10 @@ msgstr "" "如果list的所有元素都可以用作集合鍵(即它們都是 :term:`hashable`),這通常會更" "快: ::" +#: ../../faq/programming.rst:1223 +msgid "mylist = list(set(mylist))" +msgstr "" + #: ../../faq/programming.rst:1225 #, fuzzy msgid "" @@ -1819,6 +2322,13 @@ msgstr "" "與刪除重複項一樣,使用刪除條件顯式反向疊代是一種可能性。但是,透過隱式或顯式" "前向疊代使用切片替換更容易和更快。這是三種變體: ::" +#: ../../faq/programming.rst:1237 +msgid "" +"mylist[:] = filter(keep_function, mylist)\n" +"mylist[:] = (x for x in mylist if keep_condition)\n" +"mylist[:] = [x for x in mylist if keep_condition]" +msgstr "" + #: ../../faq/programming.rst:1241 #, fuzzy msgid "The list comprehension may be fastest." @@ -1834,6 +2344,10 @@ msgstr "你如何在 Python 中建立數組?" msgid "Use a list::" msgstr "使用 list: ::" +#: ../../faq/programming.rst:1249 +msgid "[\"this\", 1, \"is\", \"an\", \"array\"]" +msgstr "" + #: ../../faq/programming.rst:1251 #, fuzzy msgid "" @@ -1862,6 +2376,10 @@ msgid "" "To get Lisp-style linked lists, you can emulate *cons cells* using tuples::" msgstr "要獲得 Lisp 風格的鍊錶,你可以使用元組模擬 *cons cells*: ::" +#: ../../faq/programming.rst:1262 +msgid "lisp_list = (\"like\", (\"this\", (\"example\", None) ) )" +msgstr "" + #: ../../faq/programming.rst:1264 #, fuzzy msgid "" @@ -1884,16 +2402,33 @@ msgstr "如何建立多維list?" msgid "You probably tried to make a multidimensional array like this::" msgstr "你可能嘗試製作這樣的多維數組: ::" +#: ../../faq/programming.rst:1277 +msgid ">>> A = [[None] * 2] * 3" +msgstr "" + #: ../../faq/programming.rst:1279 #, fuzzy msgid "This looks correct if you print it:" msgstr "如果你印出它,這看起來是正確的:" +#: ../../faq/programming.rst:1285 +msgid "" +">>> A\n" +"[[None, None], [None, None], [None, None]]" +msgstr "" + #: ../../faq/programming.rst:1290 #, fuzzy msgid "But when you assign a value, it shows up in multiple places:" msgstr "但是當你分配一個值時,它會出現在多個地方:" +#: ../../faq/programming.rst:1296 +msgid "" +">>> A[0][0] = 5\n" +">>> A\n" +"[[5, None], [5, None], [5, None]]" +msgstr "" + #: ../../faq/programming.rst:1302 #, fuzzy msgid "" @@ -1913,6 +2448,13 @@ msgid "" "then fill in each element with a newly created list::" msgstr "建議的方法是先建立所需長度的list,然後用新建立的list填充每個元素: ::" +#: ../../faq/programming.rst:1310 +msgid "" +"A = [None] * 3\n" +"for i in range(3):\n" +" A[i] = [None] * 2" +msgstr "" + #: ../../faq/programming.rst:1314 #, fuzzy msgid "" @@ -1921,6 +2463,12 @@ msgid "" msgstr "" "這會生成一個包含 3 個長度為 2 的不同list的list。你還可以使用list推導: ::" +#: ../../faq/programming.rst:1317 +msgid "" +"w, h = 2, 3\n" +"A = [[None] * w for i in range(h)]" +msgstr "" + #: ../../faq/programming.rst:1320 #, fuzzy msgid "" @@ -1944,6 +2492,13 @@ msgstr "" "呼叫一個方法或函式並累積回傳值是一個list,一個 :term:`list comprehension` 是" "一個優雅的解決方案: ::" +#: ../../faq/programming.rst:1330 +msgid "" +"result = [obj.method() for obj in mylist]\n" +"\n" +"result = [function(obj) for obj in mylist]" +msgstr "" + #: ../../faq/programming.rst:1334 #, fuzzy msgid "" @@ -1951,6 +2506,15 @@ msgid "" "plain :keyword:`for` loop will suffice::" msgstr "要只運行方法或函式而不保存回傳值,一個普通的 for 循環就足夠了: ::" +#: ../../faq/programming.rst:1337 +msgid "" +"for obj in mylist:\n" +" obj.method()\n" +"\n" +"for obj in mylist:\n" +" function(obj)" +msgstr "" + #: ../../faq/programming.rst:1346 #, fuzzy msgid "" @@ -1982,6 +2546,15 @@ msgstr "" msgid "If you wrote::" msgstr "如果你寫了: ::" +#: ../../faq/programming.rst:1358 +msgid "" +">>> a_tuple = (1, 2)\n" +">>> a_tuple[0] += 1\n" +"Traceback (most recent call last):\n" +" ...\n" +"TypeError: 'tuple' object does not support item assignment" +msgstr "" + #: ../../faq/programming.rst:1364 #, fuzzy msgid "" @@ -2002,6 +2575,15 @@ msgid "" "approximately this::" msgstr "在幕後,這個擴充賦值陳述式所做的大致是這樣的: ::" +#: ../../faq/programming.rst:1373 +msgid "" +">>> result = a_tuple[0] + 1\n" +">>> a_tuple[0] = result\n" +"Traceback (most recent call last):\n" +" ...\n" +"TypeError: 'tuple' object does not support item assignment" +msgstr "" + #: ../../faq/programming.rst:1379 #, fuzzy msgid "" @@ -2014,6 +2596,15 @@ msgstr "產生錯誤的是操作的賦值部分,因為元組是不可變的。 msgid "When you write something like::" msgstr "當你寫這樣的東西時: ::" +#: ../../faq/programming.rst:1384 +msgid "" +">>> a_tuple = (['foo'], 'bar')\n" +">>> a_tuple[0] += ['item']\n" +"Traceback (most recent call last):\n" +" ...\n" +"TypeError: 'tuple' object does not support item assignment" +msgstr "" + #: ../../faq/programming.rst:1390 #, fuzzy msgid "" @@ -2021,6 +2612,12 @@ msgid "" "that even though there was an error, the append worked::" msgstr "這個例外有點令人驚訝,更令人驚訝的是即使出現錯誤,追加仍然有效: ::" +#: ../../faq/programming.rst:1393 +msgid "" +">>> a_tuple[0]\n" +"['foo', 'item']" +msgstr "" + #: ../../faq/programming.rst:1396 #, fuzzy msgid "" @@ -2037,10 +2634,24 @@ msgstr "" "呼叫 :meth:`!extend` 並回傳list。這就是為什麼我們說對於list,``+=`` 是 :meth:" "`!list.extend` 的「簡寫」: ::" +#: ../../faq/programming.rst:1404 +msgid "" +">>> a_list = []\n" +">>> a_list += [1]\n" +">>> a_list\n" +"[1]" +msgstr "" + #: ../../faq/programming.rst:1409 msgid "This is equivalent to::" msgstr "這等價於: ::" +#: ../../faq/programming.rst:1411 +msgid "" +">>> result = a_list.__iadd__([1])\n" +">>> a_list = result" +msgstr "" + #: ../../faq/programming.rst:1414 #, fuzzy msgid "" @@ -2058,6 +2669,15 @@ msgstr "" msgid "Thus, in our tuple example what is happening is equivalent to::" msgstr "因此,在我們的元組示例中,發生的事情等同於: ::" +#: ../../faq/programming.rst:1421 +msgid "" +">>> result = a_tuple[0].__iadd__(['item'])\n" +">>> a_tuple[0] = result\n" +"Traceback (most recent call last):\n" +" ...\n" +"TypeError: 'tuple' object does not support item assignment" +msgstr "" + #: ../../faq/programming.rst:1427 #, fuzzy msgid "" @@ -2089,6 +2709,12 @@ msgstr "" "的度量對list的元素進行排序。在 Python 中,對 :meth:`list.sort` 方法使用 " "``key`` 引數: ::" +#: ../../faq/programming.rst:1439 +msgid "" +"Isorted = L[:]\n" +"Isorted.sort(key=lambda s: int(s[10:15]))" +msgstr "" + #: ../../faq/programming.rst:1444 #, fuzzy msgid "How can I sort one list by values from another list?" @@ -2103,6 +2729,20 @@ msgstr "" "將它們合併到一個元組疊代器中,對結果list進行排序,然後挑選出你想要的元" "素。: ::" +#: ../../faq/programming.rst:1449 +msgid "" +">>> list1 = [\"what\", \"I'm\", \"sorting\", \"by\"]\n" +">>> list2 = [\"something\", \"else\", \"to\", \"sort\"]\n" +">>> pairs = zip(list1, list2)\n" +">>> pairs = sorted(pairs)\n" +">>> pairs\n" +"[(\"I'm\", 'else'), ('by', 'sort'), ('sorting', 'to'), ('what', " +"'something')]\n" +">>> result = [x[1] for x in pairs]\n" +">>> result\n" +"['else', 'sort', 'to', 'something']" +msgstr "" + #: ../../faq/programming.rst:1461 msgid "Objects" msgstr "物件" @@ -2151,6 +2791,13 @@ msgstr "" "方法是一些物件 ``x`` 上的函式,你通常將其稱為 ``x.name(arguments...)`` 。方法" "在類別定義中被定義為函式: ::" +#: ../../faq/programming.rst:1485 +msgid "" +"class C:\n" +" def meth(self, arg):\n" +" return arg * 2 + self.attribute" +msgstr "" + #: ../../faq/programming.rst:1491 #, fuzzy msgid "What is self?" @@ -2207,6 +2854,38 @@ msgstr "" "試將為已註冊的類別回傳 ``True``,即使沒有直接或間接繼承自它。要測試「真正的繼" "承」,請掃描該類別的 MRO:" +#: ../../faq/programming.rst:1516 +msgid "" +"from collections.abc import Mapping\n" +"\n" +"class P:\n" +" pass\n" +"\n" +"class C(P):\n" +" pass\n" +"\n" +"Mapping.register(P)" +msgstr "" + +#: ../../faq/programming.rst:1528 +msgid "" +">>> c = C()\n" +">>> isinstance(c, C) # direct\n" +"True\n" +">>> isinstance(c, P) # indirect\n" +"True\n" +">>> isinstance(c, Mapping) # virtual\n" +"True\n" +"\n" +"# Actual inheritance chain\n" +">>> type(c).__mro__\n" +"(, , )\n" +"\n" +"# Test for \"true inheritance\"\n" +">>> Mapping in type(c).__mro__\n" +"False" +msgstr "" + #: ../../faq/programming.rst:1546 #, fuzzy msgid "" @@ -2221,6 +2900,16 @@ msgstr "" "自己開發類別,更合適的面向物件風格是在封裝特定行為的類別上定義方法,而不是檢" "查物件的類別並根據它是什麼類別做不同的事情。例如,如果你有一個函式做某事: ::" +#: ../../faq/programming.rst:1553 +msgid "" +"def search(obj):\n" +" if isinstance(obj, Mailbox):\n" +" ... # code to search a mailbox\n" +" elif isinstance(obj, Document):\n" +" ... # code to search a document\n" +" elif ..." +msgstr "" + #: ../../faq/programming.rst:1560 #, fuzzy msgid "" @@ -2228,6 +2917,19 @@ msgid "" "just call it::" msgstr "更好的方法是在所有類別上定義一個 ``search()`` 方法,然後呼叫它: ::" +#: ../../faq/programming.rst:1563 +msgid "" +"class Mailbox:\n" +" def search(self):\n" +" ... # code to search a mailbox\n" +"\n" +"class Document:\n" +" def search(self):\n" +" ... # code to search a document\n" +"\n" +"obj.search()" +msgstr "" + #: ../../faq/programming.rst:1575 #, fuzzy msgid "What is delegation?" @@ -2256,6 +2958,20 @@ msgstr "" "Python 程式員可以輕鬆實作委託。例如,下面的類別實作了一個行為類似於檔案但將所" "有寫入資料轉換為大寫的類別: ::" +#: ../../faq/programming.rst:1587 +msgid "" +"class UpperOut:\n" +"\n" +" def __init__(self, outfile):\n" +" self._outfile = outfile\n" +"\n" +" def write(self, s):\n" +" self._outfile.write(s.upper())\n" +"\n" +" def __getattr__(self, name):\n" +" return getattr(self._outfile, name)" +msgstr "" + #: ../../faq/programming.rst:1598 #, fuzzy msgid "" @@ -2284,6 +3000,15 @@ msgstr "" "類別也必須定義一個 :meth:`~object.__setattr__` 方法,而且必須小心謹慎。 :" "meth:`!__setattr__` 的基本實作大致等同於以下: ::" +#: ../../faq/programming.rst:1610 +msgid "" +"class X:\n" +" ...\n" +" def __setattr__(self, name, value):\n" +" self.__dict__[name] = value\n" +" ..." +msgstr "" + #: ../../faq/programming.rst:1616 #, fuzzy msgid "" @@ -2306,6 +3031,13 @@ msgstr "如何從擴充它的衍生類別呼叫基底類別中定義的方法? msgid "Use the built-in :func:`super` function::" msgstr "使用內置的 :func:`super` 函式: ::" +#: ../../faq/programming.rst:1626 +msgid "" +"class Derived(Base):\n" +" def meth(self):\n" +" super().meth() # calls Base.meth" +msgstr "" + #: ../../faq/programming.rst:1630 #, fuzzy msgid "" @@ -2334,6 +3066,17 @@ msgstr "" "說一句,如果你想動態決定(例如,取決於資源的可用性)使用哪個基底類別,這個技" "巧也很方便。例子: ::" +#: ../../faq/programming.rst:1644 +msgid "" +"class Base:\n" +" ...\n" +"\n" +"BaseAlias = Base\n" +"\n" +"class Derived(BaseAlias):\n" +" ..." +msgstr "" + #: ../../faq/programming.rst:1654 #, fuzzy msgid "How do I create static class data and static class methods?" @@ -2355,6 +3098,18 @@ msgstr "" "對於靜態資料,只需定義一個類別屬性即可。要為屬性分配新值,你必須在分配中顯式" "使用類別名: ::" +#: ../../faq/programming.rst:1662 +msgid "" +"class C:\n" +" count = 0 # number of times C.__init__ called\n" +"\n" +" def __init__(self):\n" +" C.count = C.count + 1\n" +"\n" +" def getcount(self):\n" +" return C.count # or return self.count" +msgstr "" + #: ../../faq/programming.rst:1671 #, fuzzy msgid "" @@ -2378,11 +3133,24 @@ msgstr "" "一個名為 \"count\" 的新的不相關實例。類別靜態資料名稱的重新綁定必須始終指定類" "別是否在方法內: ::" +#: ../../faq/programming.rst:1680 +msgid "C.count = 314" +msgstr "" + #: ../../faq/programming.rst:1682 #, fuzzy msgid "Static methods are possible::" msgstr "靜態方法是可能的: ::" +#: ../../faq/programming.rst:1684 +msgid "" +"class C:\n" +" @staticmethod\n" +" def static(arg1, arg2, arg3):\n" +" # No 'self' parameter!\n" +" ..." +msgstr "" + #: ../../faq/programming.rst:1690 #, fuzzy msgid "" @@ -2391,6 +3159,12 @@ msgid "" msgstr "" "然而,獲得靜態方法效果的一種更直接的方法是透過一個簡單的模組級函式: ::" +#: ../../faq/programming.rst:1693 +msgid "" +"def getcount():\n" +" return C.count" +msgstr "" + #: ../../faq/programming.rst:1696 #, fuzzy msgid "" @@ -2418,6 +3192,14 @@ msgstr "" msgid "In C++ you'd write" msgstr "在 C++ 中你會寫" +#: ../../faq/programming.rst:1708 +msgid "" +"class C {\n" +" C() { cout << \"No arguments\\n\"; }\n" +" C(int i) { cout << \"Argument is \" << i << \"\\n\"; }\n" +"}" +msgstr "" + #: ../../faq/programming.rst:1715 #, fuzzy msgid "" @@ -2426,6 +3208,16 @@ msgid "" msgstr "" "在 Python 中,你必須編寫一個構造函式來捕獲所有使用預設引數的情況。例如: ::" +#: ../../faq/programming.rst:1718 +msgid "" +"class C:\n" +" def __init__(self, i=None):\n" +" if i is None:\n" +" print(\"No arguments\")\n" +" else:\n" +" print(\"Argument is\", i)" +msgstr "" + #: ../../faq/programming.rst:1725 #, fuzzy msgid "This is not entirely equivalent, but close enough in practice." @@ -2436,6 +3228,12 @@ msgstr "這並不完全等價,但在實踐中足夠接近。" msgid "You could also try a variable-length argument list, e.g. ::" msgstr "你也可以嘗試可變長度引數list,例如: ::" +#: ../../faq/programming.rst:1729 +msgid "" +"def __init__(self, *args):\n" +" ..." +msgstr "" + #: ../../faq/programming.rst:1732 #, fuzzy msgid "The same approach works for all method definitions." @@ -2467,6 +3265,21 @@ msgid "" "outside the class, the mangled name must be used:" msgstr "" +#: ../../faq/programming.rst:1747 +msgid "" +"class A:\n" +" def __one(self):\n" +" return 1\n" +" def two(self):\n" +" return 2 * self.__one()\n" +"\n" +"class B(A):\n" +" def three(self):\n" +" return 3 * self._A__one()\n" +"\n" +"four = 4 * A()._A__one()" +msgstr "" + #: ../../faq/programming.rst:1761 #, fuzzy msgid "" @@ -2673,11 +3486,34 @@ msgstr "" "在大多數其他情況下,識別性測試是不可取的,相等性測試是首選。特別是,識別性測" "試不應用於檢查常數,例如不能保證是單例的 :class:`int` 和 :class:`str`: ::" +#: ../../faq/programming.rst:1879 +msgid "" +">>> a = 1000\n" +">>> b = 500\n" +">>> c = b + 500\n" +">>> a is c\n" +"False\n" +"\n" +">>> a = 'Python'\n" +">>> b = 'Py'\n" +">>> c = b + 'thon'\n" +">>> a is c\n" +"False" +msgstr "" + #: ../../faq/programming.rst:1891 #, fuzzy msgid "Likewise, new instances of mutable containers are never identical::" msgstr "同樣,可變容器的新實例永遠不會相同: ::" +#: ../../faq/programming.rst:1893 +msgid "" +">>> a = []\n" +">>> b = []\n" +">>> a is b\n" +"False" +msgstr "" + #: ../../faq/programming.rst:1898 msgid "" "In the standard library code, you will see several common patterns for " @@ -2706,6 +3542,20 @@ msgstr "" "建立一個保證與其他物件不同的單例哨兵物件。例如,這裡是如何實作一個行為類似" "於 :meth:`dict.pop` 的方法: ::" +#: ../../faq/programming.rst:1910 +msgid "" +"_sentinel = object()\n" +"\n" +"def pop(self, key, default=_sentinel):\n" +" if key in self:\n" +" value = self[key]\n" +" del self[key]\n" +" return value\n" +" if default is _sentinel:\n" +" raise KeyError(key)\n" +" return default" +msgstr "" + #: ../../faq/programming.rst:1921 msgid "" "3) Container implementations sometimes need to augment equality tests with " @@ -2722,6 +3572,15 @@ msgid "" msgstr "" "例如,以下是 :meth:`!collections.abc.Sequence.__contains__` 的實作: ::" +#: ../../faq/programming.rst:1928 +msgid "" +"def __contains__(self, value):\n" +" for v in self:\n" +" if v is value or v == value:\n" +" return True\n" +" return False" +msgstr "" + #: ../../faq/programming.rst:1936 msgid "" "How can a subclass control what data is stored in an immutable instance?" @@ -2746,10 +3605,46 @@ msgid "" "class:" msgstr "所有這些不可變類別都具有與其父類別不同的簽名:" +#: ../../faq/programming.rst:1946 +msgid "" +"from datetime import date\n" +"\n" +"class FirstOfMonthDate(date):\n" +" \"Always choose the first day of the month\"\n" +" def __new__(cls, year, month, day):\n" +" return super().__new__(cls, year, month, 1)\n" +"\n" +"class NamedInt(int):\n" +" \"Allow text names for some numbers\"\n" +" xlat = {'zero': 0, 'one': 1, 'ten': 10}\n" +" def __new__(cls, value):\n" +" value = cls.xlat.get(value, value)\n" +" return super().__new__(cls, value)\n" +"\n" +"class TitleStr(str):\n" +" \"Convert str to name suitable for a URL path\"\n" +" def __new__(cls, s):\n" +" s = s.lower().replace(' ', '-')\n" +" s = ''.join([c for c in s if c.isalnum() or c == '-'])\n" +" return super().__new__(cls, s)" +msgstr "" + #: ../../faq/programming.rst:1969 msgid "The classes can be used like this:" msgstr "這些類別可以像這樣使用:" +#: ../../faq/programming.rst:1971 +msgid "" +">>> FirstOfMonthDate(2012, 2, 14)\n" +"FirstOfMonthDate(2012, 2, 1)\n" +">>> NamedInt('ten')\n" +"10\n" +">>> NamedInt(20)\n" +"20\n" +">>> TitleStr('Blog: Why Python Rocks')\n" +"'blog-why-python-rocks'" +msgstr "" + #: ../../faq/programming.rst:1986 #, fuzzy msgid "How do I cache method calls?" @@ -2810,6 +3705,31 @@ msgstr "" msgid "This example shows the various techniques::" msgstr "這個例子展示了各種技術: ::" +#: ../../faq/programming.rst:2013 +msgid "" +"class Weather:\n" +" \"Lookup weather information on a government website\"\n" +"\n" +" def __init__(self, station_id):\n" +" self._station_id = station_id\n" +" # The _station_id is private and immutable\n" +"\n" +" def current_temperature(self):\n" +" \"Latest hourly observation\"\n" +" # Do not cache this because old results\n" +" # can be out of date.\n" +"\n" +" @cached_property\n" +" def location(self):\n" +" \"Return the longitude/latitude coordinates of the station\"\n" +" # Result only depends on the station_id\n" +"\n" +" @lru_cache(maxsize=20)\n" +" def historic_rainfall(self, date, units='mm'):\n" +" \"Rainfall on a given date\"\n" +" # Depends on the station_id, date, and units." +msgstr "" + #: ../../faq/programming.rst:2035 #, fuzzy msgid "" @@ -2831,6 +3751,29 @@ msgstr "" "`~object.__eq__` 和 :meth:`~object.__hash__` 方法,以便快取可以檢測相關屬性更" "新: ::" +#: ../../faq/programming.rst:2044 +msgid "" +"class Weather:\n" +" \"Example with a mutable station identifier\"\n" +"\n" +" def __init__(self, station_id):\n" +" self.station_id = station_id\n" +"\n" +" def change_station(self, station_id):\n" +" self.station_id = station_id\n" +"\n" +" def __eq__(self, other):\n" +" return self.station_id == other.station_id\n" +"\n" +" def __hash__(self):\n" +" return hash(self.station_id)\n" +"\n" +" @lru_cache(maxsize=20)\n" +" def historic_rainfall(self, date, units='cm'):\n" +" 'Rainfall on a given date'\n" +" # Depends on the station_id, date, and units." +msgstr "" + #: ../../faq/programming.rst:2066 msgid "Modules" msgstr "模組" @@ -2917,6 +3860,12 @@ msgstr "" ":mod:`py_compile` 模組可以手動編譯任何模組。一種方法是在該模組中以交互方式使" "用 ``compile()`` 函式: ::" +#: ../../faq/programming.rst:2103 +msgid "" +">>> import py_compile\n" +">>> py_compile.compile('foo.py') " +msgstr "" + #: ../../faq/programming.rst:2106 #, fuzzy msgid "" @@ -2938,6 +3887,10 @@ msgstr "" "你還可以使用 :mod:`compileall` 模組自動編譯目錄中的所有檔案。你可以在 shell " "提示符下運行 ``compileall.py`` 並提供包含要編譯的 Python 檔案的目錄路徑: ::" +#: ../../faq/programming.rst:2115 +msgid "python -m compileall ." +msgstr "" + #: ../../faq/programming.rst:2119 #, fuzzy msgid "How do I find the current module name?" @@ -2956,6 +3909,16 @@ msgstr "" "值為``'__main__'``,則該程式作為腳本運行。許多通常透過引入使用的模組還提供命" "令行界面或自檢,只有在檢查 ``__name__`` 後才執行此程式碼: ::" +#: ../../faq/programming.rst:2127 +msgid "" +"def main():\n" +" print('Running test...')\n" +" ...\n" +"\n" +"if __name__ == '__main__':\n" +" main()" +msgstr "" + #: ../../faq/programming.rst:2136 #, fuzzy msgid "How can I have modules that mutually import each other?" @@ -2970,10 +3933,22 @@ msgstr "假設你有以下模組:" msgid ":file:`foo.py`::" msgstr ":file:`foo.py`: ::" +#: ../../faq/programming.rst:2142 +msgid "" +"from bar import bar_var\n" +"foo_var = 1" +msgstr "" + #: ../../faq/programming.rst:2145 msgid ":file:`bar.py`::" msgstr ":file:`bar.py`: ::" +#: ../../faq/programming.rst:2147 +msgid "" +"from foo import foo_var\n" +"bar_var = 2" +msgstr "" + #: ../../faq/programming.rst:2150 #, fuzzy msgid "The problem is that the interpreter will perform the following steps:" @@ -3112,6 +4087,10 @@ msgstr "" "考慮使用來自 :mod:`importlib` 的便利函式 :func:`~importlib.import_module` 代" "替: ::" +#: ../../faq/programming.rst:2196 +msgid "z = importlib.import_module('x.y.z')" +msgstr "" + #: ../../faq/programming.rst:2200 msgid "" "When I edit an imported module and reimport it, the changes don't show up. " @@ -3131,6 +4110,13 @@ msgstr "" "一個由許多模組組成的程式中,每個模組都引入相同的基本模組,基本模組將被解析和" "重新解析很多次。要強制重新讀取已更改的模組,請執行以下操作: ::" +#: ../../faq/programming.rst:2208 +msgid "" +"import importlib\n" +"import modname\n" +"importlib.reload(modname)" +msgstr "" + #: ../../faq/programming.rst:2212 #, fuzzy msgid "" @@ -3138,6 +4124,10 @@ msgid "" "containing statements like ::" msgstr "警告:此技術並非 100% 萬無一失。尤其是,包含像這樣的陳述式的模組: ::" +#: ../../faq/programming.rst:2215 +msgid "from modname import some_objects" +msgstr "" + #: ../../faq/programming.rst:2217 #, fuzzy msgid "" @@ -3149,12 +4139,31 @@ msgstr "" "將繼續使用舊版本的引入物件。如果模組包含類別定義,現有的類別實例將*不會*更新" "為使用新的類別定義。這可能會導致以下自相矛盾的行為: ::" +#: ../../faq/programming.rst:2222 +msgid "" +">>> import importlib\n" +">>> import cls\n" +">>> c = cls.C() # Create an instance of C\n" +">>> importlib.reload(cls)\n" +"\n" +">>> isinstance(c, cls.C) # isinstance is false?!?\n" +"False" +msgstr "" + #: ../../faq/programming.rst:2230 msgid "" "The nature of the problem is made clear if you print out the \"identity\" of " "the class objects::" msgstr "如果印出類別物件的「識別性」,問題的本質就很清楚了: ::" +#: ../../faq/programming.rst:2233 +msgid "" +">>> hex(id(c.__class__))\n" +"'0x7352a0'\n" +">>> hex(id(cls.C))\n" +"'0x4198d0'" +msgstr "" + #: ../../faq/programming.rst:408 msgid "argument" msgstr "argument(引數)" diff --git a/glossary.po b/glossary.po index a996679f43..c822de3d41 100644 --- a/glossary.po +++ b/glossary.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-09-01 22:24+0800\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2023-07-02 22:47+0800\n" "Last-Translator: Matt Wang \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -1359,10 +1359,27 @@ msgstr "" "一起被提供。" #: ../../glossary.rst:593 +msgid "immortal" +msgstr "" + +#: ../../glossary.rst:595 +msgid "" +"*Immortal objects* are a CPython implementation detail introduced in :pep:" +"`683`." +msgstr "" + +#: ../../glossary.rst:598 +msgid "" +"If an object is immortal, its :term:`reference count` is never modified, and " +"therefore it is never deallocated while the interpreter is running. For " +"example, :const:`True` and :const:`None` are immortal in CPython." +msgstr "" + +#: ../../glossary.rst:601 msgid "immutable" msgstr "immutable(不可變物件)" -#: ../../glossary.rst:595 +#: ../../glossary.rst:603 msgid "" "An object with a fixed value. Immutable objects include numbers, strings " "and tuples. Such an object cannot be altered. A new object has to be " @@ -1374,11 +1391,11 @@ msgstr "" "能被改變的。如果一個不同的值必須被儲存,則必須建立一個新的物件。它們在需要恆" "定雜湊值的地方,扮演重要的角色,例如 dictionary(字典)中的一個鍵。" -#: ../../glossary.rst:600 +#: ../../glossary.rst:608 msgid "import path" msgstr "import path(引入路徑)" -#: ../../glossary.rst:602 +#: ../../glossary.rst:610 msgid "" "A list of locations (or :term:`path entries `) that are searched " "by the :term:`path based finder` for modules to import. During import, this " @@ -1390,11 +1407,11 @@ msgstr "" "的位置。在 import 期間,此位置列表通常是來自 :data:`sys.path`,但對於子套件 " "(subpackage) 而言,它也可能是來自父套件的 ``__path__`` 屬性。" -#: ../../glossary.rst:607 +#: ../../glossary.rst:615 msgid "importing" msgstr "importing(引入)" -#: ../../glossary.rst:609 +#: ../../glossary.rst:617 msgid "" "The process by which Python code in one module is made available to Python " "code in another module." @@ -1402,11 +1419,11 @@ msgstr "" "一個過程。一個模組中的 Python 程式碼可以透過此過程,被另一個模組中的 Python " "程式碼使用。" -#: ../../glossary.rst:611 +#: ../../glossary.rst:619 msgid "importer" msgstr "importer(引入器)" -#: ../../glossary.rst:613 +#: ../../glossary.rst:621 msgid "" "An object that both finds and loads a module; both a :term:`finder` and :" "term:`loader` object." @@ -1414,11 +1431,11 @@ msgstr "" "一個能夠尋找及載入模組的物件;它既是 :term:`finder`\\ (尋檢器)也是 :term:" "`loader`\\ (載入器)物件。" -#: ../../glossary.rst:615 +#: ../../glossary.rst:623 msgid "interactive" msgstr "interactive(互動的)" -#: ../../glossary.rst:617 +#: ../../glossary.rst:625 msgid "" "Python has an interactive interpreter which means you can enter statements " "and expressions at the interpreter prompt, immediately execute them and see " @@ -1431,11 +1448,11 @@ msgstr "" "從你的電腦的主選單選擇它)。這是測試新想法或檢查模塊和包的非常強大的方法(請" "記住help(x))。" -#: ../../glossary.rst:623 +#: ../../glossary.rst:631 msgid "interpreted" msgstr "interpreted(直譯的)" -#: ../../glossary.rst:625 +#: ../../glossary.rst:633 msgid "" "Python is an interpreted language, as opposed to a compiled one, though the " "distinction can be blurry because of the presence of the bytecode compiler. " @@ -1449,11 +1466,11 @@ msgstr "" "一個執行檔,然後再執行它。直譯語言通常比編譯語言有更短的開發/除錯週期,不過" "它們的程式通常也運行得較慢。另請參閱 :term:`interactive`\\ (互動的)。" -#: ../../glossary.rst:632 +#: ../../glossary.rst:640 msgid "interpreter shutdown" msgstr "interpreter shutdown(直譯器關閉)" -#: ../../glossary.rst:634 +#: ../../glossary.rst:642 msgid "" "When asked to shut down, the Python interpreter enters a special phase where " "it gradually releases all allocated resources, such as modules and various " @@ -1471,18 +1488,18 @@ msgstr "" "段被執行的程式碼會遇到各種例外,因為它所依賴的資源可能不再有作用了(常見的例" "子是函式庫模組或是警告機制)。" -#: ../../glossary.rst:643 +#: ../../glossary.rst:651 msgid "" "The main reason for interpreter shutdown is that the ``__main__`` module or " "the script being run has finished executing." msgstr "" "直譯器關閉的主要原因,是 ``__main__`` 模組或正被運行的腳本已經執行完成。" -#: ../../glossary.rst:645 +#: ../../glossary.rst:653 msgid "iterable" msgstr "iterable(可疊代物件)" -#: ../../glossary.rst:647 +#: ../../glossary.rst:655 msgid "" "An object capable of returning its members one at a time. Examples of " "iterables include all sequence types (such as :class:`list`, :class:`str`, " @@ -1498,7 +1515,7 @@ msgstr "" "`sequence`\\ (序列)語意的 :meth:`~object.__getitem__` method,該物件就是可" "疊代物件。" -#: ../../glossary.rst:655 +#: ../../glossary.rst:663 msgid "" "Iterables can be used in a :keyword:`for` loop and in many other places " "where a sequence is needed (:func:`zip`, :func:`map`, ...). When an " @@ -1518,11 +1535,11 @@ msgstr "" "數,用於在迴圈期間保有該疊代器。另請參閱 :term:`iterator`\\ (疊代器)、:" "term:`sequence`\\ (序列)和 :term:`generator`\\ (產生器)。" -#: ../../glossary.rst:665 +#: ../../glossary.rst:673 msgid "iterator" msgstr "iterator(疊代器)" -#: ../../glossary.rst:667 +#: ../../glossary.rst:675 msgid "" "An object representing a stream of data. Repeated calls to the iterator's :" "meth:`~iterator.__next__` method (or passing it to the built-in function :" @@ -1551,11 +1568,11 @@ msgstr "" "此事(多遍疊代)時,只會回傳在前一遍疊代中被用過的、同一個已被用盡的疊代器物" "件,使其看起來就像一個空的容器。" -#: ../../glossary.rst:682 +#: ../../glossary.rst:690 msgid "More information can be found in :ref:`typeiter`." msgstr "在\\ :ref:`typeiter`\\ 文中可以找到更多資訊。" -#: ../../glossary.rst:686 +#: ../../glossary.rst:694 msgid "" "CPython does not consistently apply the requirement that an iterator define :" "meth:`~iterator.__iter__`." @@ -1563,11 +1580,11 @@ msgstr "" "CPython 並不是始終如一地都會檢查「疊代器有定義 :meth:`~iterator." "__iter__`\\ 」這個規定。" -#: ../../glossary.rst:688 +#: ../../glossary.rst:696 msgid "key function" msgstr "key function(鍵函式)" -#: ../../glossary.rst:690 +#: ../../glossary.rst:698 msgid "" "A key function or collation function is a callable that returns a value used " "for sorting or ordering. For example, :func:`locale.strxfrm` is used to " @@ -1577,7 +1594,7 @@ msgstr "" "一個用於排序 (sorting) 或定序 (ordering) 的值。例如,:func:`locale.strxfrm` " "被用來產生一個了解區域特定排序慣例的排序鍵。" -#: ../../glossary.rst:695 +#: ../../glossary.rst:703 msgid "" "A number of tools in Python accept key functions to control how elements are " "ordered or grouped. They include :func:`min`, :func:`max`, :func:`sorted`, :" @@ -1589,7 +1606,7 @@ msgstr "" "merge`、:func:`heapq.nsmallest`、:func:`heapq.nlargest` 和 :func:`itertools." "groupby`。" -#: ../../glossary.rst:701 +#: ../../glossary.rst:709 msgid "" "There are several ways to create a key function. For example. the :meth:" "`str.lower` method can serve as a key function for case insensitive sorts. " @@ -1606,19 +1623,19 @@ msgstr "" "式 (constructor)。關於如何建立和使用鍵函式的範例,請參閱\\ :ref:`如何排序 " "`。" -#: ../../glossary.rst:708 +#: ../../glossary.rst:716 msgid "keyword argument" msgstr "keyword argument(關鍵字引數)" -#: ../../glossary.rst:710 ../../glossary.rst:1000 +#: ../../glossary.rst:718 ../../glossary.rst:1008 msgid "See :term:`argument`." msgstr "請參閱 :term:`argument`\\ (引數)。" -#: ../../glossary.rst:711 +#: ../../glossary.rst:719 msgid "lambda" msgstr "lambda" -#: ../../glossary.rst:713 +#: ../../glossary.rst:721 msgid "" "An anonymous inline function consisting of a single :term:`expression` which " "is evaluated when the function is called. The syntax to create a lambda " @@ -1628,11 +1645,11 @@ msgstr "" "function),於該函式被呼叫時求值。建立 lambda 函式的語法是 ``lambda " "[parameters]: expression``" -#: ../../glossary.rst:716 +#: ../../glossary.rst:724 msgid "LBYL" msgstr "LBYL" -#: ../../glossary.rst:718 +#: ../../glossary.rst:726 msgid "" "Look before you leap. This coding style explicitly tests for pre-conditions " "before making calls or lookups. This style contrasts with the :term:`EAFP` " @@ -1643,7 +1660,7 @@ msgstr "" "地測試先決條件。這種風格與 :term:`EAFP` 方式形成對比,且它的特色是會有許多 :" "keyword:`if` 陳述式的存在。" -#: ../../glossary.rst:723 +#: ../../glossary.rst:731 msgid "" "In a multi-threaded environment, the LBYL approach can risk introducing a " "race condition between \"the looking\" and \"the leaping\". For example, " @@ -1657,11 +1674,11 @@ msgstr "" "了 *key*,則該程式碼就會失效。這個問題可以用鎖 (lock) 或使用 EAFP 編碼方式來" "解決。" -#: ../../glossary.rst:728 +#: ../../glossary.rst:736 msgid "list" msgstr "list(串列)" -#: ../../glossary.rst:730 +#: ../../glossary.rst:738 msgid "" "A built-in Python :term:`sequence`. Despite its name it is more akin to an " "array in other languages than to a linked list since access to elements is " @@ -1671,11 +1688,11 @@ msgstr "" "似其他語言中的一個陣列 (array) 而較不像一個鏈結串列 (linked list),因為存取元" "素的時間複雜度是 *O*\\ (1)。" -#: ../../glossary.rst:733 +#: ../../glossary.rst:741 msgid "list comprehension" msgstr "list comprehension(串列綜合運算)" -#: ../../glossary.rst:735 +#: ../../glossary.rst:743 msgid "" "A compact way to process all or part of the elements in a sequence and " "return a list with the results. ``result = ['{:#04x}'.format(x) for x in " @@ -1689,11 +1706,11 @@ msgstr "" "keyword:`if` 子句是選擇性的。如果省略它,則 ``range(256)`` 中的所有元素都會被" "處理。" -#: ../../glossary.rst:741 +#: ../../glossary.rst:749 msgid "loader" msgstr "loader(載入器)" -#: ../../glossary.rst:743 +#: ../../glossary.rst:751 msgid "" "An object that loads a module. It must define a method named :meth:" "`load_module`. A loader is typically returned by a :term:`finder`. See :pep:" @@ -1705,11 +1722,11 @@ msgstr "" "`302`,關於 :term:`abstract base class`\\ (抽象基底類別),請參閱 :class:" "`importlib.abc.Loader`。" -#: ../../glossary.rst:747 +#: ../../glossary.rst:755 msgid "locale encoding" msgstr "locale encoding(區域編碼)" -#: ../../glossary.rst:749 +#: ../../glossary.rst:757 msgid "" "On Unix, it is the encoding of the LC_CTYPE locale. It can be set with :func:" "`locale.setlocale(locale.LC_CTYPE, new_locale) `." @@ -1717,36 +1734,36 @@ msgstr "" "在 Unix 上,它是 LC_CTYPE 區域設定的編碼。它可以用 :func:`locale." "setlocale(locale.LC_CTYPE, new_locale) ` 來設定。" -#: ../../glossary.rst:752 +#: ../../glossary.rst:760 msgid "On Windows, it is the ANSI code page (ex: ``\"cp1252\"``)." msgstr "在 Windows 上,它是 ANSI 代碼頁(code page,例如 ``\"cp1252\"``\\ )。" -#: ../../glossary.rst:754 +#: ../../glossary.rst:762 msgid "" "On Android and VxWorks, Python uses ``\"utf-8\"`` as the locale encoding." msgstr "在 Android 和 VxWorks 上,Python 使用 ``\"utf-8\"`` 作為區域編碼。" -#: ../../glossary.rst:756 +#: ../../glossary.rst:764 msgid ":func:`locale.getencoding` can be used to get the locale encoding." msgstr ":func:`locale.getencoding` 可以用來取得區域編碼。" -#: ../../glossary.rst:758 +#: ../../glossary.rst:766 msgid "See also the :term:`filesystem encoding and error handler`." msgstr "也請參考 :term:`filesystem encoding and error handler`。" -#: ../../glossary.rst:759 +#: ../../glossary.rst:767 msgid "magic method" msgstr "magic method(魔術方法)" -#: ../../glossary.rst:763 +#: ../../glossary.rst:771 msgid "An informal synonym for :term:`special method`." msgstr ":term:`special method`\\ (特殊方法)的一個非正式同義詞。" -#: ../../glossary.rst:764 +#: ../../glossary.rst:772 msgid "mapping" msgstr "mapping(對映)" -#: ../../glossary.rst:766 +#: ../../glossary.rst:774 msgid "" "A container object that supports arbitrary key lookups and implements the " "methods specified in the :class:`collections.abc.Mapping` or :class:" @@ -1761,11 +1778,11 @@ msgstr "" "包括 :class:`dict`、:class:`collections.defaultdict`、:class:`collections." "OrderedDict` 和 :class:`collections.Counter`。" -#: ../../glossary.rst:772 +#: ../../glossary.rst:780 msgid "meta path finder" msgstr "meta path finder(元路徑尋檢器)" -#: ../../glossary.rst:774 +#: ../../glossary.rst:782 msgid "" "A :term:`finder` returned by a search of :data:`sys.meta_path`. Meta path " "finders are related to, but different from :term:`path entry finders ` " "相關但是不同。" -#: ../../glossary.rst:778 +#: ../../glossary.rst:786 msgid "" "See :class:`importlib.abc.MetaPathFinder` for the methods that meta path " "finders implement." msgstr "" "關於元路徑尋檢器實作的 method,請參閱 :class:`importlib.abc.MetaPathFinder`。" -#: ../../glossary.rst:780 +#: ../../glossary.rst:788 msgid "metaclass" msgstr "metaclass(元類別)" -#: ../../glossary.rst:782 +#: ../../glossary.rst:790 msgid "" "The class of a class. Class definitions create a class name, a class " "dictionary, and a list of base classes. The metaclass is responsible for " @@ -1806,15 +1823,15 @@ msgstr "" "性存取、增加執行緒安全性、追蹤物件建立、實作單例模式 (singleton),以及許多其" "他的任務。" -#: ../../glossary.rst:792 +#: ../../glossary.rst:800 msgid "More information can be found in :ref:`metaclasses`." msgstr "更多資訊可以在\\ :ref:`metaclasses`\\ 章節中找到。" -#: ../../glossary.rst:761 ../../glossary.rst:793 ../../glossary.rst:1130 +#: ../../glossary.rst:769 ../../glossary.rst:801 ../../glossary.rst:1138 msgid "method" msgstr "method(方法)" -#: ../../glossary.rst:795 +#: ../../glossary.rst:803 msgid "" "A function which is defined inside a class body. If called as an attribute " "of an instance of that class, the method will get the instance object as its " @@ -1826,11 +1843,11 @@ msgstr "" "通常被稱為 ``self``)。請參閱 :term:`function`\\ (函式)和 :term:`nested " "scope`\\ (巢狀作用域)。" -#: ../../glossary.rst:799 +#: ../../glossary.rst:807 msgid "method resolution order" msgstr "method resolution order(方法解析順序)" -#: ../../glossary.rst:801 +#: ../../glossary.rst:809 msgid "" "Method Resolution Order is the order in which base classes are searched for " "a member during lookup. See :ref:`python_2.3_mro` for details of the " @@ -1839,11 +1856,11 @@ msgstr "" "方法解析順序是在查找某個成員的過程中,base class(基底類別)被搜尋的順序。關" "於 Python 自 2.3 版直譯器所使用的演算法細節,請參閱 :ref:`python_2.3_mro`。" -#: ../../glossary.rst:804 +#: ../../glossary.rst:812 msgid "module" msgstr "module(模組)" -#: ../../glossary.rst:806 +#: ../../glossary.rst:814 msgid "" "An object that serves as an organizational unit of Python code. Modules " "have a namespace containing arbitrary Python objects. Modules are loaded " @@ -1853,15 +1870,15 @@ msgstr "" "空間,它包含任意的 Python 物件。模組是藉由 :term:`importing` 的過程,被載入" "至 Python。" -#: ../../glossary.rst:810 +#: ../../glossary.rst:818 msgid "See also :term:`package`." msgstr "另請參閱 :term:`package`\\ (套件)。" -#: ../../glossary.rst:811 +#: ../../glossary.rst:819 msgid "module spec" msgstr "module spec(模組規格)" -#: ../../glossary.rst:813 +#: ../../glossary.rst:821 msgid "" "A namespace containing the import-related information used to load a module. " "An instance of :class:`importlib.machinery.ModuleSpec`." @@ -1869,19 +1886,19 @@ msgstr "" "一個命名空間,它包含用於載入模組的 import 相關資訊。它是 :class:`importlib." "machinery.ModuleSpec` 的一個實例。" -#: ../../glossary.rst:815 +#: ../../glossary.rst:823 msgid "MRO" msgstr "MRO" -#: ../../glossary.rst:817 +#: ../../glossary.rst:825 msgid "See :term:`method resolution order`." msgstr "請參閱 :term:`method resolution order`\\ (方法解析順序)。" -#: ../../glossary.rst:818 +#: ../../glossary.rst:826 msgid "mutable" msgstr "mutable(可變物件)" -#: ../../glossary.rst:820 +#: ../../glossary.rst:828 msgid "" "Mutable objects can change their value but keep their :func:`id`. See also :" "term:`immutable`." @@ -1889,11 +1906,11 @@ msgstr "" "可變物件可以改變它們的值,但維持它們的 :func:`id`。另請參閱 :term:" "`immutable`\\ (不可變物件)。" -#: ../../glossary.rst:822 +#: ../../glossary.rst:830 msgid "named tuple" msgstr "named tuple(附名元組)" -#: ../../glossary.rst:824 +#: ../../glossary.rst:832 msgid "" "The term \"named tuple\" applies to any type or class that inherits from " "tuple and whose indexable elements are also accessible using named " @@ -1903,7 +1920,7 @@ msgstr "" "索引 (indexable) 元素也可以用附名屬性來存取。這些型別或 class 也可以具有其他" "的特性。" -#: ../../glossary.rst:828 +#: ../../glossary.rst:836 msgid "" "Several built-in types are named tuples, including the values returned by :" "func:`time.localtime` and :func:`os.stat`. Another example is :data:`sys." @@ -1912,7 +1929,7 @@ msgstr "" "有些內建型別是 named tuple,包括由 :func:`time.localtime` 和 :func:`os.stat` " "回傳的值。另一個例子是 :data:`sys.float_info`: ::" -#: ../../glossary.rst:832 +#: ../../glossary.rst:840 msgid "" ">>> sys.float_info[1] # indexed access\n" "1024\n" @@ -1922,7 +1939,7 @@ msgid "" "True" msgstr "" -#: ../../glossary.rst:839 +#: ../../glossary.rst:847 msgid "" "Some named tuples are built-in types (such as the above examples). " "Alternatively, a named tuple can be created from a regular class definition " @@ -1939,11 +1956,11 @@ msgstr "" "namedtuple` 來建立。後者技術也增加了一些額外的 method,這些 method 可能是在手" "寫或內建的 named tuple 中,無法找到的。" -#: ../../glossary.rst:847 +#: ../../glossary.rst:855 msgid "namespace" msgstr "namespace(命名空間)" -#: ../../glossary.rst:849 +#: ../../glossary.rst:857 msgid "" "The place where a variable is stored. Namespaces are implemented as " "dictionaries. There are the local, global and built-in namespaces as well " @@ -1963,11 +1980,11 @@ msgstr "" "func:`itertools.islice` 明確地表示,這些函式分別是由 :mod:`random` 和 :mod:" "`itertools` 模組在實作。" -#: ../../glossary.rst:859 +#: ../../glossary.rst:867 msgid "namespace package" msgstr "namespace package(命名空間套件)" -#: ../../glossary.rst:861 +#: ../../glossary.rst:869 msgid "" "A :pep:`420` :term:`package` which serves only as a container for " "subpackages. Namespace packages may have no physical representation, and " @@ -1978,15 +1995,15 @@ msgstr "" "一個容器。命名空間套件可能沒有實體的表示法,而且具體來說它們不像是一個 :term:" "`regular package`\\ (正規套件),因為它們並沒有 ``__init__.py`` 這個檔案。" -#: ../../glossary.rst:866 +#: ../../glossary.rst:874 msgid "See also :term:`module`." msgstr "另請參閱 :term:`module`\\ (模組)。" -#: ../../glossary.rst:867 +#: ../../glossary.rst:875 msgid "nested scope" msgstr "nested scope(巢狀作用域)" -#: ../../glossary.rst:869 +#: ../../glossary.rst:877 msgid "" "The ability to refer to a variable in an enclosing definition. For " "instance, a function defined inside another function can refer to variables " @@ -2001,11 +2018,11 @@ msgstr "" "寫入。同樣地,全域變數是在全域命名空間中讀取及寫入。:keyword:`nonlocal` 容許" "對外層作用域進行寫入。" -#: ../../glossary.rst:876 +#: ../../glossary.rst:884 msgid "new-style class" msgstr "new-style class(新式類別)" -#: ../../glossary.rst:878 +#: ../../glossary.rst:886 msgid "" "Old name for the flavor of classes now used for all class objects. In " "earlier Python versions, only new-style classes could use Python's newer, " @@ -2017,11 +2034,11 @@ msgstr "" "__slots__`、描述器 (descriptor)、屬性 (property)、:meth:`~object." "__getattribute__`、class method(類別方法)和 static method(靜態方法)。" -#: ../../glossary.rst:883 +#: ../../glossary.rst:891 msgid "object" msgstr "object(物件)" -#: ../../glossary.rst:885 +#: ../../glossary.rst:893 msgid "" "Any data with state (attributes or value) and defined behavior (methods). " "Also the ultimate base class of any :term:`new-style class`." @@ -2029,11 +2046,11 @@ msgstr "" "具有狀態(屬性或值)及被定義的行為(method)的任何資料。它也是任何 :term:" "`new-style class`\\ (新式類別)的最終 base class(基底類別)。" -#: ../../glossary.rst:888 +#: ../../glossary.rst:896 msgid "package" msgstr "package(套件)" -#: ../../glossary.rst:890 +#: ../../glossary.rst:898 msgid "" "A Python :term:`module` which can contain submodules or recursively, " "subpackages. Technically, a package is a Python module with a ``__path__`` " @@ -2043,17 +2060,17 @@ msgstr "" "迴的子套件 (subpackage)。技術上而言,套件就是具有 ``__path__`` 屬性的一個 " "Python 模組。" -#: ../../glossary.rst:894 +#: ../../glossary.rst:902 msgid "See also :term:`regular package` and :term:`namespace package`." msgstr "" "另請參閱 :term:`regular package`\\ (正規套件)和 :term:`namespace " "package`\\ (命名空間套件)。" -#: ../../glossary.rst:895 +#: ../../glossary.rst:903 msgid "parameter" msgstr "parameter(參數)" -#: ../../glossary.rst:897 +#: ../../glossary.rst:905 msgid "" "A named entity in a :term:`function` (or method) definition that specifies " "an :term:`argument` (or in some cases, arguments) that the function can " @@ -2063,7 +2080,7 @@ msgstr "" "它指明該函式能夠接受的一個 :term:`argument`\\ (引數),或在某些情況下指示多" "個引數。共有有五種不同的參數類型:" -#: ../../glossary.rst:901 +#: ../../glossary.rst:909 msgid "" ":dfn:`positional-or-keyword`: specifies an argument that can be passed " "either :term:`positionally ` or as a :term:`keyword argument " @@ -2074,11 +2091,11 @@ msgstr "" "置 `\\ 或是作為\\ :term:`關鍵字引數 `\\ 被傳遞的引數。這" "是參數的預設類型,例如以下的 *foo* 和 *bar*: ::" -#: ../../glossary.rst:906 +#: ../../glossary.rst:914 msgid "def func(foo, bar=None): ..." msgstr "def func(foo, bar=None): ..." -#: ../../glossary.rst:910 +#: ../../glossary.rst:918 msgid "" ":dfn:`positional-only`: specifies an argument that can be supplied only by " "position. Positional-only parameters can be defined by including a ``/`` " @@ -2089,11 +2106,11 @@ msgstr "" "式定義的參數列表中包含一個 ``/`` 字元,就可以在該字元前面定義僅限位置參數,例" "如以下的 *posonly1* 和 *posonly2*: ::" -#: ../../glossary.rst:915 +#: ../../glossary.rst:923 msgid "def func(posonly1, posonly2, /, positional_or_keyword): ..." msgstr "def func(posonly1, posonly2, /, positional_or_keyword): ..." -#: ../../glossary.rst:919 +#: ../../glossary.rst:927 msgid "" ":dfn:`keyword-only`: specifies an argument that can be supplied only by " "keyword. Keyword-only parameters can be defined by including a single var-" @@ -2106,11 +2123,11 @@ msgstr "" "單純的 ``*`` 字元,就可以在其後方定義僅限關鍵字參數,例如以下的 *kw_only1* " "和 *kw_only2*: ::" -#: ../../glossary.rst:925 +#: ../../glossary.rst:933 msgid "def func(arg, *, kw_only1, kw_only2): ..." msgstr "def func(arg, *, kw_only1, kw_only2): ..." -#: ../../glossary.rst:927 +#: ../../glossary.rst:935 msgid "" ":dfn:`var-positional`: specifies that an arbitrary sequence of positional " "arguments can be provided (in addition to any positional arguments already " @@ -2122,11 +2139,11 @@ msgstr "" "數(在已被其他參數接受的任何位置引數之外)。這類參數是透過在其參數名稱字首加" "上 ``*`` 來定義的,例如以下的 *args*: ::" -#: ../../glossary.rst:933 +#: ../../glossary.rst:941 msgid "def func(*args, **kwargs): ..." msgstr "def func(*args, **kwargs): ..." -#: ../../glossary.rst:935 +#: ../../glossary.rst:943 msgid "" ":dfn:`var-keyword`: specifies that arbitrarily many keyword arguments can be " "provided (in addition to any keyword arguments already accepted by other " @@ -2137,14 +2154,14 @@ msgstr "" "已被其他參數接受的任何關鍵字引數之外)。這類參數是透過在其參數名稱字首加上 " "``**`` 來定義的,例如上面範例中的 *kwargs*。" -#: ../../glossary.rst:941 +#: ../../glossary.rst:949 msgid "" "Parameters can specify both optional and required arguments, as well as " "default values for some optional arguments." msgstr "" "參數可以指明引數是選擇性的或必需的,也可以為一些選擇性的引數指定預設值。" -#: ../../glossary.rst:944 +#: ../../glossary.rst:952 msgid "" "See also the :term:`argument` glossary entry, the FAQ question on :ref:`the " "difference between arguments and parameters `, " @@ -2155,11 +2172,11 @@ msgstr "" "參數之間的差異 `、:class:`inspect.Parameter` " "class、:ref:`function`\\ 章節,以及 :pep:`362`。" -#: ../../glossary.rst:948 +#: ../../glossary.rst:956 msgid "path entry" msgstr "path entry(路徑項目)" -#: ../../glossary.rst:950 +#: ../../glossary.rst:958 msgid "" "A single location on the :term:`import path` which the :term:`path based " "finder` consults to find modules for importing." @@ -2167,11 +2184,11 @@ msgstr "" "在 :term:`import path`\\ (引入路徑)中的一個位置,而 :term:`path based " "finder` (基於路徑的尋檢器)會參考該位置來尋找要 import 的模組。" -#: ../../glossary.rst:952 +#: ../../glossary.rst:960 msgid "path entry finder" msgstr "path entry finder(路徑項目尋檢器)" -#: ../../glossary.rst:954 +#: ../../glossary.rst:962 msgid "" "A :term:`finder` returned by a callable on :data:`sys.path_hooks` (i.e. a :" "term:`path entry hook`) which knows how to locate modules given a :term:" @@ -2181,7 +2198,7 @@ msgstr "" "`path entry hook`\\ )所回傳的一種 :term:`finder`,它知道如何以一個 :term:" "`path entry`\\ 定位模組。" -#: ../../glossary.rst:958 +#: ../../glossary.rst:966 msgid "" "See :class:`importlib.abc.PathEntryFinder` for the methods that path entry " "finders implement." @@ -2189,11 +2206,11 @@ msgstr "" "關於路徑項目尋檢器實作的 method,請參閱 :class:`importlib.abc." "PathEntryFinder`。" -#: ../../glossary.rst:960 +#: ../../glossary.rst:968 msgid "path entry hook" msgstr "path entry hook(路徑項目鉤)" -#: ../../glossary.rst:962 +#: ../../glossary.rst:970 msgid "" "A callable on the :data:`sys.path_hooks` list which returns a :term:`path " "entry finder` if it knows how to find modules on a specific :term:`path " @@ -2203,11 +2220,11 @@ msgstr "" "個特定的 :term:`path entry` 中尋找模組,則會回傳一個 :term:`path entry " "finder`\\ (路徑項目尋檢器)。" -#: ../../glossary.rst:965 +#: ../../glossary.rst:973 msgid "path based finder" msgstr "path based finder(基於路徑的尋檢器)" -#: ../../glossary.rst:967 +#: ../../glossary.rst:975 msgid "" "One of the default :term:`meta path finders ` which " "searches an :term:`import path` for modules." @@ -2215,11 +2232,11 @@ msgstr "" "預設的\\ :term:`元路徑尋檢器 (meta path finder) ` 之一,它" "會在一個 :term:`import path` 中搜尋模組。" -#: ../../glossary.rst:969 +#: ../../glossary.rst:977 msgid "path-like object" msgstr "path-like object(類路徑物件)" -#: ../../glossary.rst:971 +#: ../../glossary.rst:979 msgid "" "An object representing a file system path. A path-like object is either a :" "class:`str` or :class:`bytes` object representing a path, or an object " @@ -2237,11 +2254,11 @@ msgstr "" "`os.fsencode` 則分別可用於確保 :class:`str` 及 :class:`bytes` 的結果。由 :" "pep:`519` 引入。" -#: ../../glossary.rst:979 +#: ../../glossary.rst:987 msgid "PEP" msgstr "PEP" -#: ../../glossary.rst:981 +#: ../../glossary.rst:989 msgid "" "Python Enhancement Proposal. A PEP is a design document providing " "information to the Python community, or describing a new feature for Python " @@ -2252,7 +2269,7 @@ msgstr "" "為 Python 社群提供資訊,或是描述 Python 的一個新功能或該功能的程序和環境。" "PEP 應該要提供簡潔的技術規範以及被提案功能的運作原理。" -#: ../../glossary.rst:987 +#: ../../glossary.rst:995 msgid "" "PEPs are intended to be the primary mechanisms for proposing major new " "features, for collecting community input on an issue, and for documenting " @@ -2264,15 +2281,15 @@ msgstr "" "已納入 Python 的設計決策的記錄,這些過程的主要機制。PEP 的作者要負責在社群內" "建立共識並記錄反對意見。" -#: ../../glossary.rst:993 +#: ../../glossary.rst:1001 msgid "See :pep:`1`." msgstr "請參閱 :pep:`1`。" -#: ../../glossary.rst:994 +#: ../../glossary.rst:1002 msgid "portion" msgstr "portion(部分)" -#: ../../glossary.rst:996 +#: ../../glossary.rst:1004 msgid "" "A set of files in a single directory (possibly stored in a zip file) that " "contribute to a namespace package, as defined in :pep:`420`." @@ -2280,15 +2297,15 @@ msgstr "" "在單一目錄中的一組檔案(也可能儲存在一個 zip 檔中),這些檔案能對一個命名空間" "套件 (namespace package) 有所貢獻,如同 :pep:`420` 中的定義。" -#: ../../glossary.rst:998 +#: ../../glossary.rst:1006 msgid "positional argument" msgstr "positional argument(位置引數)" -#: ../../glossary.rst:1001 +#: ../../glossary.rst:1009 msgid "provisional API" msgstr "provisional API(暫行 API)" -#: ../../glossary.rst:1003 +#: ../../glossary.rst:1011 msgid "" "A provisional API is one which has been deliberately excluded from the " "standard library's backwards compatibility guarantees. While major changes " @@ -2304,7 +2321,7 @@ msgstr "" "該介面)。這種變更並不會無端地產生——只有 API 被納入之前未察覺的嚴重基本缺陷被" "揭露時,它們才會發生。" -#: ../../glossary.rst:1012 +#: ../../glossary.rst:1020 msgid "" "Even for provisional APIs, backwards incompatible changes are seen as a " "\"solution of last resort\" - every attempt will still be made to find a " @@ -2313,7 +2330,7 @@ msgstr "" "即使對於暫行 API,向後不相容的變更也會被視為「最後的解決方案」——對於任何被發" "現的問題,仍然會盡可能找出一個向後相容的解決方案。" -#: ../../glossary.rst:1016 +#: ../../glossary.rst:1024 msgid "" "This process allows the standard library to continue to evolve over time, " "without locking in problematic design errors for extended periods of time. " @@ -2322,19 +2339,19 @@ msgstr "" "這個過程使得標準函式庫能隨著時間不斷進化,而避免耗費過長的時間去鎖定有問題的" "設計錯誤。請參閱 :pep:`411` 了解更多細節。" -#: ../../glossary.rst:1019 +#: ../../glossary.rst:1027 msgid "provisional package" msgstr "provisional package(暫行套件)" -#: ../../glossary.rst:1021 +#: ../../glossary.rst:1029 msgid "See :term:`provisional API`." msgstr "請參閱 :term:`provisional API`\\ (暫行 API)。" -#: ../../glossary.rst:1022 +#: ../../glossary.rst:1030 msgid "Python 3000" msgstr "Python 3000" -#: ../../glossary.rst:1024 +#: ../../glossary.rst:1032 msgid "" "Nickname for the Python 3.x release line (coined long ago when the release " "of version 3 was something in the distant future.) This is also abbreviated " @@ -2343,11 +2360,11 @@ msgstr "" "Python 3.x 系列版本的暱稱(很久以前創造的,當時第 3 版的發布是在遙遠的未" "來。)也可以縮寫為「Py3k」。" -#: ../../glossary.rst:1027 +#: ../../glossary.rst:1035 msgid "Pythonic" msgstr "Pythonic(Python 風格的)" -#: ../../glossary.rst:1029 +#: ../../glossary.rst:1037 msgid "" "An idea or piece of code which closely follows the most common idioms of the " "Python language, rather than implementing code using concepts common to " @@ -2361,7 +2378,7 @@ msgstr "" "keyword:`for` 陳述式,對一個可疊代物件的所有元素進行迴圈。許多其他語言並沒有" "這種類型的架構,所以不熟悉 Python 的人有時會使用一個數值計數器來代替: ::" -#: ../../glossary.rst:1036 +#: ../../glossary.rst:1044 msgid "" "for i in range(len(food)):\n" " print(food[i])" @@ -2369,11 +2386,11 @@ msgstr "" "for i in range(len(food)):\n" " print(food[i])" -#: ../../glossary.rst:1039 +#: ../../glossary.rst:1047 msgid "As opposed to the cleaner, Pythonic method::" msgstr "相較之下,以下方法更簡潔、更具有 Python 風格: ::" -#: ../../glossary.rst:1041 +#: ../../glossary.rst:1049 msgid "" "for piece in food:\n" " print(piece)" @@ -2381,11 +2398,11 @@ msgstr "" "for piece in food:\n" " print(piece)" -#: ../../glossary.rst:1043 +#: ../../glossary.rst:1051 msgid "qualified name" msgstr "qualified name(限定名稱)" -#: ../../glossary.rst:1045 +#: ../../glossary.rst:1053 msgid "" "A dotted name showing the \"path\" from a module's global scope to a class, " "function or method defined in that module, as defined in :pep:`3155`. For " @@ -2396,7 +2413,7 @@ msgstr "" "或 method 的「路徑」,如 :pep:`3155` 中的定義。對於頂層的函式和 class 而言," "限定名稱與其物件名稱相同: ::" -#: ../../glossary.rst:1050 +#: ../../glossary.rst:1058 msgid "" ">>> class C:\n" "... class D:\n" @@ -2422,7 +2439,7 @@ msgstr "" ">>> C.D.meth.__qualname__\n" "'C.D.meth'" -#: ../../glossary.rst:1062 +#: ../../glossary.rst:1070 msgid "" "When used to refer to modules, the *fully qualified name* means the entire " "dotted path to the module, including any parent packages, e.g. ``email.mime." @@ -2431,7 +2448,7 @@ msgstr "" "當用於引用模組時,*完全限定名稱 (fully qualified name)* 是表示該模組的完整點" "分隔路徑,包括任何的父套件,例如 ``email.mime.text``: ::" -#: ../../glossary.rst:1066 +#: ../../glossary.rst:1074 msgid "" ">>> import email.mime.text\n" ">>> email.mime.text.__name__\n" @@ -2441,11 +2458,11 @@ msgstr "" ">>> email.mime.text.__name__\n" "'email.mime.text'" -#: ../../glossary.rst:1069 +#: ../../glossary.rst:1077 msgid "reference count" msgstr "reference count(參照計數)" -#: ../../glossary.rst:1071 +#: ../../glossary.rst:1079 msgid "" "The number of references to an object. When the reference count of an " "object drops to zero, it is deallocated. Some objects are \"immortal\" and " @@ -2461,11 +2478,11 @@ msgstr "" "`CPython` 實作的一個關鍵元素。程式設計師可以呼叫 :func:`~sys.getrefcount` 函" "式來回傳一個特定物件的參照計數。" -#: ../../glossary.rst:1079 +#: ../../glossary.rst:1087 msgid "regular package" msgstr "regular package(正規套件)" -#: ../../glossary.rst:1081 +#: ../../glossary.rst:1089 msgid "" "A traditional :term:`package`, such as a directory containing an ``__init__." "py`` file." @@ -2473,15 +2490,15 @@ msgstr "" "一個傳統的 :term:`package`\\ (套件),例如一個包含 ``__init__.py`` 檔案的目" "錄。" -#: ../../glossary.rst:1084 +#: ../../glossary.rst:1092 msgid "See also :term:`namespace package`." msgstr "另請參閱 :term:`namespace package`\\ (命名空間套件)。" -#: ../../glossary.rst:1085 +#: ../../glossary.rst:1093 msgid "__slots__" msgstr "__slots__" -#: ../../glossary.rst:1087 +#: ../../glossary.rst:1095 msgid "" "A declaration inside a class that saves memory by pre-declaring space for " "instance attributes and eliminating instance dictionaries. Though popular, " @@ -2494,11 +2511,11 @@ msgstr "" "最好保留給那種在一個記憶體關鍵 (memory-critical) 的應用程式中存在大量實例的罕" "見情況。" -#: ../../glossary.rst:1092 +#: ../../glossary.rst:1100 msgid "sequence" msgstr "sequence(序列)" -#: ../../glossary.rst:1094 +#: ../../glossary.rst:1102 msgid "" "An :term:`iterable` which supports efficient element access using integer " "indices via the :meth:`~object.__getitem__` special method and defines a :" @@ -2517,7 +2534,7 @@ msgstr "" "為對映 (mapping) 而不是序列,因為其查找方式是使用任意的 :term:`immutable` " "鍵,而不是整數。" -#: ../../glossary.rst:1103 +#: ../../glossary.rst:1111 msgid "" "The :class:`collections.abc.Sequence` abstract base class defines a much " "richer interface that goes beyond just :meth:`~object.__getitem__` and :meth:" @@ -2534,11 +2551,11 @@ msgstr "" "用 :func:`~abc.ABCMeta.register` 被明確地註冊。更多關於序列方法的文件,請見" "\\ :ref:`常見序列操作 `。" -#: ../../glossary.rst:1112 +#: ../../glossary.rst:1120 msgid "set comprehension" msgstr "set comprehension(集合綜合運算)" -#: ../../glossary.rst:1114 +#: ../../glossary.rst:1122 msgid "" "A compact way to process all or part of the elements in an iterable and " "return a set with the results. ``results = {c for c in 'abracadabra' if c " @@ -2549,11 +2566,11 @@ msgstr "" "set 回傳。``results = {c for c in 'abracadabra' if c not in 'abc'}`` 會產生一" "個字串 set:``{'r', 'd'}``。請參閱\\ :ref:`comprehensions`。" -#: ../../glossary.rst:1118 +#: ../../glossary.rst:1126 msgid "single dispatch" msgstr "single dispatch(單一調度)" -#: ../../glossary.rst:1120 +#: ../../glossary.rst:1128 msgid "" "A form of :term:`generic function` dispatch where the implementation is " "chosen based on the type of a single argument." @@ -2561,11 +2578,11 @@ msgstr "" ":term:`generic function`\\ (泛型函式)調度的一種形式,在此,實作的選擇是基於" "單一引數的型別。" -#: ../../glossary.rst:1122 +#: ../../glossary.rst:1130 msgid "slice" msgstr "slice(切片)" -#: ../../glossary.rst:1124 +#: ../../glossary.rst:1132 msgid "" "An object usually containing a portion of a :term:`sequence`. A slice is " "created using the subscript notation, ``[]`` with colons between numbers " @@ -2577,11 +2594,11 @@ msgstr "" "之間使用冒號,例如 ``variable_name[1:3:5]``。在括號(下標)符號的內部,會使" "用 :class:`slice` 物件。" -#: ../../glossary.rst:1128 +#: ../../glossary.rst:1136 msgid "special method" msgstr "special method(特殊方法)" -#: ../../glossary.rst:1132 +#: ../../glossary.rst:1140 msgid "" "A method that is called implicitly by Python to execute a certain operation " "on a type, such as addition. Such methods have names starting and ending " @@ -2592,11 +2609,11 @@ msgstr "" "種 method 的名稱會在開頭和結尾有兩個下底線。Special method 在\\ :ref:" "`specialnames`\\ 中有詳細說明。" -#: ../../glossary.rst:1136 +#: ../../glossary.rst:1144 msgid "statement" msgstr "statement(陳述式)" -#: ../../glossary.rst:1138 +#: ../../glossary.rst:1146 msgid "" "A statement is part of a suite (a \"block\" of code). A statement is either " "an :term:`expression` or one of several constructs with a keyword, such as :" @@ -2606,11 +2623,11 @@ msgstr "" "term:`expression`\\ (運算式),或是含有關鍵字(例如 :keyword:`if`、:keyword:" "`while` 或 :keyword:`for`\\ )的多種結構之一。" -#: ../../glossary.rst:1141 +#: ../../glossary.rst:1149 msgid "static type checker" msgstr "static type checker(靜態型別檢查器)" -#: ../../glossary.rst:1143 +#: ../../glossary.rst:1151 msgid "" "An external tool that reads Python code and analyzes it, looking for issues " "such as incorrect types. See also :term:`type hints ` and the :" @@ -2620,11 +2637,11 @@ msgstr "" "另請參閱\\ :term:`型別提示 (type hints) ` 以及 :mod:`typing` 模" "組。" -#: ../../glossary.rst:1146 +#: ../../glossary.rst:1154 msgid "strong reference" msgstr "strong reference(強參照)" -#: ../../glossary.rst:1148 +#: ../../glossary.rst:1156 msgid "" "In Python's C API, a strong reference is a reference to an object which is " "owned by the code holding the reference. The strong reference is taken by " @@ -2635,7 +2652,7 @@ msgstr "" "有。建立參照時透過呼叫 :c:func:`Py_INCREF` 來獲得強參照、刪除參照時透過 :c:" "func:`Py_DECREF` 釋放強參照。" -#: ../../glossary.rst:1154 +#: ../../glossary.rst:1162 msgid "" "The :c:func:`Py_NewRef` function can be used to create a strong reference to " "an object. Usually, the :c:func:`Py_DECREF` function must be called on the " @@ -2645,15 +2662,15 @@ msgstr "" ":c:func:`Py_NewRef` 函式可用於建立一個對物件的強參照。通常,在退出強參照的作" "用域之前,必須在該強參照上呼叫 :c:func:`Py_DECREF` 函式,以避免洩漏一個參照。" -#: ../../glossary.rst:1159 +#: ../../glossary.rst:1167 msgid "See also :term:`borrowed reference`." msgstr "另請參閱 :term:`borrowed reference`\\ (借用參照)。" -#: ../../glossary.rst:1160 +#: ../../glossary.rst:1168 msgid "text encoding" msgstr "text encoding(文字編碼)" -#: ../../glossary.rst:1162 +#: ../../glossary.rst:1170 msgid "" "A string in Python is a sequence of Unicode code points (in range " "``U+0000``--``U+10FFFF``). To store or transfer a string, it needs to be " @@ -2662,7 +2679,7 @@ msgstr "" "Python 中的字串是一個 Unicode 碼點 (code point) 的序列(範圍在 ``U+0000`` -- " "``U+10FFFF`` 之間)。若要儲存或傳送一個字串,它必須被序列化為一個位元組序列。" -#: ../../glossary.rst:1166 +#: ../../glossary.rst:1174 msgid "" "Serializing a string into a sequence of bytes is known as \"encoding\", and " "recreating the string from the sequence of bytes is known as \"decoding\"." @@ -2670,7 +2687,7 @@ msgstr "" "將一個字串序列化為位元組序列,稱為「編碼」,而從位元組序列重新建立該字串則稱" "為「解碼 (decoding)」。" -#: ../../glossary.rst:1169 +#: ../../glossary.rst:1177 msgid "" "There are a variety of different text serialization :ref:`codecs `, which are collectively referred to as \"text encodings\"." @@ -2678,11 +2695,11 @@ msgstr "" "有多種不同的文字序列化編解碼器 (:ref:`codecs `),它們被統" "稱為「文字編碼」。" -#: ../../glossary.rst:1172 +#: ../../glossary.rst:1180 msgid "text file" msgstr "text file(文字檔案)" -#: ../../glossary.rst:1174 +#: ../../glossary.rst:1182 msgid "" "A :term:`file object` able to read and write :class:`str` objects. Often, a " "text file actually accesses a byte-oriented datastream and handles the :term:" @@ -2696,7 +2713,7 @@ msgstr "" "有:以文字模式(``'r'`` 或 ``'w'``)開啟的檔案、:data:`sys.stdin`、:data:" "`sys.stdout` 以及 :class:`io.StringIO` 的實例。" -#: ../../glossary.rst:1181 +#: ../../glossary.rst:1189 msgid "" "See also :term:`binary file` for a file object able to read and write :term:" "`bytes-like objects `." @@ -2704,11 +2721,11 @@ msgstr "" "另請參閱 :term:`binary file`\\ (二進位檔案),它是一個能夠讀取和寫入\\ :" "term:`類位元組串物件 (bytes-like object) ` 的檔案物件。" -#: ../../glossary.rst:1183 +#: ../../glossary.rst:1191 msgid "triple-quoted string" msgstr "triple-quoted string(三引號內字串)" -#: ../../glossary.rst:1185 +#: ../../glossary.rst:1193 msgid "" "A string which is bound by three instances of either a quotation mark (\") " "or an apostrophe ('). While they don't provide any functionality not " @@ -2723,11 +2740,11 @@ msgstr "" "中包含未跳脫 (unescaped) 的單引號和雙引號,而且它們不需使用連續字元 " "(continuation character) 就可以跨越多行,這使得它們在編寫說明字串時特別有用。" -#: ../../glossary.rst:1192 +#: ../../glossary.rst:1200 msgid "type" msgstr "type(型別)" -#: ../../glossary.rst:1194 +#: ../../glossary.rst:1202 msgid "" "The type of a Python object determines what kind of object it is; every " "object has a type. An object's type is accessible as its :attr:`~instance." @@ -2737,22 +2754,22 @@ msgstr "" "件的型別可以用它的 :attr:`~instance.__class__` 屬性來存取,或以 " "``type(obj)`` 來檢索。" -#: ../../glossary.rst:1198 +#: ../../glossary.rst:1206 msgid "type alias" msgstr "type alias(型別別名)" -#: ../../glossary.rst:1200 +#: ../../glossary.rst:1208 msgid "A synonym for a type, created by assigning the type to an identifier." msgstr "一個型別的同義詞,透過將型別指定給一個識別符 (identifier) 來建立。" -#: ../../glossary.rst:1202 +#: ../../glossary.rst:1210 msgid "" "Type aliases are useful for simplifying :term:`type hints `. For " "example::" msgstr "" "型別別名對於簡化\\ :term:`型別提示 (type hint) ` 很有用。例如: ::" -#: ../../glossary.rst:1205 +#: ../../glossary.rst:1213 msgid "" "def remove_gray_shades(\n" " colors: list[tuple[int, int, int]]) -> list[tuple[int, int, int]]:\n" @@ -2762,11 +2779,11 @@ msgstr "" " colors: list[tuple[int, int, int]]) -> list[tuple[int, int, int]]:\n" " pass" -#: ../../glossary.rst:1209 +#: ../../glossary.rst:1217 msgid "could be made more readable like this::" msgstr "可以寫成這樣,更具有可讀性: ::" -#: ../../glossary.rst:1211 +#: ../../glossary.rst:1219 msgid "" "Color = tuple[int, int, int]\n" "\n" @@ -2778,15 +2795,15 @@ msgstr "" "def remove_gray_shades(colors: list[Color]) -> list[Color]:\n" " pass" -#: ../../glossary.rst:1216 ../../glossary.rst:1230 +#: ../../glossary.rst:1224 ../../glossary.rst:1238 msgid "See :mod:`typing` and :pep:`484`, which describe this functionality." msgstr "請參閱 :mod:`typing` 和 :pep:`484`,有此功能的描述。" -#: ../../glossary.rst:1217 +#: ../../glossary.rst:1225 msgid "type hint" msgstr "type hint(型別提示)" -#: ../../glossary.rst:1219 +#: ../../glossary.rst:1227 msgid "" "An :term:`annotation` that specifies the expected type for a variable, a " "class attribute, or a function parameter or return value." @@ -2794,7 +2811,7 @@ msgstr "" "一種 :term:`annotation`\\ (註釋),它指定一個變數、一個 class 屬性或一個函式" "的參數或回傳值的預期型別。" -#: ../../glossary.rst:1222 +#: ../../glossary.rst:1230 msgid "" "Type hints are optional and are not enforced by Python but they are useful " "to :term:`static type checkers `. They can also aid " @@ -2804,7 +2821,7 @@ msgstr "" "(static type checkers) `\\ 很有用,並能協助 IDE 完成程式" "碼的補全 (completion) 和重構 (refactoring)。" -#: ../../glossary.rst:1226 +#: ../../glossary.rst:1234 msgid "" "Type hints of global variables, class attributes, and functions, but not " "local variables, can be accessed using :func:`typing.get_type_hints`." @@ -2812,11 +2829,11 @@ msgstr "" "全域變數、class 屬性和函式(不含區域變數)的型別提示,都可以使用 :func:" "`typing.get_type_hints` 來存取。" -#: ../../glossary.rst:1231 +#: ../../glossary.rst:1239 msgid "universal newlines" msgstr "universal newlines(通用換行字元)" -#: ../../glossary.rst:1233 +#: ../../glossary.rst:1241 msgid "" "A manner of interpreting text streams in which all of the following are " "recognized as ending a line: the Unix end-of-line convention ``'\\n'``, the " @@ -2829,20 +2846,20 @@ msgstr "" "``'\\r'``。請參閱 :pep:`278` 和 :pep:`3116`,以及用於 :func:`bytes." "splitlines` 的附加用途。" -#: ../../glossary.rst:1238 +#: ../../glossary.rst:1246 msgid "variable annotation" msgstr "variable annotation(變數註釋)" -#: ../../glossary.rst:1240 +#: ../../glossary.rst:1248 msgid "An :term:`annotation` of a variable or a class attribute." msgstr "一個變數或 class 屬性的 :term:`annotation`\\ (註釋)。" -#: ../../glossary.rst:1242 +#: ../../glossary.rst:1250 msgid "" "When annotating a variable or a class attribute, assignment is optional::" msgstr "註釋變數或 class 屬性時,賦值是選擇性的: ::" -#: ../../glossary.rst:1244 +#: ../../glossary.rst:1252 msgid "" "class C:\n" " field: 'annotation'" @@ -2850,7 +2867,7 @@ msgstr "" "class C:\n" " field: 'annotation'" -#: ../../glossary.rst:1247 +#: ../../glossary.rst:1255 msgid "" "Variable annotations are usually used for :term:`type hints `: " "for example this variable is expected to take :class:`int` values::" @@ -2858,15 +2875,15 @@ msgstr "" "變數註釋通常用於\\ :term:`型別提示 (type hint) `:例如,這個變數預" "期會取得 :class:`int`\\ (整數)值: ::" -#: ../../glossary.rst:1251 +#: ../../glossary.rst:1259 msgid "count: int = 0" msgstr "count: int = 0" -#: ../../glossary.rst:1253 +#: ../../glossary.rst:1261 msgid "Variable annotation syntax is explained in section :ref:`annassign`." msgstr "變數註釋的語法在\\ :ref:`annassign`\\ 章節有詳細的解釋。" -#: ../../glossary.rst:1255 +#: ../../glossary.rst:1263 msgid "" "See :term:`function annotation`, :pep:`484` and :pep:`526`, which describe " "this functionality. Also see :ref:`annotations-howto` for best practices on " @@ -2875,11 +2892,11 @@ msgstr "" "請參閱 :term:`function annotation`\\ (函式註釋)、:pep:`484` 和 :pep:`526`," "皆有此功能的描述。關於註釋的最佳實踐方法,另請參閱 :ref:`annotations-howto`。" -#: ../../glossary.rst:1259 +#: ../../glossary.rst:1267 msgid "virtual environment" msgstr "virtual environment(虛擬環境)" -#: ../../glossary.rst:1261 +#: ../../glossary.rst:1269 msgid "" "A cooperatively isolated runtime environment that allows Python users and " "applications to install and upgrade Python distribution packages without " @@ -2890,15 +2907,15 @@ msgstr "" "程式得以安裝和升級 Python 發佈套件,而不會對同一個系統上運行的其他 Python 應" "用程式的行為產生干擾。" -#: ../../glossary.rst:1266 +#: ../../glossary.rst:1274 msgid "See also :mod:`venv`." msgstr "另請參閱 :mod:`venv`。" -#: ../../glossary.rst:1267 +#: ../../glossary.rst:1275 msgid "virtual machine" msgstr "virtual machine(虛擬機器)" -#: ../../glossary.rst:1269 +#: ../../glossary.rst:1277 msgid "" "A computer defined entirely in software. Python's virtual machine executes " "the :term:`bytecode` emitted by the bytecode compiler." @@ -2906,11 +2923,11 @@ msgstr "" "一部完全由軟體所定義的電腦 (computer)。Python 的虛擬機器會執行由 :term:" "`bytecode`\\ (位元組碼)編譯器所發出的位元組碼。" -#: ../../glossary.rst:1271 +#: ../../glossary.rst:1279 msgid "Zen of Python" msgstr "Zen of Python(Python 之禪)" -#: ../../glossary.rst:1273 +#: ../../glossary.rst:1281 msgid "" "Listing of Python design principles and philosophies that are helpful in " "understanding and using the language. The listing can be found by typing " @@ -2927,10 +2944,10 @@ msgstr "C-contiguous(C 連續的)" msgid "Fortran contiguous" msgstr "Fortran contiguous(Fortran 連續的)" -#: ../../glossary.rst:761 +#: ../../glossary.rst:769 msgid "magic" msgstr "magic" -#: ../../glossary.rst:1130 +#: ../../glossary.rst:1138 msgid "special" msgstr "special" diff --git a/howto/argparse.po b/howto/argparse.po index 089914495b..a7aa86ddb4 100644 --- a/howto/argparse.po +++ b/howto/argparse.po @@ -12,7 +12,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-07-24 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2023-12-11 17:33+0800\n" "Last-Translator: Matt Wang \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -66,6 +66,26 @@ msgid "" msgstr "" "讓我們透過使用 :command:`ls` 指令來展示我們將在本介紹教學中探索的功能類型:" +#: ../../howto/argparse.rst:29 +msgid "" +"$ ls\n" +"cpython devguide prog.py pypy rm-unused-function.patch\n" +"$ ls pypy\n" +"ctypes_configure demo dotviewer include lib_pypy lib-python ...\n" +"$ ls -l\n" +"total 20\n" +"drwxr-xr-x 19 wena wena 4096 Feb 18 18:51 cpython\n" +"drwxr-xr-x 4 wena wena 4096 Feb 8 12:04 devguide\n" +"-rwxr-xr-x 1 wena wena 535 Feb 19 00:05 prog.py\n" +"drwxr-xr-x 14 wena wena 4096 Feb 7 00:59 pypy\n" +"-rw-r--r-- 1 wena wena 741 Feb 18 01:01 rm-unused-function.patch\n" +"$ ls --help\n" +"Usage: ls [OPTION]... [FILE]...\n" +"List information about the FILEs (the current directory by default).\n" +"Sort entries alphabetically if none of -cftuvSUX nor --sort is specified.\n" +"..." +msgstr "" + #: ../../howto/argparse.rst:48 msgid "A few concepts we can learn from the four commands:" msgstr "我們可以從這四個命令中學到一些概念:" @@ -121,11 +141,34 @@ msgstr "基本用法" msgid "Let us start with a very simple example which does (almost) nothing::" msgstr "讓我們從一個非常簡單的例子開始,它(幾乎)什麼都不做: ::" +#: ../../howto/argparse.rst:76 +msgid "" +"import argparse\n" +"parser = argparse.ArgumentParser()\n" +"parser.parse_args()" +msgstr "" + #: ../../howto/argparse.rst:80 ../../howto/argparse.rst:188 #: ../../howto/argparse.rst:209 msgid "Following is a result of running the code:" msgstr "程式碼執行結果如下:" +#: ../../howto/argparse.rst:82 +msgid "" +"$ python prog.py\n" +"$ python prog.py --help\n" +"usage: prog.py [-h]\n" +"\n" +"options:\n" +" -h, --help show this help message and exit\n" +"$ python prog.py --verbose\n" +"usage: prog.py [-h]\n" +"prog.py: error: unrecognized arguments: --verbose\n" +"$ python prog.py foo\n" +"usage: prog.py [-h]\n" +"prog.py: error: unrecognized arguments: foo" +msgstr "" + #: ../../howto/argparse.rst:97 ../../howto/argparse.rst:254 #: ../../howto/argparse.rst:298 msgid "Here is what is happening:" @@ -164,10 +207,36 @@ msgstr "位置引數的介紹" msgid "An example::" msgstr "例如: ::" +#: ../../howto/argparse.rst:116 +msgid "" +"import argparse\n" +"parser = argparse.ArgumentParser()\n" +"parser.add_argument(\"echo\")\n" +"args = parser.parse_args()\n" +"print(args.echo)" +msgstr "" + #: ../../howto/argparse.rst:122 msgid "And running the code:" msgstr "執行這段程式碼:" +#: ../../howto/argparse.rst:124 +msgid "" +"$ python prog.py\n" +"usage: prog.py [-h] echo\n" +"prog.py: error: the following arguments are required: echo\n" +"$ python prog.py --help\n" +"usage: prog.py [-h] echo\n" +"\n" +"positional arguments:\n" +" echo\n" +"\n" +"options:\n" +" -h, --help show this help message and exit\n" +"$ python prog.py foo\n" +"foo" +msgstr "" + #: ../../howto/argparse.rst:140 msgid "Here is what's happening:" msgstr "這是會發生的事情:" @@ -216,14 +285,54 @@ msgstr "" "看到 ``echo`` 作為位置引數,但除了猜測或閱讀原始程式碼之外,我們不知道它的作" "用。那麼,我們來讓它變得更有用一點: ::" +#: ../../howto/argparse.rst:161 +msgid "" +"import argparse\n" +"parser = argparse.ArgumentParser()\n" +"parser.add_argument(\"echo\", help=\"echo the string you use here\")\n" +"args = parser.parse_args()\n" +"print(args.echo)" +msgstr "" + #: ../../howto/argparse.rst:167 msgid "And we get:" msgstr "然後我們得到:" +#: ../../howto/argparse.rst:169 +msgid "" +"$ python prog.py -h\n" +"usage: prog.py [-h] echo\n" +"\n" +"positional arguments:\n" +" echo echo the string you use here\n" +"\n" +"options:\n" +" -h, --help show this help message and exit" +msgstr "" + #: ../../howto/argparse.rst:180 msgid "Now, how about doing something even more useful::" msgstr "現在來做一些更有用處的事情: ::" +#: ../../howto/argparse.rst:182 +msgid "" +"import argparse\n" +"parser = argparse.ArgumentParser()\n" +"parser.add_argument(\"square\", help=\"display a square of a given " +"number\")\n" +"args = parser.parse_args()\n" +"print(args.square**2)" +msgstr "" + +#: ../../howto/argparse.rst:190 +msgid "" +"$ python prog.py 4\n" +"Traceback (most recent call last):\n" +" File \"prog.py\", line 5, in \n" +" print(args.square**2)\n" +"TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'int'" +msgstr "" + #: ../../howto/argparse.rst:198 msgid "" "That didn't go so well. That's because :mod:`argparse` treats the options we " @@ -233,6 +342,26 @@ msgstr "" "進展不太順利。這是因為,除非我們另有說明,:mod:`argparse` 會將我們給它的選項" "視為字串。因此,讓我們告訴 :mod:`argparse` 將該輸入視為整數: ::" +#: ../../howto/argparse.rst:202 +msgid "" +"import argparse\n" +"parser = argparse.ArgumentParser()\n" +"parser.add_argument(\"square\", help=\"display a square of a given " +"number\",\n" +" type=int)\n" +"args = parser.parse_args()\n" +"print(args.square**2)" +msgstr "" + +#: ../../howto/argparse.rst:211 +msgid "" +"$ python prog.py 4\n" +"16\n" +"$ python prog.py four\n" +"usage: prog.py [-h] square\n" +"prog.py: error: argument square: invalid int value: 'four'" +msgstr "" + #: ../../howto/argparse.rst:219 msgid "" "That went well. The program now even helpfully quits on bad illegal input " @@ -249,11 +378,38 @@ msgid "" "how to add optional ones::" msgstr "到目前為止,我們一直在討論位置引數。我們來看看如何新增可選引數: ::" +#: ../../howto/argparse.rst:229 +msgid "" +"import argparse\n" +"parser = argparse.ArgumentParser()\n" +"parser.add_argument(\"--verbosity\", help=\"increase output verbosity\")\n" +"args = parser.parse_args()\n" +"if args.verbosity:\n" +" print(\"verbosity turned on\")" +msgstr "" + #: ../../howto/argparse.rst:236 ../../howto/argparse.rst:282 #: ../../howto/argparse.rst:398 ../../howto/argparse.rst:432 msgid "And the output:" msgstr "接者是結果:" +#: ../../howto/argparse.rst:238 +msgid "" +"$ python prog.py --verbosity 1\n" +"verbosity turned on\n" +"$ python prog.py\n" +"$ python prog.py --help\n" +"usage: prog.py [-h] [--verbosity VERBOSITY]\n" +"\n" +"options:\n" +" -h, --help show this help message and exit\n" +" --verbosity VERBOSITY\n" +" increase output verbosity\n" +"$ python prog.py --verbosity\n" +"usage: prog.py [-h] [--verbosity VERBOSITY]\n" +"prog.py: error: argument --verbosity: expected one argument" +msgstr "" + #: ../../howto/argparse.rst:256 msgid "" "The program is written so as to display something when ``--verbosity`` is " @@ -293,6 +449,32 @@ msgstr "" "在上面的例子中,``--verbosity`` 接受任意的整數,但對我們的程式來說只接受兩個" "輸入值, ``True`` 或 ``False``。所以我們來修改一下程式碼使其符合: ::" +#: ../../howto/argparse.rst:274 +msgid "" +"import argparse\n" +"parser = argparse.ArgumentParser()\n" +"parser.add_argument(\"--verbose\", help=\"increase output verbosity\",\n" +" action=\"store_true\")\n" +"args = parser.parse_args()\n" +"if args.verbose:\n" +" print(\"verbosity turned on\")" +msgstr "" + +#: ../../howto/argparse.rst:284 +msgid "" +"$ python prog.py --verbose\n" +"verbosity turned on\n" +"$ python prog.py --verbose 1\n" +"usage: prog.py [-h] [--verbose]\n" +"prog.py: error: unrecognized arguments: 1\n" +"$ python prog.py --help\n" +"usage: prog.py [-h] [--verbose]\n" +"\n" +"options:\n" +" -h, --help show this help message and exit\n" +" --verbose increase output verbosity" +msgstr "" + #: ../../howto/argparse.rst:300 msgid "" "The option is now more of a flag than something that requires a value. We " @@ -328,10 +510,34 @@ msgid "" msgstr "" "如果你熟悉命令列用法,你會注意到我尚未提及選項的簡短版本。這很簡單: ::" +#: ../../howto/argparse.rst:320 +msgid "" +"import argparse\n" +"parser = argparse.ArgumentParser()\n" +"parser.add_argument(\"-v\", \"--verbose\", help=\"increase output " +"verbosity\",\n" +" action=\"store_true\")\n" +"args = parser.parse_args()\n" +"if args.verbose:\n" +" print(\"verbosity turned on\")" +msgstr "" + #: ../../howto/argparse.rst:328 msgid "And here goes:" msgstr "而這為:" +#: ../../howto/argparse.rst:330 +msgid "" +"$ python prog.py -v\n" +"verbosity turned on\n" +"$ python prog.py --help\n" +"usage: prog.py [-h] [-v]\n" +"\n" +"options:\n" +" -h, --help show this help message and exit\n" +" -v, --verbose increase output verbosity" +msgstr "" + #: ../../howto/argparse.rst:341 msgid "Note that the new ability is also reflected in the help text." msgstr "請注意,新功能也反映在幫助文字中。" @@ -344,10 +550,39 @@ msgstr "組合位置引數和可選引數" msgid "Our program keeps growing in complexity::" msgstr "我們的程式的複雜性不斷增加: ::" +#: ../../howto/argparse.rst:349 +msgid "" +"import argparse\n" +"parser = argparse.ArgumentParser()\n" +"parser.add_argument(\"square\", type=int,\n" +" help=\"display a square of a given number\")\n" +"parser.add_argument(\"-v\", \"--verbose\", action=\"store_true\",\n" +" help=\"increase output verbosity\")\n" +"args = parser.parse_args()\n" +"answer = args.square**2\n" +"if args.verbose:\n" +" print(f\"the square of {args.square} equals {answer}\")\n" +"else:\n" +" print(answer)" +msgstr "" + #: ../../howto/argparse.rst:362 msgid "And now the output:" msgstr "然後現在的輸出結果:" +#: ../../howto/argparse.rst:364 +msgid "" +"$ python prog.py\n" +"usage: prog.py [-h] [-v] square\n" +"prog.py: error: the following arguments are required: square\n" +"$ python prog.py 4\n" +"16\n" +"$ python prog.py 4 --verbose\n" +"the square of 4 equals 16\n" +"$ python prog.py --verbose 4\n" +"the square of 4 equals 16" +msgstr "" + #: ../../howto/argparse.rst:376 msgid "We've brought back a positional argument, hence the complaint." msgstr "我們帶回了位置引數,因而被抱怨。" @@ -364,6 +599,39 @@ msgstr "" "我們讓這個程式擁有多個訊息詳細級別 (verbosity) 之值的能力,並實際使用它" "們: ::" +#: ../../howto/argparse.rst:383 +msgid "" +"import argparse\n" +"parser = argparse.ArgumentParser()\n" +"parser.add_argument(\"square\", type=int,\n" +" help=\"display a square of a given number\")\n" +"parser.add_argument(\"-v\", \"--verbosity\", type=int,\n" +" help=\"increase output verbosity\")\n" +"args = parser.parse_args()\n" +"answer = args.square**2\n" +"if args.verbosity == 2:\n" +" print(f\"the square of {args.square} equals {answer}\")\n" +"elif args.verbosity == 1:\n" +" print(f\"{args.square}^2 == {answer}\")\n" +"else:\n" +" print(answer)" +msgstr "" + +#: ../../howto/argparse.rst:400 +msgid "" +"$ python prog.py 4\n" +"16\n" +"$ python prog.py 4 -v\n" +"usage: prog.py [-h] [-v VERBOSITY] square\n" +"prog.py: error: argument -v/--verbosity: expected one argument\n" +"$ python prog.py 4 -v 1\n" +"4^2 == 16\n" +"$ python prog.py 4 -v 2\n" +"the square of 4 equals 16\n" +"$ python prog.py 4 -v 3\n" +"16" +msgstr "" + #: ../../howto/argparse.rst:414 msgid "" "These all look good except the last one, which exposes a bug in our program. " @@ -373,6 +641,42 @@ msgstr "" "除了最後一個外都看起來正常,它透露了我們程式中的一個錯誤。我們可透過限制 ``--" "verbosity`` 選項可以接受的值來修復它: ::" +#: ../../howto/argparse.rst:417 +msgid "" +"import argparse\n" +"parser = argparse.ArgumentParser()\n" +"parser.add_argument(\"square\", type=int,\n" +" help=\"display a square of a given number\")\n" +"parser.add_argument(\"-v\", \"--verbosity\", type=int, choices=[0, 1, 2],\n" +" help=\"increase output verbosity\")\n" +"args = parser.parse_args()\n" +"answer = args.square**2\n" +"if args.verbosity == 2:\n" +" print(f\"the square of {args.square} equals {answer}\")\n" +"elif args.verbosity == 1:\n" +" print(f\"{args.square}^2 == {answer}\")\n" +"else:\n" +" print(answer)" +msgstr "" + +#: ../../howto/argparse.rst:434 +msgid "" +"$ python prog.py 4 -v 3\n" +"usage: prog.py [-h] [-v {0,1,2}] square\n" +"prog.py: error: argument -v/--verbosity: invalid choice: 3 (choose from 0, " +"1, 2)\n" +"$ python prog.py 4 -h\n" +"usage: prog.py [-h] [-v {0,1,2}] square\n" +"\n" +"positional arguments:\n" +" square display a square of a given number\n" +"\n" +"options:\n" +" -h, --help show this help message and exit\n" +" -v {0,1,2}, --verbosity {0,1,2}\n" +" increase output verbosity" +msgstr "" + #: ../../howto/argparse.rst:450 msgid "" "Note that the change also reflects both in the error message as well as the " @@ -388,12 +692,56 @@ msgstr "" "現在,讓我們使用另一種常見方法來玩玩訊息詳細級別。它也與 CPython 執行檔處理其" "自身訊息詳細級別引數的方式相符(請見 ``python --help`` 的輸出): ::" +#: ../../howto/argparse.rst:457 +msgid "" +"import argparse\n" +"parser = argparse.ArgumentParser()\n" +"parser.add_argument(\"square\", type=int,\n" +" help=\"display the square of a given number\")\n" +"parser.add_argument(\"-v\", \"--verbosity\", action=\"count\",\n" +" help=\"increase output verbosity\")\n" +"args = parser.parse_args()\n" +"answer = args.square**2\n" +"if args.verbosity == 2:\n" +" print(f\"the square of {args.square} equals {answer}\")\n" +"elif args.verbosity == 1:\n" +" print(f\"{args.square}^2 == {answer}\")\n" +"else:\n" +" print(answer)" +msgstr "" + #: ../../howto/argparse.rst:472 msgid "" "We have introduced another action, \"count\", to count the number of " "occurrences of specific options." msgstr "我們已經介紹過另一個操作 \"count\" 用來計算指定的選項出現的次數。" +#: ../../howto/argparse.rst:476 +msgid "" +"$ python prog.py 4\n" +"16\n" +"$ python prog.py 4 -v\n" +"4^2 == 16\n" +"$ python prog.py 4 -vv\n" +"the square of 4 equals 16\n" +"$ python prog.py 4 --verbosity --verbosity\n" +"the square of 4 equals 16\n" +"$ python prog.py 4 -v 1\n" +"usage: prog.py [-h] [-v] square\n" +"prog.py: error: unrecognized arguments: 1\n" +"$ python prog.py 4 -h\n" +"usage: prog.py [-h] [-v] square\n" +"\n" +"positional arguments:\n" +" square display a square of a given number\n" +"\n" +"options:\n" +" -h, --help show this help message and exit\n" +" -v, --verbosity increase output verbosity\n" +"$ python prog.py 4 -vvv\n" +"16" +msgstr "" + #: ../../howto/argparse.rst:501 msgid "" "Yes, it's now more of a flag (similar to ``action=\"store_true\"``) in the " @@ -441,10 +789,43 @@ msgstr "最後的輸出透露了我們程式中的一個錯誤。" msgid "Let's fix::" msgstr "讓我們來解決問題: ::" +#: ../../howto/argparse.rst:524 +msgid "" +"import argparse\n" +"parser = argparse.ArgumentParser()\n" +"parser.add_argument(\"square\", type=int,\n" +" help=\"display a square of a given number\")\n" +"parser.add_argument(\"-v\", \"--verbosity\", action=\"count\",\n" +" help=\"increase output verbosity\")\n" +"args = parser.parse_args()\n" +"answer = args.square**2\n" +"\n" +"# bugfix: replace == with >=\n" +"if args.verbosity >= 2:\n" +" print(f\"the square of {args.square} equals {answer}\")\n" +"elif args.verbosity >= 1:\n" +" print(f\"{args.square}^2 == {answer}\")\n" +"else:\n" +" print(answer)" +msgstr "" + #: ../../howto/argparse.rst:541 msgid "And this is what it gives:" msgstr "這就是它給出的:" +#: ../../howto/argparse.rst:543 +msgid "" +"$ python prog.py 4 -vvv\n" +"the square of 4 equals 16\n" +"$ python prog.py 4 -vvvv\n" +"the square of 4 equals 16\n" +"$ python prog.py 4\n" +"Traceback (most recent call last):\n" +" File \"prog.py\", line 11, in \n" +" if args.verbosity >= 2:\n" +"TypeError: '>=' not supported between instances of 'NoneType' and 'int'" +msgstr "" + #: ../../howto/argparse.rst:556 msgid "" "First output went well, and fixes the bug we had before. That is, we want " @@ -461,6 +842,24 @@ msgstr "第三個輸出不太好。" msgid "Let's fix that bug::" msgstr "我們來修復這個錯誤: ::" +#: ../../howto/argparse.rst:563 +msgid "" +"import argparse\n" +"parser = argparse.ArgumentParser()\n" +"parser.add_argument(\"square\", type=int,\n" +" help=\"display a square of a given number\")\n" +"parser.add_argument(\"-v\", \"--verbosity\", action=\"count\", default=0,\n" +" help=\"increase output verbosity\")\n" +"args = parser.parse_args()\n" +"answer = args.square**2\n" +"if args.verbosity >= 2:\n" +" print(f\"the square of {args.square} equals {answer}\")\n" +"elif args.verbosity >= 1:\n" +" print(f\"{args.square}^2 == {answer}\")\n" +"else:\n" +" print(answer)" +msgstr "" + #: ../../howto/argparse.rst:578 msgid "" "We've just introduced yet another keyword, ``default``. We've set it to " @@ -477,6 +876,12 @@ msgstr "" msgid "And:" msgstr "而且:" +#: ../../howto/argparse.rst:587 +msgid "" +"$ python prog.py 4\n" +"16" +msgstr "" + #: ../../howto/argparse.rst:592 msgid "" "You can go quite far just with what we've learned so far, and we have only " @@ -497,10 +902,46 @@ msgid "" "just squares::" msgstr "如果我們想擴充我們的小程式來執行其他次方的運算,而不僅是平方: ::" +#: ../../howto/argparse.rst:604 +msgid "" +"import argparse\n" +"parser = argparse.ArgumentParser()\n" +"parser.add_argument(\"x\", type=int, help=\"the base\")\n" +"parser.add_argument(\"y\", type=int, help=\"the exponent\")\n" +"parser.add_argument(\"-v\", \"--verbosity\", action=\"count\", default=0)\n" +"args = parser.parse_args()\n" +"answer = args.x**args.y\n" +"if args.verbosity >= 2:\n" +" print(f\"{args.x} to the power {args.y} equals {answer}\")\n" +"elif args.verbosity >= 1:\n" +" print(f\"{args.x}^{args.y} == {answer}\")\n" +"else:\n" +" print(answer)" +msgstr "" + #: ../../howto/argparse.rst:618 ../../howto/argparse.rst:656 msgid "Output:" msgstr "結果:" +#: ../../howto/argparse.rst:620 +msgid "" +"$ python prog.py\n" +"usage: prog.py [-h] [-v] x y\n" +"prog.py: error: the following arguments are required: x, y\n" +"$ python prog.py -h\n" +"usage: prog.py [-h] [-v] x y\n" +"\n" +"positional arguments:\n" +" x the base\n" +" y the exponent\n" +"\n" +"options:\n" +" -h, --help show this help message and exit\n" +" -v, --verbosity\n" +"$ python prog.py 4 2 -v\n" +"4^2 == 16" +msgstr "" + #: ../../howto/argparse.rst:639 msgid "" "Notice that so far we've been using verbosity level to *change* the text " @@ -510,6 +951,33 @@ msgstr "" "請注意,到目前為止,我們一直在使用詳細級別來\\ *更改*\\ 顯示的文字。以下範例" "使用詳細級別來顯示\\ *更多*\\ 文字: ::" +#: ../../howto/argparse.rst:643 +msgid "" +"import argparse\n" +"parser = argparse.ArgumentParser()\n" +"parser.add_argument(\"x\", type=int, help=\"the base\")\n" +"parser.add_argument(\"y\", type=int, help=\"the exponent\")\n" +"parser.add_argument(\"-v\", \"--verbosity\", action=\"count\", default=0)\n" +"args = parser.parse_args()\n" +"answer = args.x**args.y\n" +"if args.verbosity >= 2:\n" +" print(f\"Running '{__file__}'\")\n" +"if args.verbosity >= 1:\n" +" print(f\"{args.x}^{args.y} == \", end=\"\")\n" +"print(answer)" +msgstr "" + +#: ../../howto/argparse.rst:658 +msgid "" +"$ python prog.py 4 2\n" +"16\n" +"$ python prog.py 4 2 -v\n" +"4^2 == 16\n" +"$ python prog.py 4 2 -vv\n" +"Running 'prog.py'\n" +"4^2 == 16" +msgstr "" + #: ../../howto/argparse.rst:672 msgid "Specifying ambiguous arguments" msgstr "指定不明確的引數" @@ -523,6 +991,28 @@ msgstr "" "當決定一個引數是位置引數還是引數會有歧義,可以使用 ``--`` 來告訴 :meth:" "`~ArgumentParser.parse_args` 之後的所有內容都是位置引數: ::" +#: ../../howto/argparse.rst:678 +msgid "" +">>> parser = argparse.ArgumentParser(prog='PROG')\n" +">>> parser.add_argument('-n', nargs='+')\n" +">>> parser.add_argument('args', nargs='*')\n" +"\n" +">>> # ambiguous, so parse_args assumes it's an option\n" +">>> parser.parse_args(['-f'])\n" +"usage: PROG [-h] [-n N [N ...]] [args ...]\n" +"PROG: error: unrecognized arguments: -f\n" +"\n" +">>> parser.parse_args(['--', '-f'])\n" +"Namespace(args=['-f'], n=None)\n" +"\n" +">>> # ambiguous, so the -n option greedily accepts arguments\n" +">>> parser.parse_args(['-n', '1', '2', '3'])\n" +"Namespace(args=[], n=['1', '2', '3'])\n" +"\n" +">>> parser.parse_args(['-n', '1', '--', '2', '3'])\n" +"Namespace(args=['2', '3'], n=['1'])" +msgstr "" + #: ../../howto/argparse.rst:699 msgid "Conflicting options" msgstr "相互衝突的選項" @@ -541,6 +1031,27 @@ msgstr "" "許我們指定彼此衝突的選項。我們還可以更改程式的其餘部分,以使得新功能更有意" "義:我們將引入 ``--quiet`` 選項,該選項與 ``--verbose`` 選項相反: ::" +#: ../../howto/argparse.rst:709 +msgid "" +"import argparse\n" +"\n" +"parser = argparse.ArgumentParser()\n" +"group = parser.add_mutually_exclusive_group()\n" +"group.add_argument(\"-v\", \"--verbose\", action=\"store_true\")\n" +"group.add_argument(\"-q\", \"--quiet\", action=\"store_true\")\n" +"parser.add_argument(\"x\", type=int, help=\"the base\")\n" +"parser.add_argument(\"y\", type=int, help=\"the exponent\")\n" +"args = parser.parse_args()\n" +"answer = args.x**args.y\n" +"\n" +"if args.quiet:\n" +" print(answer)\n" +"elif args.verbose:\n" +" print(f\"{args.x} to the power {args.y} equals {answer}\")\n" +"else:\n" +" print(f\"{args.x}^{args.y} == {answer}\")" +msgstr "" + #: ../../howto/argparse.rst:727 msgid "" "Our program is now simpler, and we've lost some functionality for the sake " @@ -549,6 +1060,22 @@ msgstr "" "我們的程式現在更簡單了,我們因為功能展示失去了一些功能,但無論如何,以下這是" "輸出:" +#: ../../howto/argparse.rst:730 +msgid "" +"$ python prog.py 4 2\n" +"4^2 == 16\n" +"$ python prog.py 4 2 -q\n" +"16\n" +"$ python prog.py 4 2 -v\n" +"4 to the power 2 equals 16\n" +"$ python prog.py 4 2 -vq\n" +"usage: prog.py [-h] [-v | -q] x y\n" +"prog.py: error: argument -q/--quiet: not allowed with argument -v/--verbose\n" +"$ python prog.py 4 2 -v --quiet\n" +"usage: prog.py [-h] [-v | -q] x y\n" +"prog.py: error: argument -q/--quiet: not allowed with argument -v/--verbose" +msgstr "" + #: ../../howto/argparse.rst:745 msgid "" "That should be easy to follow. I've added that last output so you can see " @@ -565,6 +1092,28 @@ msgid "" msgstr "" "在我們結束之前,你可能想告訴使用者你的程式的主要目的,以防他們不知道: ::" +#: ../../howto/argparse.rst:752 +msgid "" +"import argparse\n" +"\n" +"parser = argparse.ArgumentParser(description=\"calculate X to the power of " +"Y\")\n" +"group = parser.add_mutually_exclusive_group()\n" +"group.add_argument(\"-v\", \"--verbose\", action=\"store_true\")\n" +"group.add_argument(\"-q\", \"--quiet\", action=\"store_true\")\n" +"parser.add_argument(\"x\", type=int, help=\"the base\")\n" +"parser.add_argument(\"y\", type=int, help=\"the exponent\")\n" +"args = parser.parse_args()\n" +"answer = args.x**args.y\n" +"\n" +"if args.quiet:\n" +" print(answer)\n" +"elif args.verbose:\n" +" print(f\"{args.x} to the power {args.y} equals {answer}\")\n" +"else:\n" +" print(f\"{args.x}^{args.y} == {answer}\")" +msgstr "" + #: ../../howto/argparse.rst:770 msgid "" "Note that slight difference in the usage text. Note the ``[-v | -q]``, which " @@ -574,6 +1123,23 @@ msgstr "" "請注意用法文字中的細微差別。注意 ``[-v | -q]``,它告訴我們可以使用 ``-v`` 或 " "``-q``,但不能同時使用:" +#: ../../howto/argparse.rst:774 ../../howto/argparse.rst:801 +msgid "" +"$ python prog.py --help\n" +"usage: prog.py [-h] [-v | -q] x y\n" +"\n" +"calculate X to the power of Y\n" +"\n" +"positional arguments:\n" +" x the base\n" +" y the exponent\n" +"\n" +"options:\n" +" -h, --help show this help message and exit\n" +" -v, --verbose\n" +" -q, --quiet" +msgstr "" + #: ../../howto/argparse.rst:792 msgid "How to translate the argparse output" msgstr "如何翻譯 argparse 輸出" @@ -610,6 +1176,10 @@ msgstr "" "為了翻譯這些字串,必須先將它們提取到 ``.po`` 檔案中。例如,使用 `Babel " "`__ 並執行下列命令:" +#: ../../howto/argparse.rst:824 +msgid "$ pybabel extract -o messages.po /usr/lib/python3.12/argparse.py" +msgstr "" + #: ../../howto/argparse.rst:828 msgid "" "This command will extract all translatable strings from the :mod:`argparse` " @@ -625,6 +1195,12 @@ msgid "" "using this script::" msgstr "你可以使用以下腳本找到 :mod:`argparse` 模組在系統上的位置: ::" +#: ../../howto/argparse.rst:835 +msgid "" +"import argparse\n" +"print(argparse.__file__)" +msgstr "" + #: ../../howto/argparse.rst:838 msgid "" "Once the messages in the ``.po`` file are translated and the translations " diff --git a/howto/curses.po b/howto/curses.po index 82f7853a4f..6f7b3d581a 100644 --- a/howto/curses.po +++ b/howto/curses.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-04-16 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2018-05-23 14:36+0000\n" "Last-Translator: Adrian Liaw \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -141,6 +141,12 @@ msgid "" "after the name of the corresponding C variable. ::" msgstr "" +#: ../../howto/curses.rst:90 +msgid "" +"import curses\n" +"stdscr = curses.initscr()" +msgstr "" + #: ../../howto/curses.rst:93 msgid "" "Usually curses applications turn off automatic echoing of keys to the " @@ -148,6 +154,10 @@ msgid "" "circumstances. This requires calling the :func:`~curses.noecho` function. ::" msgstr "" +#: ../../howto/curses.rst:98 +msgid "curses.noecho()" +msgstr "" + #: ../../howto/curses.rst:100 msgid "" "Applications will also commonly need to react to keys instantly, without " @@ -155,6 +165,10 @@ msgid "" "opposed to the usual buffered input mode. ::" msgstr "" +#: ../../howto/curses.rst:104 +msgid "curses.cbreak()" +msgstr "" + #: ../../howto/curses.rst:106 msgid "" "Terminals usually return special keys, such as the cursor keys or navigation " @@ -165,12 +179,23 @@ msgid "" "keypad mode. ::" msgstr "" +#: ../../howto/curses.rst:113 +msgid "stdscr.keypad(True)" +msgstr "" + #: ../../howto/curses.rst:115 msgid "" "Terminating a curses application is much easier than starting one. You'll " "need to call::" msgstr "" +#: ../../howto/curses.rst:118 +msgid "" +"curses.nocbreak()\n" +"stdscr.keypad(False)\n" +"curses.echo()" +msgstr "" + #: ../../howto/curses.rst:122 msgid "" "to reverse the curses-friendly terminal settings. Then call the :func:" @@ -178,6 +203,10 @@ msgid "" "mode. ::" msgstr "" +#: ../../howto/curses.rst:126 +msgid "curses.endwin()" +msgstr "" + #: ../../howto/curses.rst:128 msgid "" "A common problem when debugging a curses application is to get your terminal " @@ -193,6 +222,25 @@ msgid "" "by importing the :func:`curses.wrapper` function and using it like this::" msgstr "" +#: ../../howto/curses.rst:137 +msgid "" +"from curses import wrapper\n" +"\n" +"def main(stdscr):\n" +" # Clear screen\n" +" stdscr.clear()\n" +"\n" +" # This raises ZeroDivisionError when i == 10.\n" +" for i in range(0, 11):\n" +" v = i-10\n" +" stdscr.addstr(i, 0, '10 divided by {} is {}'.format(v, 10/v))\n" +"\n" +" stdscr.refresh()\n" +" stdscr.getkey()\n" +"\n" +"wrapper(main)" +msgstr "" + #: ../../howto/curses.rst:153 msgid "" "The :func:`~curses.wrapper` function takes a callable object and does the " @@ -227,6 +275,13 @@ msgid "" "window object. ::" msgstr "" +#: ../../howto/curses.rst:178 +msgid "" +"begin_x = 20; begin_y = 7\n" +"height = 5; width = 40\n" +"win = curses.newwin(height, width, begin_y, begin_x)" +msgstr "" + #: ../../howto/curses.rst:182 msgid "" "Note that the coordinate system used in curses is unusual. Coordinates are " @@ -282,6 +337,24 @@ msgid "" "will be displayed. ::" msgstr "" +#: ../../howto/curses.rst:223 +msgid "" +"pad = curses.newpad(100, 100)\n" +"# These loops fill the pad with letters; addch() is\n" +"# explained in the next section\n" +"for y in range(0, 99):\n" +" for x in range(0, 99):\n" +" pad.addch(y,x, ord('a') + (x*x+y*y) % 26)\n" +"\n" +"# Displays a section of the pad in the middle of the screen.\n" +"# (0,0) : coordinate of upper-left corner of pad area to display.\n" +"# (5,5) : coordinate of upper-left corner of window area to be filled\n" +"# with pad content.\n" +"# (20, 75) : coordinate of lower-right corner of window area to be\n" +"# : filled with pad content.\n" +"pad.refresh( 0,0, 5,5, 20,75)" +msgstr "" + #: ../../howto/curses.rst:238 msgid "" "The :meth:`!refresh` call displays a section of the pad in the rectangle " @@ -515,6 +588,13 @@ msgid "" "you could code::" msgstr "" +#: ../../howto/curses.rst:364 +msgid "" +"stdscr.addstr(0, 0, \"Current mode: Typing mode\",\n" +" curses.A_REVERSE)\n" +"stdscr.refresh()" +msgstr "" + #: ../../howto/curses.rst:368 msgid "" "The curses library also supports color on those terminals that provide it. " @@ -548,6 +628,12 @@ msgstr "" msgid "An example, which displays a line of text using color pair 1::" msgstr "" +#: ../../howto/curses.rst:391 +msgid "" +"stdscr.addstr(\"Pretty text\", curses.color_pair(1))\n" +"stdscr.refresh()" +msgstr "" + #: ../../howto/curses.rst:394 msgid "" "As I said before, a color pair consists of a foreground and background " @@ -571,6 +657,10 @@ msgid "" "background, you would call::" msgstr "" +#: ../../howto/curses.rst:408 +msgid "curses.init_pair(1, curses.COLOR_RED, curses.COLOR_WHITE)" +msgstr "" + #: ../../howto/curses.rst:410 msgid "" "When you change a color pair, any text already displayed using that color " @@ -578,6 +668,10 @@ msgid "" "color with::" msgstr "" +#: ../../howto/curses.rst:414 +msgid "stdscr.addstr(0,0, \"RED ALERT!\", curses.color_pair(1))" +msgstr "" + #: ../../howto/curses.rst:416 msgid "" "Very fancy terminals can change the definitions of the actual colors to a " @@ -643,6 +737,18 @@ msgid "" "program may look something like this::" msgstr "" +#: ../../howto/curses.rst:462 +msgid "" +"while True:\n" +" c = stdscr.getch()\n" +" if c == ord('p'):\n" +" PrintDocument()\n" +" elif c == ord('q'):\n" +" break # Exit the while loop\n" +" elif c == curses.KEY_HOME:\n" +" x = y = 0" +msgstr "" + #: ../../howto/curses.rst:471 msgid "" "The :mod:`curses.ascii` module supplies ASCII class membership functions " @@ -662,6 +768,14 @@ msgid "" "number of characters. ::" msgstr "" +#: ../../howto/curses.rst:484 +msgid "" +"curses.echo() # Enable echoing of characters\n" +"\n" +"# Get a 15-character string, with the cursor on the top line\n" +"s = stdscr.getstr(0,0, 15)" +msgstr "" + #: ../../howto/curses.rst:489 msgid "" "The :mod:`curses.textpad` module supplies a text box that supports an Emacs-" @@ -670,6 +784,27 @@ msgid "" "results either with or without trailing spaces. Here's an example::" msgstr "" +#: ../../howto/curses.rst:495 +msgid "" +"import curses\n" +"from curses.textpad import Textbox, rectangle\n" +"\n" +"def main(stdscr):\n" +" stdscr.addstr(0, 0, \"Enter IM message: (hit Ctrl-G to send)\")\n" +"\n" +" editwin = curses.newwin(5,30, 2,1)\n" +" rectangle(stdscr, 1,0, 1+5+1, 1+30+1)\n" +" stdscr.refresh()\n" +"\n" +" box = Textbox(editwin)\n" +"\n" +" # Let the user edit until Ctrl-G is struck.\n" +" box.edit()\n" +"\n" +" # Get resulting contents\n" +" message = box.gather()" +msgstr "" + #: ../../howto/curses.rst:513 msgid "" "See the library documentation on :mod:`curses.textpad` for more details." diff --git a/howto/descriptor.po b/howto/descriptor.po index 65087d1a6c..89a7c0cf1a 100644 --- a/howto/descriptor.po +++ b/howto/descriptor.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-08-30 18:24+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2018-05-23 14:36+0000\n" "Last-Translator: Adrian Liaw \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -99,18 +99,41 @@ msgid "" "returns the constant ``10``:" msgstr "" +#: ../../howto/descriptor.rst:48 +msgid "" +"class Ten:\n" +" def __get__(self, obj, objtype=None):\n" +" return 10" +msgstr "" + #: ../../howto/descriptor.rst:54 msgid "" "To use the descriptor, it must be stored as a class variable in another " "class:" msgstr "" +#: ../../howto/descriptor.rst:56 +msgid "" +"class A:\n" +" x = 5 # Regular class attribute\n" +" y = Ten() # Descriptor instance" +msgstr "" + #: ../../howto/descriptor.rst:62 msgid "" "An interactive session shows the difference between normal attribute lookup " "and descriptor lookup:" msgstr "" +#: ../../howto/descriptor.rst:65 +msgid "" +">>> a = A() # Make an instance of class A\n" +">>> a.x # Normal attribute lookup\n" +"5\n" +">>> a.y # Descriptor lookup\n" +"10" +msgstr "" + #: ../../howto/descriptor.rst:73 msgid "" "In the ``a.x`` attribute lookup, the dot operator finds ``'x': 5`` in the " @@ -146,12 +169,45 @@ msgid "" "constants:" msgstr "" +#: ../../howto/descriptor.rst:93 +msgid "" +"import os\n" +"\n" +"class DirectorySize:\n" +"\n" +" def __get__(self, obj, objtype=None):\n" +" return len(os.listdir(obj.dirname))\n" +"\n" +"class Directory:\n" +"\n" +" size = DirectorySize() # Descriptor instance\n" +"\n" +" def __init__(self, dirname):\n" +" self.dirname = dirname # Regular instance attribute" +msgstr "" + #: ../../howto/descriptor.rst:109 msgid "" "An interactive session shows that the lookup is dynamic — it computes " "different, updated answers each time::" msgstr "" +#: ../../howto/descriptor.rst:112 +msgid "" +">>> s = Directory('songs')\n" +">>> g = Directory('games')\n" +">>> s.size # The songs directory has twenty " +"files\n" +"20\n" +">>> g.size # The games directory has three " +"files\n" +"3\n" +">>> os.remove('games/chess') # Delete a game\n" +">>> g.size # File count is automatically " +"updated\n" +"2" +msgstr "" + #: ../../howto/descriptor.rst:122 msgid "" "Besides showing how descriptors can run computations, this example also " @@ -182,12 +238,71 @@ msgid "" "logs the lookup or update:" msgstr "" +#: ../../howto/descriptor.rst:143 +msgid "" +"import logging\n" +"\n" +"logging.basicConfig(level=logging.INFO)\n" +"\n" +"class LoggedAgeAccess:\n" +"\n" +" def __get__(self, obj, objtype=None):\n" +" value = obj._age\n" +" logging.info('Accessing %r giving %r', 'age', value)\n" +" return value\n" +"\n" +" def __set__(self, obj, value):\n" +" logging.info('Updating %r to %r', 'age', value)\n" +" obj._age = value\n" +"\n" +"class Person:\n" +"\n" +" age = LoggedAgeAccess() # Descriptor instance\n" +"\n" +" def __init__(self, name, age):\n" +" self.name = name # Regular instance attribute\n" +" self.age = age # Calls __set__()\n" +"\n" +" def birthday(self):\n" +" self.age += 1 # Calls both __get__() and __set__()" +msgstr "" + #: ../../howto/descriptor.rst:172 msgid "" "An interactive session shows that all access to the managed attribute *age* " "is logged, but that the regular attribute *name* is not logged:" msgstr "" +#: ../../howto/descriptor.rst:181 +msgid "" +">>> mary = Person('Mary M', 30) # The initial age update is logged\n" +"INFO:root:Updating 'age' to 30\n" +">>> dave = Person('David D', 40)\n" +"INFO:root:Updating 'age' to 40\n" +"\n" +">>> vars(mary) # The actual data is in a private " +"attribute\n" +"{'name': 'Mary M', '_age': 30}\n" +">>> vars(dave)\n" +"{'name': 'David D', '_age': 40}\n" +"\n" +">>> mary.age # Access the data and log the " +"lookup\n" +"INFO:root:Accessing 'age' giving 30\n" +"30\n" +">>> mary.birthday() # Updates are logged as well\n" +"INFO:root:Accessing 'age' giving 30\n" +"INFO:root:Updating 'age' to 31\n" +"\n" +">>> dave.name # Regular attribute lookup isn't " +"logged\n" +"'David D'\n" +">>> dave.age # Only the managed attribute is " +"logged\n" +"INFO:root:Accessing 'age' giving 40\n" +"40" +msgstr "" + #: ../../howto/descriptor.rst:206 msgid "" "One major issue with this example is that the private name *_age* is " @@ -215,6 +330,40 @@ msgid "" "*private_name*:" msgstr "" +#: ../../howto/descriptor.rst:223 +msgid "" +"import logging\n" +"\n" +"logging.basicConfig(level=logging.INFO)\n" +"\n" +"class LoggedAccess:\n" +"\n" +" def __set_name__(self, owner, name):\n" +" self.public_name = name\n" +" self.private_name = '_' + name\n" +"\n" +" def __get__(self, obj, objtype=None):\n" +" value = getattr(obj, self.private_name)\n" +" logging.info('Accessing %r giving %r', self.public_name, value)\n" +" return value\n" +"\n" +" def __set__(self, obj, value):\n" +" logging.info('Updating %r to %r', self.public_name, value)\n" +" setattr(obj, self.private_name, value)\n" +"\n" +"class Person:\n" +"\n" +" name = LoggedAccess() # First descriptor instance\n" +" age = LoggedAccess() # Second descriptor instance\n" +"\n" +" def __init__(self, name, age):\n" +" self.name = name # Calls the first descriptor\n" +" self.age = age # Calls the second descriptor\n" +"\n" +" def birthday(self):\n" +" self.age += 1" +msgstr "" + #: ../../howto/descriptor.rst:256 msgid "" "An interactive session shows that the :class:`Person` class has called :meth:" @@ -222,14 +371,40 @@ msgid "" "func:`vars` to look up the descriptor without triggering it:" msgstr "" +#: ../../howto/descriptor.rst:260 +msgid "" +">>> vars(vars(Person)['name'])\n" +"{'public_name': 'name', 'private_name': '_name'}\n" +">>> vars(vars(Person)['age'])\n" +"{'public_name': 'age', 'private_name': '_age'}" +msgstr "" + #: ../../howto/descriptor.rst:267 msgid "The new class now logs access to both *name* and *age*:" msgstr "" +#: ../../howto/descriptor.rst:275 +msgid "" +">>> pete = Person('Peter P', 10)\n" +"INFO:root:Updating 'name' to 'Peter P'\n" +"INFO:root:Updating 'age' to 10\n" +">>> kate = Person('Catherine C', 20)\n" +"INFO:root:Updating 'name' to 'Catherine C'\n" +"INFO:root:Updating 'age' to 20" +msgstr "" + #: ../../howto/descriptor.rst:284 msgid "The two *Person* instances contain only the private names:" msgstr "" +#: ../../howto/descriptor.rst:286 +msgid "" +">>> vars(pete)\n" +"{'_name': 'Peter P', '_age': 10}\n" +">>> vars(kate)\n" +"{'_name': 'Catherine C', '_age': 20}" +msgstr "" + #: ../../howto/descriptor.rst:295 msgid "Closing thoughts" msgstr "" @@ -310,6 +485,27 @@ msgid "" "managed attribute descriptor:" msgstr "" +#: ../../howto/descriptor.rst:343 +msgid "" +"from abc import ABC, abstractmethod\n" +"\n" +"class Validator(ABC):\n" +"\n" +" def __set_name__(self, owner, name):\n" +" self.private_name = '_' + name\n" +"\n" +" def __get__(self, obj, objtype=None):\n" +" return getattr(obj, self.private_name)\n" +"\n" +" def __set__(self, obj, value):\n" +" self.validate(value)\n" +" setattr(obj, self.private_name, value)\n" +"\n" +" @abstractmethod\n" +" def validate(self, value):\n" +" pass" +msgstr "" + #: ../../howto/descriptor.rst:363 msgid "" "Custom validators need to inherit from :class:`Validator` and must supply a :" @@ -344,6 +540,61 @@ msgid "" "as well." msgstr "" +#: ../../howto/descriptor.rst:383 +msgid "" +"class OneOf(Validator):\n" +"\n" +" def __init__(self, *options):\n" +" self.options = set(options)\n" +"\n" +" def validate(self, value):\n" +" if value not in self.options:\n" +" raise ValueError(f'Expected {value!r} to be one of {self.options!" +"r}')\n" +"\n" +"class Number(Validator):\n" +"\n" +" def __init__(self, minvalue=None, maxvalue=None):\n" +" self.minvalue = minvalue\n" +" self.maxvalue = maxvalue\n" +"\n" +" def validate(self, value):\n" +" if not isinstance(value, (int, float)):\n" +" raise TypeError(f'Expected {value!r} to be an int or float')\n" +" if self.minvalue is not None and value < self.minvalue:\n" +" raise ValueError(\n" +" f'Expected {value!r} to be at least {self.minvalue!r}'\n" +" )\n" +" if self.maxvalue is not None and value > self.maxvalue:\n" +" raise ValueError(\n" +" f'Expected {value!r} to be no more than {self.maxvalue!r}'\n" +" )\n" +"\n" +"class String(Validator):\n" +"\n" +" def __init__(self, minsize=None, maxsize=None, predicate=None):\n" +" self.minsize = minsize\n" +" self.maxsize = maxsize\n" +" self.predicate = predicate\n" +"\n" +" def validate(self, value):\n" +" if not isinstance(value, str):\n" +" raise TypeError(f'Expected {value!r} to be an str')\n" +" if self.minsize is not None and len(value) < self.minsize:\n" +" raise ValueError(\n" +" f'Expected {value!r} to be no smaller than {self.minsize!" +"r}'\n" +" )\n" +" if self.maxsize is not None and len(value) > self.maxsize:\n" +" raise ValueError(\n" +" f'Expected {value!r} to be no bigger than {self.maxsize!r}'\n" +" )\n" +" if self.predicate is not None and not self.predicate(value):\n" +" raise ValueError(\n" +" f'Expected {self.predicate} to be true for {value!r}'\n" +" )" +msgstr "" + #: ../../howto/descriptor.rst:437 msgid "Practical application" msgstr "" @@ -352,10 +603,50 @@ msgstr "" msgid "Here's how the data validators can be used in a real class:" msgstr "" +#: ../../howto/descriptor.rst:441 +msgid "" +"class Component:\n" +"\n" +" name = String(minsize=3, maxsize=10, predicate=str.isupper)\n" +" kind = OneOf('wood', 'metal', 'plastic')\n" +" quantity = Number(minvalue=0)\n" +"\n" +" def __init__(self, name, kind, quantity):\n" +" self.name = name\n" +" self.kind = kind\n" +" self.quantity = quantity" +msgstr "" + #: ../../howto/descriptor.rst:454 msgid "The descriptors prevent invalid instances from being created:" msgstr "" +#: ../../howto/descriptor.rst:456 +msgid "" +">>> Component('Widget', 'metal', 5) # Blocked: 'Widget' is not all " +"uppercase\n" +"Traceback (most recent call last):\n" +" ...\n" +"ValueError: Expected to be true for " +"'Widget'\n" +"\n" +">>> Component('WIDGET', 'metle', 5) # Blocked: 'metle' is misspelled\n" +"Traceback (most recent call last):\n" +" ...\n" +"ValueError: Expected 'metle' to be one of {'metal', 'plastic', 'wood'}\n" +"\n" +">>> Component('WIDGET', 'metal', -5) # Blocked: -5 is negative\n" +"Traceback (most recent call last):\n" +" ...\n" +"ValueError: Expected -5 to be at least 0\n" +">>> Component('WIDGET', 'metal', 'V') # Blocked: 'V' isn't a number\n" +"Traceback (most recent call last):\n" +" ...\n" +"TypeError: Expected 'V' to be an int or float\n" +"\n" +">>> c = Component('WIDGET', 'metal', 5) # Allowed: The inputs are valid" +msgstr "" + #: ../../howto/descriptor.rst:481 msgid "Technical Tutorial" msgstr "" @@ -517,6 +808,35 @@ msgid "" "is a pure Python equivalent:" msgstr "" +#: ../../howto/descriptor.rst:583 +msgid "" +"def find_name_in_mro(cls, name, default):\n" +" \"Emulate _PyType_Lookup() in Objects/typeobject.c\"\n" +" for base in cls.__mro__:\n" +" if name in vars(base):\n" +" return vars(base)[name]\n" +" return default\n" +"\n" +"def object_getattribute(obj, name):\n" +" \"Emulate PyObject_GenericGetAttr() in Objects/object.c\"\n" +" null = object()\n" +" objtype = type(obj)\n" +" cls_var = find_name_in_mro(objtype, name, null)\n" +" descr_get = getattr(type(cls_var), '__get__', null)\n" +" if descr_get is not null:\n" +" if (hasattr(type(cls_var), '__set__')\n" +" or hasattr(type(cls_var), '__delete__')):\n" +" return descr_get(cls_var, obj, objtype) # data descriptor\n" +" if hasattr(obj, '__dict__') and name in vars(obj):\n" +" return vars(obj)[name] # instance variable\n" +" if descr_get is not null:\n" +" return descr_get(cls_var, obj, objtype) # non-data " +"descriptor\n" +" if cls_var is not null:\n" +" return cls_var # class variable\n" +" raise AttributeError(name)" +msgstr "" + #: ../../howto/descriptor.rst:719 msgid "" "Note, there is no :meth:`__getattr__` hook in the :meth:`__getattribute__` " @@ -532,6 +852,18 @@ msgid "" "encapsulated in a helper function:" msgstr "" +#: ../../howto/descriptor.rst:728 +msgid "" +"def getattr_hook(obj, name):\n" +" \"Emulate slot_tp_getattr_hook() in Objects/typeobject.c\"\n" +" try:\n" +" return obj.__getattribute__(name)\n" +" except AttributeError:\n" +" if not hasattr(type(obj), '__getattr__'):\n" +" raise\n" +" return type(obj).__getattr__(obj, name) # __getattr__" +msgstr "" + #: ../../howto/descriptor.rst:773 msgid "Invocation from a class" msgstr "" @@ -671,6 +1003,24 @@ msgid "" "care of lookups or updates:" msgstr "" +#: ../../howto/descriptor.rst:858 +msgid "" +"class Field:\n" +"\n" +" def __set_name__(self, owner, name):\n" +" self.fetch = f'SELECT {name} FROM {owner.table} WHERE {owner.key}" +"=?;'\n" +" self.store = f'UPDATE {owner.table} SET {name}=? WHERE {owner.key}" +"=?;'\n" +"\n" +" def __get__(self, obj, objtype=None):\n" +" return conn.execute(self.fetch, [obj.key]).fetchone()[0]\n" +"\n" +" def __set__(self, obj, value):\n" +" conn.execute(self.store, [value, obj.key])\n" +" conn.commit()" +msgstr "" + #: ../../howto/descriptor.rst:873 msgid "" "We can use the :class:`Field` class to define `models >> import sqlite3\n" +">>> conn = sqlite3.connect('entertainment.db')" +msgstr "" + #: ../../howto/descriptor.rst:903 msgid "" "An interactive session shows how data is retrieved from the database and how " "it can be updated:" msgstr "" +#: ../../howto/descriptor.rst:931 +msgid "" +">>> Movie('Star Wars').director\n" +"'George Lucas'\n" +">>> jaws = Movie('Jaws')\n" +">>> f'Released in {jaws.year} by {jaws.director}'\n" +"'Released in 1975 by Steven Spielberg'\n" +"\n" +">>> Song('Country Roads').artist\n" +"'John Denver'\n" +"\n" +">>> Movie('Star Wars').director = 'J.J. Abrams'\n" +">>> Movie('Star Wars').director\n" +"'J.J. Abrams'" +msgstr "" + #: ../../howto/descriptor.rst:952 msgid "Pure Python Equivalents" msgstr "" @@ -711,17 +1105,89 @@ msgid "" "is::" msgstr "" +#: ../../howto/descriptor.rst:966 +msgid "property(fget=None, fset=None, fdel=None, doc=None) -> property" +msgstr "" + #: ../../howto/descriptor.rst:968 msgid "" "The documentation shows a typical use to define a managed attribute ``x``:" msgstr "" +#: ../../howto/descriptor.rst:970 +msgid "" +"class C:\n" +" def getx(self): return self.__x\n" +" def setx(self, value): self.__x = value\n" +" def delx(self): del self.__x\n" +" x = property(getx, setx, delx, \"I'm the 'x' property.\")" +msgstr "" + #: ../../howto/descriptor.rst:992 msgid "" "To see how :func:`property` is implemented in terms of the descriptor " "protocol, here is a pure Python equivalent:" msgstr "" +#: ../../howto/descriptor.rst:995 +msgid "" +"class Property:\n" +" \"Emulate PyProperty_Type() in Objects/descrobject.c\"\n" +"\n" +" def __init__(self, fget=None, fset=None, fdel=None, doc=None):\n" +" self.fget = fget\n" +" self.fset = fset\n" +" self.fdel = fdel\n" +" if doc is None and fget is not None:\n" +" doc = fget.__doc__\n" +" self.__doc__ = doc\n" +" self._name = ''\n" +"\n" +" def __set_name__(self, owner, name):\n" +" self._name = name\n" +"\n" +" def __get__(self, obj, objtype=None):\n" +" if obj is None:\n" +" return self\n" +" if self.fget is None:\n" +" raise AttributeError(\n" +" f'property {self._name!r} of {type(obj).__name__!r} object " +"has no getter'\n" +" )\n" +" return self.fget(obj)\n" +"\n" +" def __set__(self, obj, value):\n" +" if self.fset is None:\n" +" raise AttributeError(\n" +" f'property {self._name!r} of {type(obj).__name__!r} object " +"has no setter'\n" +" )\n" +" self.fset(obj, value)\n" +"\n" +" def __delete__(self, obj):\n" +" if self.fdel is None:\n" +" raise AttributeError(\n" +" f'property {self._name!r} of {type(obj).__name__!r} object " +"has no deleter'\n" +" )\n" +" self.fdel(obj)\n" +"\n" +" def getter(self, fget):\n" +" prop = type(self)(fget, self.fset, self.fdel, self.__doc__)\n" +" prop._name = self._name\n" +" return prop\n" +"\n" +" def setter(self, fset):\n" +" prop = type(self)(self.fget, fset, self.fdel, self.__doc__)\n" +" prop._name = self._name\n" +" return prop\n" +"\n" +" def deleter(self, fdel):\n" +" prop = type(self)(self.fget, self.fset, fdel, self.__doc__)\n" +" prop._name = self._name\n" +" return prop" +msgstr "" + #: ../../howto/descriptor.rst:1132 msgid "" "The :func:`property` builtin helps whenever a user interface has granted " @@ -739,6 +1205,18 @@ msgid "" "descriptor:" msgstr "" +#: ../../howto/descriptor.rst:1142 +msgid "" +"class Cell:\n" +" ...\n" +"\n" +" @property\n" +" def value(self):\n" +" \"Recalculate the cell before returning value\"\n" +" self.recalc()\n" +" return self._value" +msgstr "" + #: ../../howto/descriptor.rst:1153 msgid "" "Either the built-in :func:`property` or our :func:`Property` equivalent " @@ -769,6 +1247,21 @@ msgid "" "roughly equivalent to:" msgstr "" +#: ../../howto/descriptor.rst:1171 +msgid "" +"class MethodType:\n" +" \"Emulate PyMethod_Type in Objects/classobject.c\"\n" +"\n" +" def __init__(self, func, obj):\n" +" self.__func__ = func\n" +" self.__self__ = obj\n" +"\n" +" def __call__(self, *args, **kwargs):\n" +" func = self.__func__\n" +" obj = self.__self__\n" +" return func(obj, *args, **kwargs)" +msgstr "" + #: ../../howto/descriptor.rst:1185 msgid "" "To support automatic creation of methods, functions include the :meth:" @@ -777,41 +1270,94 @@ msgid "" "dotted lookup from an instance. Here's how it works:" msgstr "" +#: ../../howto/descriptor.rst:1190 +msgid "" +"class Function:\n" +" ...\n" +"\n" +" def __get__(self, obj, objtype=None):\n" +" \"Simulate func_descr_get() in Objects/funcobject.c\"\n" +" if obj is None:\n" +" return self\n" +" return MethodType(self, obj)" +msgstr "" + #: ../../howto/descriptor.rst:1201 msgid "" "Running the following class in the interpreter shows how the function " "descriptor works in practice:" msgstr "" +#: ../../howto/descriptor.rst:1204 +msgid "" +"class D:\n" +" def f(self, x):\n" +" return x" +msgstr "" + #: ../../howto/descriptor.rst:1210 msgid "" "The function has a :term:`qualified name` attribute to support introspection:" msgstr "" +#: ../../howto/descriptor.rst:1212 +msgid "" +">>> D.f.__qualname__\n" +"'D.f'" +msgstr "" + #: ../../howto/descriptor.rst:1217 msgid "" "Accessing the function through the class dictionary does not invoke :meth:" "`__get__`. Instead, it just returns the underlying function object::" msgstr "" +#: ../../howto/descriptor.rst:1220 +msgid "" +">>> D.__dict__['f']\n" +"" +msgstr "" + #: ../../howto/descriptor.rst:1223 msgid "" "Dotted access from a class calls :meth:`__get__` which just returns the " "underlying function unchanged::" msgstr "" +#: ../../howto/descriptor.rst:1226 +msgid "" +">>> D.f\n" +"" +msgstr "" + #: ../../howto/descriptor.rst:1229 msgid "" "The interesting behavior occurs during dotted access from an instance. The " "dotted lookup calls :meth:`__get__` which returns a bound method object::" msgstr "" +#: ../../howto/descriptor.rst:1232 +msgid "" +">>> d = D()\n" +">>> d.f\n" +">" +msgstr "" + #: ../../howto/descriptor.rst:1236 msgid "" "Internally, the bound method stores the underlying function and the bound " "instance::" msgstr "" +#: ../../howto/descriptor.rst:1239 +msgid "" +">>> d.f.__func__\n" +"\n" +"\n" +">>> d.f.__self__\n" +"<__main__.D object at 0x00B18C90>" +msgstr "" + #: ../../howto/descriptor.rst:1245 msgid "" "If you have ever wondered where *self* comes from in regular methods or " @@ -917,12 +1463,46 @@ msgid "" "example calls are unexciting:" msgstr "" +#: ../../howto/descriptor.rst:1298 +msgid "" +"class E:\n" +" @staticmethod\n" +" def f(x):\n" +" return x * 10" +msgstr "" + +#: ../../howto/descriptor.rst:1305 +msgid "" +">>> E.f(3)\n" +"30\n" +">>> E().f(3)\n" +"30" +msgstr "" + #: ../../howto/descriptor.rst:1312 msgid "" "Using the non-data descriptor protocol, a pure Python version of :func:" "`staticmethod` would look like this:" msgstr "" +#: ../../howto/descriptor.rst:1315 +msgid "" +"import functools\n" +"\n" +"class StaticMethod:\n" +" \"Emulate PyStaticMethod_Type() in Objects/funcobject.c\"\n" +"\n" +" def __init__(self, f):\n" +" self.f = f\n" +" functools.update_wrapper(self, f)\n" +"\n" +" def __get__(self, obj, objtype=None):\n" +" return self.f\n" +"\n" +" def __call__(self, *args, **kwds):\n" +" return self.f(*args, **kwds)" +msgstr "" + #: ../../howto/descriptor.rst:1332 msgid "" "The :func:`functools.update_wrapper` call adds a ``__wrapped__`` attribute " @@ -943,6 +1523,22 @@ msgid "" "whether the caller is an object or a class:" msgstr "" +#: ../../howto/descriptor.rst:1407 +msgid "" +"class F:\n" +" @classmethod\n" +" def f(cls, x):\n" +" return cls.__name__, x" +msgstr "" + +#: ../../howto/descriptor.rst:1414 +msgid "" +">>> F.f(3)\n" +"('F', 3)\n" +">>> F().f(3)\n" +"('F', 3)" +msgstr "" + #: ../../howto/descriptor.rst:1421 msgid "" "This behavior is useful whenever the method only needs to have a class " @@ -952,16 +1548,58 @@ msgid "" "of keys. The pure Python equivalent is:" msgstr "" +#: ../../howto/descriptor.rst:1427 +msgid "" +"class Dict(dict):\n" +" @classmethod\n" +" def fromkeys(cls, iterable, value=None):\n" +" \"Emulate dict_fromkeys() in Objects/dictobject.c\"\n" +" d = cls()\n" +" for key in iterable:\n" +" d[key] = value\n" +" return d" +msgstr "" + #: ../../howto/descriptor.rst:1438 msgid "Now a new dictionary of unique keys can be constructed like this:" msgstr "" +#: ../../howto/descriptor.rst:1440 +msgid "" +">>> d = Dict.fromkeys('abracadabra')\n" +">>> type(d) is Dict\n" +"True\n" +">>> d\n" +"{'a': None, 'b': None, 'r': None, 'c': None, 'd': None}" +msgstr "" + #: ../../howto/descriptor.rst:1448 msgid "" "Using the non-data descriptor protocol, a pure Python version of :func:" "`classmethod` would look like this:" msgstr "" +#: ../../howto/descriptor.rst:1451 +msgid "" +"import functools\n" +"\n" +"class ClassMethod:\n" +" \"Emulate PyClassMethod_Type() in Objects/funcobject.c\"\n" +"\n" +" def __init__(self, f):\n" +" self.f = f\n" +" functools.update_wrapper(self, f)\n" +"\n" +" def __get__(self, obj, cls=None):\n" +" if cls is None:\n" +" cls = type(obj)\n" +" if hasattr(type(self.f), '__get__'):\n" +" # This code path was added in Python 3.9\n" +" # and was deprecated in Python 3.11.\n" +" return self.f.__get__(cls, cls)\n" +" return MethodType(self.f, cls)" +msgstr "" + #: ../../howto/descriptor.rst:1526 msgid "" "The code path for ``hasattr(type(self.f), '__get__')`` was added in Python " @@ -970,6 +1608,21 @@ msgid "" "together. In Python 3.11, this functionality was deprecated." msgstr "" +#: ../../howto/descriptor.rst:1531 +msgid "" +"class G:\n" +" @classmethod\n" +" @property\n" +" def __doc__(cls):\n" +" return f'A doc for {cls.__name__!r}'" +msgstr "" + +#: ../../howto/descriptor.rst:1539 +msgid "" +">>> G.__doc__\n" +"\"A doc for 'G'\"" +msgstr "" + #: ../../howto/descriptor.rst:1544 msgid "" "The :func:`functools.update_wrapper` call in ``ClassMethod`` adds a " @@ -997,12 +1650,62 @@ msgid "" "assignments. Only attribute names specified in ``__slots__`` are allowed:" msgstr "" +#: ../../howto/descriptor.rst:1562 +msgid "" +"class Vehicle:\n" +" __slots__ = ('id_number', 'make', 'model')" +msgstr "" + +#: ../../howto/descriptor.rst:1567 +msgid "" +">>> auto = Vehicle()\n" +">>> auto.id_nubmer = 'VYE483814LQEX'\n" +"Traceback (most recent call last):\n" +" ...\n" +"AttributeError: 'Vehicle' object has no attribute 'id_nubmer'" +msgstr "" + #: ../../howto/descriptor.rst:1575 msgid "" "2. Helps create immutable objects where descriptors manage access to private " "attributes stored in ``__slots__``:" msgstr "" +#: ../../howto/descriptor.rst:1578 +msgid "" +"class Immutable:\n" +"\n" +" __slots__ = ('_dept', '_name') # Replace the instance " +"dictionary\n" +"\n" +" def __init__(self, dept, name):\n" +" self._dept = dept # Store to private attribute\n" +" self._name = name # Store to private attribute\n" +"\n" +" @property # Read-only descriptor\n" +" def dept(self):\n" +" return self._dept\n" +"\n" +" @property\n" +" def name(self): # Read-only descriptor\n" +" return self._name" +msgstr "" + +#: ../../howto/descriptor.rst:1596 +msgid "" +">>> mark = Immutable('Botany', 'Mark Watney')\n" +">>> mark.dept\n" +"'Botany'\n" +">>> mark.dept = 'Space Pirate'\n" +"Traceback (most recent call last):\n" +" ...\n" +"AttributeError: property 'dept' of 'Immutable' object has no setter\n" +">>> mark.location = 'Mars'\n" +"Traceback (most recent call last):\n" +" ...\n" +"AttributeError: 'Immutable' object has no attribute 'location'" +msgstr "" + #: ../../howto/descriptor.rst:1610 msgid "" "3. Saves memory. On a 64-bit Linux build, an instance with two attributes " @@ -1023,6 +1726,27 @@ msgid "" "instance dictionary to function correctly:" msgstr "" +#: ../../howto/descriptor.rst:1621 +msgid "" +"from functools import cached_property\n" +"\n" +"class CP:\n" +" __slots__ = () # Eliminates the instance dict\n" +"\n" +" @cached_property # Requires an instance dict\n" +" def pi(self):\n" +" return 4 * sum((-1.0)**n / (2.0*n + 1.0)\n" +" for n in reversed(range(100_000)))" +msgstr "" + +#: ../../howto/descriptor.rst:1633 +msgid "" +">>> CP().pi\n" +"Traceback (most recent call last):\n" +" ...\n" +"TypeError: No '__dict__' attribute on 'CP' instance to cache 'pi' property." +msgstr "" + #: ../../howto/descriptor.rst:1640 msgid "" "It is not possible to create an exact drop-in pure Python version of " @@ -1033,12 +1757,65 @@ msgid "" "managed by member descriptors:" msgstr "" +#: ../../howto/descriptor.rst:1647 +msgid "" +"null = object()\n" +"\n" +"class Member:\n" +"\n" +" def __init__(self, name, clsname, offset):\n" +" 'Emulate PyMemberDef in Include/structmember.h'\n" +" # Also see descr_new() in Objects/descrobject.c\n" +" self.name = name\n" +" self.clsname = clsname\n" +" self.offset = offset\n" +"\n" +" def __get__(self, obj, objtype=None):\n" +" 'Emulate member_get() in Objects/descrobject.c'\n" +" # Also see PyMember_GetOne() in Python/structmember.c\n" +" if obj is None:\n" +" return self\n" +" value = obj._slotvalues[self.offset]\n" +" if value is null:\n" +" raise AttributeError(self.name)\n" +" return value\n" +"\n" +" def __set__(self, obj, value):\n" +" 'Emulate member_set() in Objects/descrobject.c'\n" +" obj._slotvalues[self.offset] = value\n" +"\n" +" def __delete__(self, obj):\n" +" 'Emulate member_delete() in Objects/descrobject.c'\n" +" value = obj._slotvalues[self.offset]\n" +" if value is null:\n" +" raise AttributeError(self.name)\n" +" obj._slotvalues[self.offset] = null\n" +"\n" +" def __repr__(self):\n" +" 'Emulate member_repr() in Objects/descrobject.c'\n" +" return f''" +msgstr "" + #: ../../howto/descriptor.rst:1685 msgid "" "The :meth:`type.__new__` method takes care of adding member objects to class " "variables:" msgstr "" +#: ../../howto/descriptor.rst:1688 +msgid "" +"class Type(type):\n" +" 'Simulate how the type metaclass adds member objects for slots'\n" +"\n" +" def __new__(mcls, clsname, bases, mapping, **kwargs):\n" +" 'Emulate type_new() in Objects/typeobject.c'\n" +" # type_new() calls PyTypeReady() which calls add_methods()\n" +" slot_names = mapping.get('slot_names', [])\n" +" for offset, name in enumerate(slot_names):\n" +" mapping[name] = Member(name, clsname, offset)\n" +" return type.__new__(mcls, clsname, bases, mapping, **kwargs)" +msgstr "" + #: ../../howto/descriptor.rst:1701 msgid "" "The :meth:`object.__new__` method takes care of creating instances that have " @@ -1046,23 +1823,97 @@ msgid "" "Python:" msgstr "" +#: ../../howto/descriptor.rst:1705 +msgid "" +"class Object:\n" +" 'Simulate how object.__new__() allocates memory for __slots__'\n" +"\n" +" def __new__(cls, *args, **kwargs):\n" +" 'Emulate object_new() in Objects/typeobject.c'\n" +" inst = super().__new__(cls)\n" +" if hasattr(cls, 'slot_names'):\n" +" empty_slots = [null] * len(cls.slot_names)\n" +" object.__setattr__(inst, '_slotvalues', empty_slots)\n" +" return inst\n" +"\n" +" def __setattr__(self, name, value):\n" +" 'Emulate _PyObject_GenericSetAttrWithDict() Objects/object.c'\n" +" cls = type(self)\n" +" if hasattr(cls, 'slot_names') and name not in cls.slot_names:\n" +" raise AttributeError(\n" +" f'{cls.__name__!r} object has no attribute {name!r}'\n" +" )\n" +" super().__setattr__(name, value)\n" +"\n" +" def __delattr__(self, name):\n" +" 'Emulate _PyObject_GenericSetAttrWithDict() Objects/object.c'\n" +" cls = type(self)\n" +" if hasattr(cls, 'slot_names') and name not in cls.slot_names:\n" +" raise AttributeError(\n" +" f'{cls.__name__!r} object has no attribute {name!r}'\n" +" )\n" +" super().__delattr__(name)" +msgstr "" + #: ../../howto/descriptor.rst:1736 msgid "" "To use the simulation in a real class, just inherit from :class:`Object` and " "set the :term:`metaclass` to :class:`Type`:" msgstr "" +#: ../../howto/descriptor.rst:1739 +msgid "" +"class H(Object, metaclass=Type):\n" +" 'Instance variables stored in slots'\n" +"\n" +" slot_names = ['x', 'y']\n" +"\n" +" def __init__(self, x, y):\n" +" self.x = x\n" +" self.y = y" +msgstr "" + #: ../../howto/descriptor.rst:1750 msgid "" "At this point, the metaclass has loaded member objects for *x* and *y*::" msgstr "" +#: ../../howto/descriptor.rst:1752 +msgid "" +">>> from pprint import pp\n" +">>> pp(dict(vars(H)))\n" +"{'__module__': '__main__',\n" +" '__doc__': 'Instance variables stored in slots',\n" +" 'slot_names': ['x', 'y'],\n" +" '__init__': ,\n" +" 'x': ,\n" +" 'y': }" +msgstr "" + #: ../../howto/descriptor.rst:1771 msgid "" "When instances are created, they have a ``slot_values`` list where the " "attributes are stored:" msgstr "" +#: ../../howto/descriptor.rst:1774 +msgid "" +">>> h = H(10, 20)\n" +">>> vars(h)\n" +"{'_slotvalues': [10, 20]}\n" +">>> h.x = 55\n" +">>> vars(h)\n" +"{'_slotvalues': [55, 20]}" +msgstr "" + #: ../../howto/descriptor.rst:1783 msgid "Misspelled or unassigned attributes will raise an exception:" msgstr "" + +#: ../../howto/descriptor.rst:1785 +msgid "" +">>> h.xz\n" +"Traceback (most recent call last):\n" +" ...\n" +"AttributeError: 'H' object has no attribute 'xz'" +msgstr "" diff --git a/howto/enum.po b/howto/enum.po index 0f7612fafe..5fd8ebb610 100644 --- a/howto/enum.po +++ b/howto/enum.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-08-30 18:24+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -34,10 +34,32 @@ msgid "" "selection of values. For example, the days of the week::" msgstr "" +#: ../../howto/enum.rst:16 +msgid "" +">>> from enum import Enum\n" +">>> class Weekday(Enum):\n" +"... MONDAY = 1\n" +"... TUESDAY = 2\n" +"... WEDNESDAY = 3\n" +"... THURSDAY = 4\n" +"... FRIDAY = 5\n" +"... SATURDAY = 6\n" +"... SUNDAY = 7" +msgstr "" + #: ../../howto/enum.rst:26 msgid "Or perhaps the RGB primary colors::" msgstr "" +#: ../../howto/enum.rst:28 +msgid "" +">>> from enum import Enum\n" +">>> class Color(Enum):\n" +"... RED = 1\n" +"... GREEN = 2\n" +"... BLUE = 3" +msgstr "" + #: ../../howto/enum.rst:34 msgid "" "As you can see, creating an :class:`Enum` is as simple as writing a class " @@ -63,6 +85,12 @@ msgid "" "member::" msgstr "" +#: ../../howto/enum.rst:48 +msgid "" +">>> Weekday(3)\n" +"" +msgstr "" + #: ../../howto/enum.rst:51 msgid "" "As you can see, the ``repr()`` of a member shows the enum name, the member " @@ -70,18 +98,44 @@ msgid "" "member name::" msgstr "" +#: ../../howto/enum.rst:55 +msgid "" +">>> print(Weekday.THURSDAY)\n" +"Weekday.THURSDAY" +msgstr "" + #: ../../howto/enum.rst:58 msgid "The *type* of an enumeration member is the enum it belongs to::" msgstr "" +#: ../../howto/enum.rst:60 +msgid "" +">>> type(Weekday.MONDAY)\n" +"\n" +">>> isinstance(Weekday.FRIDAY, Weekday)\n" +"True" +msgstr "" + #: ../../howto/enum.rst:65 msgid "Enum members have an attribute that contains just their :attr:`name`::" msgstr "" +#: ../../howto/enum.rst:67 +msgid "" +">>> print(Weekday.TUESDAY.name)\n" +"TUESDAY" +msgstr "" + #: ../../howto/enum.rst:70 msgid "Likewise, they have an attribute for their :attr:`value`::" msgstr "" +#: ../../howto/enum.rst:73 +msgid "" +">>> Weekday.WEDNESDAY.value\n" +"3" +msgstr "" + #: ../../howto/enum.rst:76 msgid "" "Unlike many languages that treat enumerations solely as name/value pairs, " @@ -93,14 +147,44 @@ msgid "" "instance and return the matching enum member::" msgstr "" +#: ../../howto/enum.rst:84 +msgid "" +"@classmethod\n" +"def from_date(cls, date):\n" +" return cls(date.isoweekday())" +msgstr "" + #: ../../howto/enum.rst:88 msgid "The complete :class:`Weekday` enum now looks like this::" msgstr "" +#: ../../howto/enum.rst:90 +msgid "" +">>> class Weekday(Enum):\n" +"... MONDAY = 1\n" +"... TUESDAY = 2\n" +"... WEDNESDAY = 3\n" +"... THURSDAY = 4\n" +"... FRIDAY = 5\n" +"... SATURDAY = 6\n" +"... SUNDAY = 7\n" +"... #\n" +"... @classmethod\n" +"... def from_date(cls, date):\n" +"... return cls(date.isoweekday())" +msgstr "" + #: ../../howto/enum.rst:103 msgid "Now we can find out what today is! Observe::" msgstr "" +#: ../../howto/enum.rst:105 +msgid "" +">>> from datetime import date\n" +">>> Weekday.from_date(date.today()) \n" +"" +msgstr "" + #: ../../howto/enum.rst:109 msgid "" "Of course, if you're reading this on some other day, you'll see that day " @@ -115,6 +199,19 @@ msgid "" "different type of :class:`Enum`::" msgstr "" +#: ../../howto/enum.rst:116 +msgid "" +">>> from enum import Flag\n" +">>> class Weekday(Flag):\n" +"... MONDAY = 1\n" +"... TUESDAY = 2\n" +"... WEDNESDAY = 4\n" +"... THURSDAY = 8\n" +"... FRIDAY = 16\n" +"... SATURDAY = 32\n" +"... SUNDAY = 64" +msgstr "" + #: ../../howto/enum.rst:126 msgid "" "We've changed two things: we're inherited from :class:`Flag`, and the values " @@ -127,30 +224,87 @@ msgid "" "selection::" msgstr "" +#: ../../howto/enum.rst:131 +msgid "" +">>> first_week_day = Weekday.MONDAY\n" +">>> first_week_day\n" +"" +msgstr "" + #: ../../howto/enum.rst:135 msgid "" "But :class:`Flag` also allows us to combine several members into a single " "variable::" msgstr "" +#: ../../howto/enum.rst:138 +msgid "" +">>> weekend = Weekday.SATURDAY | Weekday.SUNDAY\n" +">>> weekend\n" +"" +msgstr "" + #: ../../howto/enum.rst:142 msgid "You can even iterate over a :class:`Flag` variable::" msgstr "" +#: ../../howto/enum.rst:144 +msgid "" +">>> for day in weekend:\n" +"... print(day)\n" +"Weekday.SATURDAY\n" +"Weekday.SUNDAY" +msgstr "" + #: ../../howto/enum.rst:149 msgid "Okay, let's get some chores set up::" msgstr "" +#: ../../howto/enum.rst:151 +msgid "" +">>> chores_for_ethan = {\n" +"... 'feed the cat': Weekday.MONDAY | Weekday.WEDNESDAY | Weekday." +"FRIDAY,\n" +"... 'do the dishes': Weekday.TUESDAY | Weekday.THURSDAY,\n" +"... 'answer SO questions': Weekday.SATURDAY,\n" +"... }" +msgstr "" + #: ../../howto/enum.rst:157 msgid "And a function to display the chores for a given day::" msgstr "" +#: ../../howto/enum.rst:159 +msgid "" +">>> def show_chores(chores, day):\n" +"... for chore, days in chores.items():\n" +"... if day in days:\n" +"... print(chore)\n" +"...\n" +">>> show_chores(chores_for_ethan, Weekday.SATURDAY)\n" +"answer SO questions" +msgstr "" + #: ../../howto/enum.rst:167 msgid "" "In cases where the actual values of the members do not matter, you can save " "yourself some work and use :func:`auto` for the values::" msgstr "" +#: ../../howto/enum.rst:170 +msgid "" +">>> from enum import auto\n" +">>> class Weekday(Flag):\n" +"... MONDAY = auto()\n" +"... TUESDAY = auto()\n" +"... WEDNESDAY = auto()\n" +"... THURSDAY = auto()\n" +"... FRIDAY = auto()\n" +"... SATURDAY = auto()\n" +"... SUNDAY = auto()\n" +"... WEEKEND = SATURDAY | SUNDAY" +msgstr "" + #: ../../howto/enum.rst:186 msgid "Programmatic access to enumeration members and their attributes" msgstr "" @@ -162,14 +316,39 @@ msgid "" "known at program-writing time). ``Enum`` allows such access::" msgstr "" +#: ../../howto/enum.rst:192 +msgid "" +">>> Color(1)\n" +"\n" +">>> Color(3)\n" +"" +msgstr "" + #: ../../howto/enum.rst:197 msgid "If you want to access enum members by *name*, use item access::" msgstr "" +#: ../../howto/enum.rst:199 +msgid "" +">>> Color['RED']\n" +"\n" +">>> Color['GREEN']\n" +"" +msgstr "" + #: ../../howto/enum.rst:204 msgid "If you have an enum member and need its :attr:`name` or :attr:`value`::" msgstr "" +#: ../../howto/enum.rst:206 +msgid "" +">>> member = Color.RED\n" +">>> member.name\n" +"'RED'\n" +">>> member.value\n" +"1" +msgstr "" + #: ../../howto/enum.rst:214 msgid "Duplicating enum members and values" msgstr "" @@ -178,6 +357,17 @@ msgstr "" msgid "Having two enum members with the same name is invalid::" msgstr "" +#: ../../howto/enum.rst:218 +msgid "" +">>> class Shape(Enum):\n" +"... SQUARE = 2\n" +"... SQUARE = 3\n" +"...\n" +"Traceback (most recent call last):\n" +"...\n" +"TypeError: 'SQUARE' already defined as 2" +msgstr "" + #: ../../howto/enum.rst:226 msgid "" "However, an enum member can have other names associated with it. Given two " @@ -187,6 +377,22 @@ msgid "" "member ``A``. By-name lookup of ``B`` will also return the member ``A``::" msgstr "" +#: ../../howto/enum.rst:232 +msgid "" +">>> class Shape(Enum):\n" +"... SQUARE = 2\n" +"... DIAMOND = 1\n" +"... CIRCLE = 3\n" +"... ALIAS_FOR_SQUARE = 2\n" +"...\n" +">>> Shape.SQUARE\n" +"\n" +">>> Shape.ALIAS_FOR_SQUARE\n" +"\n" +">>> Shape(2)\n" +"" +msgstr "" + #: ../../howto/enum.rst:247 msgid "" "Attempting to create a member with the same name as an already defined " @@ -204,6 +410,21 @@ msgid "" "When this behavior isn't desired, you can use the :func:`unique` decorator::" msgstr "" +#: ../../howto/enum.rst:258 +msgid "" +">>> from enum import Enum, unique\n" +">>> @unique\n" +"... class Mistake(Enum):\n" +"... ONE = 1\n" +"... TWO = 2\n" +"... THREE = 3\n" +"... FOUR = 3\n" +"...\n" +"Traceback (most recent call last):\n" +"...\n" +"ValueError: duplicate values found in : FOUR -> THREE" +msgstr "" + #: ../../howto/enum.rst:272 msgid "Using automatic values" msgstr "" @@ -212,12 +433,41 @@ msgstr "" msgid "If the exact value is unimportant you can use :class:`auto`::" msgstr "" +#: ../../howto/enum.rst:276 +msgid "" +">>> from enum import Enum, auto\n" +">>> class Color(Enum):\n" +"... RED = auto()\n" +"... BLUE = auto()\n" +"... GREEN = auto()\n" +"...\n" +">>> [member.value for member in Color]\n" +"[1, 2, 3]" +msgstr "" + #: ../../howto/enum.rst:285 msgid "" "The values are chosen by :func:`_generate_next_value_`, which can be " "overridden::" msgstr "" +#: ../../howto/enum.rst:288 +msgid "" +">>> class AutoName(Enum):\n" +"... @staticmethod\n" +"... def _generate_next_value_(name, start, count, last_values):\n" +"... return name\n" +"...\n" +">>> class Ordinal(AutoName):\n" +"... NORTH = auto()\n" +"... SOUTH = auto()\n" +"... EAST = auto()\n" +"... WEST = auto()\n" +"...\n" +">>> [member.value for member in Ordinal]\n" +"['NORTH', 'SOUTH', 'EAST', 'WEST']" +msgstr "" + #: ../../howto/enum.rst:304 msgid "" "The :meth:`_generate_next_value_` method must be defined before any members." @@ -231,6 +481,16 @@ msgstr "" msgid "Iterating over the members of an enum does not provide the aliases::" msgstr "" +#: ../../howto/enum.rst:311 +msgid "" +">>> list(Shape)\n" +"[, , ]\n" +">>> list(Weekday)\n" +"[, , , , , , ]" +msgstr "" + #: ../../howto/enum.rst:316 msgid "" "Note that the aliases ``Shape.ALIAS_FOR_SQUARE`` and ``Weekday.WEEKEND`` " @@ -244,12 +504,30 @@ msgid "" "including the aliases::" msgstr "" +#: ../../howto/enum.rst:322 +msgid "" +">>> for name, member in Shape.__members__.items():\n" +"... name, member\n" +"...\n" +"('SQUARE', )\n" +"('DIAMOND', )\n" +"('CIRCLE', )\n" +"('ALIAS_FOR_SQUARE', )" +msgstr "" + #: ../../howto/enum.rst:330 msgid "" "The ``__members__`` attribute can be used for detailed programmatic access " "to the enumeration members. For example, finding all the aliases::" msgstr "" +#: ../../howto/enum.rst:333 +msgid "" +">>> [name for name, member in Shape.__members__.items() if member.name != " +"name]\n" +"['ALIAS_FOR_SQUARE']" +msgstr "" + #: ../../howto/enum.rst:338 msgid "" "Aliases for flags include values with multiple flags set, such as ``3``, and " @@ -264,16 +542,44 @@ msgstr "" msgid "Enumeration members are compared by identity::" msgstr "" +#: ../../howto/enum.rst:347 +msgid "" +">>> Color.RED is Color.RED\n" +"True\n" +">>> Color.RED is Color.BLUE\n" +"False\n" +">>> Color.RED is not Color.BLUE\n" +"True" +msgstr "" + #: ../../howto/enum.rst:354 msgid "" "Ordered comparisons between enumeration values are *not* supported. Enum " "members are not integers (but see `IntEnum`_ below)::" msgstr "" +#: ../../howto/enum.rst:357 +msgid "" +">>> Color.RED < Color.BLUE\n" +"Traceback (most recent call last):\n" +" File \"\", line 1, in \n" +"TypeError: '<' not supported between instances of 'Color' and 'Color'" +msgstr "" + #: ../../howto/enum.rst:362 msgid "Equality comparisons are defined though::" msgstr "" +#: ../../howto/enum.rst:364 +msgid "" +">>> Color.BLUE == Color.RED\n" +"False\n" +">>> Color.BLUE != Color.RED\n" +"True\n" +">>> Color.BLUE == Color.BLUE\n" +"True" +msgstr "" + #: ../../howto/enum.rst:371 msgid "" "Comparisons against non-enumeration values will always compare not equal " @@ -281,6 +587,12 @@ msgid "" "below)::" msgstr "" +#: ../../howto/enum.rst:375 +msgid "" +">>> Color.BLUE == 2\n" +"False" +msgstr "" + #: ../../howto/enum.rst:380 msgid "" "It is possible to reload modules -- if a reloaded module contains enums, " @@ -307,10 +619,40 @@ msgid "" "usual. If we have this enumeration::" msgstr "" +#: ../../howto/enum.rst:396 +msgid "" +">>> class Mood(Enum):\n" +"... FUNKY = 1\n" +"... HAPPY = 3\n" +"...\n" +"... def describe(self):\n" +"... # self is the member here\n" +"... return self.name, self.value\n" +"...\n" +"... def __str__(self):\n" +"... return 'my custom str! {0}'.format(self.value)\n" +"...\n" +"... @classmethod\n" +"... def favorite_mood(cls):\n" +"... # cls here is the enumeration\n" +"... return cls.HAPPY\n" +"..." +msgstr "" + #: ../../howto/enum.rst:413 msgid "Then::" msgstr "" +#: ../../howto/enum.rst:415 +msgid "" +">>> Mood.favorite_mood()\n" +"\n" +">>> Mood.HAPPY.describe()\n" +"('HAPPY', 3)\n" +">>> str(Mood.FUNKY)\n" +"'my custom str! 1'" +msgstr "" + #: ../../howto/enum.rst:422 msgid "" "The rules for what is allowed are as follows: names that start and end with " @@ -347,16 +689,44 @@ msgid "" "order of these base classes is::" msgstr "" +#: ../../howto/enum.rst:448 +msgid "" +"class EnumName([mix-in, ...,] [data-type,] base-enum):\n" +" pass" +msgstr "" + #: ../../howto/enum.rst:451 msgid "" "Also, subclassing an enumeration is allowed only if the enumeration does not " "define any members. So this is forbidden::" msgstr "" +#: ../../howto/enum.rst:454 +msgid "" +">>> class MoreColor(Color):\n" +"... PINK = 17\n" +"...\n" +"Traceback (most recent call last):\n" +"...\n" +"TypeError: cannot extend " +msgstr "" + #: ../../howto/enum.rst:461 msgid "But this is allowed::" msgstr "" +#: ../../howto/enum.rst:463 +msgid "" +">>> class Foo(Enum):\n" +"... def some_behavior(self):\n" +"... pass\n" +"...\n" +">>> class Bar(Foo):\n" +"... HAPPY = 1\n" +"... SAD = 2\n" +"..." +msgstr "" + #: ../../howto/enum.rst:472 msgid "" "Allowing subclassing of enums that define members would lead to a violation " @@ -375,6 +745,23 @@ msgid "" "__repr__` omits the inherited class' name. For example::" msgstr "" +#: ../../howto/enum.rst:486 +msgid "" +">>> from dataclasses import dataclass, field\n" +">>> @dataclass\n" +"... class CreatureDataMixin:\n" +"... size: str\n" +"... legs: int\n" +"... tail: bool = field(repr=False, default=True)\n" +"...\n" +">>> class Creature(CreatureDataMixin, Enum):\n" +"... BEETLE = 'small', 6\n" +"... DOG = 'medium', 4\n" +"...\n" +">>> Creature.DOG\n" +"" +msgstr "" + #: ../../howto/enum.rst:500 msgid "" "Use the :func:`!dataclass` argument ``repr=False`` to use the standard :func:" @@ -395,6 +782,14 @@ msgstr "" msgid "Enumerations can be pickled and unpickled::" msgstr "" +#: ../../howto/enum.rst:513 +msgid "" +">>> from test.test_enum import Fruit\n" +">>> from pickle import dumps, loads\n" +">>> Fruit.TOMATO is loads(dumps(Fruit.TOMATO))\n" +"True" +msgstr "" + #: ../../howto/enum.rst:518 msgid "" "The usual restrictions for pickling apply: picklable enums must be defined " @@ -415,6 +810,13 @@ msgid "" "value, but enums with complicated values may want to use by-name::" msgstr "" +#: ../../howto/enum.rst:531 +msgid "" +">>> import enum\n" +">>> class MyEnum(enum.Enum):\n" +"... __reduce_ex__ = enum.pickle_by_enum_name" +msgstr "" + #: ../../howto/enum.rst:537 msgid "" "Using by-name for flags is not recommended, as unnamed aliases will not " @@ -430,6 +832,17 @@ msgid "" "The :class:`Enum` class is callable, providing the following functional API::" msgstr "" +#: ../../howto/enum.rst:546 +msgid "" +">>> Animal = Enum('Animal', 'ANT BEE CAT DOG')\n" +">>> Animal\n" +"\n" +">>> Animal.ANT\n" +"\n" +">>> list(Animal)\n" +"[, , , ]" +msgstr "" + #: ../../howto/enum.rst:554 msgid "" "The semantics of this API resemble :class:`~collections.namedtuple`. The " @@ -448,6 +861,16 @@ msgid "" "assignment to :class:`Animal` is equivalent to::" msgstr "" +#: ../../howto/enum.rst:566 +msgid "" +">>> class Animal(Enum):\n" +"... ANT = 1\n" +"... BEE = 2\n" +"... CAT = 3\n" +"... DOG = 4\n" +"..." +msgstr "" + #: ../../howto/enum.rst:573 msgid "" "The reason for defaulting to ``1`` as the starting number and not ``0`` is " @@ -464,6 +887,10 @@ msgid "" "Jython). The solution is to specify the module name explicitly as follows::" msgstr "" +#: ../../howto/enum.rst:583 +msgid ">>> Animal = Enum('Animal', 'ANT BEE CAT DOG', module=__name__)" +msgstr "" + #: ../../howto/enum.rst:587 msgid "" "If ``module`` is not supplied, and Enum cannot determine what it is, the new " @@ -479,10 +906,28 @@ msgid "" "class SomeData in the global scope::" msgstr "" +#: ../../howto/enum.rst:596 +msgid "" +">>> Animal = Enum('Animal', 'ANT BEE CAT DOG', qualname='SomeData.Animal')" +msgstr "" + #: ../../howto/enum.rst:598 msgid "The complete signature is::" msgstr "" +#: ../../howto/enum.rst:600 +msgid "" +"Enum(\n" +" value='NewEnumName',\n" +" names=<...>,\n" +" *,\n" +" module='...',\n" +" qualname='...',\n" +" type=,\n" +" start=1,\n" +" )" +msgstr "" + #: ../../howto/enum.rst:610 msgid "*value*: What the new enum class will record as its name." msgstr "" @@ -493,18 +938,34 @@ msgid "" "string (values will start at 1 unless otherwise specified)::" msgstr "" +#: ../../howto/enum.rst:615 +msgid "'RED GREEN BLUE' | 'RED,GREEN,BLUE' | 'RED, GREEN, BLUE'" +msgstr "" + #: ../../howto/enum.rst:617 msgid "or an iterator of names::" msgstr "" +#: ../../howto/enum.rst:619 +msgid "['RED', 'GREEN', 'BLUE']" +msgstr "" + #: ../../howto/enum.rst:621 msgid "or an iterator of (name, value) pairs::" msgstr "" +#: ../../howto/enum.rst:623 +msgid "[('CYAN', 4), ('MAGENTA', 5), ('YELLOW', 6)]" +msgstr "" + #: ../../howto/enum.rst:625 msgid "or a mapping::" msgstr "" +#: ../../howto/enum.rst:627 +msgid "{'CHARTREUSE': 7, 'SEA_GREEN': 11, 'ROSEMARY': 42}" +msgstr "" + #: ../../howto/enum.rst:629 msgid "*module*: name of module where new enum class can be found." msgstr "" @@ -541,17 +1002,60 @@ msgid "" "each other::" msgstr "" +#: ../../howto/enum.rst:652 +msgid "" +">>> from enum import IntEnum\n" +">>> class Shape(IntEnum):\n" +"... CIRCLE = 1\n" +"... SQUARE = 2\n" +"...\n" +">>> class Request(IntEnum):\n" +"... POST = 1\n" +"... GET = 2\n" +"...\n" +">>> Shape == 1\n" +"False\n" +">>> Shape.CIRCLE == 1\n" +"True\n" +">>> Shape.CIRCLE == Request.POST\n" +"True" +msgstr "" + #: ../../howto/enum.rst:668 msgid "" "However, they still can't be compared to standard :class:`Enum` " "enumerations::" msgstr "" +#: ../../howto/enum.rst:670 +msgid "" +">>> class Shape(IntEnum):\n" +"... CIRCLE = 1\n" +"... SQUARE = 2\n" +"...\n" +">>> class Color(Enum):\n" +"... RED = 1\n" +"... GREEN = 2\n" +"...\n" +">>> Shape.CIRCLE == Color.RED\n" +"False" +msgstr "" + #: ../../howto/enum.rst:681 msgid "" ":class:`IntEnum` values behave like integers in other ways you'd expect::" msgstr "" +#: ../../howto/enum.rst:683 +msgid "" +">>> int(Shape.CIRCLE)\n" +"1\n" +">>> ['a', 'b', 'c'][Shape.CIRCLE]\n" +"'b'\n" +">>> [i for i in range(Shape.SQUARE)]\n" +"[0, 1]" +msgstr "" + #: ../../howto/enum.rst:692 msgid "StrEnum" msgstr "" @@ -594,10 +1098,43 @@ msgstr "" msgid "Sample :class:`IntFlag` class::" msgstr "" +#: ../../howto/enum.rst:725 +msgid "" +">>> from enum import IntFlag\n" +">>> class Perm(IntFlag):\n" +"... R = 4\n" +"... W = 2\n" +"... X = 1\n" +"...\n" +">>> Perm.R | Perm.W\n" +"\n" +">>> Perm.R + Perm.W\n" +"6\n" +">>> RW = Perm.R | Perm.W\n" +">>> Perm.R in RW\n" +"True" +msgstr "" + #: ../../howto/enum.rst:739 msgid "It is also possible to name the combinations::" msgstr "" +#: ../../howto/enum.rst:741 +msgid "" +">>> class Perm(IntFlag):\n" +"... R = 4\n" +"... W = 2\n" +"... X = 1\n" +"... RWX = 7\n" +"...\n" +">>> Perm.RWX\n" +"\n" +">>> ~Perm.RWX\n" +"\n" +">>> Perm(7)\n" +"" +msgstr "" + #: ../../howto/enum.rst:756 msgid "" "Named combinations are considered aliases. Aliases do not show up during " @@ -611,22 +1148,51 @@ msgid "" "`False`::" msgstr "" +#: ../../howto/enum.rst:764 +msgid "" +">>> Perm.R & Perm.X\n" +"\n" +">>> bool(Perm.R & Perm.X)\n" +"False" +msgstr "" + #: ../../howto/enum.rst:769 msgid "" "Because :class:`IntFlag` members are also subclasses of :class:`int` they " "can be combined with them (but may lose :class:`IntFlag` membership::" msgstr "" +#: ../../howto/enum.rst:772 +msgid "" +">>> Perm.X | 4\n" +"\n" +"\n" +">>> Perm.X + 8\n" +"9" +msgstr "" + #: ../../howto/enum.rst:780 msgid "" "The negation operator, ``~``, always returns an :class:`IntFlag` member with " "a positive value::" msgstr "" +#: ../../howto/enum.rst:783 +msgid "" +">>> (~Perm.X).value == (Perm.R|Perm.W).value == 6\n" +"True" +msgstr "" + #: ../../howto/enum.rst:786 msgid ":class:`IntFlag` members can also be iterated over::" msgstr "" +#: ../../howto/enum.rst:788 +msgid "" +">>> list(RW)\n" +"[, ]" +msgstr "" + #: ../../howto/enum.rst:795 msgid "Flag" msgstr "" @@ -647,22 +1213,69 @@ msgid "" "no flags being set, the boolean evaluation is :data:`False`::" msgstr "" +#: ../../howto/enum.rst:809 +msgid "" +">>> from enum import Flag, auto\n" +">>> class Color(Flag):\n" +"... RED = auto()\n" +"... BLUE = auto()\n" +"... GREEN = auto()\n" +"...\n" +">>> Color.RED & Color.GREEN\n" +"\n" +">>> bool(Color.RED & Color.GREEN)\n" +"False" +msgstr "" + #: ../../howto/enum.rst:820 msgid "" "Individual flags should have values that are powers of two (1, 2, 4, " "8, ...), while combinations of flags will not::" msgstr "" +#: ../../howto/enum.rst:823 +msgid "" +">>> class Color(Flag):\n" +"... RED = auto()\n" +"... BLUE = auto()\n" +"... GREEN = auto()\n" +"... WHITE = RED | BLUE | GREEN\n" +"...\n" +">>> Color.WHITE\n" +"" +msgstr "" + #: ../../howto/enum.rst:832 msgid "" "Giving a name to the \"no flags set\" condition does not change its boolean " "value::" msgstr "" +#: ../../howto/enum.rst:835 +msgid "" +">>> class Color(Flag):\n" +"... BLACK = 0\n" +"... RED = auto()\n" +"... BLUE = auto()\n" +"... GREEN = auto()\n" +"...\n" +">>> Color.BLACK\n" +"\n" +">>> bool(Color.BLACK)\n" +"False" +msgstr "" + #: ../../howto/enum.rst:846 msgid ":class:`Flag` members can also be iterated over::" msgstr "" +#: ../../howto/enum.rst:848 +msgid "" +">>> purple = Color.RED | Color.BLUE\n" +">>> list(purple)\n" +"[, ]" +msgstr "" + #: ../../howto/enum.rst:856 msgid "" "For the majority of new code, :class:`Enum` and :class:`Flag` are strongly " @@ -684,6 +1297,12 @@ msgid "" "simple to implement independently::" msgstr "" +#: ../../howto/enum.rst:871 +msgid "" +"class IntEnum(int, Enum):\n" +" pass" +msgstr "" + #: ../../howto/enum.rst:874 msgid "" "This demonstrates how similar derived enumerations can be defined; for " @@ -767,6 +1386,31 @@ msgid "" "want one of them to be the value::" msgstr "" +#: ../../howto/enum.rst:919 +msgid "" +">>> class Coordinate(bytes, Enum):\n" +"... \"\"\"\n" +"... Coordinate with binary codes that can be indexed by the int code.\n" +"... \"\"\"\n" +"... def __new__(cls, value, label, unit):\n" +"... obj = bytes.__new__(cls, [value])\n" +"... obj._value_ = value\n" +"... obj.label = label\n" +"... obj.unit = unit\n" +"... return obj\n" +"... PX = (0, 'P.X', 'km')\n" +"... PY = (1, 'P.Y', 'km')\n" +"... VX = (2, 'V.X', 'km/s')\n" +"... VY = (3, 'V.Y', 'km/s')\n" +"...\n" +"\n" +">>> print(Coordinate['PY'])\n" +"Coordinate.PY\n" +"\n" +">>> print(Coordinate(3))\n" +"Coordinate.VY" +msgstr "" + #: ../../howto/enum.rst:943 msgid "" "*Do not* call ``super().__new__()``, as the lookup-only ``__new__`` is the " @@ -859,6 +1503,21 @@ msgid "" "enumeration and raise an error if the two do not match::" msgstr "" +#: ../../howto/enum.rst:993 +msgid "" +">>> class Color(Enum):\n" +"... _order_ = 'RED GREEN BLUE'\n" +"... RED = 1\n" +"... BLUE = 3\n" +"... GREEN = 2\n" +"...\n" +"Traceback (most recent call last):\n" +"...\n" +"TypeError: member order does not match _order_:\n" +" ['RED', 'BLUE', 'GREEN']\n" +" ['RED', 'GREEN', 'BLUE']" +msgstr "" + #: ../../howto/enum.rst:1007 msgid "" "In Python 2 code the :attr:`_order_` attribute is necessary as definition " @@ -900,6 +1559,15 @@ msgid "" "type's constructor. For example::" msgstr "" +#: ../../howto/enum.rst:1040 +msgid "" +">>> class MyEnum(IntEnum): # help(int) -> int(x, base=10) -> integer\n" +"... example = '11', 16 # so x='11' and base=16\n" +"...\n" +">>> MyEnum.example.value # and hex(11) is...\n" +"17" +msgstr "" + #: ../../howto/enum.rst:1048 msgid "Boolean value of ``Enum`` classes and members" msgstr "" @@ -913,6 +1581,12 @@ msgid "" "your class::" msgstr "" +#: ../../howto/enum.rst:1056 +msgid "" +"def __bool__(self):\n" +" return bool(self.value)" +msgstr "" + #: ../../howto/enum.rst:1059 msgid "Plain :class:`Enum` classes always evaluate as :data:`True`." msgstr "" @@ -928,6 +1602,16 @@ msgid "" "the class::" msgstr "" +#: ../../howto/enum.rst:1069 +msgid "" +">>> dir(Planet) \n" +"['EARTH', 'JUPITER', 'MARS', 'MERCURY', 'NEPTUNE', 'SATURN', 'URANUS', " +"'VENUS', '__class__', '__doc__', '__members__', '__module__']\n" +">>> dir(Planet.EARTH) \n" +"['__class__', '__doc__', '__module__', 'mass', 'name', 'radius', " +"'surface_gravity', 'value']" +msgstr "" + #: ../../howto/enum.rst:1076 msgid "Combining members of ``Flag``" msgstr "" @@ -938,6 +1622,22 @@ msgid "" "members that are comprised of a single bit::" msgstr "" +#: ../../howto/enum.rst:1081 +msgid "" +">>> class Color(Flag):\n" +"... RED = auto()\n" +"... GREEN = auto()\n" +"... BLUE = auto()\n" +"... MAGENTA = RED | BLUE\n" +"... YELLOW = RED | GREEN\n" +"... CYAN = GREEN | BLUE\n" +"...\n" +">>> Color(3) # named combination\n" +"\n" +">>> Color(7) # not named combination\n" +"" +msgstr "" + #: ../../howto/enum.rst:1096 msgid "``Flag`` and ``IntFlag`` minutia" msgstr "" @@ -946,6 +1646,18 @@ msgstr "" msgid "Using the following snippet for our examples::" msgstr "" +#: ../../howto/enum.rst:1100 +msgid "" +">>> class Color(IntFlag):\n" +"... BLACK = 0\n" +"... RED = 1\n" +"... GREEN = 2\n" +"... BLUE = 4\n" +"... PURPLE = RED | BLUE\n" +"... WHITE = RED | GREEN | BLUE\n" +"..." +msgstr "" + #: ../../howto/enum.rst:1109 msgid "the following are true:" msgstr "" @@ -962,32 +1674,88 @@ msgstr "" msgid "only canonical flags are returned during iteration::" msgstr "" +#: ../../howto/enum.rst:1115 +msgid "" +">>> list(Color.WHITE)\n" +"[, , ]" +msgstr "" + #: ../../howto/enum.rst:1118 msgid "" "negating a flag or flag set returns a new flag/flag set with the " "corresponding positive integer value::" msgstr "" +#: ../../howto/enum.rst:1121 +msgid "" +">>> Color.BLUE\n" +"\n" +"\n" +">>> ~Color.BLUE\n" +"" +msgstr "" + #: ../../howto/enum.rst:1127 msgid "names of pseudo-flags are constructed from their members' names::" msgstr "" +#: ../../howto/enum.rst:1129 +msgid "" +">>> (Color.RED | Color.GREEN).name\n" +"'RED|GREEN'\n" +"\n" +">>> class Perm(IntFlag):\n" +"... R = 4\n" +"... W = 2\n" +"... X = 1\n" +"...\n" +">>> (Perm.R & Perm.W).name is None # effectively Perm(0)\n" +"True" +msgstr "" + #: ../../howto/enum.rst:1140 msgid "multi-bit flags, aka aliases, can be returned from operations::" msgstr "" +#: ../../howto/enum.rst:1142 +msgid "" +">>> Color.RED | Color.BLUE\n" +"\n" +"\n" +">>> Color(7) # or Color(-1)\n" +"\n" +"\n" +">>> Color(0)\n" +"" +msgstr "" + #: ../../howto/enum.rst:1151 msgid "" "membership / containment checking: zero-valued flags are always considered " "to be contained::" msgstr "" +#: ../../howto/enum.rst:1154 +msgid "" +">>> Color.BLACK in Color.WHITE\n" +"True" +msgstr "" + #: ../../howto/enum.rst:1157 msgid "" "otherwise, only if all bits of one flag are in the other flag will True be " "returned::" msgstr "" +#: ../../howto/enum.rst:1160 +msgid "" +">>> Color.PURPLE in Color.WHITE\n" +"True\n" +"\n" +">>> Color.GREEN in Color.PURPLE\n" +"False" +msgstr "" + #: ../../howto/enum.rst:1166 msgid "" "There is a new boundary mechanism that controls how out-of-range / invalid " @@ -1090,6 +1858,12 @@ msgid "" "only the canonical members will be returned. For example::" msgstr "" +#: ../../howto/enum.rst:1225 +msgid "" +">>> list(Color)\n" +"[, , ]" +msgstr "" + #: ../../howto/enum.rst:1228 msgid "(Note that ``BLACK``, ``PURPLE``, and ``WHITE`` do not show up.)" msgstr "" @@ -1100,12 +1874,24 @@ msgid "" "than a negative value --- for example::" msgstr "" +#: ../../howto/enum.rst:1233 +msgid "" +">>> ~Color.RED\n" +"" +msgstr "" + #: ../../howto/enum.rst:1236 msgid "" "Flag members have a length corresponding to the number of power-of-two " "values they contain. For example::" msgstr "" +#: ../../howto/enum.rst:1239 +msgid "" +">>> len(Color.PURPLE)\n" +"2" +msgstr "" + #: ../../howto/enum.rst:1246 msgid "Enum Cookbook" msgstr "" @@ -1161,6 +1947,17 @@ msgstr "" msgid "Using :class:`auto` would look like::" msgstr "" +#: ../../howto/enum.rst:1277 +msgid "" +">>> class Color(Enum):\n" +"... RED = auto()\n" +"... BLUE = auto()\n" +"... GREEN = auto()\n" +"...\n" +">>> Color.GREEN\n" +"" +msgstr "" + #: ../../howto/enum.rst:1287 msgid "Using :class:`object`" msgstr "" @@ -1169,12 +1966,36 @@ msgstr "" msgid "Using :class:`object` would look like::" msgstr "" +#: ../../howto/enum.rst:1291 +msgid "" +">>> class Color(Enum):\n" +"... RED = object()\n" +"... GREEN = object()\n" +"... BLUE = object()\n" +"...\n" +">>> Color.GREEN \n" +">" +msgstr "" + #: ../../howto/enum.rst:1299 msgid "" "This is also a good example of why you might want to write your own :meth:" "`__repr__`::" msgstr "" +#: ../../howto/enum.rst:1302 +msgid "" +">>> class Color(Enum):\n" +"... RED = object()\n" +"... GREEN = object()\n" +"... BLUE = object()\n" +"... def __repr__(self):\n" +"... return \"<%s.%s>\" % (self.__class__.__name__, self._name_)\n" +"...\n" +">>> Color.GREEN\n" +"" +msgstr "" + #: ../../howto/enum.rst:1315 msgid "Using a descriptive string" msgstr "" @@ -1183,6 +2004,17 @@ msgstr "" msgid "Using a string as the value would look like::" msgstr "" +#: ../../howto/enum.rst:1319 +msgid "" +">>> class Color(Enum):\n" +"... RED = 'stop'\n" +"... GREEN = 'go'\n" +"... BLUE = 'too fast!'\n" +"...\n" +">>> Color.GREEN\n" +"" +msgstr "" + #: ../../howto/enum.rst:1329 msgid "Using a custom :meth:`__new__`" msgstr "" @@ -1191,18 +2023,64 @@ msgstr "" msgid "Using an auto-numbering :meth:`__new__` would look like::" msgstr "" +#: ../../howto/enum.rst:1333 +msgid "" +">>> class AutoNumber(Enum):\n" +"... def __new__(cls):\n" +"... value = len(cls.__members__) + 1\n" +"... obj = object.__new__(cls)\n" +"... obj._value_ = value\n" +"... return obj\n" +"...\n" +">>> class Color(AutoNumber):\n" +"... RED = ()\n" +"... GREEN = ()\n" +"... BLUE = ()\n" +"...\n" +">>> Color.GREEN\n" +"" +msgstr "" + #: ../../howto/enum.rst:1348 msgid "" "To make a more general purpose ``AutoNumber``, add ``*args`` to the " "signature::" msgstr "" +#: ../../howto/enum.rst:1350 +msgid "" +">>> class AutoNumber(Enum):\n" +"... def __new__(cls, *args): # this is the only change from above\n" +"... value = len(cls.__members__) + 1\n" +"... obj = object.__new__(cls)\n" +"... obj._value_ = value\n" +"... return obj\n" +"..." +msgstr "" + #: ../../howto/enum.rst:1358 msgid "" "Then when you inherit from ``AutoNumber`` you can write your own " "``__init__`` to handle any extra arguments::" msgstr "" +#: ../../howto/enum.rst:1361 +msgid "" +">>> class Swatch(AutoNumber):\n" +"... def __init__(self, pantone='unknown'):\n" +"... self.pantone = pantone\n" +"... AUBURN = '3497'\n" +"... SEA_GREEN = '1246'\n" +"... BLEACHED_CORAL = () # New color, no Pantone code yet!\n" +"...\n" +">>> Swatch.SEA_GREEN\n" +"\n" +">>> Swatch.SEA_GREEN.pantone\n" +"'1246'\n" +">>> Swatch.BLEACHED_CORAL.pantone\n" +"'unknown'" +msgstr "" + #: ../../howto/enum.rst:1377 msgid "" "The :meth:`__new__` method, if defined, is used during creation of the Enum " @@ -1216,6 +2094,10 @@ msgid "" "one that is found; instead, use the data type directly -- e.g.::" msgstr "" +#: ../../howto/enum.rst:1386 +msgid "obj = int.__new__(cls, value)" +msgstr "" + #: ../../howto/enum.rst:1390 msgid "OrderedEnum" msgstr "" @@ -1227,6 +2109,37 @@ msgid "" "to other enumerations)::" msgstr "" +#: ../../howto/enum.rst:1396 +msgid "" +">>> class OrderedEnum(Enum):\n" +"... def __ge__(self, other):\n" +"... if self.__class__ is other.__class__:\n" +"... return self.value >= other.value\n" +"... return NotImplemented\n" +"... def __gt__(self, other):\n" +"... if self.__class__ is other.__class__:\n" +"... return self.value > other.value\n" +"... return NotImplemented\n" +"... def __le__(self, other):\n" +"... if self.__class__ is other.__class__:\n" +"... return self.value <= other.value\n" +"... return NotImplemented\n" +"... def __lt__(self, other):\n" +"... if self.__class__ is other.__class__:\n" +"... return self.value < other.value\n" +"... return NotImplemented\n" +"...\n" +">>> class Grade(OrderedEnum):\n" +"... A = 5\n" +"... B = 4\n" +"... C = 3\n" +"... D = 2\n" +"... F = 1\n" +"...\n" +">>> Grade.C < Grade.A\n" +"True" +msgstr "" + #: ../../howto/enum.rst:1426 msgid "DuplicateFreeEnum" msgstr "" @@ -1237,6 +2150,30 @@ msgid "" "alias::" msgstr "" +#: ../../howto/enum.rst:1431 +msgid "" +">>> class DuplicateFreeEnum(Enum):\n" +"... def __init__(self, *args):\n" +"... cls = self.__class__\n" +"... if any(self.value == e.value for e in cls):\n" +"... a = self.name\n" +"... e = cls(self.value).name\n" +"... raise ValueError(\n" +"... \"aliases not allowed in DuplicateFreeEnum: %r --> " +"%r\"\n" +"... % (a, e))\n" +"...\n" +">>> class Color(DuplicateFreeEnum):\n" +"... RED = 1\n" +"... GREEN = 2\n" +"... BLUE = 3\n" +"... GRENE = 2\n" +"...\n" +"Traceback (most recent call last):\n" +" ...\n" +"ValueError: aliases not allowed in DuplicateFreeEnum: 'GRENE' --> 'GREEN'" +msgstr "" + #: ../../howto/enum.rst:1453 msgid "" "This is a useful example for subclassing Enum to add or change other " @@ -1254,6 +2191,32 @@ msgid "" "member will be passed to those methods::" msgstr "" +#: ../../howto/enum.rst:1464 +msgid "" +">>> class Planet(Enum):\n" +"... MERCURY = (3.303e+23, 2.4397e6)\n" +"... VENUS = (4.869e+24, 6.0518e6)\n" +"... EARTH = (5.976e+24, 6.37814e6)\n" +"... MARS = (6.421e+23, 3.3972e6)\n" +"... JUPITER = (1.9e+27, 7.1492e7)\n" +"... SATURN = (5.688e+26, 6.0268e7)\n" +"... URANUS = (8.686e+25, 2.5559e7)\n" +"... NEPTUNE = (1.024e+26, 2.4746e7)\n" +"... def __init__(self, mass, radius):\n" +"... self.mass = mass # in kilograms\n" +"... self.radius = radius # in meters\n" +"... @property\n" +"... def surface_gravity(self):\n" +"... # universal gravitational constant (m3 kg-1 s-2)\n" +"... G = 6.67300E-11\n" +"... return G * self.mass / (self.radius * self.radius)\n" +"...\n" +">>> Planet.EARTH.value\n" +"(5.976e+24, 6378140.0)\n" +">>> Planet.EARTH.surface_gravity\n" +"9.802652743337129" +msgstr "" + #: ../../howto/enum.rst:1490 msgid "TimePeriod" msgstr "" @@ -1262,6 +2225,24 @@ msgstr "" msgid "An example to show the :attr:`_ignore_` attribute in use::" msgstr "" +#: ../../howto/enum.rst:1494 +msgid "" +">>> from datetime import timedelta\n" +">>> class Period(timedelta, Enum):\n" +"... \"different lengths of time\"\n" +"... _ignore_ = 'Period i'\n" +"... Period = vars()\n" +"... for i in range(367):\n" +"... Period['day_%d' % i] = i\n" +"...\n" +">>> list(Period)[:2]\n" +"[, ]\n" +">>> list(Period)[-2:]\n" +"[, ]" +msgstr "" + #: ../../howto/enum.rst:1511 msgid "Subclassing EnumType" msgstr "" diff --git a/howto/functional.po b/howto/functional.po index 8e9b7a7529..4b5679730a 100644 --- a/howto/functional.po +++ b/howto/functional.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-04-18 00:04+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2018-05-23 14:36+0000\n" "Last-Translator: Adrian Liaw \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -333,6 +333,15 @@ msgid "" "an iterator. These two statements are equivalent::" msgstr "" +#: ../../howto/functional.rst:222 +msgid "" +"for i in iter(obj):\n" +" print(i)\n" +"\n" +"for i in obj:\n" +" print(i)" +msgstr "" + #: ../../howto/functional.rst:228 msgid "" "Iterators can be materialized as lists or tuples by using the :func:`list` " @@ -384,6 +393,26 @@ msgid "" "the dictionary's keys::" msgstr "" +#: ../../howto/functional.rst:273 +msgid "" +">>> m = {'Jan': 1, 'Feb': 2, 'Mar': 3, 'Apr': 4, 'May': 5, 'Jun': 6,\n" +"... 'Jul': 7, 'Aug': 8, 'Sep': 9, 'Oct': 10, 'Nov': 11, 'Dec': 12}\n" +">>> for key in m:\n" +"... print(key, m[key])\n" +"Jan 1\n" +"Feb 2\n" +"Mar 3\n" +"Apr 4\n" +"May 5\n" +"Jun 6\n" +"Jul 7\n" +"Aug 8\n" +"Sep 9\n" +"Oct 10\n" +"Nov 11\n" +"Dec 12" +msgstr "" + #: ../../howto/functional.rst:290 msgid "" "Note that starting with Python 3.7, dictionary iteration order is guaranteed " @@ -412,12 +441,32 @@ msgid "" "each line of a file like this::" msgstr "" +#: ../../howto/functional.rst:311 +msgid "" +"for line in file:\n" +" # do something for each line\n" +" ..." +msgstr "" + #: ../../howto/functional.rst:315 msgid "" "Sets can take their contents from an iterable and let you iterate over the " "set's elements::" msgstr "" +#: ../../howto/functional.rst:318 +msgid "" +">>> S = {2, 3, 5, 7, 11, 13}\n" +">>> for i in S:\n" +"... print(i)\n" +"2\n" +"3\n" +"5\n" +"7\n" +"11\n" +"13" +msgstr "" + #: ../../howto/functional.rst:331 msgid "Generator expressions and list comprehensions" msgstr "" @@ -439,11 +488,28 @@ msgid "" "strip all the whitespace from a stream of strings with the following code::" msgstr "" +#: ../../howto/functional.rst:344 +msgid "" +">>> line_list = [' line 1\\n', 'line 2 \\n', ' \\n', '']\n" +"\n" +">>> # Generator expression -- returns iterator\n" +">>> stripped_iter = (line.strip() for line in line_list)\n" +"\n" +">>> # List comprehension -- returns list\n" +">>> stripped_list = [line.strip() for line in line_list]" +msgstr "" + #: ../../howto/functional.rst:352 msgid "" "You can select only certain elements by adding an ``\"if\"`` condition::" msgstr "" +#: ../../howto/functional.rst:354 +msgid "" +">>> stripped_list = [line.strip() for line in line_list\n" +"... if line != \"\"]" +msgstr "" + #: ../../howto/functional.rst:357 msgid "" "With a list comprehension, you get back a Python list; ``stripped_list`` is " @@ -462,6 +528,19 @@ msgid "" "expressions have the form::" msgstr "" +#: ../../howto/functional.rst:368 +msgid "" +"( expression for expr in sequence1\n" +" if condition1\n" +" for expr2 in sequence2\n" +" if condition2\n" +" for expr3 in sequence3\n" +" ...\n" +" if condition3\n" +" for exprN in sequenceN\n" +" if conditionN )" +msgstr "" + #: ../../howto/functional.rst:378 msgid "" "Again, for a list comprehension only the outside brackets are different " @@ -483,6 +562,10 @@ msgid "" "iterator that will be immediately passed to a function you can write::" msgstr "" +#: ../../howto/functional.rst:389 +msgid "obj_total = sum(obj.count for obj in list_all_objects())" +msgstr "" + #: ../../howto/functional.rst:391 msgid "" "The ``for...in`` clauses contain the sequences to be iterated over. The " @@ -499,6 +582,23 @@ msgid "" "equivalent to the following Python code::" msgstr "" +#: ../../howto/functional.rst:400 +msgid "" +"for expr1 in sequence1:\n" +" if not (condition1):\n" +" continue # Skip this element\n" +" for expr2 in sequence2:\n" +" if not (condition2):\n" +" continue # Skip this element\n" +" ...\n" +" for exprN in sequenceN:\n" +" if not (conditionN):\n" +" continue # Skip this element\n" +"\n" +" # Output the value of\n" +" # the expression." +msgstr "" + #: ../../howto/functional.rst:414 msgid "" "This means that when there are multiple ``for...in`` clauses but no ``if`` " @@ -514,6 +614,14 @@ msgid "" "comprehension below is a syntax error, while the second one is correct::" msgstr "" +#: ../../howto/functional.rst:430 +msgid "" +"# Syntax error\n" +"[x, y for x in seq1 for y in seq2]\n" +"# Correct\n" +"[(x, y) for x in seq1 for y in seq2]" +msgstr "" + #: ../../howto/functional.rst:437 msgid "Generators" msgstr "" @@ -597,6 +705,20 @@ msgid "" "generators recursively. ::" msgstr "" +#: ../../howto/functional.rst:509 +msgid "" +"# A recursive generator that generates Tree leaves in in-order.\n" +"def inorder(t):\n" +" if t:\n" +" for x in inorder(t.left):\n" +" yield x\n" +"\n" +" yield t.label\n" +"\n" +" for x in inorder(t.right):\n" +" yield x" +msgstr "" + #: ../../howto/functional.rst:520 msgid "" "Two other examples in ``test_generators.py`` produce solutions for the N-" @@ -627,6 +749,10 @@ msgid "" "variable or otherwise operated on::" msgstr "" +#: ../../howto/functional.rst:541 +msgid "val = (yield i)" +msgstr "" + #: ../../howto/functional.rst:543 msgid "" "I recommend that you **always** put parentheses around a ``yield`` " @@ -658,6 +784,19 @@ msgid "" "of the internal counter." msgstr "" +#: ../../howto/functional.rst:562 +msgid "" +"def counter(maximum):\n" +" i = 0\n" +" while i < maximum:\n" +" val = (yield i)\n" +" # If value provided, change counter\n" +" if val is not None:\n" +" i = val\n" +" else:\n" +" i += 1" +msgstr "" + #: ../../howto/functional.rst:574 msgid "And here's an example of changing the counter:" msgstr "" @@ -765,12 +904,29 @@ msgid "" "element. ::" msgstr "" +#: ../../howto/functional.rst:667 +msgid "" +">>> for item in enumerate(['subject', 'verb', 'object']):\n" +"... print(item)\n" +"(0, 'subject')\n" +"(1, 'verb')\n" +"(2, 'object')" +msgstr "" + #: ../../howto/functional.rst:673 msgid "" ":func:`enumerate` is often used when looping through a list and recording " "the indexes at which certain conditions are met::" msgstr "" +#: ../../howto/functional.rst:676 +msgid "" +"f = open('data.txt', 'r')\n" +"for i, line in enumerate(f):\n" +" if line.strip() == '':\n" +" print('Blank line at line #%i' % i)" +msgstr "" + #: ../../howto/functional.rst:681 msgid "" ":func:`sorted(iterable, key=None, reverse=False) ` collects all the " @@ -779,6 +935,19 @@ msgid "" "constructed list's :meth:`~list.sort` method. ::" msgstr "" +#: ../../howto/functional.rst:686 +msgid "" +">>> import random\n" +">>> # Generate 8 random numbers between [0, 10000)\n" +">>> rand_list = random.sample(range(10000), 8)\n" +">>> rand_list \n" +"[769, 7953, 9828, 6431, 8442, 9878, 6213, 2207]\n" +">>> sorted(rand_list) \n" +"[769, 2207, 6213, 6431, 7953, 8442, 9828, 9878]\n" +">>> sorted(rand_list, reverse=True) \n" +"[9878, 9828, 8442, 7953, 6431, 6213, 2207, 769]" +msgstr "" + #: ../../howto/functional.rst:696 msgid "" "(For a more detailed discussion of sorting, see the :ref:`sortinghowto`.)" @@ -798,6 +967,12 @@ msgid "" "and returns them in a tuple::" msgstr "" +#: ../../howto/functional.rst:721 +msgid "" +"zip(['a', 'b', 'c'], (1, 2, 3)) =>\n" +" ('a', 1), ('b', 2), ('c', 3)" +msgstr "" + #: ../../howto/functional.rst:724 msgid "" "It doesn't construct an in-memory list and exhaust all the input iterators " @@ -813,6 +988,12 @@ msgid "" "will be the same length as the shortest iterable. ::" msgstr "" +#: ../../howto/functional.rst:733 +msgid "" +"zip(['a', 'b'], (1, 2, 3)) =>\n" +" ('a', 1), ('b', 2)" +msgstr "" + #: ../../howto/functional.rst:736 msgid "" "You should avoid doing this, though, because an element may be taken from " @@ -863,6 +1044,16 @@ msgid "" "defaults to 1::" msgstr "" +#: ../../howto/functional.rst:762 +msgid "" +"itertools.count() =>\n" +" 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ...\n" +"itertools.count(10) =>\n" +" 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, ...\n" +"itertools.count(10, 5) =>\n" +" 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, ..." +msgstr "" + #: ../../howto/functional.rst:769 msgid "" ":func:`itertools.cycle(iter) ` saves a copy of the contents " @@ -871,6 +1062,12 @@ msgid "" "infinitely. ::" msgstr "" +#: ../../howto/functional.rst:773 +msgid "" +"itertools.cycle([1, 2, 3, 4, 5]) =>\n" +" 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, ..." +msgstr "" + #: ../../howto/functional.rst:776 msgid "" ":func:`itertools.repeat(elem, [n]) ` returns the provided " @@ -878,6 +1075,14 @@ msgid "" "provided. ::" msgstr "" +#: ../../howto/functional.rst:779 +msgid "" +"itertools.repeat('abc') =>\n" +" abc, abc, abc, abc, abc, abc, abc, abc, abc, abc, ...\n" +"itertools.repeat('abc', 5) =>\n" +" abc, abc, abc, abc, abc" +msgstr "" + #: ../../howto/functional.rst:784 msgid "" ":func:`itertools.chain(iterA, iterB, ...) ` takes an " @@ -886,6 +1091,12 @@ msgid "" "the iterables have been exhausted. ::" msgstr "" +#: ../../howto/functional.rst:789 +msgid "" +"itertools.chain(['a', 'b', 'c'], (1, 2, 3)) =>\n" +" a, b, c, 1, 2, 3" +msgstr "" + #: ../../howto/functional.rst:792 msgid "" ":func:`itertools.islice(iter, [start], stop, [step]) ` " @@ -897,6 +1108,16 @@ msgid "" "*step*. ::" msgstr "" +#: ../../howto/functional.rst:799 +msgid "" +"itertools.islice(range(10), 8) =>\n" +" 0, 1, 2, 3, 4, 5, 6, 7\n" +"itertools.islice(range(10), 2, 8) =>\n" +" 2, 3, 4, 5, 6, 7\n" +"itertools.islice(range(10), 2, 8, 2) =>\n" +" 2, 4, 6" +msgstr "" + #: ../../howto/functional.rst:806 msgid "" ":func:`itertools.tee(iter, [n]) ` replicates an iterator; it " @@ -907,6 +1128,18 @@ msgid "" "and one of the new iterators is consumed more than the others. ::" msgstr "" +#: ../../howto/functional.rst:814 +msgid "" +"itertools.tee( itertools.count() ) =>\n" +" iterA, iterB\n" +"\n" +"where iterA ->\n" +" 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ...\n" +"\n" +"and iterB ->\n" +" 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ..." +msgstr "" + #: ../../howto/functional.rst:825 msgid "Calling functions on elements" msgstr "" @@ -927,6 +1160,15 @@ msgid "" "as the arguments::" msgstr "" +#: ../../howto/functional.rst:837 +msgid "" +"itertools.starmap(os.path.join,\n" +" [('/bin', 'python'), ('/usr', 'bin', 'java'),\n" +" ('/usr', 'bin', 'perl'), ('/usr', 'bin', 'ruby')])\n" +"=>\n" +" /bin/python, /usr/bin/java, /usr/bin/perl, /usr/bin/ruby" +msgstr "" + #: ../../howto/functional.rst:845 msgid "Selecting elements" msgstr "" @@ -944,6 +1186,12 @@ msgid "" "predicate returns false::" msgstr "" +#: ../../howto/functional.rst:854 +msgid "" +"itertools.filterfalse(is_even, itertools.count()) =>\n" +" 1, 3, 5, 7, 9, 11, 13, 15, ..." +msgstr "" + #: ../../howto/functional.rst:857 msgid "" ":func:`itertools.takewhile(predicate, iter) ` returns " @@ -951,6 +1199,18 @@ msgid "" "returns false, the iterator will signal the end of its results. ::" msgstr "" +#: ../../howto/functional.rst:861 +msgid "" +"def less_than_10(x):\n" +" return x < 10\n" +"\n" +"itertools.takewhile(less_than_10, itertools.count()) =>\n" +" 0, 1, 2, 3, 4, 5, 6, 7, 8, 9\n" +"\n" +"itertools.takewhile(is_even, itertools.count()) =>\n" +" 0" +msgstr "" + #: ../../howto/functional.rst:870 msgid "" ":func:`itertools.dropwhile(predicate, iter) ` discards " @@ -958,6 +1218,15 @@ msgid "" "iterable's results. ::" msgstr "" +#: ../../howto/functional.rst:874 +msgid "" +"itertools.dropwhile(less_than_10, itertools.count()) =>\n" +" 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, ...\n" +"\n" +"itertools.dropwhile(is_even, itertools.count()) =>\n" +" 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ..." +msgstr "" + #: ../../howto/functional.rst:880 msgid "" ":func:`itertools.compress(data, selectors) ` takes two " @@ -966,6 +1235,12 @@ msgid "" "is exhausted::" msgstr "" +#: ../../howto/functional.rst:884 +msgid "" +"itertools.compress([1, 2, 3, 4, 5], [True, True, False, False, True]) =>\n" +" 1, 2, 5" +msgstr "" + #: ../../howto/functional.rst:889 msgid "Combinatoric functions" msgstr "" @@ -977,6 +1252,20 @@ msgid "" "elements contained in *iterable*. ::" msgstr "" +#: ../../howto/functional.rst:895 +msgid "" +"itertools.combinations([1, 2, 3, 4, 5], 2) =>\n" +" (1, 2), (1, 3), (1, 4), (1, 5),\n" +" (2, 3), (2, 4), (2, 5),\n" +" (3, 4), (3, 5),\n" +" (4, 5)\n" +"\n" +"itertools.combinations([1, 2, 3, 4, 5], 3) =>\n" +" (1, 2, 3), (1, 2, 4), (1, 2, 5), (1, 3, 4), (1, 3, 5), (1, 4, 5),\n" +" (2, 3, 4), (2, 3, 5), (2, 4, 5),\n" +" (3, 4, 5)" +msgstr "" + #: ../../howto/functional.rst:906 msgid "" "The elements within each tuple remain in the same order as *iterable* " @@ -986,6 +1275,21 @@ msgid "" "constraint on the order, returning all possible arrangements of length *r*::" msgstr "" +#: ../../howto/functional.rst:913 +msgid "" +"itertools.permutations([1, 2, 3, 4, 5], 2) =>\n" +" (1, 2), (1, 3), (1, 4), (1, 5),\n" +" (2, 1), (2, 3), (2, 4), (2, 5),\n" +" (3, 1), (3, 2), (3, 4), (3, 5),\n" +" (4, 1), (4, 2), (4, 3), (4, 5),\n" +" (5, 1), (5, 2), (5, 3), (5, 4)\n" +"\n" +"itertools.permutations([1, 2, 3, 4, 5]) =>\n" +" (1, 2, 3, 4, 5), (1, 2, 3, 5, 4), (1, 2, 4, 3, 5),\n" +" ...\n" +" (5, 4, 3, 2, 1)" +msgstr "" + #: ../../howto/functional.rst:925 msgid "" "If you don't supply a value for *r* the length of the iterable is used, " @@ -998,6 +1302,13 @@ msgid "" "position and don't require that the contents of *iterable* are unique::" msgstr "" +#: ../../howto/functional.rst:931 +msgid "" +"itertools.permutations('aba', 3) =>\n" +" ('a', 'b', 'a'), ('a', 'a', 'b'), ('b', 'a', 'a'),\n" +" ('b', 'a', 'a'), ('a', 'a', 'b'), ('a', 'b', 'a')" +msgstr "" + #: ../../howto/functional.rst:935 msgid "" "The identical tuple ``('a', 'a', 'b')`` occurs twice, but the two 'a' " @@ -1013,6 +1324,16 @@ msgid "" "the second element is selected. ::" msgstr "" +#: ../../howto/functional.rst:944 +msgid "" +"itertools.combinations_with_replacement([1, 2, 3, 4, 5], 2) =>\n" +" (1, 1), (1, 2), (1, 3), (1, 4), (1, 5),\n" +" (2, 2), (2, 3), (2, 4), (2, 5),\n" +" (3, 3), (3, 4), (3, 5),\n" +" (4, 4), (4, 5),\n" +" (5, 5)" +msgstr "" + #: ../../howto/functional.rst:953 msgid "Grouping elements" msgstr "" @@ -1033,6 +1354,31 @@ msgid "" "tuples containing a key value and an iterator for the elements with that key." msgstr "" +#: ../../howto/functional.rst:966 +msgid "" +"city_list = [('Decatur', 'AL'), ('Huntsville', 'AL'), ('Selma', 'AL'),\n" +" ('Anchorage', 'AK'), ('Nome', 'AK'),\n" +" ('Flagstaff', 'AZ'), ('Phoenix', 'AZ'), ('Tucson', 'AZ'),\n" +" ...\n" +" ]\n" +"\n" +"def get_state(city_state):\n" +" return city_state[1]\n" +"\n" +"itertools.groupby(city_list, get_state) =>\n" +" ('AL', iterator-1),\n" +" ('AK', iterator-2),\n" +" ('AZ', iterator-3), ...\n" +"\n" +"where\n" +"iterator-1 =>\n" +" ('Decatur', 'AL'), ('Huntsville', 'AL'), ('Selma', 'AL')\n" +"iterator-2 =>\n" +" ('Anchorage', 'AK'), ('Nome', 'AK')\n" +"iterator-3 =>\n" +" ('Flagstaff', 'AZ'), ('Phoenix', 'AZ'), ('Tucson', 'AZ')" +msgstr "" + #: ../../howto/functional.rst:988 msgid "" ":func:`~itertools.groupby` assumes that the underlying iterable's contents " @@ -1075,6 +1421,19 @@ msgstr "" msgid "Here's a small but realistic example::" msgstr "以下是個很小但實際的範例: ::" +#: ../../howto/functional.rst:1015 +msgid "" +"import functools\n" +"\n" +"def log(message, subsystem):\n" +" \"\"\"Write the contents of 'message' to the specified subsystem.\"\"\"\n" +" print('%s: %s' % (subsystem, message))\n" +" ...\n" +"\n" +"server_log = functools.partial(log, subsystem='server')\n" +"server_log('Unable to open socket')" +msgstr "" + #: ../../howto/functional.rst:1025 msgid "" ":func:`functools.reduce(func, iter, [initial_value]) ` " @@ -1090,6 +1449,21 @@ msgid "" "``func(initial_value, A)`` is the first calculation. ::" msgstr "" +#: ../../howto/functional.rst:1037 +msgid "" +">>> import operator, functools\n" +">>> functools.reduce(operator.concat, ['A', 'BB', 'C'])\n" +"'ABBC'\n" +">>> functools.reduce(operator.concat, [])\n" +"Traceback (most recent call last):\n" +" ...\n" +"TypeError: reduce() of empty sequence with no initial value\n" +">>> functools.reduce(operator.mul, [1, 2, 3], 1)\n" +"6\n" +">>> functools.reduce(operator.mul, [], 1)\n" +"1" +msgstr "" + #: ../../howto/functional.rst:1049 msgid "" "If you use :func:`operator.add` with :func:`functools.reduce`, you'll add up " @@ -1103,6 +1477,18 @@ msgid "" "write the obvious :keyword:`for` loop::" msgstr "" +#: ../../howto/functional.rst:1064 +msgid "" +"import functools\n" +"# Instead of:\n" +"product = functools.reduce(operator.mul, [1, 2, 3], 1)\n" +"\n" +"# You can write:\n" +"product = 1\n" +"for i in [1, 2, 3]:\n" +" product *= i" +msgstr "" + #: ../../howto/functional.rst:1073 msgid "" "A related function is :func:`itertools.accumulate(iterable, func=operator." @@ -1111,6 +1497,15 @@ msgid "" "iterator that also yields each partial result::" msgstr "" +#: ../../howto/functional.rst:1078 +msgid "" +"itertools.accumulate([1, 2, 3, 4, 5]) =>\n" +" 1, 3, 6, 10, 15\n" +"\n" +"itertools.accumulate([1, 2, 3, 4, 5], operator.mul) =>\n" +" 1, 2, 6, 24, 120" +msgstr "" + #: ../../howto/functional.rst:1086 msgid "The operator module" msgstr "" @@ -1170,6 +1565,12 @@ msgid "" "need to define a new function at all::" msgstr "" +#: ../../howto/functional.rst:1113 +msgid "" +"stripped_lines = [line.strip() for line in lines]\n" +"existing_files = filter(os.path.exists, file_list)" +msgstr "" + #: ../../howto/functional.rst:1116 msgid "" "If the function you need doesn't exist, you need to write it. One way to " @@ -1179,12 +1580,28 @@ msgid "" "expression::" msgstr "" +#: ../../howto/functional.rst:1121 +msgid "" +"adder = lambda x, y: x+y\n" +"\n" +"print_assign = lambda name, value: name + '=' + str(value)" +msgstr "" + #: ../../howto/functional.rst:1125 msgid "" "An alternative is to just use the ``def`` statement and define a function in " "the usual way::" msgstr "" +#: ../../howto/functional.rst:1128 +msgid "" +"def adder(x, y):\n" +" return x + y\n" +"\n" +"def print_assign(name, value):\n" +" return name + '=' + str(value)" +msgstr "" + #: ../../howto/functional.rst:1134 msgid "" "Which alternative is preferable? That's a style question; my usual course " @@ -1201,6 +1618,12 @@ msgid "" "that's hard to read. Quick, what's the following code doing? ::" msgstr "" +#: ../../howto/functional.rst:1144 +msgid "" +"import functools\n" +"total = functools.reduce(lambda a, b: (0, a[1] + b[1]), items)[1]" +msgstr "" + #: ../../howto/functional.rst:1147 msgid "" "You can figure it out, but it takes time to disentangle the expression to " @@ -1208,14 +1631,34 @@ msgid "" "things a little bit better::" msgstr "" +#: ../../howto/functional.rst:1151 +msgid "" +"import functools\n" +"def combine(a, b):\n" +" return 0, a[1] + b[1]\n" +"\n" +"total = functools.reduce(combine, items)[1]" +msgstr "" + #: ../../howto/functional.rst:1157 msgid "But it would be best of all if I had simply used a ``for`` loop::" msgstr "" +#: ../../howto/functional.rst:1159 +msgid "" +"total = 0\n" +"for a, b in items:\n" +" total += b" +msgstr "" + #: ../../howto/functional.rst:1163 msgid "Or the :func:`sum` built-in and a generator expression::" msgstr "" +#: ../../howto/functional.rst:1165 +msgid "total = sum(b for a, b in items)" +msgstr "" + #: ../../howto/functional.rst:1167 msgid "" "Many uses of :func:`functools.reduce` are clearer when written as ``for`` " diff --git a/howto/gdb_helpers.po b/howto/gdb_helpers.po index 2d8f2205a3..2b1edf32c6 100644 --- a/howto/gdb_helpers.po +++ b/howto/gdb_helpers.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-24 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -114,6 +114,10 @@ msgid "" "configuration file (``~/.gdbinit`` or ``~/.config/gdb/gdbinit``)::" msgstr "" +#: ../../howto/gdb_helpers.rst:68 +msgid "add-auto-load-safe-path /path/to/cpython" +msgstr "" + #: ../../howto/gdb_helpers.rst:70 msgid "You can also add multiple paths, separated by ``:``." msgstr "" @@ -132,10 +136,20 @@ msgstr "" msgid "Fedora:" msgstr "" +#: ../../howto/gdb_helpers.rst:82 +msgid "" +"sudo dnf install gdb\n" +"sudo dnf debuginfo-install python3" +msgstr "" + #: ../../howto/gdb_helpers.rst:87 msgid "Ubuntu:" msgstr "" +#: ../../howto/gdb_helpers.rst:89 +msgid "sudo apt install gdb python3-dbg" +msgstr "" + #: ../../howto/gdb_helpers.rst:93 msgid "" "On several recent Linux systems, GDB can download debugging symbols " @@ -190,6 +204,37 @@ msgid "" "enabled::" msgstr "" +#: ../../howto/gdb_helpers.rst:126 +msgid "" +"#0 0x000000000041a6b1 in PyObject_Malloc (nbytes=Cannot access memory at " +"address 0x7fffff7fefe8\n" +") at Objects/obmalloc.c:748\n" +"#1 0x000000000041b7c0 in _PyObject_DebugMallocApi (id=111 'o', nbytes=24) " +"at Objects/obmalloc.c:1445\n" +"#2 0x000000000041b717 in _PyObject_DebugMalloc (nbytes=24) at Objects/" +"obmalloc.c:1412\n" +"#3 0x000000000044060a in _PyUnicode_New (length=11) at Objects/" +"unicodeobject.c:346\n" +"#4 0x00000000004466aa in PyUnicodeUCS2_DecodeUTF8Stateful (s=0x5c2b8d " +"\"__lltrace__\", size=11, errors=0x0, consumed=\n" +" 0x0) at Objects/unicodeobject.c:2531\n" +"#5 0x0000000000446647 in PyUnicodeUCS2_DecodeUTF8 (s=0x5c2b8d " +"\"__lltrace__\", size=11, errors=0x0)\n" +" at Objects/unicodeobject.c:2495\n" +"#6 0x0000000000440d1b in PyUnicodeUCS2_FromStringAndSize (u=0x5c2b8d " +"\"__lltrace__\", size=11)\n" +" at Objects/unicodeobject.c:551\n" +"#7 0x0000000000440d94 in PyUnicodeUCS2_FromString (u=0x5c2b8d " +"\"__lltrace__\") at Objects/unicodeobject.c:569\n" +"#8 0x0000000000584abd in PyDict_GetItemString (v=\n" +" {'Yuck': , '__builtins__': , '__file__': 'Lib/test/crashers/nasty_eq_vs_dict.py', " +"'__package__': None, 'y': , 'dict': {0: 0, 1: " +"1, 2: 2, 3: 3}, '__cached__': None, '__name__': '__main__', 'z': , '__doc__': None}, key=\n" +" 0x5c2b8d \"__lltrace__\") at Objects/dictobject.c:2171" +msgstr "" + #: ../../howto/gdb_helpers.rst:142 msgid "" "Notice how the dictionary argument to ``PyDict_GetItemString`` is displayed " @@ -204,6 +249,28 @@ msgid "" "example::" msgstr "" +#: ../../howto/gdb_helpers.rst:149 +msgid "" +"(gdb) p globals\n" +"$1 = {'__builtins__': , '__name__':\n" +"'__main__', 'ctypes': , '__doc__': None,\n" +"'__package__': None}\n" +"\n" +"(gdb) p *(PyDictObject*)globals\n" +"$2 = {ob_refcnt = 3, ob_type = 0x3dbdf85820, ma_fill = 5, ma_used = 5,\n" +"ma_mask = 7, ma_table = 0x63d0f8, ma_lookup = 0x3dbdc7ea70\n" +", ma_smalltable = {{me_hash = 7065186196740147912,\n" +"me_key = '__builtins__', me_value = },\n" +"{me_hash = -368181376027291943, me_key = '__name__',\n" +"me_value ='__main__'}, {me_hash = 0, me_key = 0x0, me_value = 0x0},\n" +"{me_hash = 0, me_key = 0x0, me_value = 0x0},\n" +"{me_hash = -9177857982131165996, me_key = 'ctypes',\n" +"me_value = },\n" +"{me_hash = -8518757509529533123, me_key = '__doc__', me_value = None},\n" +"{me_hash = 0, me_key = 0x0, me_value = 0x0}, {\n" +" me_hash = 6614918939584953775, me_key = '__package__', me_value = None}}}" +msgstr "" + #: ../../howto/gdb_helpers.rst:168 msgid "" "Note that the pretty-printers do not actually call ``repr()``. For basic " @@ -219,6 +286,15 @@ msgid "" "level integer::" msgstr "" +#: ../../howto/gdb_helpers.rst:177 +msgid "" +"(gdb) p some_machine_integer\n" +"$3 = 42\n" +"\n" +"(gdb) p some_python_integer\n" +"$4 = 42" +msgstr "" + #: ../../howto/gdb_helpers.rst:183 msgid "" "The internal structure can be revealed with a cast to :c:expr:`PyLongObject " @@ -237,6 +313,12 @@ msgid "" "a lot like gdb's built-in printer for ``char *``::" msgstr "" +#: ../../howto/gdb_helpers.rst:192 +msgid "" +"(gdb) p ptr_to_python_str\n" +"$6 = '__builtins__'" +msgstr "" + #: ../../howto/gdb_helpers.rst:195 msgid "" "The pretty-printer for ``str`` instances defaults to using single-quotes (as " @@ -244,12 +326,25 @@ msgid "" "*`` values uses double-quotes and contains a hexadecimal address::" msgstr "" +#: ../../howto/gdb_helpers.rst:199 +msgid "" +"(gdb) p ptr_to_char_star\n" +"$7 = 0x6d72c0 \"hello world\"" +msgstr "" + #: ../../howto/gdb_helpers.rst:202 msgid "" "Again, the implementation details can be revealed with a cast to :c:expr:" "`PyUnicodeObject *`::" msgstr "" +#: ../../howto/gdb_helpers.rst:205 +msgid "" +"(gdb) p *(PyUnicodeObject*)$6\n" +"$8 = {ob_base = {ob_refcnt = 33, ob_type = 0x3dad3a95a0}, length = 12,\n" +"str = 0x7ffff2128500, hash = 7065186196740147912, state = 1, defenc = 0x0}" +msgstr "" + #: ../../howto/gdb_helpers.rst:210 msgid "``py-list``" msgstr "" @@ -261,6 +356,22 @@ msgid "" "marked with a \">\"::" msgstr "" +#: ../../howto/gdb_helpers.rst:216 +msgid "" +"(gdb) py-list\n" +" 901 if options.profile:\n" +" 902 options.profile = False\n" +" 903 profile_me()\n" +" 904 return\n" +" 905\n" +">906 u = UI()\n" +" 907 if not u.quit:\n" +" 908 try:\n" +" 909 gtk.main()\n" +" 910 except KeyboardInterrupt:\n" +" 911 # properly quit on a keyboard interrupt..." +msgstr "" + #: ../../howto/gdb_helpers.rst:229 msgid "" "Use ``py-list START`` to list at a different line number within the Python " @@ -296,6 +407,21 @@ msgstr "" msgid "For example::" msgstr "" +#: ../../howto/gdb_helpers.rst:250 +msgid "" +"(gdb) py-up\n" +"#37 Frame 0x9420b04, for file /usr/lib/python2.6/site-packages/\n" +"gnome_sudoku/main.py, line 906, in start_game ()\n" +" u = UI()\n" +"(gdb) py-up\n" +"#40 Frame 0x948e82c, for file /usr/lib/python2.6/site-packages/\n" +"gnome_sudoku/gnome_sudoku.py, line 22, in start_game(main=)\n" +" main.start_game()\n" +"(gdb) py-up\n" +"Unable to find an older python frame" +msgstr "" + #: ../../howto/gdb_helpers.rst:261 msgid "so we're at the top of the Python stack." msgstr "" @@ -311,6 +437,47 @@ msgstr "" msgid "Going back down::" msgstr "" +#: ../../howto/gdb_helpers.rst:269 +msgid "" +"(gdb) py-down\n" +"#37 Frame 0x9420b04, for file /usr/lib/python2.6/site-packages/gnome_sudoku/" +"main.py, line 906, in start_game ()\n" +" u = UI()\n" +"(gdb) py-down\n" +"#34 (unable to read python frame information)\n" +"(gdb) py-down\n" +"#23 (unable to read python frame information)\n" +"(gdb) py-down\n" +"#19 (unable to read python frame information)\n" +"(gdb) py-down\n" +"#14 Frame 0x99262ac, for file /usr/lib/python2.6/site-packages/gnome_sudoku/" +"game_selector.py, line 201, in run_swallowed_dialog " +"(self=, puzzle=None, saved_games=[{'gsd.auto_fills': 0, 'tracking': {}, " +"'trackers': {}, 'notes': [], 'saved_at': 1270084485, 'game': '7 8 0 0 0 0 0 " +"5 6 0 0 9 0 8 0 1 0 0 0 4 6 0 0 0 0 7 0 6 5 0 0 0 4 7 9 2 0 0 0 9 0 1 0 0 0 " +"3 9 7 6 0 0 0 1 8 0 6 0 0 0 0 2 8 0 0 0 5 0 4 0 6 0 0 2 1 0 0 0 0 0 4 5\\n7 " +"8 0 0 0 0 0 5 6 0 0 9 0 8 0 1 0 0 0 4 6 0 0 0 0 7 0 6 5 1 8 3 4 7 9 2 0 0 0 " +"9 0 1 0 0 0 3 9 7 6 0 0 0 1 8 0 6 0 0 0 0 2 8 0 0 0 5 0 4 0 6 0 0 2 1 0 0 0 " +"0 0 4 5', 'gsd.impossible_hints': 0, 'timer.__absolute_start_time__': , 'gsd.hints': 0, 'timer.active_time': , 'timer.total_time': }], dialog=, saved_game_model=, sudoku_maker=, main_page=0) " +"at remote 0x98fa6e4>, d=)\n" +" gtk.main()\n" +"(gdb) py-down\n" +"#8 (unable to read python frame information)\n" +"(gdb) py-down\n" +"Unable to find a newer python frame" +msgstr "" + #: ../../howto/gdb_helpers.rst:289 msgid "and we're at the bottom of the Python stack." msgstr "" @@ -322,6 +489,33 @@ msgid "" "move multiple Python frames at once. For example::" msgstr "" +#: ../../howto/gdb_helpers.rst:295 +msgid "" +"(gdb) py-up\n" +"#6 Frame 0x7ffff7fb62b0, for file /tmp/rec.py, line 5, in recursive_function " +"(n=0)\n" +" time.sleep(5)\n" +"#6 Frame 0x7ffff7fb6240, for file /tmp/rec.py, line 7, in recursive_function " +"(n=1)\n" +" recursive_function(n-1)\n" +"#6 Frame 0x7ffff7fb61d0, for file /tmp/rec.py, line 7, in recursive_function " +"(n=2)\n" +" recursive_function(n-1)\n" +"#6 Frame 0x7ffff7fb6160, for file /tmp/rec.py, line 7, in recursive_function " +"(n=3)\n" +" recursive_function(n-1)\n" +"#6 Frame 0x7ffff7fb60f0, for file /tmp/rec.py, line 7, in recursive_function " +"(n=4)\n" +" recursive_function(n-1)\n" +"#6 Frame 0x7ffff7fb6080, for file /tmp/rec.py, line 7, in recursive_function " +"(n=5)\n" +" recursive_function(n-1)\n" +"#6 Frame 0x7ffff7fb6020, for file /tmp/rec.py, line 9, in ()\n" +" recursive_function(5)\n" +"(gdb) py-up\n" +"Unable to find an older python frame" +msgstr "" + #: ../../howto/gdb_helpers.rst:315 msgid "``py-bt``" msgstr "" @@ -332,6 +526,43 @@ msgid "" "current thread." msgstr "" +#: ../../howto/gdb_helpers.rst:322 +msgid "" +"(gdb) py-bt\n" +"#8 (unable to read python frame information)\n" +"#11 Frame 0x9aead74, for file /usr/lib/python2.6/site-packages/gnome_sudoku/" +"dialog_swallower.py, line 48, in run_dialog " +"(self=, main_page=0) " +"at remote 0x98fa6e4>, d=)\n" +" gtk.main()\n" +"#14 Frame 0x99262ac, for file /usr/lib/python2.6/site-packages/gnome_sudoku/" +"game_selector.py, line 201, in run_swallowed_dialog " +"(self=, puzzle=None, saved_games=[{'gsd.auto_fills': 0, 'tracking': {}, " +"'trackers': {}, 'notes': [], 'saved_at': 1270084485, 'game': '7 8 0 0 0 0 0 " +"5 6 0 0 9 0 8 0 1 0 0 0 4 6 0 0 0 0 7 0 6 5 0 0 0 4 7 9 2 0 0 0 9 0 1 0 0 0 " +"3 9 7 6 0 0 0 1 8 0 6 0 0 0 0 2 8 0 0 0 5 0 4 0 6 0 0 2 1 0 0 0 0 0 4 5\\n7 " +"8 0 0 0 0 0 5 6 0 0 9 0 8 0 1 0 0 0 4 6 0 0 0 0 7 0 6 5 1 8 3 4 7 9 2 0 0 0 " +"9 0 1 0 0 0 3 9 7 6 0 0 0 1 8 0 6 0 0 0 0 2 8 0 0 0 5 0 4 0 6 0 0 2 1 0 0 0 " +"0 0 4 5', 'gsd.impossible_hints': 0, 'timer.__absolute_start_time__': , 'gsd.hints': 0, 'timer.active_time': , 'timer.total_time': }], dialog=, saved_game_model=, sudoku_maker=)\n" +" main.start_game()" +msgstr "" + #: ../../howto/gdb_helpers.rst:336 msgid "" "The frame numbers correspond to those displayed by GDB's standard " @@ -349,6 +580,19 @@ msgid "" "builtins::" msgstr "" +#: ../../howto/gdb_helpers.rst:346 +msgid "" +"(gdb) py-print self\n" +"local 'self' = ,\n" +"main_page=0) at remote 0x98fa6e4>\n" +"(gdb) py-print __name__\n" +"global '__name__' = 'gnome_sudoku.dialog_swallower'\n" +"(gdb) py-print len\n" +"builtin 'len' = \n" +"(gdb) py-print scarlet_pimpernel\n" +"'scarlet_pimpernel' not found" +msgstr "" + #: ../../howto/gdb_helpers.rst:356 msgid "" "If the current C frame corresponds to multiple Python frames, ``py-print`` " @@ -365,12 +609,38 @@ msgid "" "Python frame in the selected thread, and prints their representations::" msgstr "" +#: ../../howto/gdb_helpers.rst:365 +msgid "" +"(gdb) py-locals\n" +"self = ,\n" +"main_page=0) at remote 0x98fa6e4>\n" +"d = " +msgstr "" + #: ../../howto/gdb_helpers.rst:370 msgid "" "If the current C frame corresponds to multiple Python frames, locals from " "all of them will be shown::" msgstr "" +#: ../../howto/gdb_helpers.rst:373 +msgid "" +"(gdb) py-locals\n" +"Locals for recursive_function\n" +"n = 0\n" +"Locals for recursive_function\n" +"n = 1\n" +"Locals for recursive_function\n" +"n = 2\n" +"Locals for recursive_function\n" +"n = 3\n" +"Locals for recursive_function\n" +"n = 4\n" +"Locals for recursive_function\n" +"n = 5\n" +"Locals for " +msgstr "" + #: ../../howto/gdb_helpers.rst:390 msgid "Use with GDB commands" msgstr "" @@ -382,15 +652,131 @@ msgid "" "a specific frame within the selected thread, like this::" msgstr "" +#: ../../howto/gdb_helpers.rst:396 +msgid "" +"(gdb) py-bt\n" +"(output snipped)\n" +"#68 Frame 0xaa4560, for file Lib/test/regrtest.py, line 1548, in " +"()\n" +" main()\n" +"(gdb) frame 68\n" +"#68 0x00000000004cd1e6 in PyEval_EvalFrameEx (f=Frame 0xaa4560, for file Lib/" +"test/regrtest.py, line 1548, in (), throwflag=0) at Python/ceval." +"c:2665\n" +"2665 x = call_function(&sp, oparg);\n" +"(gdb) py-list\n" +"1543 # Run the tests in a context manager that temporary changes the " +"CWD to a\n" +"1544 # temporary and writable directory. If it's not possible to " +"create or\n" +"1545 # change the CWD, the original CWD will be used. The original " +"CWD is\n" +"1546 # available from test_support.SAVEDCWD.\n" +"1547 with test_support.temp_cwd(TESTCWD, quiet=True):\n" +">1548 main()" +msgstr "" + #: ../../howto/gdb_helpers.rst:411 msgid "" "The ``info threads`` command will give you a list of the threads within the " "process, and you can use the ``thread`` command to select a different one::" msgstr "" +#: ../../howto/gdb_helpers.rst:414 +msgid "" +"(gdb) info threads\n" +" 105 Thread 0x7fffefa18710 (LWP 10260) sem_wait () at ../nptl/sysdeps/unix/" +"sysv/linux/x86_64/sem_wait.S:86\n" +" 104 Thread 0x7fffdf5fe710 (LWP 10259) sem_wait () at ../nptl/sysdeps/unix/" +"sysv/linux/x86_64/sem_wait.S:86\n" +"* 1 Thread 0x7ffff7fe2700 (LWP 10145) 0x00000038e46d73e3 in select () at ../" +"sysdeps/unix/syscall-template.S:82" +msgstr "" + #: ../../howto/gdb_helpers.rst:419 msgid "" "You can use ``thread apply all COMMAND`` or (``t a a COMMAND`` for short) to " "run a command on all threads. With ``py-bt``, this lets you see what every " "thread is doing at the Python level::" msgstr "" + +#: ../../howto/gdb_helpers.rst:423 +msgid "" +"(gdb) t a a py-bt\n" +"\n" +"Thread 105 (Thread 0x7fffefa18710 (LWP 10260)):\n" +"#5 Frame 0x7fffd00019d0, for file /home/david/coding/python-svn/Lib/" +"threading.py, line 155, in _acquire_restore " +"(self=<_RLock(_Verbose__verbose=False, _RLock__owner=140737354016512, " +"_RLock__block=, _RLock__count=1) at remote " +"0xd7ff40>, count_owner=(1, 140737213728528), count=1, " +"owner=140737213728528)\n" +" self.__block.acquire()\n" +"#8 Frame 0x7fffac001640, for file /home/david/coding/python-svn/Lib/" +"threading.py, line 269, in wait " +"(self=<_Condition(_Condition__lock=<_RLock(_Verbose__verbose=False, " +"_RLock__owner=140737354016512, _RLock__block=, _RLock__count=1) at remote 0xd7ff40>, acquire=, _is_owned=, " +"_release_save=, release=, _acquire_restore=, " +"_Verbose__verbose=False, _Condition__waiters=[]) at remote 0xd7fd10>, " +"timeout=None, waiter=, saved_state=(1, " +"140737213728528))\n" +" self._acquire_restore(saved_state)\n" +"#12 Frame 0x7fffb8001a10, for file /home/david/coding/python-svn/Lib/test/" +"lock_tests.py, line 348, in f ()\n" +" cond.wait()\n" +"#16 Frame 0x7fffb8001c40, for file /home/david/coding/python-svn/Lib/test/" +"lock_tests.py, line 37, in task (tid=140737213728528)\n" +" f()\n" +"\n" +"Thread 104 (Thread 0x7fffdf5fe710 (LWP 10259)):\n" +"#5 Frame 0x7fffe4001580, for file /home/david/coding/python-svn/Lib/" +"threading.py, line 155, in _acquire_restore " +"(self=<_RLock(_Verbose__verbose=False, _RLock__owner=140737354016512, " +"_RLock__block=, _RLock__count=1) at remote " +"0xd7ff40>, count_owner=(1, 140736940992272), count=1, " +"owner=140736940992272)\n" +" self.__block.acquire()\n" +"#8 Frame 0x7fffc8002090, for file /home/david/coding/python-svn/Lib/" +"threading.py, line 269, in wait " +"(self=<_Condition(_Condition__lock=<_RLock(_Verbose__verbose=False, " +"_RLock__owner=140737354016512, _RLock__block=, _RLock__count=1) at remote 0xd7ff40>, acquire=, _is_owned=, " +"_release_save=, release=, _acquire_restore=, " +"_Verbose__verbose=False, _Condition__waiters=[]) at remote 0xd7fd10>, " +"timeout=None, waiter=, saved_state=(1, " +"140736940992272))\n" +" self._acquire_restore(saved_state)\n" +"#12 Frame 0x7fffac001c90, for file /home/david/coding/python-svn/Lib/test/" +"lock_tests.py, line 348, in f ()\n" +" cond.wait()\n" +"#16 Frame 0x7fffac0011c0, for file /home/david/coding/python-svn/Lib/test/" +"lock_tests.py, line 37, in task (tid=140736940992272)\n" +" f()\n" +"\n" +"Thread 1 (Thread 0x7ffff7fe2700 (LWP 10145)):\n" +"#5 Frame 0xcb5380, for file /home/david/coding/python-svn/Lib/test/" +"lock_tests.py, line 16, in _wait ()\n" +" time.sleep(0.01)\n" +"#8 Frame 0x7fffd00024a0, for file /home/david/coding/python-svn/Lib/test/" +"lock_tests.py, line 378, in _check_notify " +"(self=, skipped=[], _mirrorOutput=False, testsRun=39, " +"buffer=False, _original_stderr=, " +"_stdout_buffer=, " +"_stderr_buffer=, " +"_moduleSetUpFailed=False, expectedFailures=[], errors=[], " +"_previousTestClass=, unexpectedSuccesses=[], " +"failures=[], shouldStop=False, failfast=False) at remote 0xc185a0>, " +"_threads=(0,), _cleanups=[], _type_equality_funcs={: , : " +", : " +", : " +", \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -94,10 +94,18 @@ msgstr "" msgid "On a Linux machine, this can be done via::" msgstr "在 Linux 機器上,這可以透過以下方式完成: ::" +#: ../../howto/instrumentation.rst:42 +msgid "$ yum install systemtap-sdt-devel" +msgstr "" + #: ../../howto/instrumentation.rst:44 msgid "or::" msgstr "或是: ::" +#: ../../howto/instrumentation.rst:46 +msgid "$ sudo apt-get install systemtap-sdt-dev" +msgstr "" + #: ../../howto/instrumentation.rst:49 msgid "" "CPython must then be :option:`configured with the --with-dtrace option <--" @@ -105,6 +113,10 @@ msgid "" msgstr "" "然後 CPython 必須使用\\ :option:`配置 --with-dtrace 選項 <--with-dtrace>`:" +#: ../../howto/instrumentation.rst:52 +msgid "checking for --with-dtrace... yes" +msgstr "" + #: ../../howto/instrumentation.rst:56 msgid "" "On macOS, you can list available DTrace probes by running a Python process " @@ -114,6 +126,28 @@ msgstr "" "在 macOS 上,你可以透過在後台運行 Python 行程並列出 Python 發布者 (provider) " "所提供的所有可用探針,以列出可用的 DTrace 探針: ::" +#: ../../howto/instrumentation.rst:60 +msgid "" +"$ python3.6 -q &\n" +"$ sudo dtrace -l -P python$! # or: dtrace -l -m python3.6\n" +"\n" +" ID PROVIDER MODULE FUNCTION NAME\n" +"29564 python18035 python3.6 _PyEval_EvalFrameDefault " +"function-entry\n" +"29565 python18035 python3.6 dtrace_function_entry " +"function-entry\n" +"29566 python18035 python3.6 _PyEval_EvalFrameDefault " +"function-return\n" +"29567 python18035 python3.6 dtrace_function_return " +"function-return\n" +"29568 python18035 python3.6 collect gc-" +"done\n" +"29569 python18035 python3.6 collect gc-" +"start\n" +"29570 python18035 python3.6 _PyEval_EvalFrameDefault line\n" +"29571 python18035 python3.6 maybe_dtrace_line line" +msgstr "" + #: ../../howto/instrumentation.rst:73 msgid "" "On Linux, you can verify if the SystemTap static markers are present in the " @@ -122,6 +156,12 @@ msgstr "" "在 Linux 上,你可以透過查看二進位建置檔案中是否包含 \".note.stapsdt\" 部分來" "驗證 SystemTap 靜態標記是否存在。" +#: ../../howto/instrumentation.rst:78 +msgid "" +"$ readelf -S ./python | grep .note.stapsdt\n" +"[30] .note.stapsdt NOTE 0000000000000000 00308d78" +msgstr "" + #: ../../howto/instrumentation.rst:81 msgid "" "If you've built Python as a shared library (with the :option:`--enable-" @@ -131,10 +171,64 @@ msgstr "" "如果你已將 Python 建置為共享函式庫(使用 :option:`--enable-shared` 配置選" "項),則需要在共享函式庫中查找。例如: ::" +#: ../../howto/instrumentation.rst:85 +msgid "" +"$ readelf -S libpython3.3dm.so.1.0 | grep .note.stapsdt\n" +"[29] .note.stapsdt NOTE 0000000000000000 00365b68" +msgstr "" + #: ../../howto/instrumentation.rst:88 msgid "Sufficiently modern readelf can print the metadata::" msgstr "足夠現代化的 readelf 可以印出元資料 (metadata): ::" +#: ../../howto/instrumentation.rst:90 +msgid "" +"$ readelf -n ./python\n" +"\n" +"Displaying notes found at file offset 0x00000254 with length 0x00000020:\n" +" Owner Data size Description\n" +" GNU 0x00000010 NT_GNU_ABI_TAG (ABI version " +"tag)\n" +" OS: Linux, ABI: 2.6.32\n" +"\n" +"Displaying notes found at file offset 0x00000274 with length 0x00000024:\n" +" Owner Data size Description\n" +" GNU 0x00000014 NT_GNU_BUILD_ID (unique build " +"ID bitstring)\n" +" Build ID: df924a2b08a7e89f6e11251d4602022977af2670\n" +"\n" +"Displaying notes found at file offset 0x002d6c30 with length 0x00000144:\n" +" Owner Data size Description\n" +" stapsdt 0x00000031 NT_STAPSDT (SystemTap probe " +"descriptors)\n" +" Provider: python\n" +" Name: gc__start\n" +" Location: 0x00000000004371c3, Base: 0x0000000000630ce2, Semaphore: " +"0x00000000008d6bf6\n" +" Arguments: -4@%ebx\n" +" stapsdt 0x00000030 NT_STAPSDT (SystemTap probe " +"descriptors)\n" +" Provider: python\n" +" Name: gc__done\n" +" Location: 0x00000000004374e1, Base: 0x0000000000630ce2, Semaphore: " +"0x00000000008d6bf8\n" +" Arguments: -8@%rax\n" +" stapsdt 0x00000045 NT_STAPSDT (SystemTap probe " +"descriptors)\n" +" Provider: python\n" +" Name: function__entry\n" +" Location: 0x000000000053db6c, Base: 0x0000000000630ce2, Semaphore: " +"0x00000000008d6be8\n" +" Arguments: 8@%rbp 8@%r12 -4@%eax\n" +" stapsdt 0x00000046 NT_STAPSDT (SystemTap probe " +"descriptors)\n" +" Provider: python\n" +" Name: function__return\n" +" Location: 0x000000000053dba8, Base: 0x0000000000630ce2, Semaphore: " +"0x00000000008d6bea\n" +" Arguments: 8@%rbp 8@%r12 -4@%eax" +msgstr "" + #: ../../howto/instrumentation.rst:125 msgid "" "The above metadata contains information for SystemTap describing how it can " @@ -158,14 +252,77 @@ msgstr "" "以下範例示範 DTrace 腳本可用於顯示 Python 腳本的呼叫/回傳階層結構,僅在名為 " "\"start\" 的函式的呼叫內進行追蹤。換句話說,引入時的函式呼叫不會被列出:" +#: ../../howto/instrumentation.rst:138 +msgid "" +"self int indent;\n" +"\n" +"python$target:::function-entry\n" +"/copyinstr(arg1) == \"start\"/\n" +"{\n" +" self->trace = 1;\n" +"}\n" +"\n" +"python$target:::function-entry\n" +"/self->trace/\n" +"{\n" +" printf(\"%d\\t%*s:\", timestamp, 15, probename);\n" +" printf(\"%*s\", self->indent, \"\");\n" +" printf(\"%s:%s:%d\\n\", basename(copyinstr(arg0)), copyinstr(arg1), " +"arg2);\n" +" self->indent++;\n" +"}\n" +"\n" +"python$target:::function-return\n" +"/self->trace/\n" +"{\n" +" self->indent--;\n" +" printf(\"%d\\t%*s:\", timestamp, 15, probename);\n" +" printf(\"%*s\", self->indent, \"\");\n" +" printf(\"%s:%s:%d\\n\", basename(copyinstr(arg0)), copyinstr(arg1), " +"arg2);\n" +"}\n" +"\n" +"python$target:::function-return\n" +"/copyinstr(arg1) == \"start\"/\n" +"{\n" +" self->trace = 0;\n" +"}" +msgstr "" + #: ../../howto/instrumentation.rst:172 ../../howto/instrumentation.rst:230 msgid "It can be invoked like this::" msgstr "可以這樣呼叫: ::" +#: ../../howto/instrumentation.rst:174 +msgid "$ sudo dtrace -q -s call_stack.d -c \"python3.6 script.py\"" +msgstr "" + #: ../../howto/instrumentation.rst:176 ../../howto/instrumentation.rst:236 msgid "The output looks like this:" msgstr "輸出如下所示:" +#: ../../howto/instrumentation.rst:178 +msgid "" +"156641360502280 function-entry:call_stack.py:start:23\n" +"156641360518804 function-entry: call_stack.py:function_1:1\n" +"156641360532797 function-entry: call_stack.py:function_3:9\n" +"156641360546807 function-return: call_stack.py:function_3:10\n" +"156641360563367 function-return: call_stack.py:function_1:2\n" +"156641360578365 function-entry: call_stack.py:function_2:5\n" +"156641360591757 function-entry: call_stack.py:function_1:1\n" +"156641360605556 function-entry: call_stack.py:function_3:9\n" +"156641360617482 function-return: call_stack.py:function_3:10\n" +"156641360629814 function-return: call_stack.py:function_1:2\n" +"156641360642285 function-return: call_stack.py:function_2:6\n" +"156641360656770 function-entry: call_stack.py:function_3:9\n" +"156641360669707 function-return: call_stack.py:function_3:10\n" +"156641360687853 function-entry: call_stack.py:function_4:13\n" +"156641360700719 function-return: call_stack.py:function_4:14\n" +"156641360719640 function-entry: call_stack.py:function_5:18\n" +"156641360732567 function-return: call_stack.py:function_5:21\n" +"156641360747370 function-return:call_stack.py:start:28" +msgstr "" + #: ../../howto/instrumentation.rst:201 msgid "Static SystemTap markers" msgstr "靜態 SystemTap 標記" @@ -185,6 +342,44 @@ msgid "" "hierarchy of a Python script:" msgstr "例如,此 SystemTap 腳本可用於顯示 Python 腳本的呼叫/回傳階層結構:" +#: ../../howto/instrumentation.rst:210 +msgid "" +"probe process(\"python\").mark(\"function__entry\") {\n" +" filename = user_string($arg1);\n" +" funcname = user_string($arg2);\n" +" lineno = $arg3;\n" +"\n" +" printf(\"%s => %s in %s:%d\\\\n\",\n" +" thread_indent(1), funcname, filename, lineno);\n" +"}\n" +"\n" +"probe process(\"python\").mark(\"function__return\") {\n" +" filename = user_string($arg1);\n" +" funcname = user_string($arg2);\n" +" lineno = $arg3;\n" +"\n" +" printf(\"%s <= %s in %s:%d\\\\n\",\n" +" thread_indent(-1), funcname, filename, lineno);\n" +"}" +msgstr "" + +#: ../../howto/instrumentation.rst:232 +msgid "" +"$ stap \\\n" +" show-call-hierarchy.stp \\\n" +" -c \"./python test.py\"" +msgstr "" + +#: ../../howto/instrumentation.rst:238 +msgid "" +"11408 python(8274): => __contains__ in Lib/_abcoll.py:362\n" +"11414 python(8274): => __getitem__ in Lib/os.py:425\n" +"11418 python(8274): => encode in Lib/os.py:490\n" +"11424 python(8274): <= encode in Lib/os.py:493\n" +"11428 python(8274): <= __getitem__ in Lib/os.py:426\n" +"11433 python(8274): <= __contains__ in Lib/_abcoll.py:366" +msgstr "" + #: ../../howto/instrumentation.rst:247 msgid "where the columns are:" msgstr "其中的行 (column) 是:" @@ -216,10 +411,20 @@ msgstr "" "函式庫中,並且探針的帶點路徑 (dotted path) 需要反映這一點。例如,上面範例中的" "這一列:" +#: ../../howto/instrumentation.rst:259 +msgid "probe process(\"python\").mark(\"function__entry\") {" +msgstr "" + #: ../../howto/instrumentation.rst:263 msgid "should instead read:" msgstr "應該改為讀取:" +#: ../../howto/instrumentation.rst:265 +msgid "" +"probe process(\"python\").library(\"libpython3.6dm.so.1.0\")." +"mark(\"function__entry\") {" +msgstr "" + #: ../../howto/instrumentation.rst:269 msgid "(assuming a :ref:`debug build ` of CPython 3.6)" msgstr "(假設 CPython 3.6 的\\ :ref:`除錯建置版本 `)" @@ -342,6 +547,29 @@ msgstr "" msgid "Here is a tapset file, based on a non-shared build of CPython:" msgstr "這是一個 tapset 檔案,是基於 CPython 的非共享建置版本:" +#: ../../howto/instrumentation.rst:351 +msgid "" +"/*\n" +" Provide a higher-level wrapping around the function__entry and\n" +" function__return markers:\n" +" \\*/\n" +"probe python.function.entry = process(\"python\").mark(\"function__entry\")\n" +"{\n" +" filename = user_string($arg1);\n" +" funcname = user_string($arg2);\n" +" lineno = $arg3;\n" +" frameptr = $arg4\n" +"}\n" +"probe python.function.return = process(\"python\")." +"mark(\"function__return\")\n" +"{\n" +" filename = user_string($arg1);\n" +" funcname = user_string($arg2);\n" +" lineno = $arg3;\n" +" frameptr = $arg4\n" +"}" +msgstr "" + #: ../../howto/instrumentation.rst:372 msgid "" "If this file is installed in SystemTap's tapset directory (e.g. ``/usr/share/" @@ -381,6 +609,21 @@ msgstr "" "此 SystemTap 腳本使用上面的 tapset 來更清晰地實作上面給出的追蹤 Python 函式呼" "叫階層結構的範例,而無需直接命名靜態標記:" +#: ../../howto/instrumentation.rst:395 +msgid "" +"probe python.function.entry\n" +"{\n" +" printf(\"%s => %s in %s:%d\\n\",\n" +" thread_indent(1), funcname, filename, lineno);\n" +"}\n" +"\n" +"probe python.function.return\n" +"{\n" +" printf(\"%s <= %s in %s:%d\\n\",\n" +" thread_indent(-1), funcname, filename, lineno);\n" +"}" +msgstr "" + #: ../../howto/instrumentation.rst:410 msgid "" "The following script uses the tapset above to provide a top-like view of all " @@ -389,3 +632,25 @@ msgid "" msgstr "" "以下腳本使用上面的 tapset 來提供所有正在運行之 CPython 程式碼的近乎最高層視" "角,顯示整個系統中每秒最常被進入的 20 個位元組碼幀 (bytecode frame):" + +#: ../../howto/instrumentation.rst:414 +msgid "" +"global fn_calls;\n" +"\n" +"probe python.function.entry\n" +"{\n" +" fn_calls[pid(), filename, funcname, lineno] += 1;\n" +"}\n" +"\n" +"probe timer.ms(1000) {\n" +" printf(\"\\033[2J\\033[1;1H\") /* clear screen \\*/\n" +" printf(\"%6s %80s %6s %30s %6s\\n\",\n" +" \"PID\", \"FILENAME\", \"LINE\", \"FUNCTION\", \"CALLS\")\n" +" foreach ([pid, filename, funcname, lineno] in fn_calls- limit 20) {\n" +" printf(\"%6d %80s %6d %30s %6d\\n\",\n" +" pid, filename, lineno, funcname,\n" +" fn_calls[pid, filename, funcname, lineno]);\n" +" }\n" +" delete fn_calls;\n" +"}" +msgstr "" diff --git a/howto/isolating-extensions.po b/howto/isolating-extensions.po index 23bf093704..61b5e1e892 100644 --- a/howto/isolating-extensions.po +++ b/howto/isolating-extensions.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-08-03 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -149,6 +149,17 @@ msgid "" "example:" msgstr "" +#: ../../howto/isolating-extensions.rst:93 +msgid "" +">>> import sys\n" +">>> import binascii\n" +">>> old_binascii = binascii\n" +">>> del sys.modules['binascii']\n" +">>> import binascii # create a new module object\n" +">>> old_binascii == binascii\n" +"False" +msgstr "" + #: ../../howto/isolating-extensions.rst:103 msgid "" "As a rule of thumb, the two modules should be completely independent. All " @@ -180,6 +191,20 @@ msgid "" "exception is *not* caught:" msgstr "" +#: ../../howto/isolating-extensions.rst:126 +msgid "" +">>> old_binascii.Error == binascii.Error\n" +"False\n" +">>> try:\n" +"... old_binascii.unhexlify(b'qwertyuiop')\n" +"... except binascii.Error:\n" +"... print('boo')\n" +"...\n" +"Traceback (most recent call last):\n" +" File \"\", line 2, in \n" +"binascii.Error: Non-hexadecimal digit found" +msgstr "" + #: ../../howto/isolating-extensions.rst:139 msgid "" "This is expected. Notice that pure-Python modules behave the same way: it is " @@ -298,6 +323,23 @@ msgid "" "For example::" msgstr "" +#: ../../howto/isolating-extensions.rst:218 +msgid "" +"static int loaded = 0;\n" +"\n" +"static int\n" +"exec_module(PyObject* module)\n" +"{\n" +" if (loaded) {\n" +" PyErr_SetString(PyExc_ImportError,\n" +" \"cannot load module more than once per process\");\n" +" return -1;\n" +" }\n" +" loaded = 1;\n" +" // ... rest of initialization\n" +"}" +msgstr "" + #: ../../howto/isolating-extensions.rst:234 msgid "Module State Access from Functions" msgstr "" @@ -309,6 +351,19 @@ msgid "" "state, you can use ``PyModule_GetState``::" msgstr "" +#: ../../howto/isolating-extensions.rst:240 +msgid "" +"static PyObject *\n" +"func(PyObject *module, PyObject *args)\n" +"{\n" +" my_struct *state = (my_struct*)PyModule_GetState(module);\n" +" if (state == NULL) {\n" +" return NULL;\n" +" }\n" +" // ... rest of logic\n" +"}" +msgstr "" + #: ../../howto/isolating-extensions.rst:251 msgid "" "``PyModule_GetState`` may return ``NULL`` without setting an exception if " @@ -466,6 +521,17 @@ msgid "" "visit the type, so it must be more complicated::" msgstr "" +#: ../../howto/isolating-extensions.rst:358 +msgid "" +"static int my_traverse(PyObject *self, visitproc visit, void *arg)\n" +"{\n" +" if (Py_Version >= 0x03090000) {\n" +" Py_VISIT(Py_TYPE(self));\n" +" }\n" +" return 0;\n" +"}" +msgstr "" + #: ../../howto/isolating-extensions.rst:366 msgid "" "Unfortunately, :c:data:`Py_Version` was only added in Python 3.11. As a " @@ -498,10 +564,25 @@ msgstr "" msgid "For example, if your traverse function includes::" msgstr "" +#: ../../howto/isolating-extensions.rst:384 +msgid "base->tp_traverse(self, visit, arg)" +msgstr "" + #: ../../howto/isolating-extensions.rst:386 msgid "...and ``base`` may be a static type, then it should also include::" msgstr "" +#: ../../howto/isolating-extensions.rst:388 +msgid "" +"if (base->tp_flags & Py_TPFLAGS_HEAPTYPE) {\n" +" // a heap type's tp_traverse already visited Py_TYPE(self)\n" +"} else {\n" +" if (Py_Version >= 0x03090000) {\n" +" Py_VISIT(Py_TYPE(self));\n" +" }\n" +"}" +msgstr "" + #: ../../howto/isolating-extensions.rst:396 msgid "" "It is not necessary to handle the type's reference count in :c:member:" @@ -533,6 +614,18 @@ msgid "" "needs to be decremented *after* the instance is deallocated. For example::" msgstr "" +#: ../../howto/isolating-extensions.rst:412 +msgid "" +"static void my_dealloc(PyObject *self)\n" +"{\n" +" PyObject_GC_UnTrack(self);\n" +" ...\n" +" PyTypeObject *type = Py_TYPE(self);\n" +" type->tp_free(self);\n" +" Py_DECREF(type);\n" +"}" +msgstr "" + #: ../../howto/isolating-extensions.rst:421 msgid "" "The default ``tp_dealloc`` function does this, so if your type does *not* " @@ -567,6 +660,10 @@ msgid "" "That is, replace ``TYPE *o = PyObject_New(TYPE, typeobj)`` with::" msgstr "" +#: ../../howto/isolating-extensions.rst:444 +msgid "TYPE *o = typeobj->tp_alloc(typeobj, 0);" +msgstr "" + #: ../../howto/isolating-extensions.rst:446 msgid "" "Replace ``o = PyObject_NewVar(TYPE, typeobj, size)`` with the same, but use " @@ -579,6 +676,13 @@ msgid "" "func:`PyObject_GC_New` or :c:func:`PyObject_GC_NewVar`::" msgstr "" +#: ../../howto/isolating-extensions.rst:452 +msgid "" +"TYPE *o = PyObject_GC_New(TYPE, typeobj);\n" +"\n" +"TYPE *o = PyObject_GC_NewVar(TYPE, typeobj, size);" +msgstr "" + #: ../../howto/isolating-extensions.rst:458 msgid "Module State Access from Classes" msgstr "" @@ -596,6 +700,14 @@ msgid "" "these two steps with :c:func:`PyType_GetModuleState`, resulting in::" msgstr "" +#: ../../howto/isolating-extensions.rst:467 +msgid "" +"my_struct *state = (my_struct*)PyType_GetModuleState(type);\n" +"if (state == NULL) {\n" +" return NULL;\n" +"}" +msgstr "" + #: ../../howto/isolating-extensions.rst:474 msgid "Module State Access from Regular Methods" msgstr "" @@ -628,6 +740,19 @@ msgid "" "get_defining_class`` returns ``Base`` even if ``type(self) == Sub``:" msgstr "" +#: ../../howto/isolating-extensions.rst:494 +msgid "" +"class Base:\n" +" def get_type_of_self(self):\n" +" return type(self)\n" +"\n" +" def get_defining_class(self):\n" +" return __class__\n" +"\n" +"class Sub(Base):\n" +" pass" +msgstr "" + #: ../../howto/isolating-extensions.rst:506 msgid "" "For a method to get its \"defining class\", it must use the :ref:" @@ -636,6 +761,16 @@ msgid "" "corresponding :c:type:`PyCMethod` signature::" msgstr "" +#: ../../howto/isolating-extensions.rst:511 +msgid "" +"PyObject *PyCMethod(\n" +" PyObject *self, // object the method was called on\n" +" PyTypeObject *defining_class, // defining class\n" +" PyObject *const *args, // C array of arguments\n" +" Py_ssize_t nargs, // length of \"args\"\n" +" PyObject *kwnames) // NULL, or dict of keyword arguments" +msgstr "" + #: ../../howto/isolating-extensions.rst:518 msgid "" "Once you have the defining class, call :c:func:`PyType_GetModuleState` to " @@ -646,6 +781,33 @@ msgstr "" msgid "For example::" msgstr "" +#: ../../howto/isolating-extensions.rst:523 +msgid "" +"static PyObject *\n" +"example_method(PyObject *self,\n" +" PyTypeObject *defining_class,\n" +" PyObject *const *args,\n" +" Py_ssize_t nargs,\n" +" PyObject *kwnames)\n" +"{\n" +" my_struct *state = (my_struct*)PyType_GetModuleState(defining_class);\n" +" if (state == NULL) {\n" +" return NULL;\n" +" }\n" +" ... // rest of logic\n" +"}\n" +"\n" +"PyDoc_STRVAR(example_method_doc, \"...\");\n" +"\n" +"static PyMethodDef my_methods[] = {\n" +" {\"example_method\",\n" +" (PyCFunction)(void(*)(void))example_method,\n" +" METH_METHOD|METH_FASTCALL|METH_KEYWORDS,\n" +" example_method_doc}\n" +" {NULL},\n" +"}" +msgstr "" + #: ../../howto/isolating-extensions.rst:549 msgid "Module State Access from Slot Methods, Getters and Setters" msgstr "" @@ -671,6 +833,15 @@ msgid "" "you have the module, call :c:func:`PyModule_GetState` to get the state::" msgstr "" +#: ../../howto/isolating-extensions.rst:573 +msgid "" +"PyObject *module = PyType_GetModuleByDef(Py_TYPE(self), &module_def);\n" +"my_struct *state = (my_struct*)PyModule_GetState(module);\n" +"if (state == NULL) {\n" +" return NULL;\n" +"}" +msgstr "" + #: ../../howto/isolating-extensions.rst:579 msgid "" ":c:func:`!PyType_GetModuleByDef` works by searching the :term:`method " diff --git a/howto/logging-cookbook.po b/howto/logging-cookbook.po index 3c3d9e0dcf..d1b4aea2d7 100644 --- a/howto/logging-cookbook.po +++ b/howto/logging-cookbook.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-07-23 00:04+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2018-05-23 14:36+0000\n" "Last-Translator: Adrian Liaw \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -53,14 +53,94 @@ msgid "" "module::" msgstr "" +#: ../../howto/logging-cookbook.rst:26 +msgid "" +"import logging\n" +"import auxiliary_module\n" +"\n" +"# create logger with 'spam_application'\n" +"logger = logging.getLogger('spam_application')\n" +"logger.setLevel(logging.DEBUG)\n" +"# create file handler which logs even debug messages\n" +"fh = logging.FileHandler('spam.log')\n" +"fh.setLevel(logging.DEBUG)\n" +"# create console handler with a higher log level\n" +"ch = logging.StreamHandler()\n" +"ch.setLevel(logging.ERROR)\n" +"# create formatter and add it to the handlers\n" +"formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - " +"%(message)s')\n" +"fh.setFormatter(formatter)\n" +"ch.setFormatter(formatter)\n" +"# add the handlers to the logger\n" +"logger.addHandler(fh)\n" +"logger.addHandler(ch)\n" +"\n" +"logger.info('creating an instance of auxiliary_module.Auxiliary')\n" +"a = auxiliary_module.Auxiliary()\n" +"logger.info('created an instance of auxiliary_module.Auxiliary')\n" +"logger.info('calling auxiliary_module.Auxiliary.do_something')\n" +"a.do_something()\n" +"logger.info('finished auxiliary_module.Auxiliary.do_something')\n" +"logger.info('calling auxiliary_module.some_function()')\n" +"auxiliary_module.some_function()\n" +"logger.info('done with auxiliary_module.some_function()')" +msgstr "" + #: ../../howto/logging-cookbook.rst:56 msgid "Here is the auxiliary module::" msgstr "" +#: ../../howto/logging-cookbook.rst:58 +msgid "" +"import logging\n" +"\n" +"# create logger\n" +"module_logger = logging.getLogger('spam_application.auxiliary')\n" +"\n" +"class Auxiliary:\n" +" def __init__(self):\n" +" self.logger = logging.getLogger('spam_application.auxiliary." +"Auxiliary')\n" +" self.logger.info('creating an instance of Auxiliary')\n" +"\n" +" def do_something(self):\n" +" self.logger.info('doing something')\n" +" a = 1 + 1\n" +" self.logger.info('done doing something')\n" +"\n" +"def some_function():\n" +" module_logger.info('received a call to \"some_function\"')" +msgstr "" + #: ../../howto/logging-cookbook.rst:76 msgid "The output looks like this:" msgstr "" +#: ../../howto/logging-cookbook.rst:78 +msgid "" +"2005-03-23 23:47:11,663 - spam_application - INFO -\n" +" creating an instance of auxiliary_module.Auxiliary\n" +"2005-03-23 23:47:11,665 - spam_application.auxiliary.Auxiliary - INFO -\n" +" creating an instance of Auxiliary\n" +"2005-03-23 23:47:11,665 - spam_application - INFO -\n" +" created an instance of auxiliary_module.Auxiliary\n" +"2005-03-23 23:47:11,668 - spam_application - INFO -\n" +" calling auxiliary_module.Auxiliary.do_something\n" +"2005-03-23 23:47:11,668 - spam_application.auxiliary.Auxiliary - INFO -\n" +" doing something\n" +"2005-03-23 23:47:11,669 - spam_application.auxiliary.Auxiliary - INFO -\n" +" done doing something\n" +"2005-03-23 23:47:11,670 - spam_application - INFO -\n" +" finished auxiliary_module.Auxiliary.do_something\n" +"2005-03-23 23:47:11,671 - spam_application - INFO -\n" +" calling auxiliary_module.some_function()\n" +"2005-03-23 23:47:11,672 - spam_application.auxiliary - INFO -\n" +" received a call to 'some_function'\n" +"2005-03-23 23:47:11,673 - spam_application - INFO -\n" +" done with auxiliary_module.some_function()" +msgstr "" + #: ../../howto/logging-cookbook.rst:102 msgid "Logging from multiple threads" msgstr "" @@ -71,10 +151,61 @@ msgid "" "example shows logging from the main (initial) thread and another thread::" msgstr "" +#: ../../howto/logging-cookbook.rst:107 +msgid "" +"import logging\n" +"import threading\n" +"import time\n" +"\n" +"def worker(arg):\n" +" while not arg['stop']:\n" +" logging.debug('Hi from myfunc')\n" +" time.sleep(0.5)\n" +"\n" +"def main():\n" +" logging.basicConfig(level=logging.DEBUG, format='%(relativeCreated)6d " +"%(threadName)s %(message)s')\n" +" info = {'stop': False}\n" +" thread = threading.Thread(target=worker, args=(info,))\n" +" thread.start()\n" +" while True:\n" +" try:\n" +" logging.debug('Hello from main')\n" +" time.sleep(0.75)\n" +" except KeyboardInterrupt:\n" +" info['stop'] = True\n" +" break\n" +" thread.join()\n" +"\n" +"if __name__ == '__main__':\n" +" main()" +msgstr "" + #: ../../howto/logging-cookbook.rst:133 msgid "When run, the script should print something like the following:" msgstr "" +#: ../../howto/logging-cookbook.rst:135 +msgid "" +" 0 Thread-1 Hi from myfunc\n" +" 3 MainThread Hello from main\n" +" 505 Thread-1 Hi from myfunc\n" +" 755 MainThread Hello from main\n" +"1007 Thread-1 Hi from myfunc\n" +"1507 MainThread Hello from main\n" +"1508 Thread-1 Hi from myfunc\n" +"2010 Thread-1 Hi from myfunc\n" +"2258 MainThread Hello from main\n" +"2512 Thread-1 Hi from myfunc\n" +"3009 MainThread Hello from main\n" +"3013 Thread-1 Hi from myfunc\n" +"3515 Thread-1 Hi from myfunc\n" +"3761 MainThread Hello from main\n" +"4017 Thread-1 Hi from myfunc\n" +"4513 MainThread Hello from main\n" +"4518 Thread-1 Hi from myfunc" +msgstr "" + #: ../../howto/logging-cookbook.rst:155 msgid "" "This shows the logging output interspersed as one might expect. This " @@ -97,6 +228,35 @@ msgid "" "example::" msgstr "" +#: ../../howto/logging-cookbook.rst:169 +msgid "" +"import logging\n" +"\n" +"logger = logging.getLogger('simple_example')\n" +"logger.setLevel(logging.DEBUG)\n" +"# create file handler which logs even debug messages\n" +"fh = logging.FileHandler('spam.log')\n" +"fh.setLevel(logging.DEBUG)\n" +"# create console handler with a higher log level\n" +"ch = logging.StreamHandler()\n" +"ch.setLevel(logging.ERROR)\n" +"# create formatter and add it to the handlers\n" +"formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - " +"%(message)s')\n" +"ch.setFormatter(formatter)\n" +"fh.setFormatter(formatter)\n" +"# add the handlers to logger\n" +"logger.addHandler(ch)\n" +"logger.addHandler(fh)\n" +"\n" +"# 'application' code\n" +"logger.debug('debug message')\n" +"logger.info('info message')\n" +"logger.warning('warn message')\n" +"logger.error('error message')\n" +"logger.critical('critical message')" +msgstr "" + #: ../../howto/logging-cookbook.rst:194 msgid "" "Notice that the 'application' code does not care about multiple handlers. " @@ -129,14 +289,69 @@ msgid "" "console messages should not. Here's how you can achieve this::" msgstr "" +#: ../../howto/logging-cookbook.rst:216 +msgid "" +"import logging\n" +"\n" +"# set up logging to file - see previous section for more details\n" +"logging.basicConfig(level=logging.DEBUG,\n" +" format='%(asctime)s %(name)-12s %(levelname)-8s " +"%(message)s',\n" +" datefmt='%m-%d %H:%M',\n" +" filename='/tmp/myapp.log',\n" +" filemode='w')\n" +"# define a Handler which writes INFO messages or higher to the sys.stderr\n" +"console = logging.StreamHandler()\n" +"console.setLevel(logging.INFO)\n" +"# set a format which is simpler for console use\n" +"formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s')\n" +"# tell the handler to use this format\n" +"console.setFormatter(formatter)\n" +"# add the handler to the root logger\n" +"logging.getLogger('').addHandler(console)\n" +"\n" +"# Now, we can log to the root logger, or any other logger. First the " +"root...\n" +"logging.info('Jackdaws love my big sphinx of quartz.')\n" +"\n" +"# Now, define a couple of other loggers which might represent areas in your\n" +"# application:\n" +"\n" +"logger1 = logging.getLogger('myapp.area1')\n" +"logger2 = logging.getLogger('myapp.area2')\n" +"\n" +"logger1.debug('Quick zephyrs blow, vexing daft Jim.')\n" +"logger1.info('How quickly daft jumping zebras vex.')\n" +"logger2.warning('Jail zesty vixen who grabbed pay from quack.')\n" +"logger2.error('The five boxing wizards jump quickly.')" +msgstr "" + #: ../../howto/logging-cookbook.rst:248 msgid "When you run this, on the console you will see" msgstr "" +#: ../../howto/logging-cookbook.rst:250 +msgid "" +"root : INFO Jackdaws love my big sphinx of quartz.\n" +"myapp.area1 : INFO How quickly daft jumping zebras vex.\n" +"myapp.area2 : WARNING Jail zesty vixen who grabbed pay from quack.\n" +"myapp.area2 : ERROR The five boxing wizards jump quickly." +msgstr "" + #: ../../howto/logging-cookbook.rst:257 msgid "and in the file you will see something like" msgstr "" +#: ../../howto/logging-cookbook.rst:259 +msgid "" +"10-22 22:19 root INFO Jackdaws love my big sphinx of quartz.\n" +"10-22 22:19 myapp.area1 DEBUG Quick zephyrs blow, vexing daft Jim.\n" +"10-22 22:19 myapp.area1 INFO How quickly daft jumping zebras vex.\n" +"10-22 22:19 myapp.area2 WARNING Jail zesty vixen who grabbed pay from " +"quack.\n" +"10-22 22:19 myapp.area2 ERROR The five boxing wizards jump quickly." +msgstr "" + #: ../../howto/logging-cookbook.rst:267 msgid "" "As you can see, the DEBUG message only shows up in the file. The other " @@ -186,6 +401,47 @@ msgstr "" msgid "Suppose you configure logging with the following JSON:" msgstr "" +#: ../../howto/logging-cookbook.rst:295 +msgid "" +"{\n" +" \"version\": 1,\n" +" \"disable_existing_loggers\": false,\n" +" \"formatters\": {\n" +" \"simple\": {\n" +" \"format\": \"%(levelname)-8s - %(message)s\"\n" +" }\n" +" },\n" +" \"handlers\": {\n" +" \"stdout\": {\n" +" \"class\": \"logging.StreamHandler\",\n" +" \"level\": \"INFO\",\n" +" \"formatter\": \"simple\",\n" +" \"stream\": \"ext://sys.stdout\"\n" +" },\n" +" \"stderr\": {\n" +" \"class\": \"logging.StreamHandler\",\n" +" \"level\": \"ERROR\",\n" +" \"formatter\": \"simple\",\n" +" \"stream\": \"ext://sys.stderr\"\n" +" },\n" +" \"file\": {\n" +" \"class\": \"logging.FileHandler\",\n" +" \"formatter\": \"simple\",\n" +" \"filename\": \"app.log\",\n" +" \"mode\": \"w\"\n" +" }\n" +" },\n" +" \"root\": {\n" +" \"level\": \"DEBUG\",\n" +" \"handlers\": [\n" +" \"stderr\",\n" +" \"stdout\",\n" +" \"file\"\n" +" ]\n" +" }\n" +"}" +msgstr "" + #: ../../howto/logging-cookbook.rst:335 msgid "" "This configuration does *almost* what we want, except that ``sys.stdout`` " @@ -195,16 +451,52 @@ msgid "" "adding a ``filters`` section parallel to ``formatters`` and ``handlers``:" msgstr "" +#: ../../howto/logging-cookbook.rst:341 +msgid "" +"{\n" +" \"filters\": {\n" +" \"warnings_and_below\": {\n" +" \"()\" : \"__main__.filter_maker\",\n" +" \"level\": \"WARNING\"\n" +" }\n" +" }\n" +"}" +msgstr "" + #: ../../howto/logging-cookbook.rst:352 msgid "and changing the section on the ``stdout`` handler to add it:" msgstr "" +#: ../../howto/logging-cookbook.rst:354 +msgid "" +"{\n" +" \"stdout\": {\n" +" \"class\": \"logging.StreamHandler\",\n" +" \"level\": \"INFO\",\n" +" \"formatter\": \"simple\",\n" +" \"stream\": \"ext://sys.stdout\",\n" +" \"filters\": [\"warnings_and_below\"]\n" +" }\n" +"}" +msgstr "" + #: ../../howto/logging-cookbook.rst:366 msgid "" "A filter is just a function, so we can define the ``filter_maker`` (a " "factory function) as follows:" msgstr "" +#: ../../howto/logging-cookbook.rst:369 +msgid "" +"def filter_maker(level):\n" +" level = getattr(logging, level)\n" +"\n" +" def filter(record):\n" +" return record.levelno <= level\n" +"\n" +" return filter" +msgstr "" + #: ../../howto/logging-cookbook.rst:379 msgid "" "This converts the string argument passed in to a numeric level, and returns " @@ -220,14 +512,110 @@ msgstr "" msgid "With the filter added, we can run ``main.py``, which in full is:" msgstr "" +#: ../../howto/logging-cookbook.rst:389 +msgid "" +"import json\n" +"import logging\n" +"import logging.config\n" +"\n" +"CONFIG = '''\n" +"{\n" +" \"version\": 1,\n" +" \"disable_existing_loggers\": false,\n" +" \"formatters\": {\n" +" \"simple\": {\n" +" \"format\": \"%(levelname)-8s - %(message)s\"\n" +" }\n" +" },\n" +" \"filters\": {\n" +" \"warnings_and_below\": {\n" +" \"()\" : \"__main__.filter_maker\",\n" +" \"level\": \"WARNING\"\n" +" }\n" +" },\n" +" \"handlers\": {\n" +" \"stdout\": {\n" +" \"class\": \"logging.StreamHandler\",\n" +" \"level\": \"INFO\",\n" +" \"formatter\": \"simple\",\n" +" \"stream\": \"ext://sys.stdout\",\n" +" \"filters\": [\"warnings_and_below\"]\n" +" },\n" +" \"stderr\": {\n" +" \"class\": \"logging.StreamHandler\",\n" +" \"level\": \"ERROR\",\n" +" \"formatter\": \"simple\",\n" +" \"stream\": \"ext://sys.stderr\"\n" +" },\n" +" \"file\": {\n" +" \"class\": \"logging.FileHandler\",\n" +" \"formatter\": \"simple\",\n" +" \"filename\": \"app.log\",\n" +" \"mode\": \"w\"\n" +" }\n" +" },\n" +" \"root\": {\n" +" \"level\": \"DEBUG\",\n" +" \"handlers\": [\n" +" \"stderr\",\n" +" \"stdout\",\n" +" \"file\"\n" +" ]\n" +" }\n" +"}\n" +"'''\n" +"\n" +"def filter_maker(level):\n" +" level = getattr(logging, level)\n" +"\n" +" def filter(record):\n" +" return record.levelno <= level\n" +"\n" +" return filter\n" +"\n" +"logging.config.dictConfig(json.loads(CONFIG))\n" +"logging.debug('A DEBUG message')\n" +"logging.info('An INFO message')\n" +"logging.warning('A WARNING message')\n" +"logging.error('An ERROR message')\n" +"logging.critical('A CRITICAL message')" +msgstr "" + #: ../../howto/logging-cookbook.rst:457 msgid "And after running it like this:" msgstr "" +#: ../../howto/logging-cookbook.rst:459 +msgid "python main.py 2>stderr.log >stdout.log" +msgstr "" + #: ../../howto/logging-cookbook.rst:463 msgid "We can see the results are as expected:" msgstr "" +#: ../../howto/logging-cookbook.rst:465 +msgid "" +"$ more *.log\n" +"::::::::::::::\n" +"app.log\n" +"::::::::::::::\n" +"DEBUG - A DEBUG message\n" +"INFO - An INFO message\n" +"WARNING - A WARNING message\n" +"ERROR - An ERROR message\n" +"CRITICAL - A CRITICAL message\n" +"::::::::::::::\n" +"stderr.log\n" +"::::::::::::::\n" +"ERROR - An ERROR message\n" +"CRITICAL - A CRITICAL message\n" +"::::::::::::::\n" +"stdout.log\n" +"::::::::::::::\n" +"INFO - An INFO message\n" +"WARNING - A WARNING message" +msgstr "" + #: ../../howto/logging-cookbook.rst:489 msgid "Configuration server example" msgstr "" @@ -236,6 +624,38 @@ msgstr "" msgid "Here is an example of a module using the logging configuration server::" msgstr "" +#: ../../howto/logging-cookbook.rst:493 +msgid "" +"import logging\n" +"import logging.config\n" +"import time\n" +"import os\n" +"\n" +"# read initial config file\n" +"logging.config.fileConfig('logging.conf')\n" +"\n" +"# create and start listener on port 9999\n" +"t = logging.config.listen(9999)\n" +"t.start()\n" +"\n" +"logger = logging.getLogger('simpleExample')\n" +"\n" +"try:\n" +" # loop through logging calls to see the difference\n" +" # new configurations make, until Ctrl+C is pressed\n" +" while True:\n" +" logger.debug('debug message')\n" +" logger.info('info message')\n" +" logger.warning('warn message')\n" +" logger.error('error message')\n" +" logger.critical('critical message')\n" +" time.sleep(5)\n" +"except KeyboardInterrupt:\n" +" # cleanup\n" +" logging.config.stopListening()\n" +" t.join()" +msgstr "" + #: ../../howto/logging-cookbook.rst:522 msgid "" "And here is a script that takes a filename and sends that file to the " @@ -243,6 +663,26 @@ msgid "" "configuration::" msgstr "" +#: ../../howto/logging-cookbook.rst:526 +msgid "" +"#!/usr/bin/env python\n" +"import socket, sys, struct\n" +"\n" +"with open(sys.argv[1], 'rb') as f:\n" +" data_to_send = f.read()\n" +"\n" +"HOST = 'localhost'\n" +"PORT = 9999\n" +"s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n" +"print('connecting...')\n" +"s.connect((HOST, PORT))\n" +"print('sending config...')\n" +"s.send(struct.pack('>L', len(data_to_send)))\n" +"s.send(data_to_send)\n" +"s.close()\n" +"print('complete')" +msgstr "" + #: ../../howto/logging-cookbook.rst:547 msgid "Dealing with handlers that block" msgstr "" @@ -303,10 +743,33 @@ msgstr "" msgid "An example of using these two classes follows (imports omitted)::" msgstr "" +#: ../../howto/logging-cookbook.rst:589 +msgid "" +"que = queue.Queue(-1) # no limit on size\n" +"queue_handler = QueueHandler(que)\n" +"handler = logging.StreamHandler()\n" +"listener = QueueListener(que, handler)\n" +"root = logging.getLogger()\n" +"root.addHandler(queue_handler)\n" +"formatter = logging.Formatter('%(threadName)s: %(message)s')\n" +"handler.setFormatter(formatter)\n" +"listener.start()\n" +"# The log output will display the thread which generated\n" +"# the event (the main thread) rather than the internal\n" +"# thread which monitors the internal queue. This is what\n" +"# you want to happen.\n" +"root.warning('Look out!')\n" +"listener.stop()" +msgstr "" + #: ../../howto/logging-cookbook.rst:605 msgid "which, when run, will produce:" msgstr "" +#: ../../howto/logging-cookbook.rst:607 +msgid "MainThread: Look out!" +msgstr "" + #: ../../howto/logging-cookbook.rst:611 msgid "" "Although the earlier discussion wasn't specifically talking about async " @@ -341,18 +804,147 @@ msgid "" "`SocketHandler` instance to the root logger at the sending end::" msgstr "" +#: ../../howto/logging-cookbook.rst:638 +msgid "" +"import logging, logging.handlers\n" +"\n" +"rootLogger = logging.getLogger('')\n" +"rootLogger.setLevel(logging.DEBUG)\n" +"socketHandler = logging.handlers.SocketHandler('localhost',\n" +" logging.handlers.DEFAULT_TCP_LOGGING_PORT)\n" +"# don't bother with a formatter, since a socket handler sends the event as\n" +"# an unformatted pickle\n" +"rootLogger.addHandler(socketHandler)\n" +"\n" +"# Now, we can log to the root logger, or any other logger. First the " +"root...\n" +"logging.info('Jackdaws love my big sphinx of quartz.')\n" +"\n" +"# Now, define a couple of other loggers which might represent areas in your\n" +"# application:\n" +"\n" +"logger1 = logging.getLogger('myapp.area1')\n" +"logger2 = logging.getLogger('myapp.area2')\n" +"\n" +"logger1.debug('Quick zephyrs blow, vexing daft Jim.')\n" +"logger1.info('How quickly daft jumping zebras vex.')\n" +"logger2.warning('Jail zesty vixen who grabbed pay from quack.')\n" +"logger2.error('The five boxing wizards jump quickly.')" +msgstr "" + #: ../../howto/logging-cookbook.rst:662 msgid "" "At the receiving end, you can set up a receiver using the :mod:" "`socketserver` module. Here is a basic working example::" msgstr "" +#: ../../howto/logging-cookbook.rst:665 +msgid "" +"import pickle\n" +"import logging\n" +"import logging.handlers\n" +"import socketserver\n" +"import struct\n" +"\n" +"\n" +"class LogRecordStreamHandler(socketserver.StreamRequestHandler):\n" +" \"\"\"Handler for a streaming logging request.\n" +"\n" +" This basically logs the record using whatever logging policy is\n" +" configured locally.\n" +" \"\"\"\n" +"\n" +" def handle(self):\n" +" \"\"\"\n" +" Handle multiple requests - each expected to be a 4-byte length,\n" +" followed by the LogRecord in pickle format. Logs the record\n" +" according to whatever policy is configured locally.\n" +" \"\"\"\n" +" while True:\n" +" chunk = self.connection.recv(4)\n" +" if len(chunk) < 4:\n" +" break\n" +" slen = struct.unpack('>L', chunk)[0]\n" +" chunk = self.connection.recv(slen)\n" +" while len(chunk) < slen:\n" +" chunk = chunk + self.connection.recv(slen - len(chunk))\n" +" obj = self.unPickle(chunk)\n" +" record = logging.makeLogRecord(obj)\n" +" self.handleLogRecord(record)\n" +"\n" +" def unPickle(self, data):\n" +" return pickle.loads(data)\n" +"\n" +" def handleLogRecord(self, record):\n" +" # if a name is specified, we use the named logger rather than the " +"one\n" +" # implied by the record.\n" +" if self.server.logname is not None:\n" +" name = self.server.logname\n" +" else:\n" +" name = record.name\n" +" logger = logging.getLogger(name)\n" +" # N.B. EVERY record gets logged. This is because Logger.handle\n" +" # is normally called AFTER logger-level filtering. If you want\n" +" # to do filtering, do it at the client end to save wasting\n" +" # cycles and network bandwidth!\n" +" logger.handle(record)\n" +"\n" +"class LogRecordSocketReceiver(socketserver.ThreadingTCPServer):\n" +" \"\"\"\n" +" Simple TCP socket-based logging receiver suitable for testing.\n" +" \"\"\"\n" +"\n" +" allow_reuse_address = True\n" +"\n" +" def __init__(self, host='localhost',\n" +" port=logging.handlers.DEFAULT_TCP_LOGGING_PORT,\n" +" handler=LogRecordStreamHandler):\n" +" socketserver.ThreadingTCPServer.__init__(self, (host, port), " +"handler)\n" +" self.abort = 0\n" +" self.timeout = 1\n" +" self.logname = None\n" +"\n" +" def serve_until_stopped(self):\n" +" import select\n" +" abort = 0\n" +" while not abort:\n" +" rd, wr, ex = select.select([self.socket.fileno()],\n" +" [], [],\n" +" self.timeout)\n" +" if rd:\n" +" self.handle_request()\n" +" abort = self.abort\n" +"\n" +"def main():\n" +" logging.basicConfig(\n" +" format='%(relativeCreated)5d %(name)-15s %(levelname)-8s " +"%(message)s')\n" +" tcpserver = LogRecordSocketReceiver()\n" +" print('About to start TCP server...')\n" +" tcpserver.serve_until_stopped()\n" +"\n" +"if __name__ == '__main__':\n" +" main()" +msgstr "" + #: ../../howto/logging-cookbook.rst:750 msgid "" "First run the server, and then the client. On the client side, nothing is " "printed on the console; on the server side, you should see something like:" msgstr "" +#: ../../howto/logging-cookbook.rst:753 +msgid "" +"About to start TCP server...\n" +" 59 root INFO Jackdaws love my big sphinx of quartz.\n" +" 59 myapp.area1 DEBUG Quick zephyrs blow, vexing daft Jim.\n" +" 69 myapp.area1 INFO How quickly daft jumping zebras vex.\n" +" 69 myapp.area2 WARNING Jail zesty vixen who grabbed pay from quack.\n" +" 69 myapp.area2 ERROR The five boxing wizards jump quickly." +msgstr "" + #: ../../howto/logging-cookbook.rst:762 msgid "" "Note that there are some security issues with pickle in some scenarios. If " @@ -555,6 +1147,17 @@ msgid "" "of :class:`LoggerAdapter`::" msgstr "" +#: ../../howto/logging-cookbook.rst:878 +msgid "" +"def debug(self, msg, /, *args, **kwargs):\n" +" \"\"\"\n" +" Delegate a debug call to the underlying logger, after adding\n" +" contextual information from this adapter instance.\n" +" \"\"\"\n" +" msg, kwargs = self.process(msg, kwargs)\n" +" self.logger.debug(msg, *args, **kwargs)" +msgstr "" + #: ../../howto/logging-cookbook.rst:886 msgid "" "The :meth:`~LoggerAdapter.process` method of :class:`LoggerAdapter` is where " @@ -579,10 +1182,27 @@ msgid "" "`~LoggerAdapter.process` to do what you need. Here is a simple example::" msgstr "" +#: ../../howto/logging-cookbook.rst:903 +msgid "" +"class CustomAdapter(logging.LoggerAdapter):\n" +" \"\"\"\n" +" This example adapter expects the passed in dict-like object to have a\n" +" 'connid' key, whose value in brackets is prepended to the log message.\n" +" \"\"\"\n" +" def process(self, msg, kwargs):\n" +" return '[%s] %s' % (self.extra['connid'], msg), kwargs" +msgstr "" + #: ../../howto/logging-cookbook.rst:911 msgid "which you can use like this::" msgstr "" +#: ../../howto/logging-cookbook.rst:913 +msgid "" +"logger = logging.getLogger(__name__)\n" +"adapter = CustomAdapter(logger, {'connid': some_conn_id})" +msgstr "" + #: ../../howto/logging-cookbook.rst:916 msgid "" "Then any events that you log to the adapter will have the value of " @@ -627,10 +1247,81 @@ msgid "" "an example script::" msgstr "" +#: ../../howto/logging-cookbook.rst:947 +msgid "" +"import logging\n" +"from random import choice\n" +"\n" +"class ContextFilter(logging.Filter):\n" +" \"\"\"\n" +" This is a filter which injects contextual information into the log.\n" +"\n" +" Rather than use actual contextual information, we just use random\n" +" data in this demo.\n" +" \"\"\"\n" +"\n" +" USERS = ['jim', 'fred', 'sheila']\n" +" IPS = ['123.231.231.123', '127.0.0.1', '192.168.0.1']\n" +"\n" +" def filter(self, record):\n" +"\n" +" record.ip = choice(ContextFilter.IPS)\n" +" record.user = choice(ContextFilter.USERS)\n" +" return True\n" +"\n" +"if __name__ == '__main__':\n" +" levels = (logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, " +"logging.CRITICAL)\n" +" logging.basicConfig(level=logging.DEBUG,\n" +" format='%(asctime)-15s %(name)-5s %(levelname)-8s " +"IP: %(ip)-15s User: %(user)-8s %(message)s')\n" +" a1 = logging.getLogger('a.b.c')\n" +" a2 = logging.getLogger('d.e.f')\n" +"\n" +" f = ContextFilter()\n" +" a1.addFilter(f)\n" +" a2.addFilter(f)\n" +" a1.debug('A debug message')\n" +" a1.info('An info message with %s', 'some parameters')\n" +" for x in range(10):\n" +" lvl = choice(levels)\n" +" lvlname = logging.getLevelName(lvl)\n" +" a2.log(lvl, 'A message at %s level with %d %s', lvlname, 2, " +"'parameters')" +msgstr "" + #: ../../howto/logging-cookbook.rst:984 msgid "which, when run, produces something like:" msgstr "" +#: ../../howto/logging-cookbook.rst:986 +msgid "" +"2010-09-06 22:38:15,292 a.b.c DEBUG IP: 123.231.231.123 User: fred A " +"debug message\n" +"2010-09-06 22:38:15,300 a.b.c INFO IP: 192.168.0.1 User: sheila An " +"info message with some parameters\n" +"2010-09-06 22:38:15,300 d.e.f CRITICAL IP: 127.0.0.1 User: sheila A " +"message at CRITICAL level with 2 parameters\n" +"2010-09-06 22:38:15,300 d.e.f ERROR IP: 127.0.0.1 User: jim A " +"message at ERROR level with 2 parameters\n" +"2010-09-06 22:38:15,300 d.e.f DEBUG IP: 127.0.0.1 User: sheila A " +"message at DEBUG level with 2 parameters\n" +"2010-09-06 22:38:15,300 d.e.f ERROR IP: 123.231.231.123 User: fred A " +"message at ERROR level with 2 parameters\n" +"2010-09-06 22:38:15,300 d.e.f CRITICAL IP: 192.168.0.1 User: jim A " +"message at CRITICAL level with 2 parameters\n" +"2010-09-06 22:38:15,300 d.e.f CRITICAL IP: 127.0.0.1 User: sheila A " +"message at CRITICAL level with 2 parameters\n" +"2010-09-06 22:38:15,300 d.e.f DEBUG IP: 192.168.0.1 User: jim A " +"message at DEBUG level with 2 parameters\n" +"2010-09-06 22:38:15,301 d.e.f ERROR IP: 127.0.0.1 User: sheila A " +"message at ERROR level with 2 parameters\n" +"2010-09-06 22:38:15,301 d.e.f DEBUG IP: 123.231.231.123 User: fred A " +"message at DEBUG level with 2 parameters\n" +"2010-09-06 22:38:15,301 d.e.f INFO IP: 123.231.231.123 User: fred A " +"message at INFO level with 2 parameters" +msgstr "" + #: ../../howto/logging-cookbook.rst:1002 msgid "Use of ``contextvars``" msgstr "" @@ -660,6 +1351,21 @@ msgstr "" msgid "Let's assume that the library can be simulated by the following code:" msgstr "" +#: ../../howto/logging-cookbook.rst:1019 +msgid "" +"# webapplib.py\n" +"import logging\n" +"import time\n" +"\n" +"logger = logging.getLogger(__name__)\n" +"\n" +"def useful():\n" +" # Just a representative event logged from the library\n" +" logger.debug('Hello from webapplib!')\n" +" # Just sleep for a bit so other threads get to run\n" +" time.sleep(0.01)" +msgstr "" + #: ../../howto/logging-cookbook.rst:1033 msgid "" "We can simulate the multiple web applications by means of two simple " @@ -667,6 +1373,161 @@ msgid "" "applications work - each request is handled by a thread:" msgstr "" +#: ../../howto/logging-cookbook.rst:1037 +msgid "" +"# main.py\n" +"import argparse\n" +"from contextvars import ContextVar\n" +"import logging\n" +"import os\n" +"from random import choice\n" +"import threading\n" +"import webapplib\n" +"\n" +"logger = logging.getLogger(__name__)\n" +"root = logging.getLogger()\n" +"root.setLevel(logging.DEBUG)\n" +"\n" +"class Request:\n" +" \"\"\"\n" +" A simple dummy request class which just holds dummy HTTP request " +"method,\n" +" client IP address and client username\n" +" \"\"\"\n" +" def __init__(self, method, ip, user):\n" +" self.method = method\n" +" self.ip = ip\n" +" self.user = user\n" +"\n" +"# A dummy set of requests which will be used in the simulation - we'll just " +"pick\n" +"# from this list randomly. Note that all GET requests are from 192.168.2." +"XXX\n" +"# addresses, whereas POST requests are from 192.16.3.XXX addresses. Three " +"users\n" +"# are represented in the sample requests.\n" +"\n" +"REQUESTS = [\n" +" Request('GET', '192.168.2.20', 'jim'),\n" +" Request('POST', '192.168.3.20', 'fred'),\n" +" Request('GET', '192.168.2.21', 'sheila'),\n" +" Request('POST', '192.168.3.21', 'jim'),\n" +" Request('GET', '192.168.2.22', 'fred'),\n" +" Request('POST', '192.168.3.22', 'sheila'),\n" +"]\n" +"\n" +"# Note that the format string includes references to request context " +"information\n" +"# such as HTTP method, client IP and username\n" +"\n" +"formatter = logging.Formatter('%(threadName)-11s %(appName)s %(name)-9s " +"%(user)-6s %(ip)s %(method)-4s %(message)s')\n" +"\n" +"# Create our context variables. These will be filled at the start of " +"request\n" +"# processing, and used in the logging that happens during that processing\n" +"\n" +"ctx_request = ContextVar('request')\n" +"ctx_appname = ContextVar('appname')\n" +"\n" +"class InjectingFilter(logging.Filter):\n" +" \"\"\"\n" +" A filter which injects context-specific information into logs and " +"ensures\n" +" that only information for a specific webapp is included in its log\n" +" \"\"\"\n" +" def __init__(self, app):\n" +" self.app = app\n" +"\n" +" def filter(self, record):\n" +" request = ctx_request.get()\n" +" record.method = request.method\n" +" record.ip = request.ip\n" +" record.user = request.user\n" +" record.appName = appName = ctx_appname.get()\n" +" return appName == self.app.name\n" +"\n" +"class WebApp:\n" +" \"\"\"\n" +" A dummy web application class which has its own handler and filter for " +"a\n" +" webapp-specific log.\n" +" \"\"\"\n" +" def __init__(self, name):\n" +" self.name = name\n" +" handler = logging.FileHandler(name + '.log', 'w')\n" +" f = InjectingFilter(self)\n" +" handler.setFormatter(formatter)\n" +" handler.addFilter(f)\n" +" root.addHandler(handler)\n" +" self.num_requests = 0\n" +"\n" +" def process_request(self, request):\n" +" \"\"\"\n" +" This is the dummy method for processing a request. It's called on a\n" +" different thread for every request. We store the context information " +"into\n" +" the context vars before doing anything else.\n" +" \"\"\"\n" +" ctx_request.set(request)\n" +" ctx_appname.set(self.name)\n" +" self.num_requests += 1\n" +" logger.debug('Request processing started')\n" +" webapplib.useful()\n" +" logger.debug('Request processing finished')\n" +"\n" +"def main():\n" +" fn = os.path.splitext(os.path.basename(__file__))[0]\n" +" adhf = argparse.ArgumentDefaultsHelpFormatter\n" +" ap = argparse.ArgumentParser(formatter_class=adhf, prog=fn,\n" +" description='Simulate a couple of web '\n" +" 'applications handling some '\n" +" 'requests, showing how request " +"'\n" +" 'context can be used to '\n" +" 'populate logs')\n" +" aa = ap.add_argument\n" +" aa('--count', '-c', type=int, default=100, help='How many requests to " +"simulate')\n" +" options = ap.parse_args()\n" +"\n" +" # Create the dummy webapps and put them in a list which we can use to " +"select\n" +" # from randomly\n" +" app1 = WebApp('app1')\n" +" app2 = WebApp('app2')\n" +" apps = [app1, app2]\n" +" threads = []\n" +" # Add a common handler which will capture all events\n" +" handler = logging.FileHandler('app.log', 'w')\n" +" handler.setFormatter(formatter)\n" +" root.addHandler(handler)\n" +"\n" +" # Generate calls to process requests\n" +" for i in range(options.count):\n" +" try:\n" +" # Pick an app at random and a request for it to process\n" +" app = choice(apps)\n" +" request = choice(REQUESTS)\n" +" # Process the request in its own thread\n" +" t = threading.Thread(target=app.process_request, " +"args=(request,))\n" +" threads.append(t)\n" +" t.start()\n" +" except KeyboardInterrupt:\n" +" break\n" +"\n" +" # Wait for the threads to terminate\n" +" for t in threads:\n" +" t.join()\n" +"\n" +" for app in apps:\n" +" print('%s processed %s requests' % (app.name, app.num_requests))\n" +"\n" +"if __name__ == '__main__':\n" +" main()" +msgstr "" + #: ../../howto/logging-cookbook.rst:1177 msgid "" "If you run the above, you should find that roughly half the requests go " @@ -678,6 +1539,61 @@ msgid "" "illustrated by the following shell output:" msgstr "" +#: ../../howto/logging-cookbook.rst:1184 +msgid "" +"~/logging-contextual-webapp$ python main.py\n" +"app1 processed 51 requests\n" +"app2 processed 49 requests\n" +"~/logging-contextual-webapp$ wc -l *.log\n" +" 153 app1.log\n" +" 147 app2.log\n" +" 300 app.log\n" +" 600 total\n" +"~/logging-contextual-webapp$ head -3 app1.log\n" +"Thread-3 (process_request) app1 __main__ jim 192.168.3.21 POST Request " +"processing started\n" +"Thread-3 (process_request) app1 webapplib jim 192.168.3.21 POST Hello " +"from webapplib!\n" +"Thread-5 (process_request) app1 __main__ jim 192.168.3.21 POST Request " +"processing started\n" +"~/logging-contextual-webapp$ head -3 app2.log\n" +"Thread-1 (process_request) app2 __main__ sheila 192.168.2.21 GET Request " +"processing started\n" +"Thread-1 (process_request) app2 webapplib sheila 192.168.2.21 GET Hello " +"from webapplib!\n" +"Thread-2 (process_request) app2 __main__ jim 192.168.2.20 GET Request " +"processing started\n" +"~/logging-contextual-webapp$ head app.log\n" +"Thread-1 (process_request) app2 __main__ sheila 192.168.2.21 GET Request " +"processing started\n" +"Thread-1 (process_request) app2 webapplib sheila 192.168.2.21 GET Hello " +"from webapplib!\n" +"Thread-2 (process_request) app2 __main__ jim 192.168.2.20 GET Request " +"processing started\n" +"Thread-3 (process_request) app1 __main__ jim 192.168.3.21 POST Request " +"processing started\n" +"Thread-2 (process_request) app2 webapplib jim 192.168.2.20 GET Hello " +"from webapplib!\n" +"Thread-3 (process_request) app1 webapplib jim 192.168.3.21 POST Hello " +"from webapplib!\n" +"Thread-4 (process_request) app2 __main__ fred 192.168.2.22 GET Request " +"processing started\n" +"Thread-5 (process_request) app1 __main__ jim 192.168.3.21 POST Request " +"processing started\n" +"Thread-4 (process_request) app2 webapplib fred 192.168.2.22 GET Hello " +"from webapplib!\n" +"Thread-6 (process_request) app1 __main__ jim 192.168.3.21 POST Request " +"processing started\n" +"~/logging-contextual-webapp$ grep app1 app1.log | wc -l\n" +"153\n" +"~/logging-contextual-webapp$ grep app2 app2.log | wc -l\n" +"147\n" +"~/logging-contextual-webapp$ grep app1 app.log | wc -l\n" +"153\n" +"~/logging-contextual-webapp$ grep app2 app.log | wc -l\n" +"147" +msgstr "" + #: ../../howto/logging-cookbook.rst:1224 msgid "Imparting contextual information in handlers" msgstr "" @@ -690,6 +1606,28 @@ msgid "" "instead of modifying it in-place, as shown in the following script::" msgstr "" +#: ../../howto/logging-cookbook.rst:1231 +msgid "" +"import copy\n" +"import logging\n" +"\n" +"def filter(record: logging.LogRecord):\n" +" record = copy.copy(record)\n" +" record.user = 'jim'\n" +" return record\n" +"\n" +"if __name__ == '__main__':\n" +" logger = logging.getLogger()\n" +" logger.setLevel(logging.INFO)\n" +" handler = logging.StreamHandler()\n" +" formatter = logging.Formatter('%(message)s from %(user)-8s')\n" +" handler.setFormatter(formatter)\n" +" handler.addFilter(filter)\n" +" logger.addHandler(handler)\n" +"\n" +" logger.info('A log message')" +msgstr "" + #: ../../howto/logging-cookbook.rst:1253 msgid "Logging to a single file from multiple processes" msgstr "" @@ -736,12 +1674,229 @@ msgid "" "requirements::" msgstr "" +#: ../../howto/logging-cookbook.rst:1289 +msgid "" +"# You'll need these imports in your own code\n" +"import logging\n" +"import logging.handlers\n" +"import multiprocessing\n" +"\n" +"# Next two import lines for this demo only\n" +"from random import choice, random\n" +"import time\n" +"\n" +"#\n" +"# Because you'll want to define the logging configurations for listener and " +"workers, the\n" +"# listener and worker process functions take a configurer parameter which is " +"a callable\n" +"# for configuring logging for that process. These functions are also passed " +"the queue,\n" +"# which they use for communication.\n" +"#\n" +"# In practice, you can configure the listener however you want, but note " +"that in this\n" +"# simple example, the listener does not apply level or filter logic to " +"received records.\n" +"# In practice, you would probably want to do this logic in the worker " +"processes, to avoid\n" +"# sending events which would be filtered out between processes.\n" +"#\n" +"# The size of the rotated files is made small so you can see the results " +"easily.\n" +"def listener_configurer():\n" +" root = logging.getLogger()\n" +" h = logging.handlers.RotatingFileHandler('mptest.log', 'a', 300, 10)\n" +" f = logging.Formatter('%(asctime)s %(processName)-10s %(name)s " +"%(levelname)-8s %(message)s')\n" +" h.setFormatter(f)\n" +" root.addHandler(h)\n" +"\n" +"# This is the listener process top-level loop: wait for logging events\n" +"# (LogRecords)on the queue and handle them, quit when you get a None for a\n" +"# LogRecord.\n" +"def listener_process(queue, configurer):\n" +" configurer()\n" +" while True:\n" +" try:\n" +" record = queue.get()\n" +" if record is None: # We send this as a sentinel to tell the " +"listener to quit.\n" +" break\n" +" logger = logging.getLogger(record.name)\n" +" logger.handle(record) # No level or filter logic applied - just " +"do it!\n" +" except Exception:\n" +" import sys, traceback\n" +" print('Whoops! Problem:', file=sys.stderr)\n" +" traceback.print_exc(file=sys.stderr)\n" +"\n" +"# Arrays used for random selections in this demo\n" +"\n" +"LEVELS = [logging.DEBUG, logging.INFO, logging.WARNING,\n" +" logging.ERROR, logging.CRITICAL]\n" +"\n" +"LOGGERS = ['a.b.c', 'd.e.f']\n" +"\n" +"MESSAGES = [\n" +" 'Random message #1',\n" +" 'Random message #2',\n" +" 'Random message #3',\n" +"]\n" +"\n" +"# The worker configuration is done at the start of the worker process run.\n" +"# Note that on Windows you can't rely on fork semantics, so each process\n" +"# will run the logging configuration code when it starts.\n" +"def worker_configurer(queue):\n" +" h = logging.handlers.QueueHandler(queue) # Just the one handler needed\n" +" root = logging.getLogger()\n" +" root.addHandler(h)\n" +" # send all messages, for demo; no other level or filter logic applied.\n" +" root.setLevel(logging.DEBUG)\n" +"\n" +"# This is the worker process top-level loop, which just logs ten events " +"with\n" +"# random intervening delays before terminating.\n" +"# The print messages are just so you know it's doing something!\n" +"def worker_process(queue, configurer):\n" +" configurer(queue)\n" +" name = multiprocessing.current_process().name\n" +" print('Worker started: %s' % name)\n" +" for i in range(10):\n" +" time.sleep(random())\n" +" logger = logging.getLogger(choice(LOGGERS))\n" +" level = choice(LEVELS)\n" +" message = choice(MESSAGES)\n" +" logger.log(level, message)\n" +" print('Worker finished: %s' % name)\n" +"\n" +"# Here's where the demo gets orchestrated. Create the queue, create and " +"start\n" +"# the listener, create ten workers and start them, wait for them to finish,\n" +"# then send a None to the queue to tell the listener to finish.\n" +"def main():\n" +" queue = multiprocessing.Queue(-1)\n" +" listener = multiprocessing.Process(target=listener_process,\n" +" args=(queue, listener_configurer))\n" +" listener.start()\n" +" workers = []\n" +" for i in range(10):\n" +" worker = multiprocessing.Process(target=worker_process,\n" +" args=(queue, worker_configurer))\n" +" workers.append(worker)\n" +" worker.start()\n" +" for w in workers:\n" +" w.join()\n" +" queue.put_nowait(None)\n" +" listener.join()\n" +"\n" +"if __name__ == '__main__':\n" +" main()" +msgstr "" + #: ../../howto/logging-cookbook.rst:1394 msgid "" "A variant of the above script keeps the logging in the main process, in a " "separate thread::" msgstr "" +#: ../../howto/logging-cookbook.rst:1397 +msgid "" +"import logging\n" +"import logging.config\n" +"import logging.handlers\n" +"from multiprocessing import Process, Queue\n" +"import random\n" +"import threading\n" +"import time\n" +"\n" +"def logger_thread(q):\n" +" while True:\n" +" record = q.get()\n" +" if record is None:\n" +" break\n" +" logger = logging.getLogger(record.name)\n" +" logger.handle(record)\n" +"\n" +"\n" +"def worker_process(q):\n" +" qh = logging.handlers.QueueHandler(q)\n" +" root = logging.getLogger()\n" +" root.setLevel(logging.DEBUG)\n" +" root.addHandler(qh)\n" +" levels = [logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR,\n" +" logging.CRITICAL]\n" +" loggers = ['foo', 'foo.bar', 'foo.bar.baz',\n" +" 'spam', 'spam.ham', 'spam.ham.eggs']\n" +" for i in range(100):\n" +" lvl = random.choice(levels)\n" +" logger = logging.getLogger(random.choice(loggers))\n" +" logger.log(lvl, 'Message no. %d', i)\n" +"\n" +"if __name__ == '__main__':\n" +" q = Queue()\n" +" d = {\n" +" 'version': 1,\n" +" 'formatters': {\n" +" 'detailed': {\n" +" 'class': 'logging.Formatter',\n" +" 'format': '%(asctime)s %(name)-15s %(levelname)-8s " +"%(processName)-10s %(message)s'\n" +" }\n" +" },\n" +" 'handlers': {\n" +" 'console': {\n" +" 'class': 'logging.StreamHandler',\n" +" 'level': 'INFO',\n" +" },\n" +" 'file': {\n" +" 'class': 'logging.FileHandler',\n" +" 'filename': 'mplog.log',\n" +" 'mode': 'w',\n" +" 'formatter': 'detailed',\n" +" },\n" +" 'foofile': {\n" +" 'class': 'logging.FileHandler',\n" +" 'filename': 'mplog-foo.log',\n" +" 'mode': 'w',\n" +" 'formatter': 'detailed',\n" +" },\n" +" 'errors': {\n" +" 'class': 'logging.FileHandler',\n" +" 'filename': 'mplog-errors.log',\n" +" 'mode': 'w',\n" +" 'level': 'ERROR',\n" +" 'formatter': 'detailed',\n" +" },\n" +" },\n" +" 'loggers': {\n" +" 'foo': {\n" +" 'handlers': ['foofile']\n" +" }\n" +" },\n" +" 'root': {\n" +" 'level': 'DEBUG',\n" +" 'handlers': ['console', 'file', 'errors']\n" +" },\n" +" }\n" +" workers = []\n" +" for i in range(5):\n" +" wp = Process(target=worker_process, name='worker %d' % (i + 1), " +"args=(q,))\n" +" workers.append(wp)\n" +" wp.start()\n" +" logging.config.dictConfig(d)\n" +" lp = threading.Thread(target=logger_thread, args=(q,))\n" +" lp.start()\n" +" # At this point, the main process could do some useful work of its own\n" +" # Once it's done that, it can wait for the workers to terminate...\n" +" for wp in workers:\n" +" wp.join()\n" +" # And now tell the logging thread to finish up, too\n" +" q.put(None)\n" +" lp.join()" +msgstr "" + #: ../../howto/logging-cookbook.rst:1489 msgid "" "This variant shows how you can e.g. apply configuration for particular " @@ -763,18 +1918,47 @@ msgid "" "Instead of" msgstr "" +#: ../../howto/logging-cookbook.rst:1502 +msgid "queue = multiprocessing.Queue(-1)" +msgstr "" + #: ../../howto/logging-cookbook.rst:1506 msgid "you should use" msgstr "" +#: ../../howto/logging-cookbook.rst:1508 +msgid "" +"queue = multiprocessing.Manager().Queue(-1) # also works with the examples " +"above" +msgstr "" + #: ../../howto/logging-cookbook.rst:1512 msgid "and you can then replace the worker creation from this::" msgstr "" +#: ../../howto/logging-cookbook.rst:1514 +msgid "" +"workers = []\n" +"for i in range(10):\n" +" worker = multiprocessing.Process(target=worker_process,\n" +" args=(queue, worker_configurer))\n" +" workers.append(worker)\n" +" worker.start()\n" +"for w in workers:\n" +" w.join()" +msgstr "" + #: ../../howto/logging-cookbook.rst:1523 msgid "to this (remembering to first import :mod:`concurrent.futures`)::" msgstr "" +#: ../../howto/logging-cookbook.rst:1525 +msgid "" +"with concurrent.futures.ProcessPoolExecutor(max_workers=10) as executor:\n" +" for i in range(10):\n" +" executor.submit(worker_process, queue, worker_configurer)" +msgstr "" + #: ../../howto/logging-cookbook.rst:1530 msgid "Deploying Web applications using Gunicorn and uWSGI" msgstr "" @@ -804,12 +1988,51 @@ msgid "" "usage pattern, the logging package provides a :class:`RotatingFileHandler`::" msgstr "" +#: ../../howto/logging-cookbook.rst:1553 +msgid "" +"import glob\n" +"import logging\n" +"import logging.handlers\n" +"\n" +"LOG_FILENAME = 'logging_rotatingfile_example.out'\n" +"\n" +"# Set up a specific logger with our desired output level\n" +"my_logger = logging.getLogger('MyLogger')\n" +"my_logger.setLevel(logging.DEBUG)\n" +"\n" +"# Add the log message handler to the logger\n" +"handler = logging.handlers.RotatingFileHandler(\n" +" LOG_FILENAME, maxBytes=20, backupCount=5)\n" +"\n" +"my_logger.addHandler(handler)\n" +"\n" +"# Log some messages\n" +"for i in range(20):\n" +" my_logger.debug('i = %d' % i)\n" +"\n" +"# See what files are created\n" +"logfiles = glob.glob('%s*' % LOG_FILENAME)\n" +"\n" +"for filename in logfiles:\n" +" print(filename)" +msgstr "" + #: ../../howto/logging-cookbook.rst:1579 msgid "" "The result should be 6 separate files, each with part of the log history for " "the application:" msgstr "" +#: ../../howto/logging-cookbook.rst:1582 +msgid "" +"logging_rotatingfile_example.out\n" +"logging_rotatingfile_example.out.1\n" +"logging_rotatingfile_example.out.2\n" +"logging_rotatingfile_example.out.3\n" +"logging_rotatingfile_example.out.4\n" +"logging_rotatingfile_example.out.5" +msgstr "" + #: ../../howto/logging-cookbook.rst:1591 msgid "" "The most current file is always :file:`logging_rotatingfile_example.out`, " @@ -850,6 +2073,31 @@ msgid "" "session to show the possibilities:" msgstr "" +#: ../../howto/logging-cookbook.rst:1622 +msgid "" +">>> import logging\n" +">>> root = logging.getLogger()\n" +">>> root.setLevel(logging.DEBUG)\n" +">>> handler = logging.StreamHandler()\n" +">>> bf = logging.Formatter('{asctime} {name} {levelname:8s} {message}',\n" +"... style='{')\n" +">>> handler.setFormatter(bf)\n" +">>> root.addHandler(handler)\n" +">>> logger = logging.getLogger('foo.bar')\n" +">>> logger.debug('This is a DEBUG message')\n" +"2010-10-28 15:11:55,341 foo.bar DEBUG This is a DEBUG message\n" +">>> logger.critical('This is a CRITICAL message')\n" +"2010-10-28 15:12:11,526 foo.bar CRITICAL This is a CRITICAL message\n" +">>> df = logging.Formatter('$asctime $name ${levelname} $message',\n" +"... style='$')\n" +">>> handler.setFormatter(df)\n" +">>> logger.debug('This is a DEBUG message')\n" +"2010-10-28 15:13:06,924 foo.bar DEBUG This is a DEBUG message\n" +">>> logger.critical('This is a CRITICAL message')\n" +"2010-10-28 15:13:11,494 foo.bar CRITICAL This is a CRITICAL message\n" +">>>" +msgstr "" + #: ../../howto/logging-cookbook.rst:1646 msgid "" "Note that the formatting of logging messages for final output to logs is " @@ -857,6 +2105,13 @@ msgid "" "That can still use %-formatting, as shown here::" msgstr "" +#: ../../howto/logging-cookbook.rst:1650 +msgid "" +">>> logger.error('This is an%s %s %s', 'other,', 'ERROR,', 'message')\n" +"2010-10-28 15:19:29,833 foo.bar ERROR This is another, ERROR, message\n" +">>>" +msgstr "" + #: ../../howto/logging-cookbook.rst:1654 msgid "" "Logging calls (``logger.debug()``, ``logger.info()`` etc.) only take " @@ -882,6 +2137,27 @@ msgid "" "the following two classes::" msgstr "" +#: ../../howto/logging-cookbook.rst:1673 ../../howto/logging-cookbook.rst:2761 +msgid "" +"class BraceMessage:\n" +" def __init__(self, fmt, /, *args, **kwargs):\n" +" self.fmt = fmt\n" +" self.args = args\n" +" self.kwargs = kwargs\n" +"\n" +" def __str__(self):\n" +" return self.fmt.format(*self.args, **self.kwargs)\n" +"\n" +"class DollarMessage:\n" +" def __init__(self, fmt, /, **kwargs):\n" +" self.fmt = fmt\n" +" self.kwargs = kwargs\n" +"\n" +" def __str__(self):\n" +" from string import Template\n" +" return Template(self.fmt).substitute(**self.kwargs)" +msgstr "" + #: ../../howto/logging-cookbook.rst:1691 msgid "" "Either of these can be used in place of a format string, to allow {}- or $-" @@ -900,6 +2176,25 @@ msgid "" "that they're declared in a module called ``wherever``):" msgstr "" +#: ../../howto/logging-cookbook.rst:1703 +msgid "" +">>> from wherever import BraceMessage as __\n" +">>> print(__('Message with {0} {name}', 2, name='placeholders'))\n" +"Message with 2 placeholders\n" +">>> class Point: pass\n" +"...\n" +">>> p = Point()\n" +">>> p.x = 0.5\n" +">>> p.y = 0.5\n" +">>> print(__('Message with coordinates: ({point.x:.2f}, {point.y:.2f})',\n" +"... point=p))\n" +"Message with coordinates: (0.50, 0.50)\n" +">>> from wherever import DollarMessage as __\n" +">>> print(__('Message with $num $what', num=2, what='placeholders'))\n" +"Message with 2 placeholders\n" +">>>" +msgstr "" + #: ../../howto/logging-cookbook.rst:1721 msgid "" "While the above examples use ``print()`` to show how the formatting works, " @@ -924,6 +2219,35 @@ msgid "" "effect to the above, as in the following example::" msgstr "" +#: ../../howto/logging-cookbook.rst:1736 +msgid "" +"import logging\n" +"\n" +"class Message:\n" +" def __init__(self, fmt, args):\n" +" self.fmt = fmt\n" +" self.args = args\n" +"\n" +" def __str__(self):\n" +" return self.fmt.format(*self.args)\n" +"\n" +"class StyleAdapter(logging.LoggerAdapter):\n" +" def log(self, level, msg, /, *args, stacklevel=1, **kwargs):\n" +" if self.isEnabledFor(level):\n" +" msg, kwargs = self.process(msg, kwargs)\n" +" self.logger.log(level, Message(msg, args), **kwargs,\n" +" stacklevel=stacklevel+1)\n" +"\n" +"logger = StyleAdapter(logging.getLogger(__name__))\n" +"\n" +"def main():\n" +" logger.debug('Hello, {}', 'world!')\n" +"\n" +"if __name__ == '__main__':\n" +" logging.basicConfig(level=logging.DEBUG)\n" +" main()" +msgstr "" + #: ../../howto/logging-cookbook.rst:1762 msgid "" "The above script should log the message ``Hello, world!`` when run with " @@ -997,6 +2321,10 @@ msgid "" "would do simply by adding new packages or modules and doing ::" msgstr "" +#: ../../howto/logging-cookbook.rst:1810 +msgid "logger = logging.getLogger(__name__)" +msgstr "" + #: ../../howto/logging-cookbook.rst:1812 msgid "" "at module level). It's probably one too many things to think about. " @@ -1025,6 +2353,18 @@ msgid "" "this::" msgstr "" +#: ../../howto/logging-cookbook.rst:1829 +msgid "" +"old_factory = logging.getLogRecordFactory()\n" +"\n" +"def record_factory(*args, **kwargs):\n" +" record = old_factory(*args, **kwargs)\n" +" record.custom_attribute = 0xdecafbad\n" +" return record\n" +"\n" +"logging.setLogRecordFactory(record_factory)" +msgstr "" + #: ../../howto/logging-cookbook.rst:1838 msgid "" "This pattern allows different libraries to chain factories together, and as " @@ -1050,12 +2390,45 @@ msgid "" "socket is created separately and passed to the handler (as its 'queue')::" msgstr "" +#: ../../howto/logging-cookbook.rst:1859 +msgid "" +"import zmq # using pyzmq, the Python binding for ZeroMQ\n" +"import json # for serializing records portably\n" +"\n" +"ctx = zmq.Context()\n" +"sock = zmq.Socket(ctx, zmq.PUB) # or zmq.PUSH, or other suitable value\n" +"sock.bind('tcp://*:5556') # or wherever\n" +"\n" +"class ZeroMQSocketHandler(QueueHandler):\n" +" def enqueue(self, record):\n" +" self.queue.send_json(record.__dict__)\n" +"\n" +"\n" +"handler = ZeroMQSocketHandler(sock)" +msgstr "" + #: ../../howto/logging-cookbook.rst:1874 msgid "" "Of course there are other ways of organizing this, for example passing in " "the data needed by the handler to create the socket::" msgstr "" +#: ../../howto/logging-cookbook.rst:1877 +msgid "" +"class ZeroMQSocketHandler(QueueHandler):\n" +" def __init__(self, uri, socktype=zmq.PUB, ctx=None):\n" +" self.ctx = ctx or zmq.Context()\n" +" socket = zmq.Socket(self.ctx, socktype)\n" +" socket.bind(uri)\n" +" super().__init__(socket)\n" +"\n" +" def enqueue(self, record):\n" +" self.queue.send_json(record.__dict__)\n" +"\n" +" def close(self):\n" +" self.queue.close()" +msgstr "" + #: ../../howto/logging-cookbook.rst:1892 ../../howto/logging-cookbook.rst:1922 msgid "Subclass ``QueueListener``" msgstr "" @@ -1066,6 +2439,22 @@ msgid "" "kinds of queues, for example a ZeroMQ 'subscribe' socket. Here's an example::" msgstr "" +#: ../../howto/logging-cookbook.rst:1897 +msgid "" +"class ZeroMQSocketListener(QueueListener):\n" +" def __init__(self, uri, /, *handlers, **kwargs):\n" +" self.ctx = kwargs.get('ctx') or zmq.Context()\n" +" socket = zmq.Socket(self.ctx, zmq.SUB)\n" +" socket.setsockopt_string(zmq.SUBSCRIBE, '') # subscribe to " +"everything\n" +" socket.connect(uri)\n" +" super().__init__(socket, *handlers, **kwargs)\n" +"\n" +" def dequeue(self):\n" +" msg = self.queue.recv_json()\n" +" return logging.makeLogRecord(msg)" +msgstr "" + #: ../../howto/logging-cookbook.rst:1912 msgid "Subclassing QueueHandler and QueueListener- a ``pynng`` example" msgstr "" @@ -1079,6 +2468,117 @@ msgid "" "``pynng`` installed. Just for variety, we present the listener first." msgstr "" +#: ../../howto/logging-cookbook.rst:1924 +msgid "" +"# listener.py\n" +"import json\n" +"import logging\n" +"import logging.handlers\n" +"\n" +"import pynng\n" +"\n" +"DEFAULT_ADDR = \"tcp://localhost:13232\"\n" +"\n" +"interrupted = False\n" +"\n" +"class NNGSocketListener(logging.handlers.QueueListener):\n" +"\n" +" def __init__(self, uri, /, *handlers, **kwargs):\n" +" # Have a timeout for interruptability, and open a\n" +" # subscriber socket\n" +" socket = pynng.Sub0(listen=uri, recv_timeout=500)\n" +" # The b'' subscription matches all topics\n" +" topics = kwargs.pop('topics', None) or b''\n" +" socket.subscribe(topics)\n" +" # We treat the socket as a queue\n" +" super().__init__(socket, *handlers, **kwargs)\n" +"\n" +" def dequeue(self, block):\n" +" data = None\n" +" # Keep looping while not interrupted and no data received over the\n" +" # socket\n" +" while not interrupted:\n" +" try:\n" +" data = self.queue.recv(block=block)\n" +" break\n" +" except pynng.Timeout:\n" +" pass\n" +" except pynng.Closed: # sometimes happens when you hit Ctrl-C\n" +" break\n" +" if data is None:\n" +" return None\n" +" # Get the logging event sent from a publisher\n" +" event = json.loads(data.decode('utf-8'))\n" +" return logging.makeLogRecord(event)\n" +"\n" +" def enqueue_sentinel(self):\n" +" # Not used in this implementation, as the socket isn't really a\n" +" # queue\n" +" pass\n" +"\n" +"logging.getLogger('pynng').propagate = False\n" +"listener = NNGSocketListener(DEFAULT_ADDR, logging.StreamHandler(), " +"topics=b'')\n" +"listener.start()\n" +"print('Press Ctrl-C to stop.')\n" +"try:\n" +" while True:\n" +" pass\n" +"except KeyboardInterrupt:\n" +" interrupted = True\n" +"finally:\n" +" listener.stop()" +msgstr "" + +#: ../../howto/logging-cookbook.rst:1990 +msgid "" +"# sender.py\n" +"import json\n" +"import logging\n" +"import logging.handlers\n" +"import time\n" +"import random\n" +"\n" +"import pynng\n" +"\n" +"DEFAULT_ADDR = \"tcp://localhost:13232\"\n" +"\n" +"class NNGSocketHandler(logging.handlers.QueueHandler):\n" +"\n" +" def __init__(self, uri):\n" +" socket = pynng.Pub0(dial=uri, send_timeout=500)\n" +" super().__init__(socket)\n" +"\n" +" def enqueue(self, record):\n" +" # Send the record as UTF-8 encoded JSON\n" +" d = dict(record.__dict__)\n" +" data = json.dumps(d)\n" +" self.queue.send(data.encode('utf-8'))\n" +"\n" +" def close(self):\n" +" self.queue.close()\n" +"\n" +"logging.getLogger('pynng').propagate = False\n" +"handler = NNGSocketHandler(DEFAULT_ADDR)\n" +"# Make sure the process ID is in the output\n" +"logging.basicConfig(level=logging.DEBUG,\n" +" handlers=[logging.StreamHandler(), handler],\n" +" format='%(levelname)-8s %(name)10s %(process)6s " +"%(message)s')\n" +"levels = (logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR,\n" +" logging.CRITICAL)\n" +"logger_names = ('myapp', 'myapp.lib1', 'myapp.lib2')\n" +"msgno = 1\n" +"while True:\n" +" # Just randomly select some loggers and levels and log away\n" +" level = random.choice(levels)\n" +" logger = logging.getLogger(random.choice(logger_names))\n" +" logger.log(level, 'Message no. %5d' % msgno)\n" +" msgno += 1\n" +" delay = random.random() * 2 + 0.5\n" +" time.sleep(delay)" +msgstr "" + #: ../../howto/logging-cookbook.rst:2037 msgid "" "You can run the above two snippets in separate command shells. If we run the " @@ -1086,14 +2586,65 @@ msgid "" "see something like the following. In the first sender shell:" msgstr "" +#: ../../howto/logging-cookbook.rst:2041 +msgid "" +"$ python sender.py\n" +"DEBUG myapp 613 Message no. 1\n" +"WARNING myapp.lib2 613 Message no. 2\n" +"CRITICAL myapp.lib2 613 Message no. 3\n" +"WARNING myapp.lib2 613 Message no. 4\n" +"CRITICAL myapp.lib1 613 Message no. 5\n" +"DEBUG myapp 613 Message no. 6\n" +"CRITICAL myapp.lib1 613 Message no. 7\n" +"INFO myapp.lib1 613 Message no. 8\n" +"(and so on)" +msgstr "" + #: ../../howto/logging-cookbook.rst:2054 msgid "In the second sender shell:" msgstr "" +#: ../../howto/logging-cookbook.rst:2056 +msgid "" +"$ python sender.py\n" +"INFO myapp.lib2 657 Message no. 1\n" +"CRITICAL myapp.lib2 657 Message no. 2\n" +"CRITICAL myapp 657 Message no. 3\n" +"CRITICAL myapp.lib1 657 Message no. 4\n" +"INFO myapp.lib1 657 Message no. 5\n" +"WARNING myapp.lib2 657 Message no. 6\n" +"CRITICAL myapp 657 Message no. 7\n" +"DEBUG myapp.lib1 657 Message no. 8\n" +"(and so on)" +msgstr "" + #: ../../howto/logging-cookbook.rst:2069 msgid "In the listener shell:" msgstr "" +#: ../../howto/logging-cookbook.rst:2071 +msgid "" +"$ python listener.py\n" +"Press Ctrl-C to stop.\n" +"DEBUG myapp 613 Message no. 1\n" +"WARNING myapp.lib2 613 Message no. 2\n" +"INFO myapp.lib2 657 Message no. 1\n" +"CRITICAL myapp.lib2 613 Message no. 3\n" +"CRITICAL myapp.lib2 657 Message no. 2\n" +"CRITICAL myapp 657 Message no. 3\n" +"WARNING myapp.lib2 613 Message no. 4\n" +"CRITICAL myapp.lib1 613 Message no. 5\n" +"CRITICAL myapp.lib1 657 Message no. 4\n" +"INFO myapp.lib1 657 Message no. 5\n" +"DEBUG myapp 613 Message no. 6\n" +"WARNING myapp.lib2 657 Message no. 6\n" +"CRITICAL myapp 657 Message no. 7\n" +"CRITICAL myapp.lib1 613 Message no. 7\n" +"INFO myapp.lib1 613 Message no. 8\n" +"DEBUG myapp.lib1 657 Message no. 8\n" +"(and so on)" +msgstr "" + #: ../../howto/logging-cookbook.rst:2093 msgid "" "As you can see, the logging from the two sender processes is interleaved in " @@ -1112,6 +2663,59 @@ msgid "" "func:`~config.dictConfig` to put the configuration into effect::" msgstr "" +#: ../../howto/logging-cookbook.rst:2104 +msgid "" +"LOGGING = {\n" +" 'version': 1,\n" +" 'disable_existing_loggers': False,\n" +" 'formatters': {\n" +" 'verbose': {\n" +" 'format': '{levelname} {asctime} {module} {process:d} {thread:d} " +"{message}',\n" +" 'style': '{',\n" +" },\n" +" 'simple': {\n" +" 'format': '{levelname} {message}',\n" +" 'style': '{',\n" +" },\n" +" },\n" +" 'filters': {\n" +" 'special': {\n" +" '()': 'project.logging.SpecialFilter',\n" +" 'foo': 'bar',\n" +" },\n" +" },\n" +" 'handlers': {\n" +" 'console': {\n" +" 'level': 'INFO',\n" +" 'class': 'logging.StreamHandler',\n" +" 'formatter': 'simple',\n" +" },\n" +" 'mail_admins': {\n" +" 'level': 'ERROR',\n" +" 'class': 'django.utils.log.AdminEmailHandler',\n" +" 'filters': ['special']\n" +" }\n" +" },\n" +" 'loggers': {\n" +" 'django': {\n" +" 'handlers': ['console'],\n" +" 'propagate': True,\n" +" },\n" +" 'django.request': {\n" +" 'handlers': ['mail_admins'],\n" +" 'level': 'ERROR',\n" +" 'propagate': False,\n" +" },\n" +" 'myproject.custom': {\n" +" 'handlers': ['console', 'mail_admins'],\n" +" 'level': 'INFO',\n" +" 'filters': ['special']\n" +" }\n" +" }\n" +"}" +msgstr "" + #: ../../howto/logging-cookbook.rst:2153 msgid "" "For more information about this configuration, you can see the `relevant " @@ -1129,11 +2733,54 @@ msgid "" "following runnable script, which shows gzip compression of the log file::" msgstr "" +#: ../../howto/logging-cookbook.rst:2165 +msgid "" +"import gzip\n" +"import logging\n" +"import logging.handlers\n" +"import os\n" +"import shutil\n" +"\n" +"def namer(name):\n" +" return name + \".gz\"\n" +"\n" +"def rotator(source, dest):\n" +" with open(source, 'rb') as f_in:\n" +" with gzip.open(dest, 'wb') as f_out:\n" +" shutil.copyfileobj(f_in, f_out)\n" +" os.remove(source)\n" +"\n" +"\n" +"rh = logging.handlers.RotatingFileHandler('rotated.log', maxBytes=128, " +"backupCount=5)\n" +"rh.rotator = rotator\n" +"rh.namer = namer\n" +"\n" +"root = logging.getLogger()\n" +"root.setLevel(logging.INFO)\n" +"root.addHandler(rh)\n" +"f = logging.Formatter('%(asctime)s %(message)s')\n" +"rh.setFormatter(f)\n" +"for i in range(1000):\n" +" root.info(f'Message no. {i + 1}')" +msgstr "" + #: ../../howto/logging-cookbook.rst:2193 msgid "" "After running this, you will see six new files, five of which are compressed:" msgstr "" +#: ../../howto/logging-cookbook.rst:2195 +msgid "" +"$ ls rotated.log*\n" +"rotated.log rotated.log.2.gz rotated.log.4.gz\n" +"rotated.log.1.gz rotated.log.3.gz rotated.log.5.gz\n" +"$ zcat rotated.log.1.gz\n" +"2023-01-20 02:28:17,767 Message no. 996\n" +"2023-01-20 02:28:17,767 Message no. 997\n" +"2023-01-20 02:28:17,767 Message no. 998" +msgstr "" + #: ../../howto/logging-cookbook.rst:2206 msgid "A more elaborate multiprocessing example" msgstr "" @@ -1165,6 +2812,229 @@ msgid "" "works::" msgstr "" +#: ../../howto/logging-cookbook.rst:2226 +msgid "" +"import logging\n" +"import logging.config\n" +"import logging.handlers\n" +"from multiprocessing import Process, Queue, Event, current_process\n" +"import os\n" +"import random\n" +"import time\n" +"\n" +"class MyHandler:\n" +" \"\"\"\n" +" A simple handler for logging events. It runs in the listener process " +"and\n" +" dispatches events to loggers based on the name in the received record,\n" +" which then get dispatched, by the logging system, to the handlers\n" +" configured for those loggers.\n" +" \"\"\"\n" +"\n" +" def handle(self, record):\n" +" if record.name == \"root\":\n" +" logger = logging.getLogger()\n" +" else:\n" +" logger = logging.getLogger(record.name)\n" +"\n" +" if logger.isEnabledFor(record.levelno):\n" +" # The process name is transformed just to show that it's the " +"listener\n" +" # doing the logging to files and console\n" +" record.processName = '%s (for %s)' % (current_process().name, " +"record.processName)\n" +" logger.handle(record)\n" +"\n" +"def listener_process(q, stop_event, config):\n" +" \"\"\"\n" +" This could be done in the main process, but is just done in a separate\n" +" process for illustrative purposes.\n" +"\n" +" This initialises logging according to the specified configuration,\n" +" starts the listener and waits for the main process to signal completion\n" +" via the event. The listener is then stopped, and the process exits.\n" +" \"\"\"\n" +" logging.config.dictConfig(config)\n" +" listener = logging.handlers.QueueListener(q, MyHandler())\n" +" listener.start()\n" +" if os.name == 'posix':\n" +" # On POSIX, the setup logger will have been configured in the\n" +" # parent process, but should have been disabled following the\n" +" # dictConfig call.\n" +" # On Windows, since fork isn't used, the setup logger won't\n" +" # exist in the child, so it would be created and the message\n" +" # would appear - hence the \"if posix\" clause.\n" +" logger = logging.getLogger('setup')\n" +" logger.critical('Should not appear, because of disabled " +"logger ...')\n" +" stop_event.wait()\n" +" listener.stop()\n" +"\n" +"def worker_process(config):\n" +" \"\"\"\n" +" A number of these are spawned for the purpose of illustration. In\n" +" practice, they could be a heterogeneous bunch of processes rather than\n" +" ones which are identical to each other.\n" +"\n" +" This initialises logging according to the specified configuration,\n" +" and logs a hundred messages with random levels to randomly selected\n" +" loggers.\n" +"\n" +" A small sleep is added to allow other processes a chance to run. This\n" +" is not strictly needed, but it mixes the output from the different\n" +" processes a bit more than if it's left out.\n" +" \"\"\"\n" +" logging.config.dictConfig(config)\n" +" levels = [logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR,\n" +" logging.CRITICAL]\n" +" loggers = ['foo', 'foo.bar', 'foo.bar.baz',\n" +" 'spam', 'spam.ham', 'spam.ham.eggs']\n" +" if os.name == 'posix':\n" +" # On POSIX, the setup logger will have been configured in the\n" +" # parent process, but should have been disabled following the\n" +" # dictConfig call.\n" +" # On Windows, since fork isn't used, the setup logger won't\n" +" # exist in the child, so it would be created and the message\n" +" # would appear - hence the \"if posix\" clause.\n" +" logger = logging.getLogger('setup')\n" +" logger.critical('Should not appear, because of disabled " +"logger ...')\n" +" for i in range(100):\n" +" lvl = random.choice(levels)\n" +" logger = logging.getLogger(random.choice(loggers))\n" +" logger.log(lvl, 'Message no. %d', i)\n" +" time.sleep(0.01)\n" +"\n" +"def main():\n" +" q = Queue()\n" +" # The main process gets a simple configuration which prints to the " +"console.\n" +" config_initial = {\n" +" 'version': 1,\n" +" 'handlers': {\n" +" 'console': {\n" +" 'class': 'logging.StreamHandler',\n" +" 'level': 'INFO'\n" +" }\n" +" },\n" +" 'root': {\n" +" 'handlers': ['console'],\n" +" 'level': 'DEBUG'\n" +" }\n" +" }\n" +" # The worker process configuration is just a QueueHandler attached to " +"the\n" +" # root logger, which allows all messages to be sent to the queue.\n" +" # We disable existing loggers to disable the \"setup\" logger used in " +"the\n" +" # parent process. This is needed on POSIX because the logger will\n" +" # be there in the child following a fork().\n" +" config_worker = {\n" +" 'version': 1,\n" +" 'disable_existing_loggers': True,\n" +" 'handlers': {\n" +" 'queue': {\n" +" 'class': 'logging.handlers.QueueHandler',\n" +" 'queue': q\n" +" }\n" +" },\n" +" 'root': {\n" +" 'handlers': ['queue'],\n" +" 'level': 'DEBUG'\n" +" }\n" +" }\n" +" # The listener process configuration shows that the full flexibility of\n" +" # logging configuration is available to dispatch events to handlers " +"however\n" +" # you want.\n" +" # We disable existing loggers to disable the \"setup\" logger used in " +"the\n" +" # parent process. This is needed on POSIX because the logger will\n" +" # be there in the child following a fork().\n" +" config_listener = {\n" +" 'version': 1,\n" +" 'disable_existing_loggers': True,\n" +" 'formatters': {\n" +" 'detailed': {\n" +" 'class': 'logging.Formatter',\n" +" 'format': '%(asctime)s %(name)-15s %(levelname)-8s " +"%(processName)-10s %(message)s'\n" +" },\n" +" 'simple': {\n" +" 'class': 'logging.Formatter',\n" +" 'format': '%(name)-15s %(levelname)-8s %(processName)-10s " +"%(message)s'\n" +" }\n" +" },\n" +" 'handlers': {\n" +" 'console': {\n" +" 'class': 'logging.StreamHandler',\n" +" 'formatter': 'simple',\n" +" 'level': 'INFO'\n" +" },\n" +" 'file': {\n" +" 'class': 'logging.FileHandler',\n" +" 'filename': 'mplog.log',\n" +" 'mode': 'w',\n" +" 'formatter': 'detailed'\n" +" },\n" +" 'foofile': {\n" +" 'class': 'logging.FileHandler',\n" +" 'filename': 'mplog-foo.log',\n" +" 'mode': 'w',\n" +" 'formatter': 'detailed'\n" +" },\n" +" 'errors': {\n" +" 'class': 'logging.FileHandler',\n" +" 'filename': 'mplog-errors.log',\n" +" 'mode': 'w',\n" +" 'formatter': 'detailed',\n" +" 'level': 'ERROR'\n" +" }\n" +" },\n" +" 'loggers': {\n" +" 'foo': {\n" +" 'handlers': ['foofile']\n" +" }\n" +" },\n" +" 'root': {\n" +" 'handlers': ['console', 'file', 'errors'],\n" +" 'level': 'DEBUG'\n" +" }\n" +" }\n" +" # Log some initial events, just to show that logging in the parent " +"works\n" +" # normally.\n" +" logging.config.dictConfig(config_initial)\n" +" logger = logging.getLogger('setup')\n" +" logger.info('About to create workers ...')\n" +" workers = []\n" +" for i in range(5):\n" +" wp = Process(target=worker_process, name='worker %d' % (i + 1),\n" +" args=(config_worker,))\n" +" workers.append(wp)\n" +" wp.start()\n" +" logger.info('Started worker: %s', wp.name)\n" +" logger.info('About to create listener ...')\n" +" stop_event = Event()\n" +" lp = Process(target=listener_process, name='listener',\n" +" args=(q, stop_event, config_listener))\n" +" lp.start()\n" +" logger.info('Started listener')\n" +" # We now hang around for the workers to finish their work.\n" +" for wp in workers:\n" +" wp.join()\n" +" # Workers all done, listening can now stop.\n" +" # Logging in the parent still works normally.\n" +" logger.info('Telling listener to stop ...')\n" +" stop_event.set()\n" +" lp.join()\n" +" logger.info('All done.')\n" +"\n" +"if __name__ == '__main__':\n" +" main()" +msgstr "" + #: ../../howto/logging-cookbook.rst:2435 msgid "Inserting a BOM into messages sent to a SysLogHandler" msgstr "" @@ -1201,6 +3071,10 @@ msgid "" "handlers.SysLogHandler` instance, with a format string such as::" msgstr "" +#: ../../howto/logging-cookbook.rst:2459 +msgid "'ASCII section\\ufeffUnicode section'" +msgstr "" + #: ../../howto/logging-cookbook.rst:2461 msgid "" "The Unicode code point U+FEFF, when encoded using UTF-8, will be encoded as " @@ -1246,10 +3120,35 @@ msgid "" "machine-parseable manner::" msgstr "" +#: ../../howto/logging-cookbook.rst:2489 +msgid "" +"import json\n" +"import logging\n" +"\n" +"class StructuredMessage:\n" +" def __init__(self, message, /, **kwargs):\n" +" self.message = message\n" +" self.kwargs = kwargs\n" +"\n" +" def __str__(self):\n" +" return '%s >>> %s' % (self.message, json.dumps(self.kwargs))\n" +"\n" +"_ = StructuredMessage # optional, to improve readability\n" +"\n" +"logging.basicConfig(level=logging.INFO, format='%(message)s')\n" +"logging.info(_('message 1', foo='bar', bar='baz', num=123, fnum=123.456))" +msgstr "" + #: ../../howto/logging-cookbook.rst:2505 msgid "If the above script is run, it prints:" msgstr "" +#: ../../howto/logging-cookbook.rst:2507 +msgid "" +"message 1 >>> {\"fnum\": 123.456, \"num\": 123, \"bar\": \"baz\", \"foo\": " +"\"bar\"}" +msgstr "" + #: ../../howto/logging-cookbook.rst:2511 ../../howto/logging-cookbook.rst:2553 msgid "" "Note that the order of items might be different according to the version of " @@ -1262,10 +3161,47 @@ msgid "" "as in the following complete example::" msgstr "" +#: ../../howto/logging-cookbook.rst:2517 +msgid "" +"import json\n" +"import logging\n" +"\n" +"\n" +"class Encoder(json.JSONEncoder):\n" +" def default(self, o):\n" +" if isinstance(o, set):\n" +" return tuple(o)\n" +" elif isinstance(o, str):\n" +" return o.encode('unicode_escape').decode('ascii')\n" +" return super().default(o)\n" +"\n" +"class StructuredMessage:\n" +" def __init__(self, message, /, **kwargs):\n" +" self.message = message\n" +" self.kwargs = kwargs\n" +"\n" +" def __str__(self):\n" +" s = Encoder().encode(self.kwargs)\n" +" return '%s >>> %s' % (self.message, s)\n" +"\n" +"_ = StructuredMessage # optional, to improve readability\n" +"\n" +"def main():\n" +" logging.basicConfig(level=logging.INFO, format='%(message)s')\n" +" logging.info(_('message 1', set_value={1, 2, 3}, snowman='\\u2603'))\n" +"\n" +"if __name__ == '__main__':\n" +" main()" +msgstr "" + #: ../../howto/logging-cookbook.rst:2547 msgid "When the above script is run, it prints:" msgstr "" +#: ../../howto/logging-cookbook.rst:2549 +msgid "message 1 >>> {\"snowman\": \"\\u2603\", \"set_value\": [1, 2, 3]}" +msgstr "" + #: ../../howto/logging-cookbook.rst:2562 msgid "Customizing handlers with :func:`dictConfig`" msgstr "" @@ -1280,12 +3216,55 @@ msgid "" "customize handler creation using a plain function such as::" msgstr "" +#: ../../howto/logging-cookbook.rst:2571 +msgid "" +"def owned_file_handler(filename, mode='a', encoding=None, owner=None):\n" +" if owner:\n" +" if not os.path.exists(filename):\n" +" open(filename, 'a').close()\n" +" shutil.chown(filename, *owner)\n" +" return logging.FileHandler(filename, mode, encoding)" +msgstr "" + #: ../../howto/logging-cookbook.rst:2578 msgid "" "You can then specify, in a logging configuration passed to :func:" "`dictConfig`, that a logging handler be created by calling this function::" msgstr "" +#: ../../howto/logging-cookbook.rst:2581 +msgid "" +"LOGGING = {\n" +" 'version': 1,\n" +" 'disable_existing_loggers': False,\n" +" 'formatters': {\n" +" 'default': {\n" +" 'format': '%(asctime)s %(levelname)s %(name)s %(message)s'\n" +" },\n" +" },\n" +" 'handlers': {\n" +" 'file':{\n" +" # The values below are popped from this dictionary and\n" +" # used to create the handler, set the handler's level and\n" +" # its formatter.\n" +" '()': owned_file_handler,\n" +" 'level':'DEBUG',\n" +" 'formatter': 'default',\n" +" # The values below are passed to the handler creator callable\n" +" # as keyword arguments.\n" +" 'owner': ['pulse', 'pulse'],\n" +" 'filename': 'chowntest.log',\n" +" 'mode': 'w',\n" +" 'encoding': 'utf-8',\n" +" },\n" +" },\n" +" 'root': {\n" +" 'handlers': ['file'],\n" +" 'level': 'DEBUG',\n" +" },\n" +"}" +msgstr "" + #: ../../howto/logging-cookbook.rst:2611 msgid "" "In this example I am setting the ownership using the ``pulse`` user and " @@ -1293,10 +3272,65 @@ msgid "" "working script, ``chowntest.py``::" msgstr "" +#: ../../howto/logging-cookbook.rst:2615 +msgid "" +"import logging, logging.config, os, shutil\n" +"\n" +"def owned_file_handler(filename, mode='a', encoding=None, owner=None):\n" +" if owner:\n" +" if not os.path.exists(filename):\n" +" open(filename, 'a').close()\n" +" shutil.chown(filename, *owner)\n" +" return logging.FileHandler(filename, mode, encoding)\n" +"\n" +"LOGGING = {\n" +" 'version': 1,\n" +" 'disable_existing_loggers': False,\n" +" 'formatters': {\n" +" 'default': {\n" +" 'format': '%(asctime)s %(levelname)s %(name)s %(message)s'\n" +" },\n" +" },\n" +" 'handlers': {\n" +" 'file':{\n" +" # The values below are popped from this dictionary and\n" +" # used to create the handler, set the handler's level and\n" +" # its formatter.\n" +" '()': owned_file_handler,\n" +" 'level':'DEBUG',\n" +" 'formatter': 'default',\n" +" # The values below are passed to the handler creator callable\n" +" # as keyword arguments.\n" +" 'owner': ['pulse', 'pulse'],\n" +" 'filename': 'chowntest.log',\n" +" 'mode': 'w',\n" +" 'encoding': 'utf-8',\n" +" },\n" +" },\n" +" 'root': {\n" +" 'handlers': ['file'],\n" +" 'level': 'DEBUG',\n" +" },\n" +"}\n" +"\n" +"logging.config.dictConfig(LOGGING)\n" +"logger = logging.getLogger('mylogger')\n" +"logger.debug('A debug message')" +msgstr "" + #: ../../howto/logging-cookbook.rst:2658 msgid "To run this, you will probably need to run as ``root``:" msgstr "" +#: ../../howto/logging-cookbook.rst:2660 +msgid "" +"$ sudo python3.3 chowntest.py\n" +"$ cat chowntest.log\n" +"2013-11-05 09:34:51,128 DEBUG mylogger A debug message\n" +"$ ls -l chowntest.log\n" +"-rw-r--r-- 1 pulse pulse 55 2013-11-05 09:34 chowntest.log" +msgstr "" + #: ../../howto/logging-cookbook.rst:2668 msgid "" "Note that this example uses Python 3.3 because that's where :func:`shutil." @@ -1312,10 +3346,18 @@ msgid "" "somewhere in your project. Instead of the line in the configuration::" msgstr "" +#: ../../howto/logging-cookbook.rst:2677 +msgid "'()': owned_file_handler," +msgstr "" + #: ../../howto/logging-cookbook.rst:2679 msgid "you could use e.g.::" msgstr "" +#: ../../howto/logging-cookbook.rst:2681 +msgid "'()': 'ext://project.util.owned_file_handler'," +msgstr "" + #: ../../howto/logging-cookbook.rst:2683 msgid "" "where ``project.util`` can be replaced with the actual name of the package " @@ -1440,10 +3482,33 @@ msgid "" "`str.format`::" msgstr "" +#: ../../howto/logging-cookbook.rst:2790 +msgid "" +">>> __ = BraceMessage\n" +">>> print(__('Message with {0} {1}', 2, 'placeholders'))\n" +"Message with 2 placeholders\n" +">>> class Point: pass\n" +"...\n" +">>> p = Point()\n" +">>> p.x = 0.5\n" +">>> p.y = 0.5\n" +">>> print(__('Message with coordinates: ({point.x:.2f}, {point.y:.2f})', " +"point=p))\n" +"Message with coordinates: (0.50, 0.50)" +msgstr "" + #: ../../howto/logging-cookbook.rst:2801 msgid "Secondly, formatting with :class:`string.Template`::" msgstr "" +#: ../../howto/logging-cookbook.rst:2803 +msgid "" +">>> __ = DollarMessage\n" +">>> print(__('Message with $num $what', num=2, what='placeholders'))\n" +"Message with 2 placeholders\n" +">>>" +msgstr "" + #: ../../howto/logging-cookbook.rst:2808 msgid "" "One thing to note is that you pay no significant performance penalty with " @@ -1475,6 +3540,51 @@ msgid "" "complete example::" msgstr "" +#: ../../howto/logging-cookbook.rst:2835 +msgid "" +"import logging\n" +"import logging.config\n" +"import sys\n" +"\n" +"class MyFilter(logging.Filter):\n" +" def __init__(self, param=None):\n" +" self.param = param\n" +"\n" +" def filter(self, record):\n" +" if self.param is None:\n" +" allow = True\n" +" else:\n" +" allow = self.param not in record.msg\n" +" if allow:\n" +" record.msg = 'changed: ' + record.msg\n" +" return allow\n" +"\n" +"LOGGING = {\n" +" 'version': 1,\n" +" 'filters': {\n" +" 'myfilter': {\n" +" '()': MyFilter,\n" +" 'param': 'noshow',\n" +" }\n" +" },\n" +" 'handlers': {\n" +" 'console': {\n" +" 'class': 'logging.StreamHandler',\n" +" 'filters': ['myfilter']\n" +" }\n" +" },\n" +" 'root': {\n" +" 'level': 'DEBUG',\n" +" 'handlers': ['console']\n" +" },\n" +"}\n" +"\n" +"if __name__ == '__main__':\n" +" logging.config.dictConfig(LOGGING)\n" +" logging.debug('hello')\n" +" logging.debug('hello - noshow')" +msgstr "" + #: ../../howto/logging-cookbook.rst:2877 msgid "" "This example shows how you can pass configuration data to the callable which " @@ -1482,6 +3592,10 @@ msgid "" "above script will print:" msgstr "" +#: ../../howto/logging-cookbook.rst:2881 +msgid "changed: hello" +msgstr "" + #: ../../howto/logging-cookbook.rst:2885 msgid "which shows that the filter is working as configured." msgstr "" @@ -1521,10 +3635,58 @@ msgid "" "formatter class, as shown in the following example::" msgstr "" +#: ../../howto/logging-cookbook.rst:2912 +msgid "" +"import logging\n" +"\n" +"class OneLineExceptionFormatter(logging.Formatter):\n" +" def formatException(self, exc_info):\n" +" \"\"\"\n" +" Format an exception so that it prints on a single line.\n" +" \"\"\"\n" +" result = super().formatException(exc_info)\n" +" return repr(result) # or format into one line however you want to\n" +"\n" +" def format(self, record):\n" +" s = super().format(record)\n" +" if record.exc_text:\n" +" s = s.replace('\\n', '') + '|'\n" +" return s\n" +"\n" +"def configure_logging():\n" +" fh = logging.FileHandler('output.txt', 'w')\n" +" f = OneLineExceptionFormatter('%(asctime)s|%(levelname)s|%(message)s|',\n" +" '%d/%m/%Y %H:%M:%S')\n" +" fh.setFormatter(f)\n" +" root = logging.getLogger()\n" +" root.setLevel(logging.DEBUG)\n" +" root.addHandler(fh)\n" +"\n" +"def main():\n" +" configure_logging()\n" +" logging.info('Sample message')\n" +" try:\n" +" x = 1 / 0\n" +" except ZeroDivisionError as e:\n" +" logging.exception('ZeroDivisionError: %s', e)\n" +"\n" +"if __name__ == '__main__':\n" +" main()" +msgstr "" + #: ../../howto/logging-cookbook.rst:2948 msgid "When run, this produces a file with exactly two lines:" msgstr "" +#: ../../howto/logging-cookbook.rst:2950 +msgid "" +"28/01/2015 07:21:23|INFO|Sample message|\n" +"28/01/2015 07:21:23|ERROR|ZeroDivisionError: integer division or modulo by " +"zero|'Traceback (most recent call last):\\n File \"logtest7.py\", line 30, " +"in main\\n x = 1 / 0\\nZeroDivisionError: integer division or modulo by " +"zero'|" +msgstr "" + #: ../../howto/logging-cookbook.rst:2955 msgid "" "While the above treatment is simplistic, it points the way to how exception " @@ -1553,6 +3715,38 @@ msgid "" "approach, which assumes that the ``espeak`` TTS package is available::" msgstr "" +#: ../../howto/logging-cookbook.rst:2977 +msgid "" +"import logging\n" +"import subprocess\n" +"import sys\n" +"\n" +"class TTSHandler(logging.Handler):\n" +" def emit(self, record):\n" +" msg = self.format(record)\n" +" # Speak slowly in a female English voice\n" +" cmd = ['espeak', '-s150', '-ven+f3', msg]\n" +" p = subprocess.Popen(cmd, stdout=subprocess.PIPE,\n" +" stderr=subprocess.STDOUT)\n" +" # wait for the program to finish\n" +" p.communicate()\n" +"\n" +"def configure_logging():\n" +" h = TTSHandler()\n" +" root = logging.getLogger()\n" +" root.addHandler(h)\n" +" # the default formatter just returns the message\n" +" root.setLevel(logging.DEBUG)\n" +"\n" +"def main():\n" +" logging.info('Hello')\n" +" logging.debug('Goodbye')\n" +"\n" +"if __name__ == '__main__':\n" +" configure_logging()\n" +" sys.exit(main())" +msgstr "" + #: ../../howto/logging-cookbook.rst:3006 msgid "" "When run, this script should say \"Hello\" and then \"Goodbye\" in a female " @@ -1618,10 +3812,105 @@ msgstr "" msgid "Here's the script::" msgstr "" +#: ../../howto/logging-cookbook.rst:3051 +msgid "" +"import logging\n" +"from logging.handlers import MemoryHandler\n" +"import sys\n" +"\n" +"logger = logging.getLogger(__name__)\n" +"logger.addHandler(logging.NullHandler())\n" +"\n" +"def log_if_errors(logger, target_handler=None, flush_level=None, " +"capacity=None):\n" +" if target_handler is None:\n" +" target_handler = logging.StreamHandler()\n" +" if flush_level is None:\n" +" flush_level = logging.ERROR\n" +" if capacity is None:\n" +" capacity = 100\n" +" handler = MemoryHandler(capacity, flushLevel=flush_level, " +"target=target_handler)\n" +"\n" +" def decorator(fn):\n" +" def wrapper(*args, **kwargs):\n" +" logger.addHandler(handler)\n" +" try:\n" +" return fn(*args, **kwargs)\n" +" except Exception:\n" +" logger.exception('call failed')\n" +" raise\n" +" finally:\n" +" super(MemoryHandler, handler).flush()\n" +" logger.removeHandler(handler)\n" +" return wrapper\n" +"\n" +" return decorator\n" +"\n" +"def write_line(s):\n" +" sys.stderr.write('%s\\n' % s)\n" +"\n" +"def foo(fail=False):\n" +" write_line('about to log at DEBUG ...')\n" +" logger.debug('Actually logged at DEBUG')\n" +" write_line('about to log at INFO ...')\n" +" logger.info('Actually logged at INFO')\n" +" write_line('about to log at WARNING ...')\n" +" logger.warning('Actually logged at WARNING')\n" +" if fail:\n" +" write_line('about to log at ERROR ...')\n" +" logger.error('Actually logged at ERROR')\n" +" write_line('about to log at CRITICAL ...')\n" +" logger.critical('Actually logged at CRITICAL')\n" +" return fail\n" +"\n" +"decorated_foo = log_if_errors(logger)(foo)\n" +"\n" +"if __name__ == '__main__':\n" +" logger.setLevel(logging.DEBUG)\n" +" write_line('Calling undecorated foo with False')\n" +" assert not foo(False)\n" +" write_line('Calling undecorated foo with True')\n" +" assert foo(True)\n" +" write_line('Calling decorated foo with False')\n" +" assert not decorated_foo(False)\n" +" write_line('Calling decorated foo with True')\n" +" assert decorated_foo(True)" +msgstr "" + #: ../../howto/logging-cookbook.rst:3112 msgid "When this script is run, the following output should be observed:" msgstr "" +#: ../../howto/logging-cookbook.rst:3114 +msgid "" +"Calling undecorated foo with False\n" +"about to log at DEBUG ...\n" +"about to log at INFO ...\n" +"about to log at WARNING ...\n" +"Calling undecorated foo with True\n" +"about to log at DEBUG ...\n" +"about to log at INFO ...\n" +"about to log at WARNING ...\n" +"about to log at ERROR ...\n" +"about to log at CRITICAL ...\n" +"Calling decorated foo with False\n" +"about to log at DEBUG ...\n" +"about to log at INFO ...\n" +"about to log at WARNING ...\n" +"Calling decorated foo with True\n" +"about to log at DEBUG ...\n" +"about to log at INFO ...\n" +"about to log at WARNING ...\n" +"about to log at ERROR ...\n" +"Actually logged at DEBUG\n" +"Actually logged at INFO\n" +"Actually logged at WARNING\n" +"Actually logged at ERROR\n" +"about to log at CRITICAL ...\n" +"Actually logged at CRITICAL" +msgstr "" + #: ../../howto/logging-cookbook.rst:3142 msgid "" "As you can see, actual logging output only occurs when an event is logged " @@ -1633,6 +3922,13 @@ msgstr "" msgid "You can of course use the conventional means of decoration::" msgstr "" +#: ../../howto/logging-cookbook.rst:3148 +msgid "" +"@log_if_errors(logger)\n" +"def foo(fail=False):\n" +" ..." +msgstr "" + #: ../../howto/logging-cookbook.rst:3156 msgid "Sending logging messages to email, with buffering" msgstr "" @@ -1648,6 +3944,74 @@ msgid "" "argument to see the required and optional arguments.)" msgstr "" +#: ../../howto/logging-cookbook.rst:3166 +msgid "" +"import logging\n" +"import logging.handlers\n" +"import smtplib\n" +"\n" +"class BufferingSMTPHandler(logging.handlers.BufferingHandler):\n" +" def __init__(self, mailhost, port, username, password, fromaddr, " +"toaddrs,\n" +" subject, capacity):\n" +" logging.handlers.BufferingHandler.__init__(self, capacity)\n" +" self.mailhost = mailhost\n" +" self.mailport = port\n" +" self.username = username\n" +" self.password = password\n" +" self.fromaddr = fromaddr\n" +" if isinstance(toaddrs, str):\n" +" toaddrs = [toaddrs]\n" +" self.toaddrs = toaddrs\n" +" self.subject = subject\n" +" self.setFormatter(logging.Formatter(\"%(asctime)s %(levelname)-5s " +"%(message)s\"))\n" +"\n" +" def flush(self):\n" +" if len(self.buffer) > 0:\n" +" try:\n" +" smtp = smtplib.SMTP(self.mailhost, self.mailport)\n" +" smtp.starttls()\n" +" smtp.login(self.username, self.password)\n" +" msg = \"From: %s\\r\\nTo: %s\\r\\nSubject: %s\\r\\n\\r\\n\" " +"% (self.fromaddr, ','.join(self.toaddrs), self.subject)\n" +" for record in self.buffer:\n" +" s = self.format(record)\n" +" msg = msg + s + \"\\r\\n\"\n" +" smtp.sendmail(self.fromaddr, self.toaddrs, msg)\n" +" smtp.quit()\n" +" except Exception:\n" +" if logging.raiseExceptions:\n" +" raise\n" +" self.buffer = []\n" +"\n" +"if __name__ == '__main__':\n" +" import argparse\n" +"\n" +" ap = argparse.ArgumentParser()\n" +" aa = ap.add_argument\n" +" aa('host', metavar='HOST', help='SMTP server')\n" +" aa('--port', '-p', type=int, default=587, help='SMTP port')\n" +" aa('user', metavar='USER', help='SMTP username')\n" +" aa('password', metavar='PASSWORD', help='SMTP password')\n" +" aa('to', metavar='TO', help='Addressee for emails')\n" +" aa('sender', metavar='SENDER', help='Sender email address')\n" +" aa('--subject', '-s',\n" +" default='Test Logging email from Python logging module (buffering)',\n" +" help='Subject of email')\n" +" options = ap.parse_args()\n" +" logger = logging.getLogger()\n" +" logger.setLevel(logging.DEBUG)\n" +" h = BufferingSMTPHandler(options.host, options.port, options.user,\n" +" options.password, options.sender,\n" +" options.to, options.subject, 10)\n" +" logger.addHandler(h)\n" +" for i in range(102):\n" +" logger.info(\"Info index = %d\", i)\n" +" h.flush()\n" +" h.close()" +msgstr "" + #: ../../howto/logging-cookbook.rst:3230 msgid "" "If you run this script and your SMTP server is correctly set up, you should " @@ -1666,6 +4030,15 @@ msgid "" "class such as ``UTCFormatter``, shown below::" msgstr "" +#: ../../howto/logging-cookbook.rst:3243 +msgid "" +"import logging\n" +"import time\n" +"\n" +"class UTCFormatter(logging.Formatter):\n" +" converter = time.gmtime" +msgstr "" + #: ../../howto/logging-cookbook.rst:3249 msgid "" "and you can then use the ``UTCFormatter`` in your code instead of :class:" @@ -1674,10 +4047,57 @@ msgid "" "the following complete example::" msgstr "" +#: ../../howto/logging-cookbook.rst:3254 +msgid "" +"import logging\n" +"import logging.config\n" +"import time\n" +"\n" +"class UTCFormatter(logging.Formatter):\n" +" converter = time.gmtime\n" +"\n" +"LOGGING = {\n" +" 'version': 1,\n" +" 'disable_existing_loggers': False,\n" +" 'formatters': {\n" +" 'utc': {\n" +" '()': UTCFormatter,\n" +" 'format': '%(asctime)s %(message)s',\n" +" },\n" +" 'local': {\n" +" 'format': '%(asctime)s %(message)s',\n" +" }\n" +" },\n" +" 'handlers': {\n" +" 'console1': {\n" +" 'class': 'logging.StreamHandler',\n" +" 'formatter': 'utc',\n" +" },\n" +" 'console2': {\n" +" 'class': 'logging.StreamHandler',\n" +" 'formatter': 'local',\n" +" },\n" +" },\n" +" 'root': {\n" +" 'handlers': ['console1', 'console2'],\n" +" }\n" +"}\n" +"\n" +"if __name__ == '__main__':\n" +" logging.config.dictConfig(LOGGING)\n" +" logging.warning('The local time is %s', time.asctime())" +msgstr "" + #: ../../howto/logging-cookbook.rst:3292 msgid "When this script is run, it should print something like:" msgstr "" +#: ../../howto/logging-cookbook.rst:3294 +msgid "" +"2015-10-17 12:53:29,501 The local time is Sat Oct 17 13:53:29 2015\n" +"2015-10-17 13:53:29,501 The local time is Sat Oct 17 13:53:29 2015" +msgstr "" + #: ../../howto/logging-cookbook.rst:3299 msgid "" "showing how the time is formatted both as local time and UTC, one for each " @@ -1698,6 +4118,35 @@ msgid "" "scope of the context manager::" msgstr "" +#: ../../howto/logging-cookbook.rst:3315 +msgid "" +"import logging\n" +"import sys\n" +"\n" +"class LoggingContext:\n" +" def __init__(self, logger, level=None, handler=None, close=True):\n" +" self.logger = logger\n" +" self.level = level\n" +" self.handler = handler\n" +" self.close = close\n" +"\n" +" def __enter__(self):\n" +" if self.level is not None:\n" +" self.old_level = self.logger.level\n" +" self.logger.setLevel(self.level)\n" +" if self.handler:\n" +" self.logger.addHandler(self.handler)\n" +"\n" +" def __exit__(self, et, ev, tb):\n" +" if self.level is not None:\n" +" self.logger.setLevel(self.old_level)\n" +" if self.handler:\n" +" self.logger.removeHandler(self.handler)\n" +" if self.handler and self.close:\n" +" self.handler.close()\n" +" # implicit return of None => don't swallow exceptions" +msgstr "" + #: ../../howto/logging-cookbook.rst:3341 msgid "" "If you specify a level value, the logger's level is set to that value in the " @@ -1713,6 +4162,26 @@ msgid "" "above::" msgstr "" +#: ../../howto/logging-cookbook.rst:3350 +msgid "" +"if __name__ == '__main__':\n" +" logger = logging.getLogger('foo')\n" +" logger.addHandler(logging.StreamHandler())\n" +" logger.setLevel(logging.INFO)\n" +" logger.info('1. This should appear just once on stderr.')\n" +" logger.debug('2. This should not appear.')\n" +" with LoggingContext(logger, level=logging.DEBUG):\n" +" logger.debug('3. This should appear once on stderr.')\n" +" logger.debug('4. This should not appear.')\n" +" h = logging.StreamHandler(sys.stdout)\n" +" with LoggingContext(logger, level=logging.DEBUG, handler=h, " +"close=True):\n" +" logger.debug('5. This should appear twice - once on stderr and once " +"on stdout.')\n" +" logger.info('6. This should appear just once on stderr.')\n" +" logger.debug('7. This should not appear.')" +msgstr "" + #: ../../howto/logging-cookbook.rst:3365 msgid "" "We initially set the logger's level to ``INFO``, so message #1 appears and " @@ -1730,16 +4199,41 @@ msgstr "" msgid "If we run the resulting script, the result is as follows:" msgstr "" +#: ../../howto/logging-cookbook.rst:3377 +msgid "" +"$ python logctx.py\n" +"1. This should appear just once on stderr.\n" +"3. This should appear once on stderr.\n" +"5. This should appear twice - once on stderr and once on stdout.\n" +"5. This should appear twice - once on stderr and once on stdout.\n" +"6. This should appear just once on stderr." +msgstr "" + #: ../../howto/logging-cookbook.rst:3386 msgid "" "If we run it again, but pipe ``stderr`` to ``/dev/null``, we see the " "following, which is the only message written to ``stdout``:" msgstr "" +#: ../../howto/logging-cookbook.rst:3389 +msgid "" +"$ python logctx.py 2>/dev/null\n" +"5. This should appear twice - once on stderr and once on stdout." +msgstr "" + #: ../../howto/logging-cookbook.rst:3394 msgid "Once again, but piping ``stdout`` to ``/dev/null``, we get:" msgstr "" +#: ../../howto/logging-cookbook.rst:3396 +msgid "" +"$ python logctx.py >/dev/null\n" +"1. This should appear just once on stderr.\n" +"3. This should appear once on stderr.\n" +"5. This should appear twice - once on stderr and once on stdout.\n" +"6. This should appear just once on stderr." +msgstr "" + #: ../../howto/logging-cookbook.rst:3404 msgid "" "In this case, the message #5 printed to ``stdout`` doesn't appear, as " @@ -1786,26 +4280,142 @@ msgid "" "``logging.INFO``. Here's one way that ``app.py`` could be written::" msgstr "" +#: ../../howto/logging-cookbook.rst:3431 +msgid "" +"import argparse\n" +"import importlib\n" +"import logging\n" +"import os\n" +"import sys\n" +"\n" +"def main(args=None):\n" +" scriptname = os.path.basename(__file__)\n" +" parser = argparse.ArgumentParser(scriptname)\n" +" levels = ('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL')\n" +" parser.add_argument('--log-level', default='INFO', choices=levels)\n" +" subparsers = parser.add_subparsers(dest='command',\n" +" help='Available commands:')\n" +" start_cmd = subparsers.add_parser('start', help='Start a service')\n" +" start_cmd.add_argument('name', metavar='NAME',\n" +" help='Name of service to start')\n" +" stop_cmd = subparsers.add_parser('stop',\n" +" help='Stop one or more services')\n" +" stop_cmd.add_argument('names', metavar='NAME', nargs='+',\n" +" help='Name of service to stop')\n" +" restart_cmd = subparsers.add_parser('restart',\n" +" help='Restart one or more " +"services')\n" +" restart_cmd.add_argument('names', metavar='NAME', nargs='+',\n" +" help='Name of service to restart')\n" +" options = parser.parse_args()\n" +" # the code to dispatch commands could all be in this file. For the " +"purposes\n" +" # of illustration only, we implement each command in a separate module.\n" +" try:\n" +" mod = importlib.import_module(options.command)\n" +" cmd = getattr(mod, 'command')\n" +" except (ImportError, AttributeError):\n" +" print('Unable to find the code for command \\'%s\\'' % options." +"command)\n" +" return 1\n" +" # Could get fancy here and load configuration from file or dictionary\n" +" logging.basicConfig(level=options.log_level,\n" +" format='%(levelname)s %(name)s %(message)s')\n" +" cmd(options)\n" +"\n" +"if __name__ == '__main__':\n" +" sys.exit(main())" +msgstr "" + #: ../../howto/logging-cookbook.rst:3472 msgid "" "And the ``start``, ``stop`` and ``restart`` commands can be implemented in " "separate modules, like so for starting::" msgstr "" +#: ../../howto/logging-cookbook.rst:3475 +msgid "" +"# start.py\n" +"import logging\n" +"\n" +"logger = logging.getLogger(__name__)\n" +"\n" +"def command(options):\n" +" logger.debug('About to start %s', options.name)\n" +" # actually do the command processing here ...\n" +" logger.info('Started the \\'%s\\' service.', options.name)" +msgstr "" + #: ../../howto/logging-cookbook.rst:3485 msgid "and thus for stopping::" msgstr "" +#: ../../howto/logging-cookbook.rst:3487 +msgid "" +"# stop.py\n" +"import logging\n" +"\n" +"logger = logging.getLogger(__name__)\n" +"\n" +"def command(options):\n" +" n = len(options.names)\n" +" if n == 1:\n" +" plural = ''\n" +" services = '\\'%s\\'' % options.names[0]\n" +" else:\n" +" plural = 's'\n" +" services = ', '.join('\\'%s\\'' % name for name in options.names)\n" +" i = services.rfind(', ')\n" +" services = services[:i] + ' and ' + services[i + 2:]\n" +" logger.debug('About to stop %s', services)\n" +" # actually do the command processing here ...\n" +" logger.info('Stopped the %s service%s.', services, plural)" +msgstr "" + #: ../../howto/logging-cookbook.rst:3506 msgid "and similarly for restarting::" msgstr "" +#: ../../howto/logging-cookbook.rst:3508 +msgid "" +"# restart.py\n" +"import logging\n" +"\n" +"logger = logging.getLogger(__name__)\n" +"\n" +"def command(options):\n" +" n = len(options.names)\n" +" if n == 1:\n" +" plural = ''\n" +" services = '\\'%s\\'' % options.names[0]\n" +" else:\n" +" plural = 's'\n" +" services = ', '.join('\\'%s\\'' % name for name in options.names)\n" +" i = services.rfind(', ')\n" +" services = services[:i] + ' and ' + services[i + 2:]\n" +" logger.debug('About to restart %s', services)\n" +" # actually do the command processing here ...\n" +" logger.info('Restarted the %s service%s.', services, plural)" +msgstr "" + #: ../../howto/logging-cookbook.rst:3527 msgid "" "If we run this application with the default log level, we get output like " "this:" msgstr "" +#: ../../howto/logging-cookbook.rst:3529 +msgid "" +"$ python app.py start foo\n" +"INFO start Started the 'foo' service.\n" +"\n" +"$ python app.py stop foo bar\n" +"INFO stop Stopped the 'foo' and 'bar' services.\n" +"\n" +"$ python app.py restart foo bar baz\n" +"INFO restart Restarted the 'foo', 'bar' and 'baz' services." +msgstr "" + #: ../../howto/logging-cookbook.rst:3540 msgid "" "The first word is the logging level, and the second word is the module or " @@ -1818,10 +4428,32 @@ msgid "" "the log. For example, if we want more information:" msgstr "" +#: ../../howto/logging-cookbook.rst:3546 +msgid "" +"$ python app.py --log-level DEBUG start foo\n" +"DEBUG start About to start foo\n" +"INFO start Started the 'foo' service.\n" +"\n" +"$ python app.py --log-level DEBUG stop foo bar\n" +"DEBUG stop About to stop 'foo' and 'bar'\n" +"INFO stop Stopped the 'foo' and 'bar' services.\n" +"\n" +"$ python app.py --log-level DEBUG restart foo bar baz\n" +"DEBUG restart About to restart 'foo', 'bar' and 'baz'\n" +"INFO restart Restarted the 'foo', 'bar' and 'baz' services." +msgstr "" + #: ../../howto/logging-cookbook.rst:3560 msgid "And if we want less:" msgstr "" +#: ../../howto/logging-cookbook.rst:3562 +msgid "" +"$ python app.py --log-level WARNING start foo\n" +"$ python app.py --log-level WARNING stop foo bar\n" +"$ python app.py --log-level WARNING restart foo bar baz" +msgstr "" + #: ../../howto/logging-cookbook.rst:3568 msgid "" "In this case, the commands don't print anything to the console, since " @@ -1865,6 +4497,257 @@ msgid "" "more detailed information." msgstr "" +#: ../../howto/logging-cookbook.rst:3597 +msgid "" +"import datetime\n" +"import logging\n" +"import random\n" +"import sys\n" +"import time\n" +"\n" +"# Deal with minor differences between different Qt packages\n" +"try:\n" +" from PySide6 import QtCore, QtGui, QtWidgets\n" +" Signal = QtCore.Signal\n" +" Slot = QtCore.Slot\n" +"except ImportError:\n" +" try:\n" +" from PyQt6 import QtCore, QtGui, QtWidgets\n" +" Signal = QtCore.pyqtSignal\n" +" Slot = QtCore.pyqtSlot\n" +" except ImportError:\n" +" try:\n" +" from PySide2 import QtCore, QtGui, QtWidgets\n" +" Signal = QtCore.Signal\n" +" Slot = QtCore.Slot\n" +" except ImportError:\n" +" from PyQt5 import QtCore, QtGui, QtWidgets\n" +" Signal = QtCore.pyqtSignal\n" +" Slot = QtCore.pyqtSlot\n" +"\n" +"logger = logging.getLogger(__name__)\n" +"\n" +"\n" +"#\n" +"# Signals need to be contained in a QObject or subclass in order to be " +"correctly\n" +"# initialized.\n" +"#\n" +"class Signaller(QtCore.QObject):\n" +" signal = Signal(str, logging.LogRecord)\n" +"\n" +"#\n" +"# Output to a Qt GUI is only supposed to happen on the main thread. So, " +"this\n" +"# handler is designed to take a slot function which is set up to run in the " +"main\n" +"# thread. In this example, the function takes a string argument which is a\n" +"# formatted log message, and the log record which generated it. The " +"formatted\n" +"# string is just a convenience - you could format a string for output any " +"way\n" +"# you like in the slot function itself.\n" +"#\n" +"# You specify the slot function to do whatever GUI updates you want. The " +"handler\n" +"# doesn't know or care about specific UI elements.\n" +"#\n" +"class QtHandler(logging.Handler):\n" +" def __init__(self, slotfunc, *args, **kwargs):\n" +" super().__init__(*args, **kwargs)\n" +" self.signaller = Signaller()\n" +" self.signaller.signal.connect(slotfunc)\n" +"\n" +" def emit(self, record):\n" +" s = self.format(record)\n" +" self.signaller.signal.emit(s, record)\n" +"\n" +"#\n" +"# This example uses QThreads, which means that the threads at the Python " +"level\n" +"# are named something like \"Dummy-1\". The function below gets the Qt name " +"of the\n" +"# current thread.\n" +"#\n" +"def ctname():\n" +" return QtCore.QThread.currentThread().objectName()\n" +"\n" +"\n" +"#\n" +"# Used to generate random levels for logging.\n" +"#\n" +"LEVELS = (logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR,\n" +" logging.CRITICAL)\n" +"\n" +"#\n" +"# This worker class represents work that is done in a thread separate to " +"the\n" +"# main thread. The way the thread is kicked off to do work is via a button " +"press\n" +"# that connects to a slot in the worker.\n" +"#\n" +"# Because the default threadName value in the LogRecord isn't much use, we " +"add\n" +"# a qThreadName which contains the QThread name as computed above, and pass " +"that\n" +"# value in an \"extra\" dictionary which is used to update the LogRecord " +"with the\n" +"# QThread name.\n" +"#\n" +"# This example worker just outputs messages sequentially, interspersed with\n" +"# random delays of the order of a few seconds.\n" +"#\n" +"class Worker(QtCore.QObject):\n" +" @Slot()\n" +" def start(self):\n" +" extra = {'qThreadName': ctname() }\n" +" logger.debug('Started work', extra=extra)\n" +" i = 1\n" +" # Let the thread run until interrupted. This allows reasonably " +"clean\n" +" # thread termination.\n" +" while not QtCore.QThread.currentThread().isInterruptionRequested():\n" +" delay = 0.5 + random.random() * 2\n" +" time.sleep(delay)\n" +" try:\n" +" if random.random() < 0.1:\n" +" raise ValueError('Exception raised: %d' % i)\n" +" else:\n" +" level = random.choice(LEVELS)\n" +" logger.log(level, 'Message after delay of %3.1f: %d', " +"delay, i, extra=extra)\n" +" except ValueError as e:\n" +" logger.exception('Failed: %s', e, extra=extra)\n" +" i += 1\n" +"\n" +"#\n" +"# Implement a simple UI for this cookbook example. This contains:\n" +"#\n" +"# * A read-only text edit window which holds formatted log messages\n" +"# * A button to start work and log stuff in a separate thread\n" +"# * A button to log something from the main thread\n" +"# * A button to clear the log window\n" +"#\n" +"class Window(QtWidgets.QWidget):\n" +"\n" +" COLORS = {\n" +" logging.DEBUG: 'black',\n" +" logging.INFO: 'blue',\n" +" logging.WARNING: 'orange',\n" +" logging.ERROR: 'red',\n" +" logging.CRITICAL: 'purple',\n" +" }\n" +"\n" +" def __init__(self, app):\n" +" super().__init__()\n" +" self.app = app\n" +" self.textedit = te = QtWidgets.QPlainTextEdit(self)\n" +" # Set whatever the default monospace font is for the platform\n" +" f = QtGui.QFont('nosuchfont')\n" +" if hasattr(f, 'Monospace'):\n" +" f.setStyleHint(f.Monospace)\n" +" else:\n" +" f.setStyleHint(f.StyleHint.Monospace) # for Qt6\n" +" te.setFont(f)\n" +" te.setReadOnly(True)\n" +" PB = QtWidgets.QPushButton\n" +" self.work_button = PB('Start background work', self)\n" +" self.log_button = PB('Log a message at a random level', self)\n" +" self.clear_button = PB('Clear log window', self)\n" +" self.handler = h = QtHandler(self.update_status)\n" +" # Remember to use qThreadName rather than threadName in the format " +"string.\n" +" fs = '%(asctime)s %(qThreadName)-12s %(levelname)-8s %(message)s'\n" +" formatter = logging.Formatter(fs)\n" +" h.setFormatter(formatter)\n" +" logger.addHandler(h)\n" +" # Set up to terminate the QThread when we exit\n" +" app.aboutToQuit.connect(self.force_quit)\n" +"\n" +" # Lay out all the widgets\n" +" layout = QtWidgets.QVBoxLayout(self)\n" +" layout.addWidget(te)\n" +" layout.addWidget(self.work_button)\n" +" layout.addWidget(self.log_button)\n" +" layout.addWidget(self.clear_button)\n" +" self.setFixedSize(900, 400)\n" +"\n" +" # Connect the non-worker slots and signals\n" +" self.log_button.clicked.connect(self.manual_update)\n" +" self.clear_button.clicked.connect(self.clear_display)\n" +"\n" +" # Start a new worker thread and connect the slots for the worker\n" +" self.start_thread()\n" +" self.work_button.clicked.connect(self.worker.start)\n" +" # Once started, the button should be disabled\n" +" self.work_button.clicked.connect(lambda : self.work_button." +"setEnabled(False))\n" +"\n" +" def start_thread(self):\n" +" self.worker = Worker()\n" +" self.worker_thread = QtCore.QThread()\n" +" self.worker.setObjectName('Worker')\n" +" self.worker_thread.setObjectName('WorkerThread') # for qThreadName\n" +" self.worker.moveToThread(self.worker_thread)\n" +" # This will start an event loop in the worker thread\n" +" self.worker_thread.start()\n" +"\n" +" def kill_thread(self):\n" +" # Just tell the worker to stop, then tell it to quit and wait for " +"that\n" +" # to happen\n" +" self.worker_thread.requestInterruption()\n" +" if self.worker_thread.isRunning():\n" +" self.worker_thread.quit()\n" +" self.worker_thread.wait()\n" +" else:\n" +" print('worker has already exited.')\n" +"\n" +" def force_quit(self):\n" +" # For use when the window is closed\n" +" if self.worker_thread.isRunning():\n" +" self.kill_thread()\n" +"\n" +" # The functions below update the UI and run in the main thread because\n" +" # that's where the slots are set up\n" +"\n" +" @Slot(str, logging.LogRecord)\n" +" def update_status(self, status, record):\n" +" color = self.COLORS.get(record.levelno, 'black')\n" +" s = '
%s
' % (color, status)\n" +" self.textedit.appendHtml(s)\n" +"\n" +" @Slot()\n" +" def manual_update(self):\n" +" # This function uses the formatted message passed in, but also uses\n" +" # information from the record to format the message in an " +"appropriate\n" +" # color according to its severity (level).\n" +" level = random.choice(LEVELS)\n" +" extra = {'qThreadName': ctname() }\n" +" logger.log(level, 'Manually logged!', extra=extra)\n" +"\n" +" @Slot()\n" +" def clear_display(self):\n" +" self.textedit.clear()\n" +"\n" +"\n" +"def main():\n" +" QtCore.QThread.currentThread().setObjectName('MainThread')\n" +" logging.getLogger().setLevel(logging.DEBUG)\n" +" app = QtWidgets.QApplication(sys.argv)\n" +" example = Window(app)\n" +" example.show()\n" +" if hasattr(app, 'exec'):\n" +" rc = app.exec()\n" +" else:\n" +" rc = app.exec_()\n" +" sys.exit(rc)\n" +"\n" +"if __name__=='__main__':\n" +" main()" +msgstr "" + #: ../../howto/logging-cookbook.rst:3829 msgid "Logging to syslog with RFC5424 support" msgstr "" @@ -1886,6 +4769,76 @@ msgid "" "you can do so with a subclassed handler which looks something like this::" msgstr "" +#: ../../howto/logging-cookbook.rst:3842 +msgid "" +"import datetime\n" +"import logging.handlers\n" +"import re\n" +"import socket\n" +"import time\n" +"\n" +"class SysLogHandler5424(logging.handlers.SysLogHandler):\n" +"\n" +" tz_offset = re.compile(r'([+-]\\d{2})(\\d{2})$')\n" +" escaped = re.compile(r'([\\]\"\\\\])')\n" +"\n" +" def __init__(self, *args, **kwargs):\n" +" self.msgid = kwargs.pop('msgid', None)\n" +" self.appname = kwargs.pop('appname', None)\n" +" super().__init__(*args, **kwargs)\n" +"\n" +" def format(self, record):\n" +" version = 1\n" +" asctime = datetime.datetime.fromtimestamp(record.created)." +"isoformat()\n" +" m = self.tz_offset.match(time.strftime('%z'))\n" +" has_offset = False\n" +" if m and time.timezone:\n" +" hrs, mins = m.groups()\n" +" if int(hrs) or int(mins):\n" +" has_offset = True\n" +" if not has_offset:\n" +" asctime += 'Z'\n" +" else:\n" +" asctime += f'{hrs}:{mins}'\n" +" try:\n" +" hostname = socket.gethostname()\n" +" except Exception:\n" +" hostname = '-'\n" +" appname = self.appname or '-'\n" +" procid = record.process\n" +" msgid = '-'\n" +" msg = super().format(record)\n" +" sdata = '-'\n" +" if hasattr(record, 'structured_data'):\n" +" sd = record.structured_data\n" +" # This should be a dict where the keys are SD-ID and the value " +"is a\n" +" # dict mapping PARAM-NAME to PARAM-VALUE (refer to the RFC for " +"what these\n" +" # mean)\n" +" # There's no error checking here - it's purely for illustration, " +"and you\n" +" # can adapt this code for use in production environments\n" +" parts = []\n" +"\n" +" def replacer(m):\n" +" g = m.groups()\n" +" return '\\\\' + g[0]\n" +"\n" +" for sdid, dv in sd.items():\n" +" part = f'[{sdid}'\n" +" for k, v in dv.items():\n" +" s = str(v)\n" +" s = self.escaped.sub(replacer, s)\n" +" part += f' {k}=\"{s}\"'\n" +" part += ']'\n" +" parts.append(part)\n" +" sdata = ''.join(parts)\n" +" return f'{version} {asctime} {hostname} {appname} {procid} {msgid} " +"{sdata} {msg}'" +msgstr "" + #: ../../howto/logging-cookbook.rst:3904 msgid "" "You'll need to be familiar with RFC 5424 to fully understand the above code, " @@ -1895,6 +4848,17 @@ msgid "" "using something like this::" msgstr "" +#: ../../howto/logging-cookbook.rst:3909 +msgid "" +"sd = {\n" +" 'foo@12345': {'bar': 'baz', 'baz': 'bozz', 'fizz': r'buzz'},\n" +" 'foo@54321': {'rab': 'baz', 'zab': 'bozz', 'zzif': r'buzz'}\n" +"}\n" +"extra = {'structured_data': sd}\n" +"i = 1\n" +"logger.debug('Message %d', i, extra=extra)" +msgstr "" + #: ../../howto/logging-cookbook.rst:3918 msgid "How to treat a logger like an output stream" msgstr "" @@ -1907,16 +4871,68 @@ msgid "" "API. Here's a short script illustrating such a class:" msgstr "" +#: ../../howto/logging-cookbook.rst:3925 +msgid "" +"import logging\n" +"\n" +"class LoggerWriter:\n" +" def __init__(self, logger, level):\n" +" self.logger = logger\n" +" self.level = level\n" +"\n" +" def write(self, message):\n" +" if message != '\\n': # avoid printing bare newlines, if you like\n" +" self.logger.log(self.level, message)\n" +"\n" +" def flush(self):\n" +" # doesn't actually do anything, but might be expected of a file-" +"like\n" +" # object - so optional depending on your situation\n" +" pass\n" +"\n" +" def close(self):\n" +" # doesn't actually do anything, but might be expected of a file-" +"like\n" +" # object - so optional depending on your situation. You might want\n" +" # to set a flag so that later calls to write raise an exception\n" +" pass\n" +"\n" +"def main():\n" +" logging.basicConfig(level=logging.DEBUG)\n" +" logger = logging.getLogger('demo')\n" +" info_fp = LoggerWriter(logger, logging.INFO)\n" +" debug_fp = LoggerWriter(logger, logging.DEBUG)\n" +" print('An INFO message', file=info_fp)\n" +" print('A DEBUG message', file=debug_fp)\n" +"\n" +"if __name__ == \"__main__\":\n" +" main()" +msgstr "" + #: ../../howto/logging-cookbook.rst:3960 msgid "When this script is run, it prints" msgstr "" +#: ../../howto/logging-cookbook.rst:3962 +msgid "" +"INFO:demo:An INFO message\n" +"DEBUG:demo:A DEBUG message" +msgstr "" + #: ../../howto/logging-cookbook.rst:3967 msgid "" "You could also use ``LoggerWriter`` to redirect ``sys.stdout`` and ``sys." "stderr`` by doing something like this:" msgstr "" +#: ../../howto/logging-cookbook.rst:3970 +msgid "" +"import sys\n" +"\n" +"sys.stdout = LoggerWriter(logger, logging.INFO)\n" +"sys.stderr = LoggerWriter(logger, logging.WARNING)" +msgstr "" + #: ../../howto/logging-cookbook.rst:3977 msgid "" "You should do this *after* configuring logging for your needs. In the above " @@ -1925,6 +4941,15 @@ msgid "" "Then, you'd get this kind of result:" msgstr "" +#: ../../howto/logging-cookbook.rst:3982 +msgid "" +">>> print('Foo')\n" +"INFO:demo:Foo\n" +">>> print('Bar', file=sys.stderr)\n" +"WARNING:demo:Bar\n" +">>>" +msgstr "" + #: ../../howto/logging-cookbook.rst:3990 msgid "" "Of course, the examples above show output according to the format used by :" @@ -1939,10 +4964,35 @@ msgid "" "with the definition of ``LoggerWriter`` above, if you have the snippet" msgstr "" +#: ../../howto/logging-cookbook.rst:3998 +msgid "" +"sys.stderr = LoggerWriter(logger, logging.WARNING)\n" +"1 / 0" +msgstr "" + #: ../../howto/logging-cookbook.rst:4003 msgid "then running the script results in" msgstr "" +#: ../../howto/logging-cookbook.rst:4005 +msgid "" +"WARNING:demo:Traceback (most recent call last):\n" +"\n" +"WARNING:demo: File \"/home/runner/cookbook-loggerwriter/test.py\", line 53, " +"in \n" +"\n" +"WARNING:demo:\n" +"WARNING:demo:main()\n" +"WARNING:demo: File \"/home/runner/cookbook-loggerwriter/test.py\", line 49, " +"in main\n" +"\n" +"WARNING:demo:\n" +"WARNING:demo:1 / 0\n" +"WARNING:demo:ZeroDivisionError\n" +"WARNING:demo::\n" +"WARNING:demo:division by zero" +msgstr "" + #: ../../howto/logging-cookbook.rst:4021 msgid "" "As you can see, this output isn't ideal. That's because the underlying code " @@ -1953,12 +5003,44 @@ msgid "" "``LoggerWriter``:" msgstr "" +#: ../../howto/logging-cookbook.rst:4027 +msgid "" +"class BufferingLoggerWriter(LoggerWriter):\n" +" def __init__(self, logger, level):\n" +" super().__init__(logger, level)\n" +" self.buffer = ''\n" +"\n" +" def write(self, message):\n" +" if '\\n' not in message:\n" +" self.buffer += message\n" +" else:\n" +" parts = message.split('\\n')\n" +" if self.buffer:\n" +" s = self.buffer + parts.pop(0)\n" +" self.logger.log(self.level, s)\n" +" self.buffer = parts.pop()\n" +" for part in parts:\n" +" self.logger.log(self.level, part)" +msgstr "" + #: ../../howto/logging-cookbook.rst:4046 msgid "" "This just buffers up stuff until a newline is seen, and then logs complete " "lines. With this approach, you get better output:" msgstr "" +#: ../../howto/logging-cookbook.rst:4049 +msgid "" +"WARNING:demo:Traceback (most recent call last):\n" +"WARNING:demo: File \"/home/runner/cookbook-loggerwriter/main.py\", line 55, " +"in \n" +"WARNING:demo: main()\n" +"WARNING:demo: File \"/home/runner/cookbook-loggerwriter/main.py\", line 52, " +"in main\n" +"WARNING:demo: 1/0\n" +"WARNING:demo:ZeroDivisionError: division by zero" +msgstr "" + #: ../../howto/logging-cookbook.rst:4062 msgid "Patterns to avoid" msgstr "" diff --git a/howto/logging.po b/howto/logging.po index bb744e4c00..d77740862c 100644 --- a/howto/logging.po +++ b/howto/logging.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-07-04 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2018-05-23 14:36+0000\n" "Last-Translator: Adrian Liaw \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -143,7 +143,7 @@ msgid "" "below (in increasing order of severity):" msgstr "" -#: ../../howto/logging.rst:75 ../../howto/logging.rst:870 +#: ../../howto/logging.rst:75 ../../howto/logging.rst:874 msgid "Level" msgstr "" @@ -151,7 +151,7 @@ msgstr "" msgid "When it's used" msgstr "" -#: ../../howto/logging.rst:77 ../../howto/logging.rst:880 +#: ../../howto/logging.rst:77 ../../howto/logging.rst:884 msgid "``DEBUG``" msgstr "``DEBUG``" @@ -160,7 +160,7 @@ msgid "" "Detailed information, typically of interest only when diagnosing problems." msgstr "" -#: ../../howto/logging.rst:80 ../../howto/logging.rst:878 +#: ../../howto/logging.rst:80 ../../howto/logging.rst:882 msgid "``INFO``" msgstr "``INFO``" @@ -168,7 +168,7 @@ msgstr "``INFO``" msgid "Confirmation that things are working as expected." msgstr "" -#: ../../howto/logging.rst:83 ../../howto/logging.rst:876 +#: ../../howto/logging.rst:83 ../../howto/logging.rst:880 msgid "``WARNING``" msgstr "``WARNING``" @@ -179,7 +179,7 @@ msgid "" "working as expected." msgstr "" -#: ../../howto/logging.rst:88 ../../howto/logging.rst:874 +#: ../../howto/logging.rst:88 ../../howto/logging.rst:878 msgid "``ERROR``" msgstr "``ERROR``" @@ -189,7 +189,7 @@ msgid "" "some function." msgstr "" -#: ../../howto/logging.rst:91 ../../howto/logging.rst:872 +#: ../../howto/logging.rst:91 ../../howto/logging.rst:876 msgid "``CRITICAL``" msgstr "``CRITICAL``" @@ -221,10 +221,21 @@ msgstr "一個簡單範例" msgid "A very simple example is::" msgstr "一個非常簡單的例子是: ::" +#: ../../howto/logging.rst:111 +msgid "" +"import logging\n" +"logging.warning('Watch out!') # will print a message to the console\n" +"logging.info('I told you so') # will not print anything" +msgstr "" + #: ../../howto/logging.rst:115 msgid "If you type these lines into a script and run it, you'll see:" msgstr "" +#: ../../howto/logging.rst:117 +msgid "WARNING:root:Watch out!" +msgstr "" + #: ../../howto/logging.rst:121 msgid "" "printed out on the console. The ``INFO`` message doesn't appear because the " @@ -258,6 +269,18 @@ msgid "" "above::" msgstr "" +#: ../../howto/logging.rst:142 +msgid "" +"import logging\n" +"logger = logging.getLogger(__name__)\n" +"logging.basicConfig(filename='example.log', encoding='utf-8', level=logging." +"DEBUG)\n" +"logger.debug('This message should go to the log file')\n" +"logger.info('So should this')\n" +"logger.warning('And this, too')\n" +"logger.error('And non-ASCII stuff, too, like Øresund and Malmö')" +msgstr "" + #: ../../howto/logging.rst:150 msgid "" "The *encoding* argument was added. In earlier Python versions, or if not " @@ -273,6 +296,14 @@ msgid "" "messages:" msgstr "" +#: ../../howto/logging.rst:160 +msgid "" +"DEBUG:__main__:This message should go to the log file\n" +"INFO:__main__:So should this\n" +"WARNING:__main__:And this, too\n" +"ERROR:__main__:And non-ASCII stuff, too, like Øresund and Malmö" +msgstr "" + #: ../../howto/logging.rst:167 msgid "" "This example also shows how you can set the logging level which acts as the " @@ -285,12 +316,20 @@ msgid "" "If you want to set the logging level from a command-line option such as:" msgstr "" +#: ../../howto/logging.rst:173 +msgid "--log=INFO" +msgstr "" + #: ../../howto/logging.rst:177 msgid "" "and you have the value of the parameter passed for ``--log`` in some " "variable *loglevel*, you can use::" msgstr "" +#: ../../howto/logging.rst:180 +msgid "getattr(logging, loglevel.upper())" +msgstr "" + #: ../../howto/logging.rst:182 msgid "" "to get the value which you'll pass to :func:`basicConfig` via the *level* " @@ -298,6 +337,17 @@ msgid "" "the following example::" msgstr "" +#: ../../howto/logging.rst:186 +msgid "" +"# assuming loglevel is bound to the string value obtained from the\n" +"# command line argument. Convert to upper case to allow the user to\n" +"# specify --log=DEBUG or --log=debug\n" +"numeric_level = getattr(logging, loglevel.upper(), None)\n" +"if not isinstance(numeric_level, int):\n" +" raise ValueError('Invalid log level: %s' % loglevel)\n" +"logging.basicConfig(level=numeric_level, ...)" +msgstr "" + #: ../../howto/logging.rst:194 msgid "" "The call to :func:`basicConfig` should come *before* any calls to a logger's " @@ -313,6 +363,12 @@ msgid "" "*filemode* argument, by changing the call in the above example to::" msgstr "" +#: ../../howto/logging.rst:203 +msgid "" +"logging.basicConfig(filename='example.log', filemode='w', level=logging." +"DEBUG)" +msgstr "" + #: ../../howto/logging.rst:205 msgid "" "The output will be the same as before, but the log file is no longer " @@ -329,10 +385,20 @@ msgid "" "and append the variable data as arguments. For example::" msgstr "" +#: ../../howto/logging.rst:215 +msgid "" +"import logging\n" +"logging.warning('%s before you %s', 'Look', 'leap!')" +msgstr "" + #: ../../howto/logging.rst:218 msgid "will display:" msgstr "" +#: ../../howto/logging.rst:220 +msgid "WARNING:root:Look before you leap!" +msgstr "" + #: ../../howto/logging.rst:224 msgid "" "As you can see, merging of variable data into the event description message " @@ -353,10 +419,27 @@ msgid "" "the format you want to use::" msgstr "" +#: ../../howto/logging.rst:238 +msgid "" +"import logging\n" +"logging.basicConfig(format='%(levelname)s:%(message)s', level=logging." +"DEBUG)\n" +"logging.debug('This message should appear on the console')\n" +"logging.info('So should this')\n" +"logging.warning('And this, too')" +msgstr "" + #: ../../howto/logging.rst:244 msgid "which would print:" msgstr "" +#: ../../howto/logging.rst:246 +msgid "" +"DEBUG:This message should appear on the console\n" +"INFO:So should this\n" +"WARNING:And this, too" +msgstr "" + #: ../../howto/logging.rst:252 msgid "" "Notice that the 'root' which appeared in earlier examples has disappeared. " @@ -377,10 +460,21 @@ msgid "" "your format string::" msgstr "" +#: ../../howto/logging.rst:266 +msgid "" +"import logging\n" +"logging.basicConfig(format='%(asctime)s %(message)s')\n" +"logging.warning('is when this event was logged.')" +msgstr "" + #: ../../howto/logging.rst:270 msgid "which should print something like this:" msgstr "" +#: ../../howto/logging.rst:272 +msgid "2010-12-12 11:41:42,612 is when this event was logged." +msgstr "" + #: ../../howto/logging.rst:276 msgid "" "The default format for date/time display (shown above) is like ISO8601 or :" @@ -388,10 +482,22 @@ msgid "" "provide a *datefmt* argument to ``basicConfig``, as in this example::" msgstr "" +#: ../../howto/logging.rst:280 +msgid "" +"import logging\n" +"logging.basicConfig(format='%(asctime)s %(message)s', datefmt='%m/%d/%Y %I:" +"%M:%S %p')\n" +"logging.warning('is when this event was logged.')" +msgstr "" + #: ../../howto/logging.rst:284 msgid "which would display something like this:" msgstr "" +#: ../../howto/logging.rst:286 +msgid "12/12/2010 11:46:36 AM is when this event was logged." +msgstr "" + #: ../../howto/logging.rst:290 msgid "" "The format of the *datefmt* argument is the same as supported by :func:`time." @@ -480,6 +586,10 @@ msgid "" "logger, in each module which uses logging, named as follows::" msgstr "" +#: ../../howto/logging.rst:342 +msgid "logger = logging.getLogger(__name__)" +msgstr "" + #: ../../howto/logging.rst:344 msgid "" "This means that logger names track the package/module hierarchy, and it's " @@ -522,6 +632,10 @@ msgstr "" msgid "The default format set by :func:`basicConfig` for messages is:" msgstr "" +#: ../../howto/logging.rst:370 +msgid "severity:logger name:message" +msgstr "" + #: ../../howto/logging.rst:374 msgid "" "You can change this by passing a format string to :func:`basicConfig` with " @@ -539,11 +653,11 @@ msgid "" "the following diagram." msgstr "" -#: ../../howto/logging.rst:428 +#: ../../howto/logging.rst:432 msgid "Loggers" msgstr "" -#: ../../howto/logging.rst:430 +#: ../../howto/logging.rst:434 msgid "" ":class:`Logger` objects have a threefold job. First, they expose several " "methods to application code so that applications can log messages at " @@ -553,17 +667,17 @@ msgid "" "handlers." msgstr "" -#: ../../howto/logging.rst:436 +#: ../../howto/logging.rst:440 msgid "" "The most widely used methods on logger objects fall into two categories: " "configuration and message sending." msgstr "" -#: ../../howto/logging.rst:439 +#: ../../howto/logging.rst:443 msgid "These are the most common configuration methods:" msgstr "" -#: ../../howto/logging.rst:441 +#: ../../howto/logging.rst:445 msgid "" ":meth:`Logger.setLevel` specifies the lowest-severity log message a logger " "will handle, where debug is the lowest built-in severity level and critical " @@ -572,32 +686,32 @@ msgid "" "messages and will ignore DEBUG messages." msgstr "" -#: ../../howto/logging.rst:447 +#: ../../howto/logging.rst:451 msgid "" ":meth:`Logger.addHandler` and :meth:`Logger.removeHandler` add and remove " "handler objects from the logger object. Handlers are covered in more detail " "in :ref:`handler-basic`." msgstr "" -#: ../../howto/logging.rst:451 +#: ../../howto/logging.rst:455 msgid "" ":meth:`Logger.addFilter` and :meth:`Logger.removeFilter` add and remove " "filter objects from the logger object. Filters are covered in more detail " "in :ref:`filter`." msgstr "" -#: ../../howto/logging.rst:455 +#: ../../howto/logging.rst:459 msgid "" "You don't need to always call these methods on every logger you create. See " "the last two paragraphs in this section." msgstr "" -#: ../../howto/logging.rst:458 +#: ../../howto/logging.rst:462 msgid "" "With the logger object configured, the following methods create log messages:" msgstr "" -#: ../../howto/logging.rst:460 +#: ../../howto/logging.rst:464 msgid "" ":meth:`Logger.debug`, :meth:`Logger.info`, :meth:`Logger.warning`, :meth:" "`Logger.error`, and :meth:`Logger.critical` all create log records with a " @@ -610,14 +724,14 @@ msgid "" "exception information." msgstr "" -#: ../../howto/logging.rst:470 +#: ../../howto/logging.rst:474 msgid "" ":meth:`Logger.exception` creates a log message similar to :meth:`Logger." "error`. The difference is that :meth:`Logger.exception` dumps a stack trace " "along with it. Call this method only from an exception handler." msgstr "" -#: ../../howto/logging.rst:474 +#: ../../howto/logging.rst:478 msgid "" ":meth:`Logger.log` takes a log level as an explicit argument. This is a " "little more verbose for logging messages than using the log level " @@ -625,7 +739,7 @@ msgid "" "levels." msgstr "" -#: ../../howto/logging.rst:478 +#: ../../howto/logging.rst:482 msgid "" ":func:`getLogger` returns a reference to a logger instance with the " "specified name if it is provided, or ``root`` if not. The names are period-" @@ -637,7 +751,7 @@ msgid "" "descendants of ``foo``." msgstr "" -#: ../../howto/logging.rst:486 +#: ../../howto/logging.rst:490 msgid "" "Loggers have a concept of *effective level*. If a level is not explicitly " "set on a logger, the level of its parent is used instead as its effective " @@ -649,7 +763,7 @@ msgid "" "handlers." msgstr "" -#: ../../howto/logging.rst:494 +#: ../../howto/logging.rst:498 msgid "" "Child loggers propagate messages up to the handlers associated with their " "ancestor loggers. Because of this, it is unnecessary to define and configure " @@ -659,11 +773,11 @@ msgid "" "attribute of a logger to ``False``.)" msgstr "" -#: ../../howto/logging.rst:505 +#: ../../howto/logging.rst:509 msgid "Handlers" msgstr "" -#: ../../howto/logging.rst:507 +#: ../../howto/logging.rst:511 msgid "" ":class:`~logging.Handler` objects are responsible for dispatching the " "appropriate log messages (based on the log messages' severity) to the " @@ -676,14 +790,14 @@ msgid "" "of a specific severity to a specific location." msgstr "" -#: ../../howto/logging.rst:517 +#: ../../howto/logging.rst:521 msgid "" "The standard library includes quite a few handler types (see :ref:`useful-" "handlers`); the tutorials use mainly :class:`StreamHandler` and :class:" "`FileHandler` in its examples." msgstr "" -#: ../../howto/logging.rst:521 +#: ../../howto/logging.rst:525 msgid "" "There are very few methods in a handler for application developers to " "concern themselves with. The only handler methods that seem relevant for " @@ -691,7 +805,7 @@ msgid "" "not creating custom handlers) are the following configuration methods:" msgstr "" -#: ../../howto/logging.rst:526 +#: ../../howto/logging.rst:530 msgid "" "The :meth:`~Handler.setLevel` method, just as in logger objects, specifies " "the lowest severity that will be dispatched to the appropriate destination. " @@ -701,19 +815,19 @@ msgid "" "send on." msgstr "" -#: ../../howto/logging.rst:532 +#: ../../howto/logging.rst:536 msgid "" ":meth:`~Handler.setFormatter` selects a Formatter object for this handler to " "use." msgstr "" -#: ../../howto/logging.rst:535 +#: ../../howto/logging.rst:539 msgid "" ":meth:`~Handler.addFilter` and :meth:`~Handler.removeFilter` respectively " "configure and deconfigure filter objects on handlers." msgstr "" -#: ../../howto/logging.rst:538 +#: ../../howto/logging.rst:542 msgid "" "Application code should not directly instantiate and use instances of :class:" "`Handler`. Instead, the :class:`Handler` class is a base class that defines " @@ -721,11 +835,11 @@ msgid "" "behavior that child classes can use (or override)." msgstr "" -#: ../../howto/logging.rst:545 +#: ../../howto/logging.rst:549 msgid "Formatters" msgstr "" -#: ../../howto/logging.rst:547 +#: ../../howto/logging.rst:551 msgid "" "Formatter objects configure the final order, structure, and contents of the " "log message. Unlike the base :class:`logging.Handler` class, application " @@ -735,20 +849,24 @@ msgid "" "string and a style indicator." msgstr "" -#: ../../howto/logging.rst:556 +#: ../../howto/logging.rst:560 msgid "" "If there is no message format string, the default is to use the raw " "message. If there is no date format string, the default date format is:" msgstr "" #: ../../howto/logging.rst:563 +msgid "%Y-%m-%d %H:%M:%S" +msgstr "" + +#: ../../howto/logging.rst:567 msgid "" "with the milliseconds tacked on at the end. The ``style`` is one of ``'%'``, " "``'{'``, or ``'$'``. If one of these is not specified, then ``'%'`` will be " "used." msgstr "" -#: ../../howto/logging.rst:566 +#: ../../howto/logging.rst:570 msgid "" "If the ``style`` is ``'%'``, the message format string uses ``%()s`` styled string substitution; the possible keys are documented in :" @@ -758,18 +876,22 @@ msgid "" "should conform to what is expected by :meth:`string.Template.substitute`." msgstr "" -#: ../../howto/logging.rst:573 +#: ../../howto/logging.rst:577 msgid "Added the ``style`` parameter." msgstr "新增 ``style`` 參數。" -#: ../../howto/logging.rst:576 +#: ../../howto/logging.rst:580 msgid "" "The following message format string will log the time in a human-readable " "format, the severity of the message, and the contents of the message, in " "that order::" msgstr "" -#: ../../howto/logging.rst:582 +#: ../../howto/logging.rst:584 +msgid "'%(asctime)s - %(levelname)s - %(message)s'" +msgstr "" + +#: ../../howto/logging.rst:586 msgid "" "Formatters use a user-configurable function to convert the creation time of " "a record to a tuple. By default, :func:`time.localtime` is used; to change " @@ -780,68 +902,167 @@ msgid "" "in the Formatter class (to ``time.gmtime`` for GMT display)." msgstr "" -#: ../../howto/logging.rst:592 +#: ../../howto/logging.rst:596 msgid "Configuring Logging" msgstr "" -#: ../../howto/logging.rst:596 +#: ../../howto/logging.rst:600 msgid "Programmers can configure logging in three ways:" msgstr "" -#: ../../howto/logging.rst:598 +#: ../../howto/logging.rst:602 msgid "" "Creating loggers, handlers, and formatters explicitly using Python code that " "calls the configuration methods listed above." msgstr "" -#: ../../howto/logging.rst:600 +#: ../../howto/logging.rst:604 msgid "" "Creating a logging config file and reading it using the :func:`fileConfig` " "function." msgstr "" -#: ../../howto/logging.rst:602 +#: ../../howto/logging.rst:606 msgid "" "Creating a dictionary of configuration information and passing it to the :" "func:`dictConfig` function." msgstr "" -#: ../../howto/logging.rst:605 +#: ../../howto/logging.rst:609 msgid "" "For the reference documentation on the last two options, see :ref:`logging-" "config-api`. The following example configures a very simple logger, a " "console handler, and a simple formatter using Python code::" msgstr "" -#: ../../howto/logging.rst:635 +#: ../../howto/logging.rst:613 +msgid "" +"import logging\n" +"\n" +"# create logger\n" +"logger = logging.getLogger('simple_example')\n" +"logger.setLevel(logging.DEBUG)\n" +"\n" +"# create console handler and set level to debug\n" +"ch = logging.StreamHandler()\n" +"ch.setLevel(logging.DEBUG)\n" +"\n" +"# create formatter\n" +"formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - " +"%(message)s')\n" +"\n" +"# add formatter to ch\n" +"ch.setFormatter(formatter)\n" +"\n" +"# add ch to logger\n" +"logger.addHandler(ch)\n" +"\n" +"# 'application' code\n" +"logger.debug('debug message')\n" +"logger.info('info message')\n" +"logger.warning('warn message')\n" +"logger.error('error message')\n" +"logger.critical('critical message')" +msgstr "" + +#: ../../howto/logging.rst:639 msgid "" "Running this module from the command line produces the following output:" msgstr "" -#: ../../howto/logging.rst:646 +#: ../../howto/logging.rst:641 +msgid "" +"$ python simple_logging_module.py\n" +"2005-03-19 15:10:26,618 - simple_example - DEBUG - debug message\n" +"2005-03-19 15:10:26,620 - simple_example - INFO - info message\n" +"2005-03-19 15:10:26,695 - simple_example - WARNING - warn message\n" +"2005-03-19 15:10:26,697 - simple_example - ERROR - error message\n" +"2005-03-19 15:10:26,773 - simple_example - CRITICAL - critical message" +msgstr "" + +#: ../../howto/logging.rst:650 msgid "" "The following Python module creates a logger, handler, and formatter nearly " "identical to those in the example listed above, with the only difference " "being the names of the objects::" msgstr "" -#: ../../howto/logging.rst:665 +#: ../../howto/logging.rst:654 +msgid "" +"import logging\n" +"import logging.config\n" +"\n" +"logging.config.fileConfig('logging.conf')\n" +"\n" +"# create logger\n" +"logger = logging.getLogger('simpleExample')\n" +"\n" +"# 'application' code\n" +"logger.debug('debug message')\n" +"logger.info('info message')\n" +"logger.warning('warn message')\n" +"logger.error('error message')\n" +"logger.critical('critical message')" +msgstr "" + +#: ../../howto/logging.rst:669 msgid "Here is the logging.conf file:" msgstr "" -#: ../../howto/logging.rst:697 +#: ../../howto/logging.rst:671 +msgid "" +"[loggers]\n" +"keys=root,simpleExample\n" +"\n" +"[handlers]\n" +"keys=consoleHandler\n" +"\n" +"[formatters]\n" +"keys=simpleFormatter\n" +"\n" +"[logger_root]\n" +"level=DEBUG\n" +"handlers=consoleHandler\n" +"\n" +"[logger_simpleExample]\n" +"level=DEBUG\n" +"handlers=consoleHandler\n" +"qualname=simpleExample\n" +"propagate=0\n" +"\n" +"[handler_consoleHandler]\n" +"class=StreamHandler\n" +"level=DEBUG\n" +"formatter=simpleFormatter\n" +"args=(sys.stdout,)\n" +"\n" +"[formatter_simpleFormatter]\n" +"format=%(asctime)s - %(name)s - %(levelname)s - %(message)s" +msgstr "" + +#: ../../howto/logging.rst:701 msgid "" "The output is nearly identical to that of the non-config-file-based example:" msgstr "" -#: ../../howto/logging.rst:708 +#: ../../howto/logging.rst:703 +msgid "" +"$ python simple_logging_config.py\n" +"2005-03-19 15:38:55,977 - simpleExample - DEBUG - debug message\n" +"2005-03-19 15:38:55,979 - simpleExample - INFO - info message\n" +"2005-03-19 15:38:56,054 - simpleExample - WARNING - warn message\n" +"2005-03-19 15:38:56,055 - simpleExample - ERROR - error message\n" +"2005-03-19 15:38:56,130 - simpleExample - CRITICAL - critical message" +msgstr "" + +#: ../../howto/logging.rst:712 msgid "" "You can see that the config file approach has a few advantages over the " "Python code approach, mainly separation of configuration and code and the " "ability of noncoders to easily modify the logging properties." msgstr "" -#: ../../howto/logging.rst:712 +#: ../../howto/logging.rst:716 msgid "" "The :func:`fileConfig` function takes a default parameter, " "``disable_existing_loggers``, which defaults to ``True`` for reasons of " @@ -852,7 +1073,7 @@ msgid "" "information, and specify ``False`` for this parameter if you wish." msgstr "" -#: ../../howto/logging.rst:720 +#: ../../howto/logging.rst:724 msgid "" "The dictionary passed to :func:`dictConfig` can also specify a Boolean value " "with key ``disable_existing_loggers``, which if not specified explicitly in " @@ -861,7 +1082,7 @@ msgid "" "want - in which case, provide the key explicitly with a value of ``False``." msgstr "" -#: ../../howto/logging.rst:730 +#: ../../howto/logging.rst:734 msgid "" "Note that the class names referenced in config files need to be either " "relative to the logging module, or absolute values which can be resolved " @@ -872,7 +1093,7 @@ msgid "" "path)." msgstr "" -#: ../../howto/logging.rst:738 +#: ../../howto/logging.rst:742 msgid "" "In Python 3.2, a new means of configuring logging has been introduced, using " "dictionaries to hold configuration information. This provides a superset of " @@ -887,30 +1108,52 @@ msgid "" "a socket, or use whatever approach makes sense for your application." msgstr "" -#: ../../howto/logging.rst:750 +#: ../../howto/logging.rst:754 msgid "" "Here's an example of the same configuration as above, in YAML format for the " "new dictionary-based approach:" msgstr "" -#: ../../howto/logging.rst:774 +#: ../../howto/logging.rst:757 +msgid "" +"version: 1\n" +"formatters:\n" +" simple:\n" +" format: '%(asctime)s - %(name)s - %(levelname)s - %(message)s'\n" +"handlers:\n" +" console:\n" +" class: logging.StreamHandler\n" +" level: DEBUG\n" +" formatter: simple\n" +" stream: ext://sys.stdout\n" +"loggers:\n" +" simpleExample:\n" +" level: DEBUG\n" +" handlers: [console]\n" +" propagate: no\n" +"root:\n" +" level: DEBUG\n" +" handlers: [console]" +msgstr "" + +#: ../../howto/logging.rst:778 msgid "" "For more information about logging using a dictionary, see :ref:`logging-" "config-api`." msgstr "" -#: ../../howto/logging.rst:778 +#: ../../howto/logging.rst:782 msgid "What happens if no configuration is provided" msgstr "" -#: ../../howto/logging.rst:780 +#: ../../howto/logging.rst:784 msgid "" "If no logging configuration is provided, it is possible to have a situation " "where a logging event needs to be output, but no handlers can be found to " "output the event." msgstr "" -#: ../../howto/logging.rst:784 +#: ../../howto/logging.rst:788 msgid "" "The event is output using a 'handler of last resort', stored in :data:" "`lastResort`. This internal handler is not associated with any logger, and " @@ -922,32 +1165,32 @@ msgid "" "severities will be output." msgstr "" -#: ../../howto/logging.rst:795 +#: ../../howto/logging.rst:799 msgid "For versions of Python prior to 3.2, the behaviour is as follows:" msgstr "" -#: ../../howto/logging.rst:797 +#: ../../howto/logging.rst:801 msgid "" "If :data:`raiseExceptions` is ``False`` (production mode), the event is " "silently dropped." msgstr "" -#: ../../howto/logging.rst:800 +#: ../../howto/logging.rst:804 msgid "" "If :data:`raiseExceptions` is ``True`` (development mode), a message 'No " "handlers could be found for logger X.Y.Z' is printed once." msgstr "" -#: ../../howto/logging.rst:803 +#: ../../howto/logging.rst:807 msgid "" "To obtain the pre-3.2 behaviour, :data:`lastResort` can be set to ``None``." msgstr "" -#: ../../howto/logging.rst:809 +#: ../../howto/logging.rst:813 msgid "Configuring Logging for a Library" msgstr "" -#: ../../howto/logging.rst:811 +#: ../../howto/logging.rst:815 msgid "" "When developing a library which uses logging, you should take care to " "document how the library uses logging - for example, the names of loggers " @@ -958,7 +1201,7 @@ msgid "" "is regarded as the best default behaviour." msgstr "" -#: ../../howto/logging.rst:819 +#: ../../howto/logging.rst:823 msgid "" "If for some reason you *don't* want these messages printed in the absence of " "any logging configuration, you can attach a do-nothing handler to the top-" @@ -970,7 +1213,7 @@ msgid "" "to those handlers, as normal." msgstr "" -#: ../../howto/logging.rst:828 +#: ../../howto/logging.rst:832 msgid "" "A do-nothing handler is included in the logging package: :class:`~logging." "NullHandler` (since Python 3.1). An instance of this handler could be added " @@ -981,14 +1224,20 @@ msgid "" "etc. then the code::" msgstr "" -#: ../../howto/logging.rst:839 +#: ../../howto/logging.rst:840 +msgid "" +"import logging\n" +"logging.getLogger('foo').addHandler(logging.NullHandler())" +msgstr "" + +#: ../../howto/logging.rst:843 msgid "" "should have the desired effect. If an organisation produces a number of " "libraries, then the logger name specified can be 'orgname.foo' rather than " "just 'foo'." msgstr "" -#: ../../howto/logging.rst:843 +#: ../../howto/logging.rst:847 msgid "" "It is strongly advised that you *do not log to the root logger* in your " "library. Instead, use a logger with a unique and easily identifiable name, " @@ -998,7 +1247,7 @@ msgid "" "library as they wish." msgstr "" -#: ../../howto/logging.rst:850 +#: ../../howto/logging.rst:854 msgid "" "It is strongly advised that you *do not add any handlers other than* :class:" "`~logging.NullHandler` *to your library's loggers*. This is because the " @@ -1009,11 +1258,11 @@ msgid "" "carry out unit tests and deliver logs which suit their requirements." msgstr "" -#: ../../howto/logging.rst:861 +#: ../../howto/logging.rst:865 msgid "Logging Levels" msgstr "" -#: ../../howto/logging.rst:863 +#: ../../howto/logging.rst:867 msgid "" "The numeric values of logging levels are given in the following table. These " "are primarily of interest if you want to define your own levels, and need " @@ -1022,39 +1271,39 @@ msgid "" "value; the predefined name is lost." msgstr "" -#: ../../howto/logging.rst:870 +#: ../../howto/logging.rst:874 msgid "Numeric value" msgstr "" -#: ../../howto/logging.rst:872 +#: ../../howto/logging.rst:876 msgid "50" msgstr "50" -#: ../../howto/logging.rst:874 +#: ../../howto/logging.rst:878 msgid "40" msgstr "40" -#: ../../howto/logging.rst:876 +#: ../../howto/logging.rst:880 msgid "30" msgstr "30" -#: ../../howto/logging.rst:878 +#: ../../howto/logging.rst:882 msgid "20" msgstr "20" -#: ../../howto/logging.rst:880 +#: ../../howto/logging.rst:884 msgid "10" msgstr "10" -#: ../../howto/logging.rst:882 +#: ../../howto/logging.rst:886 msgid "``NOTSET``" msgstr "``NOTSET``" -#: ../../howto/logging.rst:882 +#: ../../howto/logging.rst:886 msgid "0" msgstr "0" -#: ../../howto/logging.rst:885 +#: ../../howto/logging.rst:889 msgid "" "Levels can also be associated with loggers, being set either by the " "developer or through loading a saved logging configuration. When a logging " @@ -1064,14 +1313,14 @@ msgid "" "basic mechanism controlling the verbosity of logging output." msgstr "" -#: ../../howto/logging.rst:892 +#: ../../howto/logging.rst:896 msgid "" "Logging messages are encoded as instances of the :class:`~logging.LogRecord` " "class. When a logger decides to actually log an event, a :class:`~logging." "LogRecord` instance is created from the logging message." msgstr "" -#: ../../howto/logging.rst:896 +#: ../../howto/logging.rst:900 msgid "" "Logging messages are subjected to a dispatch mechanism through the use of :" "dfn:`handlers`, which are instances of subclasses of the :class:`Handler` " @@ -1088,7 +1337,7 @@ msgid "" "at which point the passing to ancestor handlers stops)." msgstr "" -#: ../../howto/logging.rst:910 +#: ../../howto/logging.rst:914 msgid "" "Just as for loggers, handlers can have levels associated with them. A " "handler's level acts as a filter in the same way as a logger's level does. " @@ -1098,11 +1347,11 @@ msgid "" "`~Handler.emit`." msgstr "" -#: ../../howto/logging.rst:919 +#: ../../howto/logging.rst:923 msgid "Custom Levels" msgstr "" -#: ../../howto/logging.rst:921 +#: ../../howto/logging.rst:925 msgid "" "Defining your own levels is possible, but should not be necessary, as the " "existing levels have been chosen on the basis of practical experience. " @@ -1115,27 +1364,27 @@ msgid "" "given numeric value might mean different things for different libraries." msgstr "" -#: ../../howto/logging.rst:934 +#: ../../howto/logging.rst:938 msgid "Useful Handlers" msgstr "" -#: ../../howto/logging.rst:936 +#: ../../howto/logging.rst:940 msgid "" "In addition to the base :class:`Handler` class, many useful subclasses are " "provided:" msgstr "" -#: ../../howto/logging.rst:939 +#: ../../howto/logging.rst:943 msgid "" ":class:`StreamHandler` instances send messages to streams (file-like " "objects)." msgstr "" -#: ../../howto/logging.rst:942 +#: ../../howto/logging.rst:946 msgid ":class:`FileHandler` instances send messages to disk files." msgstr "" -#: ../../howto/logging.rst:944 +#: ../../howto/logging.rst:948 msgid "" ":class:`~handlers.BaseRotatingHandler` is the base class for handlers that " "rotate log files at a certain point. It is not meant to be instantiated " @@ -1143,61 +1392,61 @@ msgid "" "`~handlers.TimedRotatingFileHandler`." msgstr "" -#: ../../howto/logging.rst:949 +#: ../../howto/logging.rst:953 msgid "" ":class:`~handlers.RotatingFileHandler` instances send messages to disk " "files, with support for maximum log file sizes and log file rotation." msgstr "" -#: ../../howto/logging.rst:952 +#: ../../howto/logging.rst:956 msgid "" ":class:`~handlers.TimedRotatingFileHandler` instances send messages to disk " "files, rotating the log file at certain timed intervals." msgstr "" -#: ../../howto/logging.rst:955 +#: ../../howto/logging.rst:959 msgid "" ":class:`~handlers.SocketHandler` instances send messages to TCP/IP sockets. " "Since 3.4, Unix domain sockets are also supported." msgstr "" -#: ../../howto/logging.rst:958 +#: ../../howto/logging.rst:962 msgid "" ":class:`~handlers.DatagramHandler` instances send messages to UDP sockets. " "Since 3.4, Unix domain sockets are also supported." msgstr "" -#: ../../howto/logging.rst:961 +#: ../../howto/logging.rst:965 msgid "" ":class:`~handlers.SMTPHandler` instances send messages to a designated email " "address." msgstr "" -#: ../../howto/logging.rst:964 +#: ../../howto/logging.rst:968 msgid "" ":class:`~handlers.SysLogHandler` instances send messages to a Unix syslog " "daemon, possibly on a remote machine." msgstr "" -#: ../../howto/logging.rst:967 +#: ../../howto/logging.rst:971 msgid "" ":class:`~handlers.NTEventLogHandler` instances send messages to a Windows " "NT/2000/XP event log." msgstr "" -#: ../../howto/logging.rst:970 +#: ../../howto/logging.rst:974 msgid "" ":class:`~handlers.MemoryHandler` instances send messages to a buffer in " "memory, which is flushed whenever specific criteria are met." msgstr "" -#: ../../howto/logging.rst:973 +#: ../../howto/logging.rst:977 msgid "" ":class:`~handlers.HTTPHandler` instances send messages to an HTTP server " "using either ``GET`` or ``POST`` semantics." msgstr "" -#: ../../howto/logging.rst:976 +#: ../../howto/logging.rst:980 msgid "" ":class:`~handlers.WatchedFileHandler` instances watch the file they are " "logging to. If the file changes, it is closed and reopened using the file " @@ -1205,13 +1454,13 @@ msgid "" "support the underlying mechanism used." msgstr "" -#: ../../howto/logging.rst:981 +#: ../../howto/logging.rst:985 msgid "" ":class:`~handlers.QueueHandler` instances send messages to a queue, such as " "those implemented in the :mod:`queue` or :mod:`multiprocessing` modules." msgstr "" -#: ../../howto/logging.rst:984 +#: ../../howto/logging.rst:988 msgid "" ":class:`NullHandler` instances do nothing with error messages. They are used " "by library developers who want to use logging, but want to avoid the 'No " @@ -1220,15 +1469,15 @@ msgid "" "more information." msgstr "" -#: ../../howto/logging.rst:990 +#: ../../howto/logging.rst:994 msgid "The :class:`NullHandler` class." msgstr "" -#: ../../howto/logging.rst:993 +#: ../../howto/logging.rst:997 msgid "The :class:`~handlers.QueueHandler` class." msgstr "" -#: ../../howto/logging.rst:996 +#: ../../howto/logging.rst:1000 msgid "" "The :class:`NullHandler`, :class:`StreamHandler` and :class:`FileHandler` " "classes are defined in the core logging package. The other handlers are " @@ -1236,14 +1485,14 @@ msgid "" "module, :mod:`logging.config`, for configuration functionality.)" msgstr "" -#: ../../howto/logging.rst:1001 +#: ../../howto/logging.rst:1005 msgid "" "Logged messages are formatted for presentation through instances of the :" "class:`Formatter` class. They are initialized with a format string suitable " "for use with the % operator and a dictionary." msgstr "" -#: ../../howto/logging.rst:1005 +#: ../../howto/logging.rst:1009 msgid "" "For formatting multiple messages in a batch, instances of :class:" "`BufferingFormatter` can be used. In addition to the format string (which is " @@ -1251,7 +1500,7 @@ msgid "" "trailer format strings." msgstr "" -#: ../../howto/logging.rst:1010 +#: ../../howto/logging.rst:1014 msgid "" "When filtering based on logger level and/or handler level is not enough, " "instances of :class:`Filter` can be added to both :class:`Logger` and :class:" @@ -1261,18 +1510,18 @@ msgid "" "value, the message is not processed further." msgstr "" -#: ../../howto/logging.rst:1017 +#: ../../howto/logging.rst:1021 msgid "" "The basic :class:`Filter` functionality allows filtering by specific logger " "name. If this feature is used, messages sent to the named logger and its " "children are allowed through the filter, and all others dropped." msgstr "" -#: ../../howto/logging.rst:1025 +#: ../../howto/logging.rst:1029 msgid "Exceptions raised during logging" msgstr "" -#: ../../howto/logging.rst:1027 +#: ../../howto/logging.rst:1031 msgid "" "The logging package is designed to swallow exceptions which occur while " "logging in production. This is so that errors which occur while handling " @@ -1280,7 +1529,7 @@ msgid "" "errors - do not cause the application using logging to terminate prematurely." msgstr "" -#: ../../howto/logging.rst:1032 +#: ../../howto/logging.rst:1036 msgid "" ":class:`SystemExit` and :class:`KeyboardInterrupt` exceptions are never " "swallowed. Other exceptions which occur during the :meth:`~Handler.emit` " @@ -1288,7 +1537,7 @@ msgid "" "handleError` method." msgstr "" -#: ../../howto/logging.rst:1037 +#: ../../howto/logging.rst:1041 msgid "" "The default implementation of :meth:`~Handler.handleError` in :class:" "`Handler` checks to see if a module-level variable, :data:`raiseExceptions`, " @@ -1296,7 +1545,7 @@ msgid "" "the exception is swallowed." msgstr "" -#: ../../howto/logging.rst:1043 +#: ../../howto/logging.rst:1047 msgid "" "The default value of :data:`raiseExceptions` is ``True``. This is because " "during development, you typically want to be notified of any exceptions that " @@ -1304,11 +1553,11 @@ msgid "" "production usage." msgstr "" -#: ../../howto/logging.rst:1053 +#: ../../howto/logging.rst:1057 msgid "Using arbitrary objects as messages" msgstr "" -#: ../../howto/logging.rst:1055 +#: ../../howto/logging.rst:1059 msgid "" "In the preceding sections and examples, it has been assumed that the message " "passed when logging the event is a string. However, this is not the only " @@ -1320,11 +1569,11 @@ msgid "" "the wire." msgstr "" -#: ../../howto/logging.rst:1066 +#: ../../howto/logging.rst:1070 msgid "Optimization" msgstr "" -#: ../../howto/logging.rst:1068 +#: ../../howto/logging.rst:1072 msgid "" "Formatting of message arguments is deferred until it cannot be avoided. " "However, computing the arguments passed to the logging method can also be " @@ -1337,11 +1586,18 @@ msgstr "" #: ../../howto/logging.rst:1080 msgid "" +"if logger.isEnabledFor(logging.DEBUG):\n" +" logger.debug('Message with %s, %s', expensive_func1(),\n" +" expensive_func2())" +msgstr "" + +#: ../../howto/logging.rst:1084 +msgid "" "so that if the logger's threshold is set above ``DEBUG``, the calls to " "``expensive_func1`` and ``expensive_func2`` are never made." msgstr "" -#: ../../howto/logging.rst:1083 +#: ../../howto/logging.rst:1087 msgid "" "In some cases, :meth:`~Logger.isEnabledFor` can itself be more expensive " "than you'd like (e.g. for deeply nested loggers where an explicit level is " @@ -1353,7 +1609,7 @@ msgid "" "while the application is running (which is not all that common)." msgstr "" -#: ../../howto/logging.rst:1092 +#: ../../howto/logging.rst:1096 msgid "" "There are other optimizations which can be made for specific applications " "which need more precise control over what logging information is collected. " @@ -1361,94 +1617,94 @@ msgid "" "you don't need:" msgstr "" -#: ../../howto/logging.rst:1098 +#: ../../howto/logging.rst:1102 msgid "What you don't want to collect" msgstr "" -#: ../../howto/logging.rst:1098 +#: ../../howto/logging.rst:1102 msgid "How to avoid collecting it" msgstr "" -#: ../../howto/logging.rst:1100 +#: ../../howto/logging.rst:1104 msgid "Information about where calls were made from." msgstr "" -#: ../../howto/logging.rst:1100 +#: ../../howto/logging.rst:1104 msgid "" "Set ``logging._srcfile`` to ``None``. This avoids calling :func:`sys." "_getframe`, which may help to speed up your code in environments like PyPy " "(which can't speed up code that uses :func:`sys._getframe`)." msgstr "" -#: ../../howto/logging.rst:1106 +#: ../../howto/logging.rst:1110 msgid "Threading information." msgstr "" -#: ../../howto/logging.rst:1106 +#: ../../howto/logging.rst:1110 msgid "Set ``logging.logThreads`` to ``False``." msgstr "" -#: ../../howto/logging.rst:1108 +#: ../../howto/logging.rst:1112 msgid "Current process ID (:func:`os.getpid`)" msgstr "" -#: ../../howto/logging.rst:1108 +#: ../../howto/logging.rst:1112 msgid "Set ``logging.logProcesses`` to ``False``." msgstr "" -#: ../../howto/logging.rst:1110 +#: ../../howto/logging.rst:1114 msgid "" "Current process name when using ``multiprocessing`` to manage multiple " "processes." msgstr "" -#: ../../howto/logging.rst:1110 +#: ../../howto/logging.rst:1114 msgid "Set ``logging.logMultiprocessing`` to ``False``." msgstr "" -#: ../../howto/logging.rst:1113 +#: ../../howto/logging.rst:1117 msgid "Current :class:`asyncio.Task` name when using ``asyncio``." msgstr "" -#: ../../howto/logging.rst:1113 +#: ../../howto/logging.rst:1117 msgid "Set ``logging.logAsyncioTasks`` to ``False``." msgstr "" -#: ../../howto/logging.rst:1117 +#: ../../howto/logging.rst:1121 msgid "" "Also note that the core logging module only includes the basic handlers. If " "you don't import :mod:`logging.handlers` and :mod:`logging.config`, they " "won't take up any memory." msgstr "" -#: ../../howto/logging.rst:1124 +#: ../../howto/logging.rst:1128 msgid "Other resources" msgstr "" -#: ../../howto/logging.rst:1128 +#: ../../howto/logging.rst:1132 msgid "Module :mod:`logging`" msgstr ":mod:`logging` 模組" -#: ../../howto/logging.rst:1129 +#: ../../howto/logging.rst:1133 msgid "API reference for the logging module." msgstr "" -#: ../../howto/logging.rst:1131 +#: ../../howto/logging.rst:1135 msgid "Module :mod:`logging.config`" msgstr ":mod:`logging.config` 模組" -#: ../../howto/logging.rst:1132 +#: ../../howto/logging.rst:1136 msgid "Configuration API for the logging module." msgstr "" -#: ../../howto/logging.rst:1134 +#: ../../howto/logging.rst:1138 msgid "Module :mod:`logging.handlers`" msgstr ":mod:`logging.handlers` 模組" -#: ../../howto/logging.rst:1135 +#: ../../howto/logging.rst:1139 msgid "Useful handlers included with the logging module." msgstr "" -#: ../../howto/logging.rst:1137 +#: ../../howto/logging.rst:1141 msgid ":ref:`A logging cookbook `" msgstr "" diff --git a/howto/mro.po b/howto/mro.po index 73af9a2376..0d1daa6c6c 100644 --- a/howto/mro.po +++ b/howto/mro.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-05-27 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -181,6 +181,20 @@ msgid "" "for new style classes:" msgstr "" +#: ../../howto/mro.rst:120 +msgid "" +" -----------\n" +"| |\n" +"| O |\n" +"| / \\ |\n" +" - X Y /\n" +" | / | /\n" +" | / |/\n" +" A B\n" +" \\ /\n" +" ?" +msgstr "" + #: ../../howto/mro.rst:133 msgid "" "In this case, it is not possible to derive a new class C from A and B, since " @@ -206,6 +220,10 @@ msgid "" "following discussion. I will use the shortcut notation::" msgstr "" +#: ../../howto/mro.rst:148 +msgid "C1 C2 ... CN" +msgstr "" + #: ../../howto/mro.rst:150 msgid "to indicate the list of classes [C1, C2, ... , CN]." msgstr "" @@ -214,14 +232,26 @@ msgstr "" msgid "The *head* of the list is its first element::" msgstr "" +#: ../../howto/mro.rst:154 +msgid "head = C1" +msgstr "" + #: ../../howto/mro.rst:156 msgid "whereas the *tail* is the rest of the list::" msgstr "" +#: ../../howto/mro.rst:158 +msgid "tail = C2 ... CN." +msgstr "" + #: ../../howto/mro.rst:160 msgid "I shall also use the notation::" msgstr "" +#: ../../howto/mro.rst:162 +msgid "C + (C1 C2 ... CN) = C C1 C2 ... CN" +msgstr "" + #: ../../howto/mro.rst:164 msgid "to denote the sum of the lists [C] + [C1, C2, ... ,CN]." msgstr "" @@ -247,12 +277,20 @@ msgstr "" msgid "In symbolic notation::" msgstr "" +#: ../../howto/mro.rst:178 +msgid "L[C(B1 ... BN)] = C + merge(L[B1] ... L[BN], B1 ... BN)" +msgstr "" + #: ../../howto/mro.rst:180 msgid "" "In particular, if C is the ``object`` class, which has no parents, the " "linearization is trivial::" msgstr "" +#: ../../howto/mro.rst:183 +msgid "L[object] = object." +msgstr "" + #: ../../howto/mro.rst:185 msgid "" "However, in general one has to compute the merge according to the following " @@ -284,6 +322,10 @@ msgid "" "inheritance); in this case::" msgstr "" +#: ../../howto/mro.rst:205 +msgid "L[C(B)] = C + merge(L[B],B) = C + L[B]" +msgstr "" + #: ../../howto/mro.rst:207 msgid "" "However, in the case of multiple inheritance things are more cumbersome and " @@ -302,14 +344,51 @@ msgstr "" msgid "In this case the inheritance graph can be drawn as:" msgstr "" +#: ../../howto/mro.rst:226 +msgid "" +" 6\n" +" ---\n" +"Level 3 | O | (more general)\n" +" / --- \\\n" +" / | \\ |\n" +" / | \\ |\n" +" / | \\ |\n" +" --- --- --- |\n" +"Level 2 3 | D | 4| E | | F | 5 |\n" +" --- --- --- |\n" +" \\ \\ _ / | |\n" +" \\ / \\ _ | |\n" +" \\ / \\ | |\n" +" --- --- |\n" +"Level 1 1 | B | | C | 2 |\n" +" --- --- |\n" +" \\ / |\n" +" \\ / \\ /\n" +" ---\n" +"Level 0 0 | A | (more specialized)\n" +" ---" +msgstr "" + #: ../../howto/mro.rst:251 msgid "The linearizations of O,D,E and F are trivial::" msgstr "" +#: ../../howto/mro.rst:253 +msgid "" +"L[O] = O\n" +"L[D] = D O\n" +"L[E] = E O\n" +"L[F] = F O" +msgstr "" + #: ../../howto/mro.rst:258 msgid "The linearization of B can be computed as::" msgstr "" +#: ../../howto/mro.rst:260 +msgid "L[B] = B + merge(DO, EO, DE)" +msgstr "" + #: ../../howto/mro.rst:262 msgid "" "We see that D is a good head, therefore we take it and we are reduced to " @@ -319,14 +398,37 @@ msgid "" "reduced to compute ``merge(O,O)`` which gives O. Therefore::" msgstr "" +#: ../../howto/mro.rst:268 +msgid "L[B] = B D E O" +msgstr "" + #: ../../howto/mro.rst:270 msgid "Using the same procedure one finds::" msgstr "" +#: ../../howto/mro.rst:272 +msgid "" +"L[C] = C + merge(DO,FO,DF)\n" +" = C + D + merge(O,FO,F)\n" +" = C + D + F + merge(O,O)\n" +" = C D F O" +msgstr "" + #: ../../howto/mro.rst:277 msgid "Now we can compute::" msgstr "" +#: ../../howto/mro.rst:279 +msgid "" +"L[A] = A + merge(BDEO,CDFO,BC)\n" +" = A + B + merge(DEO,CDFO,C)\n" +" = A + B + C + merge(DEO,DFO)\n" +" = A + B + C + D + merge(EO,FO)\n" +" = A + B + C + D + E + merge(O,FO)\n" +" = A + B + C + D + E + F + merge(O,O)\n" +" = A B C D E F O" +msgstr "" + #: ../../howto/mro.rst:287 msgid "" "In this example, the linearization is ordered in a pretty nice way according " @@ -348,6 +450,31 @@ msgid "" "of the hierarchy:" msgstr "" +#: ../../howto/mro.rst:307 +msgid "" +" 6\n" +" ---\n" +"Level 3 | O |\n" +" / --- \\\n" +" / | \\\n" +" / | \\\n" +" / | \\\n" +" --- --- ---\n" +"Level 2 2 | E | 4 | D | | F | 5\n" +" --- --- ---\n" +" \\ / \\ /\n" +" \\ / \\ /\n" +" \\ / \\ /\n" +" --- ---\n" +"Level 1 1 | B | | C | 3\n" +" --- ---\n" +" \\ /\n" +" \\ /\n" +" ---\n" +"Level 0 0 | A |\n" +" ---" +msgstr "" + #: ../../howto/mro.rst:332 msgid "" "Notice that the class E, which is in the second level of the hierarchy, " @@ -369,12 +496,28 @@ msgid "" "to compute the linearizations of O, X, Y, A and B:" msgstr "" +#: ../../howto/mro.rst:349 +msgid "" +"L[O] = 0\n" +"L[X] = X O\n" +"L[Y] = Y O\n" +"L[A] = A X Y O\n" +"L[B] = B Y X O" +msgstr "" + #: ../../howto/mro.rst:357 msgid "" "However, it is impossible to compute the linearization for a class C that " "inherits from A and B::" msgstr "" +#: ../../howto/mro.rst:360 +msgid "" +"L[C] = C + merge(AXYO, BYXO, AB)\n" +" = C + A + merge(XYO, BYXO, B)\n" +" = C + A + B + merge(XYO, YXO)" +msgstr "" + #: ../../howto/mro.rst:364 msgid "" "At this point we cannot merge the lists XYO and YXO, since X is in the tail " @@ -405,6 +548,19 @@ msgstr "" msgid "with inheritance diagram" msgstr "" +#: ../../howto/mro.rst:386 +msgid "" +" O\n" +" |\n" +"(buy spam) F\n" +" | \\\n" +" | E (buy eggs)\n" +" | /\n" +" G\n" +"\n" +" (buy eggs or spam ?)" +msgstr "" + #: ../../howto/mro.rst:399 msgid "" "We see that class G inherits from F and E, with F *before* E: therefore we " @@ -419,6 +575,10 @@ msgid "" "Python 2.2 linearization of G::" msgstr "" +#: ../../howto/mro.rst:411 +msgid "L[G,P22]= G E F object # F *follows* E" +msgstr "" + #: ../../howto/mro.rst:413 msgid "" "One could argue that the reason why F follows E in the Python 2.2 " @@ -442,6 +602,10 @@ msgid "" "The reason for that is that the C3 algorithm fails when the merge::" msgstr "" +#: ../../howto/mro.rst:435 +msgid "merge(FO,EFO,FE)" +msgstr "" + #: ../../howto/mro.rst:437 msgid "" "cannot be computed, because F is in the tail of EFO and E is in the tail of " @@ -455,6 +619,18 @@ msgid "" "the MRO is GEF without any doubt." msgstr "" +#: ../../howto/mro.rst:444 +msgid "" +" O\n" +" |\n" +" F (spam)\n" +" / |\n" +"(eggs) E |\n" +" \\ |\n" +" G\n" +" (eggs, no doubt)" +msgstr "" + #: ../../howto/mro.rst:456 msgid "" "Python 2.3 forces the programmer to write good hierarchies (or, at least, " @@ -504,16 +680,37 @@ msgid "" "trivial, it is enough to look at the diamond diagram:" msgstr "" +#: ../../howto/mro.rst:489 +msgid "" +" C\n" +" / \\\n" +" / \\\n" +"A B\n" +" \\ /\n" +" \\ /\n" +" D" +msgstr "" + #: ../../howto/mro.rst:500 msgid "One easily discerns the inconsistency::" msgstr "" +#: ../../howto/mro.rst:502 +msgid "" +"L[B,P21] = B C # B precedes C : B's methods win\n" +"L[D,P21] = D A C B C # B follows C : C's methods win!" +msgstr "" + #: ../../howto/mro.rst:505 msgid "" "On the other hand, there are no problems with the Python 2.2 and 2.3 MROs, " "they give both::" msgstr "" +#: ../../howto/mro.rst:508 +msgid "L[D] = D A B C" +msgstr "" + #: ../../howto/mro.rst:510 msgid "" "Guido points out in his essay [#]_ that the classic MRO is not so bad in " @@ -536,12 +733,29 @@ msgid "" "diagram ;-) ::" msgstr "" +#: ../../howto/mro.rst:534 +msgid "" +"L[A] = A O\n" +"L[B] = B O\n" +"L[C] = C O\n" +"L[D] = D O\n" +"L[E] = E O\n" +"L[K1]= K1 A B C O\n" +"L[K2]= K2 D B E O\n" +"L[K3]= K3 D A O\n" +"L[Z] = Z K1 K2 K3 D A B C E O" +msgstr "" + #: ../../howto/mro.rst:544 msgid "" "Python 2.2 gives exactly the same linearizations for A, B, C, D, E, K1, K2 " "and K3, but a different linearization for Z::" msgstr "" +#: ../../howto/mro.rst:547 +msgid "L[Z,P22] = Z K1 K3 A K2 D B C E O" +msgstr "" + #: ../../howto/mro.rst:549 msgid "" "It is clear that this linearization is *wrong*, since A comes before D " @@ -573,6 +787,92 @@ msgid "" "paper.::" msgstr "" +#: ../../howto/mro.rst:574 +msgid "" +"#\n" +"\n" +"\"\"\"C3 algorithm by Samuele Pedroni (with readability enhanced by me)." +"\"\"\"\n" +"\n" +"class __metaclass__(type):\n" +" \"All classes are metamagically modified to be nicely printed\"\n" +" __repr__ = lambda cls: cls.__name__\n" +"\n" +"class ex_2:\n" +" \"Serious order disagreement\" #From Guido\n" +" class O: pass\n" +" class X(O): pass\n" +" class Y(O): pass\n" +" class A(X,Y): pass\n" +" class B(Y,X): pass\n" +" try:\n" +" class Z(A,B): pass #creates Z(A,B) in Python 2.2\n" +" except TypeError:\n" +" pass # Z(A,B) cannot be created in Python 2.3\n" +"\n" +"class ex_5:\n" +" \"My first example\"\n" +" class O: pass\n" +" class F(O): pass\n" +" class E(O): pass\n" +" class D(O): pass\n" +" class C(D,F): pass\n" +" class B(D,E): pass\n" +" class A(B,C): pass\n" +"\n" +"class ex_6:\n" +" \"My second example\"\n" +" class O: pass\n" +" class F(O): pass\n" +" class E(O): pass\n" +" class D(O): pass\n" +" class C(D,F): pass\n" +" class B(E,D): pass\n" +" class A(B,C): pass\n" +"\n" +"class ex_9:\n" +" \"Difference between Python 2.2 MRO and C3\" #From Samuele\n" +" class O: pass\n" +" class A(O): pass\n" +" class B(O): pass\n" +" class C(O): pass\n" +" class D(O): pass\n" +" class E(O): pass\n" +" class K1(A,B,C): pass\n" +" class K2(D,B,E): pass\n" +" class K3(D,A): pass\n" +" class Z(K1,K2,K3): pass\n" +"\n" +"def merge(seqs):\n" +" print '\\n\\nCPL[%s]=%s' % (seqs[0][0],seqs),\n" +" res = []; i=0\n" +" while 1:\n" +" nonemptyseqs=[seq for seq in seqs if seq]\n" +" if not nonemptyseqs: return res\n" +" i+=1; print '\\n',i,'round: candidates...',\n" +" for seq in nonemptyseqs: # find merge candidates among seq heads\n" +" cand = seq[0]; print ' ',cand,\n" +" nothead=[s for s in nonemptyseqs if cand in s[1:]]\n" +" if nothead: cand=None #reject candidate\n" +" else: break\n" +" if not cand: raise \"Inconsistent hierarchy\"\n" +" res.append(cand)\n" +" for seq in nonemptyseqs: # remove cand\n" +" if seq[0] == cand: del seq[0]\n" +"\n" +"def mro(C):\n" +" \"Compute the class precedence list (mro) according to C3\"\n" +" return merge([[C]]+map(mro,C.__bases__)+[list(C.__bases__)])\n" +"\n" +"def print_mro(C):\n" +" print '\\nMRO[%s]=%s' % (C,mro(C))\n" +" print '\\nP22 MRO[%s]=%s' % (C,C.mro())\n" +"\n" +"print_mro(ex_9.Z)\n" +"\n" +"#" +msgstr "" + #: ../../howto/mro.rst:656 msgid "That's all folks," msgstr "" diff --git a/howto/perf_profiling.po b/howto/perf_profiling.po index acd562a323..1b8ad84727 100644 --- a/howto/perf_profiling.po +++ b/howto/perf_profiling.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-16 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2023-12-09 17:39+0800\n" "Last-Translator: Matt Wang \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -81,14 +81,92 @@ msgstr "" msgid "For example, consider the following script:" msgstr "例如,參考以下腳本:" +#: ../../howto/perf_profiling.rst:38 +msgid "" +"def foo(n):\n" +" result = 0\n" +" for _ in range(n):\n" +" result += 1\n" +" return result\n" +"\n" +"def bar(n):\n" +" foo(n)\n" +"\n" +"def baz(n):\n" +" bar(n)\n" +"\n" +"if __name__ == \"__main__\":\n" +" baz(1000000)" +msgstr "" + #: ../../howto/perf_profiling.rst:55 msgid "We can run ``perf`` to sample CPU stack traces at 9999 hertz::" msgstr "我們可以執行 ``perf`` 以 9999 赫茲採樣 CPU 堆疊追蹤 (stack trace): ::" +#: ../../howto/perf_profiling.rst:57 +msgid "$ perf record -F 9999 -g -o perf.data python my_script.py" +msgstr "" + #: ../../howto/perf_profiling.rst:59 msgid "Then we can use ``perf report`` to analyze the data:" msgstr "然後我們可以使用 ``perf report`` 來分析資料:" +#: ../../howto/perf_profiling.rst:61 +msgid "" +"$ perf report --stdio -n -g\n" +"\n" +"# Children Self Samples Command Shared Object Symbol\n" +"# ........ ........ ............ .......... .................. ..........................................\n" +"#\n" +" 91.08% 0.00% 0 python.exe python.exe [.] " +"_start\n" +" |\n" +" ---_start\n" +" |\n" +" --90.71%--__libc_start_main\n" +" Py_BytesMain\n" +" |\n" +" |--56.88%--pymain_run_python.constprop.0\n" +" | |\n" +" | |--56.13%--_PyRun_AnyFileObject\n" +" | | _PyRun_SimpleFileObject\n" +" | | |\n" +" | | |--55.02%--run_mod\n" +" | | | |\n" +" | | | --54.65%--" +"PyEval_EvalCode\n" +" | | | " +"_PyEval_EvalFrameDefault\n" +" | | | " +"PyObject_Vectorcall\n" +" | | | " +"_PyEval_Vector\n" +" | | | " +"_PyEval_EvalFrameDefault\n" +" | | | " +"PyObject_Vectorcall\n" +" | | | " +"_PyEval_Vector\n" +" | | | " +"_PyEval_EvalFrameDefault\n" +" | | | " +"PyObject_Vectorcall\n" +" | | | " +"_PyEval_Vector\n" +" | | | |\n" +" | | | " +"|--51.67%--_PyEval_EvalFrameDefault\n" +" | | | " +"| |\n" +" | | | " +"| |--11.52%--_PyLong_Add\n" +" | | | " +"| | |\n" +" | | | " +"| | |--2.97%--_PyObject_Malloc\n" +"..." +msgstr "" + #: ../../howto/perf_profiling.rst:100 msgid "" "As you can see, the Python functions are not shown in the output, only " @@ -108,6 +186,69 @@ msgid "" msgstr "" "作為替代,如果我們在啟用 ``perf`` 支援的情況下執行相同的實驗,我們會得到:" +#: ../../howto/perf_profiling.rst:107 +msgid "" +"$ perf report --stdio -n -g\n" +"\n" +"# Children Self Samples Command Shared Object Symbol\n" +"# ........ ........ ............ .......... .................. .....................................................................\n" +"#\n" +" 90.58% 0.36% 1 python.exe python.exe [.] " +"_start\n" +" |\n" +" ---_start\n" +" |\n" +" --89.86%--__libc_start_main\n" +" Py_BytesMain\n" +" |\n" +" |--55.43%--pymain_run_python.constprop.0\n" +" | |\n" +" | |--54.71%--_PyRun_AnyFileObject\n" +" | | _PyRun_SimpleFileObject\n" +" | | |\n" +" | | |--53.62%--run_mod\n" +" | | | |\n" +" | | | --53.26%--" +"PyEval_EvalCode\n" +" | | | py::" +":/src/script.py\n" +" | | | " +"_PyEval_EvalFrameDefault\n" +" | | | " +"PyObject_Vectorcall\n" +" | | | " +"_PyEval_Vector\n" +" | | | py::baz:/" +"src/script.py\n" +" | | | " +"_PyEval_EvalFrameDefault\n" +" | | | " +"PyObject_Vectorcall\n" +" | | | " +"_PyEval_Vector\n" +" | | | py::bar:/" +"src/script.py\n" +" | | | " +"_PyEval_EvalFrameDefault\n" +" | | | " +"PyObject_Vectorcall\n" +" | | | " +"_PyEval_Vector\n" +" | | | py::foo:/" +"src/script.py\n" +" | | | |\n" +" | | | " +"|--51.81%--_PyEval_EvalFrameDefault\n" +" | | | " +"| |\n" +" | | | " +"| |--13.77%--_PyLong_Add\n" +" | | | " +"| | |\n" +" | | | " +"| | |--3.26%--_PyObject_Malloc" +msgstr "" + #: ../../howto/perf_profiling.rst:152 msgid "How to enable ``perf`` profiling support" msgstr "如何啟用 ``perf`` 分析支援" @@ -135,18 +276,47 @@ msgstr "" msgid "Example, using the environment variable::" msgstr "例如,使用環境變數: ::" +#: ../../howto/perf_profiling.rst:165 +msgid "" +"$ PYTHONPERFSUPPORT=1 python script.py\n" +"$ perf report -g -i perf.data" +msgstr "" + #: ../../howto/perf_profiling.rst:168 msgid "Example, using the :option:`!-X` option::" msgstr "例如,使用 :option:`!-X` 選項: ::" +#: ../../howto/perf_profiling.rst:170 +msgid "" +"$ python -X perf script.py\n" +"$ perf report -g -i perf.data" +msgstr "" + #: ../../howto/perf_profiling.rst:173 msgid "Example, using the :mod:`sys` APIs in file :file:`example.py`:" msgstr "例如,在 :file:`example.py` 檔案中使用 :mod:`sys` API:" +#: ../../howto/perf_profiling.rst:175 +msgid "" +"import sys\n" +"\n" +"sys.activate_stack_trampoline(\"perf\")\n" +"do_profiled_stuff()\n" +"sys.deactivate_stack_trampoline()\n" +"\n" +"non_profiled_stuff()" +msgstr "" + #: ../../howto/perf_profiling.rst:185 msgid "...then::" msgstr "...然後: ::" +#: ../../howto/perf_profiling.rst:187 +msgid "" +"$ python ./example.py\n" +"$ perf report -g -i perf.data" +msgstr "" + #: ../../howto/perf_profiling.rst:192 msgid "How to obtain the best results" msgstr "如何獲得最佳結果" @@ -170,6 +340,10 @@ msgid "" "You can check if your system has been compiled with this flag by running::" msgstr "你可以透過執行以下指令來檢查你的系統是否已使用此旗標進行編譯: ::" +#: ../../howto/perf_profiling.rst:203 +msgid "$ python -m sysconfig | grep 'no-omit-frame-pointer'" +msgstr "" + #: ../../howto/perf_profiling.rst:205 msgid "" "If you don't see any output it means that your interpreter has not been " diff --git a/howto/regex.po b/howto/regex.po index 1e193d2328..657af4bddf 100644 --- a/howto/regex.po +++ b/howto/regex.po @@ -9,7 +9,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-04-18 00:04+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2018-05-23 14:37+0000\n" "Last-Translator: Adrian Liaw \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -135,6 +135,10 @@ msgid "" "discussed in the rest of this HOWTO." msgstr "" +#: ../../howto/regex.rst:79 +msgid ". ^ $ * + ? { } [ ] \\ | ( )" +msgstr "" + #: ../../howto/regex.rst:83 msgid "" "The first metacharacters we'll look at are ``[`` and ``]``. They're used for " @@ -491,6 +495,14 @@ msgid "" "string substitutions. ::" msgstr "" +#: ../../howto/regex.rst:274 +msgid "" +">>> import re\n" +">>> p = re.compile('ab*')\n" +">>> p\n" +"re.compile('ab*')" +msgstr "" + #: ../../howto/regex.rst:279 msgid "" ":func:`re.compile` also accepts an optional *flags* argument, used to enable " @@ -498,6 +510,10 @@ msgid "" "settings later, but for now a single example will do::" msgstr "" +#: ../../howto/regex.rst:283 +msgid ">>> p = re.compile('ab*', re.IGNORECASE)" +msgstr "" + #: ../../howto/regex.rst:285 msgid "" "The RE is passed to :func:`re.compile` as a string. REs are handled as " @@ -703,6 +719,14 @@ msgid "" "the Python interpreter, import the :mod:`re` module, and compile a RE::" msgstr "" +#: ../../howto/regex.rst:389 +msgid "" +">>> import re\n" +">>> p = re.compile('[a-z]+')\n" +">>> p\n" +"re.compile('[a-z]+')" +msgstr "" + #: ../../howto/regex.rst:394 msgid "" "Now, you can try matching various strings against the RE ``[a-z]+``. An " @@ -712,6 +736,13 @@ msgid "" "print the result of :meth:`!match` to make this clear. ::" msgstr "" +#: ../../howto/regex.rst:400 +msgid "" +">>> p.match(\"\")\n" +">>> print(p.match(\"\"))\n" +"None" +msgstr "" + #: ../../howto/regex.rst:404 msgid "" "Now, let's try it on a string that it should match, such as ``tempo``. In " @@ -719,6 +750,13 @@ msgid "" "objects>`, so you should store the result in a variable for later use. ::" msgstr "" +#: ../../howto/regex.rst:408 +msgid "" +">>> m = p.match('tempo')\n" +">>> m\n" +"" +msgstr "" + #: ../../howto/regex.rst:412 msgid "" "Now you can query the :ref:`match object ` for information " @@ -762,6 +800,16 @@ msgstr "" msgid "Trying these methods will soon clarify their meaning::" msgstr "" +#: ../../howto/regex.rst:431 +msgid "" +">>> m.group()\n" +"'tempo'\n" +">>> m.start(), m.end()\n" +"(0, 5)\n" +">>> m.span()\n" +"(0, 5)" +msgstr "" + #: ../../howto/regex.rst:438 msgid "" ":meth:`~re.Match.group` returns the substring that was matched by the RE. :" @@ -774,6 +822,18 @@ msgid "" "case. ::" msgstr "" +#: ../../howto/regex.rst:446 +msgid "" +">>> print(p.match('::: message'))\n" +"None\n" +">>> m = p.search('::: message'); print(m)\n" +"\n" +">>> m.group()\n" +"'message'\n" +">>> m.span()\n" +"(4, 11)" +msgstr "" + #: ../../howto/regex.rst:455 msgid "" "In actual programs, the most common style is to store the :ref:`match object " @@ -781,12 +841,29 @@ msgid "" "usually looks like::" msgstr "" +#: ../../howto/regex.rst:459 +msgid "" +"p = re.compile( ... )\n" +"m = p.match( 'string goes here' )\n" +"if m:\n" +" print('Match found: ', m.group())\n" +"else:\n" +" print('No match')" +msgstr "" + #: ../../howto/regex.rst:466 msgid "" "Two pattern methods return all of the matches for a pattern. :meth:`~re." "Pattern.findall` returns a list of matching strings::" msgstr "" +#: ../../howto/regex.rst:469 +msgid "" +">>> p = re.compile(r'\\d+')\n" +">>> p.findall('12 drummers drumming, 11 pipers piping, 10 lords a-leaping')\n" +"['12', '11', '10']" +msgstr "" + #: ../../howto/regex.rst:473 msgid "" "The ``r`` prefix, making the literal a raw string literal, is needed in this " @@ -804,6 +881,19 @@ msgid "" "`iterator`::" msgstr "" +#: ../../howto/regex.rst:483 +msgid "" +">>> iterator = p.finditer('12 drummers drumming, 11 ... 10 ...')\n" +">>> iterator \n" +"\n" +">>> for match in iterator:\n" +"... print(match.span())\n" +"...\n" +"(0, 2)\n" +"(22, 24)\n" +"(29, 31)" +msgstr "" + #: ../../howto/regex.rst:495 msgid "Module-Level Functions" msgstr "" @@ -818,6 +908,14 @@ msgid "" "``None`` or a :ref:`match object ` instance. ::" msgstr "" +#: ../../howto/regex.rst:504 +msgid "" +">>> print(re.match(r'From\\s+', 'Fromage amk'))\n" +"None\n" +">>> re.match(r'From\\s+', 'From amk Thu May 14 19:12:10 1998') \n" +"" +msgstr "" + #: ../../howto/regex.rst:509 msgid "" "Under the hood, these functions simply create a pattern object for you and " @@ -922,13 +1020,13 @@ msgid "" "letters, too. Full Unicode matching also works unless the :const:`ASCII` " "flag is used to disable non-ASCII matches. When the Unicode patterns ``[a-" "z]`` or ``[A-Z]`` are used in combination with the :const:`IGNORECASE` flag, " -"they will match the 52 ASCII letters and 4 additional non-ASCII letters: 'İ' " -"(U+0130, Latin capital letter I with dot above), 'ı' (U+0131, Latin small " -"letter dotless i), 'ſ' (U+017F, Latin small letter long s) and 'K' (U+212A, " -"Kelvin sign). ``Spam`` will match ``'Spam'``, ``'spam'``, ``'spAM'``, or " -"``'ſpam'`` (the latter is matched only in Unicode mode). This lowercasing " -"doesn't take the current locale into account; it will if you also set the :" -"const:`LOCALE` flag." +"they will match the 52 ASCII letters and 4 additional non-ASCII letters: " +"'İ' (U+0130, Latin capital letter I with dot above), 'ı' (U+0131, Latin " +"small letter dotless i), 'ſ' (U+017F, Latin small letter long s) and " +"'K' (U+212A, Kelvin sign). ``Spam`` will match ``'Spam'``, ``'spam'``, " +"``'spAM'``, or ``'ſpam'`` (the latter is matched only in Unicode mode). This " +"lowercasing doesn't take the current locale into account; it will if you " +"also set the :const:`LOCALE` flag." msgstr "" #: ../../howto/regex.rst:581 @@ -1004,10 +1102,30 @@ msgid "" "it is to read? ::" msgstr "" +#: ../../howto/regex.rst:651 +msgid "" +"charref = re.compile(r\"\"\"\n" +" &[#] # Start of a numeric entity reference\n" +" (\n" +" 0[0-7]+ # Octal form\n" +" | [0-9]+ # Decimal form\n" +" | x[0-9a-fA-F]+ # Hexadecimal form\n" +" )\n" +" ; # Trailing semicolon\n" +"\"\"\", re.VERBOSE)" +msgstr "" + #: ../../howto/regex.rst:661 msgid "Without the verbose setting, the RE would look like this::" msgstr "" +#: ../../howto/regex.rst:663 +msgid "" +"charref = re.compile(\"&#(0[0-7]+\"\n" +" \"|[0-9]+\"\n" +" \"|x[0-9a-fA-F]+);\")" +msgstr "" + #: ../../howto/regex.rst:667 msgid "" "In the above example, Python's automatic concatenation of string literals " @@ -1086,6 +1204,14 @@ msgid "" "a line, the RE to use is ``^From``. ::" msgstr "" +#: ../../howto/regex.rst:714 +msgid "" +">>> print(re.search('^From', 'From Here to Eternity')) \n" +"\n" +">>> print(re.search('^From', 'Reciting From Memory'))\n" +"None" +msgstr "" + #: ../../howto/regex.rst:719 msgid "To match a literal ``'^'``, use ``\\^``." msgstr "" @@ -1100,6 +1226,16 @@ msgid "" "string, or any location followed by a newline character. ::" msgstr "" +#: ../../howto/regex.rst:725 +msgid "" +">>> print(re.search('}$', '{block}')) \n" +"\n" +">>> print(re.search('}$', '{block} '))\n" +"None\n" +">>> print(re.search('}$', '{block}\\n')) \n" +"" +msgstr "" + #: ../../howto/regex.rst:732 msgid "" "To match a literal ``'$'``, use ``\\$`` or enclose it inside a character " @@ -1145,6 +1281,17 @@ msgid "" "won't match when it's contained inside another word. ::" msgstr "" +#: ../../howto/regex.rst:753 +msgid "" +">>> p = re.compile(r'\\bclass\\b')\n" +">>> print(p.search('no class at all'))\n" +"\n" +">>> print(p.search('the declassified algorithm'))\n" +"None\n" +">>> print(p.search('one subclass is'))\n" +"None" +msgstr "" + #: ../../howto/regex.rst:761 msgid "" "There are two subtleties you should remember when using this special " @@ -1156,6 +1303,15 @@ msgid "" "previous RE, but omits the ``'r'`` in front of the RE string. ::" msgstr "" +#: ../../howto/regex.rst:769 +msgid "" +">>> p = re.compile('\\bclass\\b')\n" +">>> print(p.search('no class at all'))\n" +"None\n" +">>> print(p.search('\\b' + 'class' + '\\b'))\n" +"" +msgstr "" + #: ../../howto/regex.rst:775 msgid "" "Second, inside a character class, where there's no use for this assertion, " @@ -1186,6 +1342,14 @@ msgid "" "name and a value, separated by a ``':'``, like this:" msgstr "" +#: ../../howto/regex.rst:793 +msgid "" +"From: author@example.com\n" +"User-Agent: Thunderbird 1.5.0.9 (X11/20061227)\n" +"MIME-Version: 1.0\n" +"To: editor@example.com" +msgstr "" + #: ../../howto/regex.rst:800 msgid "" "This can be handled by writing a regular expression which matches an entire " @@ -1203,6 +1367,13 @@ msgid "" "repetitions of ``ab``. ::" msgstr "" +#: ../../howto/regex.rst:811 +msgid "" +">>> p = re.compile('(ab)*')\n" +">>> print(p.match('ababababab').span())\n" +"(0, 10)" +msgstr "" + #: ../../howto/regex.rst:815 msgid "" "Groups indicated with ``'('``, ``')'`` also capture the starting and ending " @@ -1215,6 +1386,16 @@ msgid "" "they match. ::" msgstr "" +#: ../../howto/regex.rst:824 +msgid "" +">>> p = re.compile('(a)b')\n" +">>> m = p.match('ab')\n" +">>> m.group()\n" +"'ab'\n" +">>> m.group(0)\n" +"'ab'" +msgstr "" + #: ../../howto/regex.rst:831 msgid "" "Subgroups are numbered from left to right, from 1 upward. Groups can be " @@ -1222,6 +1403,18 @@ msgid "" "characters, going from left to right. ::" msgstr "" +#: ../../howto/regex.rst:835 +msgid "" +">>> p = re.compile('(a(b)c)d')\n" +">>> m = p.match('abcd')\n" +">>> m.group(0)\n" +"'abcd'\n" +">>> m.group(1)\n" +"'abc'\n" +">>> m.group(2)\n" +"'b'" +msgstr "" + #: ../../howto/regex.rst:844 msgid "" ":meth:`~re.Match.group` can be passed multiple group numbers at a time, in " @@ -1229,12 +1422,24 @@ msgid "" "those groups. ::" msgstr "" +#: ../../howto/regex.rst:847 +msgid "" +">>> m.group(2,1,2)\n" +"('b', 'abc', 'b')" +msgstr "" + #: ../../howto/regex.rst:850 msgid "" "The :meth:`~re.Match.groups` method returns a tuple containing the strings " "for all the subgroups, from 1 up to however many there are. ::" msgstr "" +#: ../../howto/regex.rst:853 +msgid "" +">>> m.groups()\n" +"('abc', 'b')" +msgstr "" + #: ../../howto/regex.rst:856 msgid "" "Backreferences in a pattern allow you to specify that the contents of an " @@ -1250,6 +1455,13 @@ msgstr "" msgid "For example, the following RE detects doubled words in a string. ::" msgstr "" +#: ../../howto/regex.rst:866 +msgid "" +">>> p = re.compile(r'\\b(\\w+)\\s+\\1\\b')\n" +">>> p.search('Paris in the the spring').group()\n" +"'the the'" +msgstr "" + #: ../../howto/regex.rst:870 msgid "" "Backreferences like this aren't often useful for just searching through a " @@ -1314,6 +1526,16 @@ msgid "" "where you can replace the ``...`` with any other regular expression. ::" msgstr "" +#: ../../howto/regex.rst:912 +msgid "" +">>> m = re.match(\"([abc])+\", \"abc\")\n" +">>> m.groups()\n" +"('c',)\n" +">>> m = re.match(\"(?:[abc])+\", \"abc\")\n" +">>> m.groups()\n" +"()" +msgstr "" + #: ../../howto/regex.rst:919 msgid "" "Except for the fact that you can't retrieve the contents of what the group " @@ -1345,12 +1567,29 @@ msgid "" "ways::" msgstr "" +#: ../../howto/regex.rst:939 +msgid "" +">>> p = re.compile(r'(?P\\b\\w+\\b)')\n" +">>> m = p.search( '(((( Lots of punctuation )))' )\n" +">>> m.group('word')\n" +"'Lots'\n" +">>> m.group(1)\n" +"'Lots'" +msgstr "" + #: ../../howto/regex.rst:946 msgid "" "Additionally, you can retrieve named groups as a dictionary with :meth:`~re." "Match.groupdict`::" msgstr "" +#: ../../howto/regex.rst:949 +msgid "" +">>> m = re.match(r'(?P\\w+) (?P\\w+)', 'Jane Doe')\n" +">>> m.groupdict()\n" +"{'first': 'Jane', 'last': 'Doe'}" +msgstr "" + #: ../../howto/regex.rst:953 msgid "" "Named groups are handy because they let you use easily remembered names, " @@ -1358,6 +1597,16 @@ msgid "" "`imaplib` module::" msgstr "" +#: ../../howto/regex.rst:957 +msgid "" +"InternalDate = re.compile(r'INTERNALDATE \"'\n" +" r'(?P[ 123][0-9])-(?P[A-Z][a-z][a-z])-'\n" +" r'(?P[0-9][0-9][0-9][0-9])'\n" +" r' (?P[0-9][0-9]):(?P[0-9][0-9]):(?P[0-9][0-9])'\n" +" r' (?P[-+])(?P[0-9][0-9])(?P[0-9][0-9])'\n" +" r'\"')" +msgstr "" + #: ../../howto/regex.rst:964 msgid "" "It's obviously much easier to retrieve ``m.group('zonem')``, instead of " @@ -1375,6 +1624,13 @@ msgid "" "P\\w+)\\s+(?P=word)\\b``::" msgstr "" +#: ../../howto/regex.rst:974 +msgid "" +">>> p = re.compile(r'\\b(?P\\w+)\\s+(?P=word)\\b')\n" +">>> p.search('Paris in the the spring').group()\n" +"'the the'" +msgstr "" + #: ../../howto/regex.rst:980 msgid "Lookahead Assertions" msgstr "" @@ -1578,6 +1834,15 @@ msgid "" "characters. ::" msgstr "" +#: ../../howto/regex.rst:1104 +msgid "" +">>> p = re.compile(r'\\W+')\n" +">>> p.split('This is a test, short and sweet, of split().')\n" +"['This', 'is', 'a', 'test', 'short', 'and', 'sweet', 'of', 'split', '']\n" +">>> p.split('This is a test, short and sweet, of split().', 3)\n" +"['This', 'is', 'a', 'test, short and sweet, of split().']" +msgstr "" + #: ../../howto/regex.rst:1110 msgid "" "Sometimes you're not only interested in what the text between delimiters is, " @@ -1586,12 +1851,32 @@ msgid "" "Compare the following calls::" msgstr "" +#: ../../howto/regex.rst:1115 +msgid "" +">>> p = re.compile(r'\\W+')\n" +">>> p2 = re.compile(r'(\\W+)')\n" +">>> p.split('This... is a test.')\n" +"['This', 'is', 'a', 'test', '']\n" +">>> p2.split('This... is a test.')\n" +"['This', '... ', 'is', ' ', 'a', ' ', 'test', '.', '']" +msgstr "" + #: ../../howto/regex.rst:1122 msgid "" "The module-level function :func:`re.split` adds the RE to be used as the " "first argument, but is otherwise the same. ::" msgstr "" +#: ../../howto/regex.rst:1125 +msgid "" +">>> re.split(r'[\\W]+', 'Words, words, words.')\n" +"['Words', 'words', 'words', '']\n" +">>> re.split(r'([\\W]+)', 'Words, words, words.')\n" +"['Words', ', ', 'words', ', ', 'words', '.', '']\n" +">>> re.split(r'[\\W]+', 'Words, words, words.', 1)\n" +"['Words', 'words, words.']" +msgstr "" + #: ../../howto/regex.rst:1134 msgid "Search and Replace" msgstr "" @@ -1624,6 +1909,15 @@ msgid "" "replaces colour names with the word ``colour``::" msgstr "" +#: ../../howto/regex.rst:1154 +msgid "" +">>> p = re.compile('(blue|white|red)')\n" +">>> p.sub('colour', 'blue socks and red shoes')\n" +"'colour socks and colour shoes'\n" +">>> p.sub('colour', 'blue socks and red shoes', count=1)\n" +"'colour socks and red shoes'" +msgstr "" + #: ../../howto/regex.rst:1160 msgid "" "The :meth:`~re.Pattern.subn` method does the same work, but returns a 2-" @@ -1631,12 +1925,28 @@ msgid "" "were performed::" msgstr "" +#: ../../howto/regex.rst:1163 +msgid "" +">>> p = re.compile('(blue|white|red)')\n" +">>> p.subn('colour', 'blue socks and red shoes')\n" +"('colour socks and colour shoes', 2)\n" +">>> p.subn('colour', 'no colours at all')\n" +"('no colours at all', 0)" +msgstr "" + #: ../../howto/regex.rst:1169 msgid "" "Empty matches are replaced only when they're not adjacent to a previous " "empty match. ::" msgstr "" +#: ../../howto/regex.rst:1172 +msgid "" +">>> p = re.compile('x*')\n" +">>> p.sub('-', 'abxd')\n" +"'-a-b--d-'" +msgstr "" + #: ../../howto/regex.rst:1176 msgid "" "If *replacement* is a string, any backslash escapes in it are processed. " @@ -1654,6 +1964,13 @@ msgid "" "``{``, ``}``, and changes ``section`` to ``subsection``::" msgstr "" +#: ../../howto/regex.rst:1186 +msgid "" +">>> p = re.compile('section{ ( [^}]* ) }', re.VERBOSE)\n" +">>> p.sub(r'subsection{\\1}','section{First} section{second}')\n" +"'subsection{First} subsection{second}'" +msgstr "" + #: ../../howto/regex.rst:1190 msgid "" "There's also a syntax for referring to named groups as defined by the ``(?" @@ -1666,6 +1983,17 @@ msgid "" "but use all three variations of the replacement string. ::" msgstr "" +#: ../../howto/regex.rst:1199 +msgid "" +">>> p = re.compile('section{ (?P [^}]* ) }', re.VERBOSE)\n" +">>> p.sub(r'subsection{\\1}','section{First}')\n" +"'subsection{First}'\n" +">>> p.sub(r'subsection{\\g<1>}','section{First}')\n" +"'subsection{First}'\n" +">>> p.sub(r'subsection{\\g}','section{First}')\n" +"'subsection{First}'" +msgstr "" + #: ../../howto/regex.rst:1207 msgid "" "*replacement* can also be a function, which gives you even more control. If " @@ -1681,6 +2009,18 @@ msgid "" "hexadecimal::" msgstr "" +#: ../../howto/regex.rst:1216 +msgid "" +">>> def hexrepl(match):\n" +"... \"Return the hex string for a decimal number\"\n" +"... value = int(match.group())\n" +"... return hex(value)\n" +"...\n" +">>> p = re.compile(r'\\d+')\n" +">>> p.sub(hexrepl, 'Call 65490 for printing, 49152 for user code.')\n" +"'Call 0xffd2 for printing, 0xc000 for user code.'" +msgstr "" + #: ../../howto/regex.rst:1225 msgid "" "When using the module-level :func:`re.sub` function, the pattern is passed " @@ -1761,12 +2101,28 @@ msgid "" "report it. ::" msgstr "" +#: ../../howto/regex.rst:1279 +msgid "" +">>> print(re.match('super', 'superstition').span())\n" +"(0, 5)\n" +">>> print(re.match('super', 'insuperable'))\n" +"None" +msgstr "" + #: ../../howto/regex.rst:1284 msgid "" "On the other hand, :func:`~re.search` will scan forward through the string, " "reporting the first match it finds. ::" msgstr "" +#: ../../howto/regex.rst:1287 +msgid "" +">>> print(re.search('super', 'superstition').span())\n" +"(0, 5)\n" +">>> print(re.search('super', 'insuperable').span())\n" +"(2, 7)" +msgstr "" + #: ../../howto/regex.rst:1292 msgid "" "Sometimes you'll be tempted to keep using :func:`re.match`, and just add ``." @@ -1799,6 +2155,17 @@ msgid "" "HTML tag doesn't work because of the greedy nature of ``.*``. ::" msgstr "" +#: ../../howto/regex.rst:1315 +msgid "" +">>> s = 'Title'\n" +">>> len(s)\n" +"32\n" +">>> print(re.match('<.*>', s).span())\n" +"(0, 32)\n" +">>> print(re.match('<.*>', s).group())\n" +"Title" +msgstr "" + #: ../../howto/regex.rst:1323 msgid "" "The RE matches the ``'<'`` in ``''``, and the ``.*`` consumes the rest " @@ -1818,6 +2185,12 @@ msgid "" "retrying the ``'>'`` at every step. This produces just the right result::" msgstr "" +#: ../../howto/regex.rst:1336 +msgid "" +">>> print(re.match('<.*?>', s).group())\n" +"" +msgstr "" + #: ../../howto/regex.rst:1339 msgid "" "(Note that parsing HTML or XML with regular expressions is painful. Quick-" @@ -1858,10 +2231,26 @@ msgid "" "quoted strings, this enables REs to be formatted more neatly::" msgstr "" +#: ../../howto/regex.rst:1366 +msgid "" +"pat = re.compile(r\"\"\"\n" +" \\s* # Skip leading whitespace\n" +" (?P
[^:]+) # Header name\n" +" \\s* : # Whitespace, and a colon\n" +" (?P.*?) # The header's value -- *? used to\n" +" # lose the following trailing whitespace\n" +" \\s*$ # Trailing whitespace to end-of-line\n" +"\"\"\", re.VERBOSE)" +msgstr "" + #: ../../howto/regex.rst:1375 msgid "This is far more readable than::" msgstr "" +#: ../../howto/regex.rst:1377 +msgid "pat = re.compile(r\"\\s*(?P
[^:]+)\\s*:(?P.*?)\\s*$\")" +msgstr "" + #: ../../howto/regex.rst:1381 msgid "Feedback" msgstr "" diff --git a/howto/sockets.po b/howto/sockets.po index 362aa5710a..f3b37ee746 100644 --- a/howto/sockets.po +++ b/howto/sockets.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.11\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-06-10 00:16+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2023-08-12 15:16+0800\n" "Last-Translator: Jay \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -126,6 +126,14 @@ msgid "" msgstr "" "大致上來說,當你點擊了帶你來到這個頁面的連結時,你的瀏覽器做了以下的操作: ::" +#: ../../howto/sockets.rst:59 +msgid "" +"# create an INET, STREAMing socket\n" +"s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n" +"# now connect to the web server on port 80 - the normal http port\n" +"s.connect((\"www.python.org\", 80))" +msgstr "" + #: ../../howto/sockets.rst:64 msgid "" "When the ``connect`` completes, the socket ``s`` can be used to send in a " @@ -145,6 +153,16 @@ msgstr "" "網路伺服器 (web server) 的運作就稍微複雜一點。首先,網路伺服器會建立一個「伺" "服器端 socket」: ::" +#: ../../howto/sockets.rst:73 +msgid "" +"# create an INET, STREAMing socket\n" +"serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n" +"# bind the socket to a public host, and a well-known port\n" +"serversocket.bind((socket.gethostname(), 80))\n" +"# become a server socket\n" +"serversocket.listen(5)" +msgstr "" + #: ../../howto/sockets.rst:80 msgid "" "A couple things to notice: we used ``socket.gethostname()`` so that the " @@ -187,6 +205,17 @@ msgstr "" "現在我們有一個監聽 80 連接埠的「伺服器端」socket 了,我們可以進入網路伺服器的" "主迴圈了: ::" +#: ../../howto/sockets.rst:98 +msgid "" +"while True:\n" +" # accept connections from outside\n" +" (clientsocket, address) = serversocket.accept()\n" +" # now do something with the clientsocket\n" +" # in this case, we'll pretend this is a threaded server\n" +" ct = client_thread(clientsocket)\n" +" ct.run()" +msgstr "" + #: ../../howto/sockets.rst:106 msgid "" "There's actually 3 general ways in which this loop could work - dispatching " @@ -339,6 +368,43 @@ msgid "" "fixed length message::" msgstr "假設你不想結束連線,最簡單的方式就是使用固定長度的訊息: ::" +#: ../../howto/sockets.rst:183 +msgid "" +"class MySocket:\n" +" \"\"\"demonstration class only\n" +" - coded for clarity, not efficiency\n" +" \"\"\"\n" +"\n" +" def __init__(self, sock=None):\n" +" if sock is None:\n" +" self.sock = socket.socket(\n" +" socket.AF_INET, socket.SOCK_STREAM)\n" +" else:\n" +" self.sock = sock\n" +"\n" +" def connect(self, host, port):\n" +" self.sock.connect((host, port))\n" +"\n" +" def mysend(self, msg):\n" +" totalsent = 0\n" +" while totalsent < MSGLEN:\n" +" sent = self.sock.send(msg[totalsent:])\n" +" if sent == 0:\n" +" raise RuntimeError(\"socket connection broken\")\n" +" totalsent = totalsent + sent\n" +"\n" +" def myreceive(self):\n" +" chunks = []\n" +" bytes_recd = 0\n" +" while bytes_recd < MSGLEN:\n" +" chunk = self.sock.recv(min(MSGLEN - bytes_recd, 2048))\n" +" if chunk == b'':\n" +" raise RuntimeError(\"socket connection broken\")\n" +" chunks.append(chunk)\n" +" bytes_recd = bytes_recd + len(chunk)\n" +" return b''.join(chunks)" +msgstr "" + #: ../../howto/sockets.rst:217 msgid "" "The sending code here is usable for almost any messaging scheme - in Python " @@ -594,6 +660,16 @@ msgstr "" "本非常類似,如果你理解了 Python 中的 ``select``,在 C 中處理它時也不會有太大" "的困難: ::" +#: ../../howto/sockets.rst:345 +msgid "" +"ready_to_read, ready_to_write, in_error = \\\n" +" select.select(\n" +" potential_readers,\n" +" potential_writers,\n" +" potential_errs,\n" +" timeout)" +msgstr "" + #: ../../howto/sockets.rst:352 msgid "" "You pass ``select`` three lists: the first contains all sockets that you " diff --git a/howto/sorting.po b/howto/sorting.po index 03271d26a5..efbcb2e3a9 100644 --- a/howto/sorting.po +++ b/howto/sorting.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-21 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2023-08-12 15:09+0800\n" "Last-Translator: Adrian Liaw \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -59,6 +59,12 @@ msgstr "" "單純的升冪排序很容易做到:只要呼叫 :func:`sorted` 函式,它會回傳一個新的串" "列:" +#: ../../howto/sorting.rst:22 +msgid "" +">>> sorted([5, 2, 3, 1, 4])\n" +"[1, 2, 3, 4, 5]" +msgstr "" + #: ../../howto/sorting.rst:27 msgid "" "You can also use the :meth:`list.sort` method. It modifies the list in-place " @@ -70,6 +76,14 @@ msgstr "" "混淆)。它通常會比 :func:`sorted` 來得不方便——但如果你不需要保留原始串列的" "話,它會稍微有效率一點。" +#: ../../howto/sorting.rst:32 +msgid "" +">>> a = [5, 2, 3, 1, 4]\n" +">>> a.sort()\n" +">>> a\n" +"[1, 2, 3, 4, 5]" +msgstr "" + #: ../../howto/sorting.rst:39 msgid "" "Another difference is that the :meth:`list.sort` method is only defined for " @@ -78,6 +92,12 @@ msgstr "" "另一個差異是 :meth:`list.sort` 方法只有定義在串列上,而 :func:`sorted` 函式可" "以接受任何可疊代物件。" +#: ../../howto/sorting.rst:42 +msgid "" +">>> sorted({1: 'D', 2: 'B', 3: 'B', 4: 'E', 5: 'A'})\n" +"[1, 2, 3, 4, 5]" +msgstr "" + #: ../../howto/sorting.rst:48 msgid "Key Functions" msgstr "鍵函式 (key functions)" @@ -95,6 +115,12 @@ msgstr "" msgid "For example, here's a case-insensitive string comparison:" msgstr "例如這裡有一個不區分大小寫的字串比對:" +#: ../../howto/sorting.rst:56 +msgid "" +">>> sorted(\"This is a test string from Andrew\".split(), key=str.casefold)\n" +"['a', 'Andrew', 'from', 'is', 'string', 'test', 'This']" +msgstr "" + #: ../../howto/sorting.rst:61 msgid "" "The value of the *key* parameter should be a function (or other callable) " @@ -113,11 +139,42 @@ msgid "" msgstr "" "一個常見的模式是在排序複雜物件的時候使用一部分物件的索引值當作鍵,例如:" +#: ../../howto/sorting.rst:69 +msgid "" +">>> student_tuples = [\n" +"... ('john', 'A', 15),\n" +"... ('jane', 'B', 12),\n" +"... ('dave', 'B', 10),\n" +"... ]\n" +">>> sorted(student_tuples, key=lambda student: student[2]) # sort by age\n" +"[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]" +msgstr "" + #: ../../howto/sorting.rst:79 msgid "" "The same technique works for objects with named attributes. For example:" msgstr "相同的做法也適用在有命名屬性的物件,例如:" +#: ../../howto/sorting.rst:81 +msgid "" +">>> class Student:\n" +"... def __init__(self, name, grade, age):\n" +"... self.name = name\n" +"... self.grade = grade\n" +"... self.age = age\n" +"... def __repr__(self):\n" +"... return repr((self.name, self.grade, self.age))\n" +"\n" +">>> student_objects = [\n" +"... Student('john', 'A', 15),\n" +"... Student('jane', 'B', 12),\n" +"... Student('dave', 'B', 10),\n" +"... ]\n" +">>> sorted(student_objects, key=lambda student: student.age) # sort by " +"age\n" +"[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]" +msgstr "" + #: ../../howto/sorting.rst:99 msgid "" "Objects with named attributes can be made by a regular class as shown above, " @@ -145,6 +202,17 @@ msgstr "" msgid "Using those functions, the above examples become simpler and faster:" msgstr "使用這些函式讓上面的範例變得更簡單且快速:" +#: ../../howto/sorting.rst:113 +msgid "" +">>> from operator import itemgetter, attrgetter\n" +"\n" +">>> sorted(student_tuples, key=itemgetter(2))\n" +"[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]\n" +"\n" +">>> sorted(student_objects, key=attrgetter('age'))\n" +"[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]" +msgstr "" + #: ../../howto/sorting.rst:123 msgid "" "The operator module functions allow multiple levels of sorting. For example, " @@ -152,6 +220,15 @@ msgid "" msgstr "" "operator 模組的函式允許多層的排序,例如先用 *grade* 排序再用 *age* 排序:" +#: ../../howto/sorting.rst:126 +msgid "" +">>> sorted(student_tuples, key=itemgetter(1,2))\n" +"[('john', 'A', 15), ('dave', 'B', 10), ('jane', 'B', 12)]\n" +"\n" +">>> sorted(student_objects, key=attrgetter('grade', 'age'))\n" +"[('john', 'A', 15), ('dave', 'B', 10), ('jane', 'B', 12)]" +msgstr "" + #: ../../howto/sorting.rst:134 msgid "" "The :mod:`functools` module provides another helpful tool for making key-" @@ -160,6 +237,20 @@ msgid "" "it suitable for use as a key-function." msgstr "" +#: ../../howto/sorting.rst:139 +msgid "" +">>> from functools import partial\n" +">>> from unicodedata import normalize\n" +"\n" +">>> names = 'Zoë Åbjørn Núñez Élana Zeke Abe Nubia Eloise'.split()\n" +"\n" +">>> sorted(names, key=partial(normalize, 'NFD'))\n" +"['Abe', 'Åbjørn', 'Eloise', 'Élana', 'Nubia', 'Núñez', 'Zeke', 'Zoë']\n" +"\n" +">>> sorted(names, key=partial(normalize, 'NFC'))\n" +"['Abe', 'Eloise', 'Nubia', 'Núñez', 'Zeke', 'Zoë', 'Åbjørn', 'Élana']" +msgstr "" + #: ../../howto/sorting.rst:153 msgid "Ascending and Descending" msgstr "升冪與降冪" @@ -173,6 +264,15 @@ msgstr "" ":meth:`list.sort` 和 :func:`sorted` 都有一個 boolean 參數 *reverse* 用來表示" "是否要降冪排序。例如將學生資料依據 *age* 做降冪排序:" +#: ../../howto/sorting.rst:159 +msgid "" +">>> sorted(student_tuples, key=itemgetter(2), reverse=True)\n" +"[('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]\n" +"\n" +">>> sorted(student_objects, key=attrgetter('age'), reverse=True)\n" +"[('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]" +msgstr "" + #: ../../howto/sorting.rst:168 msgid "Sort Stability and Complex Sorts" msgstr "排序穩定性與複合排序" @@ -187,6 +287,13 @@ msgstr "" "Sorting_algorithm#Stability>`_,意思是當有多筆資料有相同的鍵,它們會維持原來" "的順序。" +#: ../../howto/sorting.rst:174 +msgid "" +">>> data = [('red', 1), ('blue', 1), ('red', 2), ('blue', 2)]\n" +">>> sorted(data, key=itemgetter(0))\n" +"[('blue', 1), ('blue', 2), ('red', 1), ('red', 2)]" +msgstr "" + #: ../../howto/sorting.rst:180 msgid "" "Notice how the two records for *blue* retain their original order so that " @@ -205,6 +312,15 @@ msgstr "" "做降冪排序再用 *age* 做升冪排序,你可以先用 *age* 排序一遍再用 *grade* 排序一" "遍:" +#: ../../howto/sorting.rst:187 +msgid "" +">>> s = sorted(student_objects, key=attrgetter('age')) # sort on " +"secondary key\n" +">>> sorted(s, key=attrgetter('grade'), reverse=True) # now sort on " +"primary key, descending\n" +"[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]" +msgstr "" + #: ../../howto/sorting.rst:193 msgid "" "This can be abstracted out into a wrapper function that can take a list and " @@ -213,6 +329,17 @@ msgstr "" "這可以抽出一個包裝函式 (wrapper function),接受一個串列及多個欄位及升降冪的元" "組為引數,來對這個串列排序多遍。" +#: ../../howto/sorting.rst:196 +msgid "" +">>> def multisort(xs, specs):\n" +"... for key, reverse in reversed(specs):\n" +"... xs.sort(key=attrgetter(key), reverse=reverse)\n" +"... return xs\n" +"\n" +">>> multisort(list(student_objects), (('grade', True), ('age', False)))\n" +"[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]" +msgstr "" + #: ../../howto/sorting.rst:206 msgid "" "The `Timsort `_ algorithm used in " @@ -251,6 +378,15 @@ msgid "" "For example, to sort the student data by *grade* using the DSU approach:" msgstr "例如用上面說的方式來以 *grade* 排序學生資料:" +#: ../../howto/sorting.rst:224 +msgid "" +">>> decorated = [(student.grade, i, student) for i, student in " +"enumerate(student_objects)]\n" +">>> decorated.sort()\n" +">>> [student for grade, i, student in decorated] # undecorate\n" +"[('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]" +msgstr "" + #: ../../howto/sorting.rst:231 msgid "" "This idiom works because tuples are compared lexicographically; the first " @@ -344,6 +480,10 @@ msgstr "" "為了滿足這些情境,Python 提供 :class:`functools.cmp_to_key` 來包裝比較函式," "讓其可以當作鍵函式來使用: ::" +#: ../../howto/sorting.rst:273 +msgid "sorted(words, key=cmp_to_key(strcoll)) # locale-aware sort order" +msgstr "" + #: ../../howto/sorting.rst:276 msgid "Odds and Ends" msgstr "雜項說明" @@ -370,6 +510,17 @@ msgstr "" "是,不加這個參數也可以模擬這個效果,只要使用內建的 :func:`reversed` 函式兩" "次:" +#: ../../howto/sorting.rst:288 +msgid "" +">>> data = [('red', 1), ('blue', 1), ('red', 2), ('blue', 2)]\n" +">>> standard_way = sorted(data, key=itemgetter(0), reverse=True)\n" +">>> double_reversed = list(reversed(sorted(reversed(data), " +"key=itemgetter(0))))\n" +">>> assert standard_way == double_reversed\n" +">>> standard_way\n" +"[('red', 1), ('red', 2), ('blue', 1), ('blue', 2)]" +msgstr "" + #: ../../howto/sorting.rst:297 msgid "" "The sort routines use ``<`` when making comparisons between two objects. So, " @@ -379,6 +530,13 @@ msgstr "" "排序時會使用 ``<`` 來比較兩個物件,因此要在類別裡面加入排序順序比較規則是簡單" "的,只要透過定義 :meth:`~object.__lt__` 方法:" +#: ../../howto/sorting.rst:301 +msgid "" +">>> Student.__lt__ = lambda self, other: self.age < other.age\n" +">>> sorted(student_objects)\n" +"[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]" +msgstr "" + #: ../../howto/sorting.rst:307 msgid "" "However, note that ``<`` can fall back to using :meth:`~object.__gt__` if :" @@ -398,6 +556,14 @@ msgstr "" "鍵函式不需要直接依賴用來排序的物件。鍵函式也可以存取外部資源,例如如果學生成" "績儲存在字典裡,它可以用來排序一個單獨的學生姓名串列:" +#: ../../howto/sorting.rst:319 +msgid "" +">>> students = ['dave', 'john', 'jane']\n" +">>> newgrades = {'john': 'F', 'jane':'A', 'dave': 'C'}\n" +">>> sorted(students, key=newgrades.__getitem__)\n" +"['jane', 'dave', 'john']" +msgstr "" + #: ../../howto/sorting.rst:327 msgid "Partial Sorts" msgstr "" diff --git a/howto/unicode.po b/howto/unicode.po index eca6919292..6709edf3b2 100644 --- a/howto/unicode.po +++ b/howto/unicode.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-07-24 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2018-05-23 14:37+0000\n" "Last-Translator: Adrian Liaw \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -91,6 +91,25 @@ msgid "" "corresponding code points:" msgstr "" +#: ../../howto/unicode.rst:53 +msgid "" +"0061 'a'; LATIN SMALL LETTER A\n" +"0062 'b'; LATIN SMALL LETTER B\n" +"0063 'c'; LATIN SMALL LETTER C\n" +"...\n" +"007B '{'; LEFT CURLY BRACKET\n" +"...\n" +"2167 'Ⅷ'; ROMAN NUMERAL EIGHT\n" +"2168 'Ⅸ'; ROMAN NUMERAL NINE\n" +"...\n" +"265E '♞'; BLACK CHESS KNIGHT\n" +"265F '♟'; BLACK CHESS PAWN\n" +"...\n" +"1F600 '😀'; GRINNING FACE\n" +"1F609 '😉'; WINKING FACE\n" +"..." +msgstr "" + #: ../../howto/unicode.rst:71 msgid "" "Strictly, these definitions imply that it's meaningless to say 'this is " @@ -131,6 +150,13 @@ msgid "" "representation, the string \"Python\" might look like this:" msgstr "" +#: ../../howto/unicode.rst:101 +msgid "" +" P y t h o n\n" +"0x50 00 00 00 79 00 00 00 74 00 00 00 68 00 00 00 6f 00 00 00 6e 00 00 00\n" +" 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23" +msgstr "" + #: ../../howto/unicode.rst:107 msgid "" "This representation is straightforward but using it presents a number of " @@ -299,11 +325,28 @@ msgid "" "include a Unicode character in a string literal::" msgstr "" +#: ../../howto/unicode.rst:199 +msgid "" +"try:\n" +" with open('/tmp/input.txt', 'r') as f:\n" +" ...\n" +"except OSError:\n" +" # 'File not found' error message.\n" +" print(\"Fichier non trouvé\")" +msgstr "" + #: ../../howto/unicode.rst:206 msgid "" "Side note: Python 3 also supports using Unicode characters in identifiers::" msgstr "" +#: ../../howto/unicode.rst:208 +msgid "" +"répertoire = \"/tmp/records.log\"\n" +"with open(répertoire, \"w\") as f:\n" +" f.write(\"test\\n\")" +msgstr "" + #: ../../howto/unicode.rst:212 msgid "" "If you can't enter a particular character in your editor or want to keep the " @@ -312,6 +355,16 @@ msgid "" "delta glyph instead of a \\u escape.) ::" msgstr "" +#: ../../howto/unicode.rst:217 +msgid "" +">>> \"\\N{GREEK CAPITAL LETTER DELTA}\" # Using the character name\n" +"'\\u0394'\n" +">>> \"\\u0394\" # Using a 16-bit hex value\n" +"'\\u0394'\n" +">>> \"\\U00000394\" # Using a 32-bit hex value\n" +"'\\u0394'" +msgstr "" + #: ../../howto/unicode.rst:224 msgid "" "In addition, one can create a string using the :func:`~bytes.decode` method " @@ -330,6 +383,21 @@ msgid "" "examples show the differences::" msgstr "" +#: ../../howto/unicode.rst:236 +msgid "" +">>> b'\\x80abc'.decode(\"utf-8\", \"strict\") \n" +"Traceback (most recent call last):\n" +" ...\n" +"UnicodeDecodeError: 'utf-8' codec can't decode byte 0x80 in position 0:\n" +" invalid start byte\n" +">>> b'\\x80abc'.decode(\"utf-8\", \"replace\")\n" +"'\\ufffdabc'\n" +">>> b'\\x80abc'.decode(\"utf-8\", \"backslashreplace\")\n" +"'\\\\x80abc'\n" +">>> b'\\x80abc'.decode(\"utf-8\", \"ignore\")\n" +"'abc'" +msgstr "" + #: ../../howto/unicode.rst:248 msgid "" "Encodings are specified as strings containing the encoding's name. Python " @@ -348,6 +416,14 @@ msgid "" "returns the code point value::" msgstr "" +#: ../../howto/unicode.rst:260 +msgid "" +">>> chr(57344)\n" +"'\\ue000'\n" +">>> ord('\\ue000')\n" +"57344" +msgstr "" + #: ../../howto/unicode.rst:266 msgid "Converting to Bytes" msgstr "" @@ -374,6 +450,28 @@ msgstr "" msgid "The following example shows the different results::" msgstr "" +#: ../../howto/unicode.rst:282 +msgid "" +">>> u = chr(40960) + 'abcd' + chr(1972)\n" +">>> u.encode('utf-8')\n" +"b'\\xea\\x80\\x80abcd\\xde\\xb4'\n" +">>> u.encode('ascii') \n" +"Traceback (most recent call last):\n" +" ...\n" +"UnicodeEncodeError: 'ascii' codec can't encode character '\\ua000' in\n" +" position 0: ordinal not in range(128)\n" +">>> u.encode('ascii', 'ignore')\n" +"b'abcd'\n" +">>> u.encode('ascii', 'replace')\n" +"b'?abcd?'\n" +">>> u.encode('ascii', 'xmlcharrefreplace')\n" +"b'ꀀabcd޴'\n" +">>> u.encode('ascii', 'backslashreplace')\n" +"b'\\\\ua000abcd\\\\u07b4'\n" +">>> u.encode('ascii', 'namereplace')\n" +"b'\\\\N{YI SYLLABLE IT}abcd\\\\u07b4'" +msgstr "" + #: ../../howto/unicode.rst:301 msgid "" "The low-level routines for registering and accessing the available encodings " @@ -396,6 +494,16 @@ msgid "" "digits, not four::" msgstr "" +#: ../../howto/unicode.rst:317 +msgid "" +">>> s = \"a\\xac\\u1234\\u20ac\\U00008000\"\n" +"... # ^^^^ two-digit hex escape\n" +"... # ^^^^^^ four-digit Unicode escape\n" +"... # ^^^^^^^^^^ eight-digit Unicode escape\n" +">>> [ord(c) for c in s]\n" +"[97, 172, 4660, 8364, 32768]" +msgstr "" + #: ../../howto/unicode.rst:324 msgid "" "Using escape sequences for code points greater than 127 is fine in small " @@ -421,6 +529,15 @@ msgid "" "file::" msgstr "" +#: ../../howto/unicode.rst:339 +msgid "" +"#!/usr/bin/env python\n" +"# -*- coding: latin-1 -*-\n" +"\n" +"u = 'abcdé'\n" +"print(ord(u[-1]))" +msgstr "" + #: ../../howto/unicode.rst:345 msgid "" "The syntax is inspired by Emacs's notation for specifying variables local to " @@ -456,10 +573,34 @@ msgid "" "and prints the numeric value of one particular character::" msgstr "" +#: ../../howto/unicode.rst:369 +msgid "" +"import unicodedata\n" +"\n" +"u = chr(233) + chr(0x0bf2) + chr(3972) + chr(6000) + chr(13231)\n" +"\n" +"for i, c in enumerate(u):\n" +" print(i, '%04x' % ord(c), unicodedata.category(c), end=\" \")\n" +" print(unicodedata.name(c))\n" +"\n" +"# Get numeric value of second character\n" +"print(unicodedata.numeric(u[1]))" +msgstr "" + #: ../../howto/unicode.rst:380 msgid "When run, this prints:" msgstr "" +#: ../../howto/unicode.rst:382 +msgid "" +"0 00e9 Ll LATIN SMALL LETTER E WITH ACUTE\n" +"1 0bf2 No TAMIL NUMBER ONE THOUSAND\n" +"2 0f84 Mn TIBETAN MARK HALANTA\n" +"3 1770 Lo TAGBANWA LETTER SA\n" +"4 33af So SQUARE RAD OVER S SQUARED\n" +"1000.0" +msgstr "" + #: ../../howto/unicode.rst:391 msgid "" "The category codes are abbreviations describing the nature of the character. " @@ -496,6 +637,13 @@ msgid "" "which becomes the pair of lowercase letters 'ss'." msgstr "" +#: ../../howto/unicode.rst:421 +msgid "" +">>> street = 'Gürzenichstraße'\n" +">>> street.casefold()\n" +"'gürzenichstrasse'" +msgstr "" + #: ../../howto/unicode.rst:425 msgid "" "A second tool is the :mod:`unicodedata` module's :func:`~unicodedata." @@ -506,10 +654,36 @@ msgid "" "combining characters differently:" msgstr "" +#: ../../howto/unicode.rst:434 +msgid "" +"import unicodedata\n" +"\n" +"def compare_strs(s1, s2):\n" +" def NFD(s):\n" +" return unicodedata.normalize('NFD', s)\n" +"\n" +" return NFD(s1) == NFD(s2)\n" +"\n" +"single_char = 'ê'\n" +"multiple_chars = '\\N{LATIN SMALL LETTER E}\\N{COMBINING CIRCUMFLEX " +"ACCENT}'\n" +"print('length of first string=', len(single_char))\n" +"print('length of second string=', len(multiple_chars))\n" +"print(compare_strs(single_char, multiple_chars))" +msgstr "" + #: ../../howto/unicode.rst:448 msgid "When run, this outputs:" msgstr "" +#: ../../howto/unicode.rst:450 +msgid "" +"$ python compare-strs.py\n" +"length of first string= 1\n" +"length of second string= 2\n" +"True" +msgstr "" + #: ../../howto/unicode.rst:457 msgid "" "The first argument to the :func:`~unicodedata.normalize` function is a " @@ -521,6 +695,24 @@ msgstr "" msgid "The Unicode Standard also specifies how to do caseless comparisons::" msgstr "" +#: ../../howto/unicode.rst:463 +msgid "" +"import unicodedata\n" +"\n" +"def compare_caseless(s1, s2):\n" +" def NFD(s):\n" +" return unicodedata.normalize('NFD', s)\n" +"\n" +" return NFD(NFD(s1).casefold()) == NFD(NFD(s2).casefold())\n" +"\n" +"# Example usage\n" +"single_char = 'ê'\n" +"multiple_chars = '\\N{LATIN CAPITAL LETTER E}\\N{COMBINING CIRCUMFLEX " +"ACCENT}'\n" +"\n" +"print(compare_caseless(single_char, multiple_chars))" +msgstr "" + #: ../../howto/unicode.rst:477 msgid "" "This will print ``True``. (Why is :func:`!NFD` invoked twice? Because " @@ -549,6 +741,16 @@ msgid "" "numerals::" msgstr "" +#: ../../howto/unicode.rst:496 +msgid "" +"import re\n" +"p = re.compile(r'\\d+')\n" +"\n" +"s = \"Over \\u0e55\\u0e57 57 flavours\"\n" +"m = p.search(s)\n" +"print(repr(m.group()))" +msgstr "" + #: ../../howto/unicode.rst:503 msgid "" "When executed, ``\\d+`` will match the Thai numerals and print them out. If " @@ -661,12 +863,27 @@ msgstr "" msgid "Reading Unicode from a file is therefore simple::" msgstr "" +#: ../../howto/unicode.rst:576 +msgid "" +"with open('unicode.txt', encoding='utf-8') as f:\n" +" for line in f:\n" +" print(repr(line))" +msgstr "" + #: ../../howto/unicode.rst:580 msgid "" "It's also possible to open files in update mode, allowing both reading and " "writing::" msgstr "" +#: ../../howto/unicode.rst:583 +msgid "" +"with open('test', encoding='utf-8', mode='w+') as f:\n" +" f.write('\\u4500 blah blah blah\\n')\n" +" f.seek(0)\n" +" print(repr(f.readline()[:1]))" +msgstr "" + #: ../../howto/unicode.rst:588 msgid "" "The Unicode character ``U+FEFF`` is used as a byte-order mark (BOM), and is " @@ -715,6 +932,13 @@ msgid "" "and it will be automatically converted to the right encoding for you::" msgstr "" +#: ../../howto/unicode.rst:622 +msgid "" +"filename = 'filename\\u4500abc'\n" +"with open(filename, 'w') as f:\n" +" f.write('blah\\n')" +msgstr "" + #: ../../howto/unicode.rst:626 msgid "" "Functions in the :mod:`os` module such as :func:`os.stat` will also accept " @@ -734,10 +958,28 @@ msgid "" "error handler>` is UTF-8, running the following program::" msgstr "" +#: ../../howto/unicode.rst:639 +msgid "" +"fn = 'filename\\u4500abc'\n" +"f = open(fn, 'w')\n" +"f.close()\n" +"\n" +"import os\n" +"print(os.listdir(b'.'))\n" +"print(os.listdir('.'))" +msgstr "" + #: ../../howto/unicode.rst:647 msgid "will produce the following output:" msgstr "" +#: ../../howto/unicode.rst:649 +msgid "" +"$ python listdir-test.py\n" +"[b'filename\\xe4\\x94\\x80abc', ...]\n" +"['filename\\u4500abc', ...]" +msgstr "" + #: ../../howto/unicode.rst:655 msgid "" "The first list contains UTF-8-encoded filenames, and the second list " @@ -810,6 +1052,17 @@ msgid "" "it with a :class:`~codecs.StreamRecoder` to return bytes encoded in UTF-8::" msgstr "" +#: ../../howto/unicode.rst:701 +msgid "" +"new_f = codecs.StreamRecoder(f,\n" +" # en/decoder: used by read() to encode its results and\n" +" # by write() to decode its input.\n" +" codecs.getencoder('utf-8'), codecs.getdecoder('utf-8'),\n" +"\n" +" # reader/writer: used to read and write to the stream.\n" +" codecs.getreader('latin-1'), codecs.getwriter('latin-1') )" +msgstr "" + #: ../../howto/unicode.rst:711 msgid "Files in an Unknown Encoding" msgstr "" @@ -822,6 +1075,18 @@ msgid "" "``surrogateescape`` error handler::" msgstr "" +#: ../../howto/unicode.rst:718 +msgid "" +"with open(fname, 'r', encoding=\"ascii\", errors=\"surrogateescape\") as f:\n" +" data = f.read()\n" +"\n" +"# make changes to the string 'data'\n" +"\n" +"with open(fname + '.new', 'w',\n" +" encoding=\"ascii\", errors=\"surrogateescape\") as f:\n" +" f.write(data)" +msgstr "" + #: ../../howto/unicode.rst:727 msgid "" "The ``surrogateescape`` error handler will decode any non-ASCII bytes as " diff --git a/howto/urllib2.po b/howto/urllib2.po index d912c08590..f0eb3d29f7 100644 --- a/howto/urllib2.po +++ b/howto/urllib2.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-05-09 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2022-06-27 09:36+0800\n" "Last-Translator: Adrian Liaw \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -102,6 +102,13 @@ msgstr "從 URL 取得資源" msgid "The simplest way to use urllib.request is as follows::" msgstr "以下是使用 urllib.request 最簡單的方法::" +#: ../../howto/urllib2.rst:48 +msgid "" +"import urllib.request\n" +"with urllib.request.urlopen('http://python.org/') as response:\n" +" html = response.read()" +msgstr "" + #: ../../howto/urllib2.rst:52 msgid "" "If you wish to retrieve a resource via URL and store it in a temporary " @@ -109,6 +116,20 @@ msgid "" "`tempfile.NamedTemporaryFile` functions::" msgstr "" +#: ../../howto/urllib2.rst:56 +msgid "" +"import shutil\n" +"import tempfile\n" +"import urllib.request\n" +"\n" +"with urllib.request.urlopen('http://python.org/') as response:\n" +" with tempfile.NamedTemporaryFile(delete=False) as tmp_file:\n" +" shutil.copyfileobj(response, tmp_file)\n" +"\n" +"with open(tmp_file.name) as html:\n" +" pass" +msgstr "" + #: ../../howto/urllib2.rst:67 msgid "" "Many uses of urllib will be that simple (note that instead of an 'http:' URL " @@ -128,12 +149,25 @@ msgid "" "for example call ``.read()`` on the response::" msgstr "" +#: ../../howto/urllib2.rst:80 +msgid "" +"import urllib.request\n" +"\n" +"req = urllib.request.Request('http://python.org/')\n" +"with urllib.request.urlopen(req) as response:\n" +" the_page = response.read()" +msgstr "" + #: ../../howto/urllib2.rst:86 msgid "" "Note that urllib.request makes use of the same Request interface to handle " "all URL schemes. For example, you can make an FTP request like so::" msgstr "" +#: ../../howto/urllib2.rst:89 +msgid "req = urllib.request.Request('ftp://example.com/')" +msgstr "" + #: ../../howto/urllib2.rst:91 msgid "" "In the case of HTTP, there are two extra things that Request objects allow " @@ -160,6 +194,23 @@ msgid "" "function from the :mod:`urllib.parse` library. ::" msgstr "" +#: ../../howto/urllib2.rst:110 +msgid "" +"import urllib.parse\n" +"import urllib.request\n" +"\n" +"url = 'http://www.someserver.com/cgi-bin/register.cgi'\n" +"values = {'name' : 'Michael Foord',\n" +" 'location' : 'Northampton',\n" +" 'language' : 'Python' }\n" +"\n" +"data = urllib.parse.urlencode(values)\n" +"data = data.encode('ascii') # data should be bytes\n" +"req = urllib.request.Request(url, data)\n" +"with urllib.request.urlopen(req) as response:\n" +" the_page = response.read()" +msgstr "" + #: ../../howto/urllib2.rst:124 msgid "" "Note that other encodings are sometimes required (e.g. for file upload from " @@ -184,6 +235,22 @@ msgstr "" msgid "This is done as follows::" msgstr "" +#: ../../howto/urllib2.rst:141 +msgid "" +">>> import urllib.request\n" +">>> import urllib.parse\n" +">>> data = {}\n" +">>> data['name'] = 'Somebody Here'\n" +">>> data['location'] = 'Northampton'\n" +">>> data['language'] = 'Python'\n" +">>> url_values = urllib.parse.urlencode(data)\n" +">>> print(url_values) # The order may differ from below. \n" +"name=Somebody+Here&language=Python&location=Northampton\n" +">>> url = 'http://www.example.com/example.cgi'\n" +">>> full_url = url + '?' + url_values\n" +">>> data = urllib.request.urlopen(full_url)" +msgstr "" + #: ../../howto/urllib2.rst:154 msgid "" "Notice that the full URL is created by adding a ``?`` to the URL, followed " @@ -213,6 +280,25 @@ msgid "" "Explorer [#]_. ::" msgstr "" +#: ../../howto/urllib2.rst:174 +msgid "" +"import urllib.parse\n" +"import urllib.request\n" +"\n" +"url = 'http://www.someserver.com/cgi-bin/register.cgi'\n" +"user_agent = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64)'\n" +"values = {'name': 'Michael Foord',\n" +" 'location': 'Northampton',\n" +" 'language': 'Python' }\n" +"headers = {'User-Agent': user_agent}\n" +"\n" +"data = urllib.parse.urlencode(values)\n" +"data = data.encode('ascii')\n" +"req = urllib.request.Request(url, data, headers)\n" +"with urllib.request.urlopen(req) as response:\n" +" the_page = response.read()" +msgstr "" + #: ../../howto/urllib2.rst:190 msgid "" "The response also has two useful methods. See the section on `info and " @@ -257,6 +343,16 @@ msgstr "" msgid "e.g. ::" msgstr "" +#: ../../howto/urllib2.rst:216 +msgid "" +">>> req = urllib.request.Request('http://www.pretend_server.org')\n" +">>> try: urllib.request.urlopen(req)\n" +"... except urllib.error.URLError as e:\n" +"... print(e.reason) \n" +"...\n" +"(4, 'getaddrinfo failed')" +msgstr "" + #: ../../howto/urllib2.rst:225 msgid "HTTPError" msgstr "HTTPError" @@ -302,6 +398,77 @@ msgid "" "The dictionary is reproduced here for convenience ::" msgstr "" +#: ../../howto/urllib2.rst:251 +msgid "" +"# Table mapping response codes to messages; entries have the\n" +"# form {code: (shortmessage, longmessage)}.\n" +"responses = {\n" +" 100: ('Continue', 'Request received, please continue'),\n" +" 101: ('Switching Protocols',\n" +" 'Switching to new protocol; obey Upgrade header'),\n" +"\n" +" 200: ('OK', 'Request fulfilled, document follows'),\n" +" 201: ('Created', 'Document created, URL follows'),\n" +" 202: ('Accepted',\n" +" 'Request accepted, processing continues off-line'),\n" +" 203: ('Non-Authoritative Information', 'Request fulfilled from cache'),\n" +" 204: ('No Content', 'Request fulfilled, nothing follows'),\n" +" 205: ('Reset Content', 'Clear input form for further input.'),\n" +" 206: ('Partial Content', 'Partial content follows.'),\n" +"\n" +" 300: ('Multiple Choices',\n" +" 'Object has several resources -- see URI list'),\n" +" 301: ('Moved Permanently', 'Object moved permanently -- see URI list'),\n" +" 302: ('Found', 'Object moved temporarily -- see URI list'),\n" +" 303: ('See Other', 'Object moved -- see Method and URL list'),\n" +" 304: ('Not Modified',\n" +" 'Document has not changed since given time'),\n" +" 305: ('Use Proxy',\n" +" 'You must use proxy specified in Location to access this '\n" +" 'resource.'),\n" +" 307: ('Temporary Redirect',\n" +" 'Object moved temporarily -- see URI list'),\n" +"\n" +" 400: ('Bad Request',\n" +" 'Bad request syntax or unsupported method'),\n" +" 401: ('Unauthorized',\n" +" 'No permission -- see authorization schemes'),\n" +" 402: ('Payment Required',\n" +" 'No payment -- see charging schemes'),\n" +" 403: ('Forbidden',\n" +" 'Request forbidden -- authorization will not help'),\n" +" 404: ('Not Found', 'Nothing matches the given URI'),\n" +" 405: ('Method Not Allowed',\n" +" 'Specified method is invalid for this server.'),\n" +" 406: ('Not Acceptable', 'URI not available in preferred format.'),\n" +" 407: ('Proxy Authentication Required', 'You must authenticate with '\n" +" 'this proxy before proceeding.'),\n" +" 408: ('Request Timeout', 'Request timed out; try again later.'),\n" +" 409: ('Conflict', 'Request conflict.'),\n" +" 410: ('Gone',\n" +" 'URI no longer exists and has been permanently removed.'),\n" +" 411: ('Length Required', 'Client must specify Content-Length.'),\n" +" 412: ('Precondition Failed', 'Precondition in headers is false.'),\n" +" 413: ('Request Entity Too Large', 'Entity is too large.'),\n" +" 414: ('Request-URI Too Long', 'URI is too long.'),\n" +" 415: ('Unsupported Media Type', 'Entity body in unsupported format.'),\n" +" 416: ('Requested Range Not Satisfiable',\n" +" 'Cannot satisfy request range.'),\n" +" 417: ('Expectation Failed',\n" +" 'Expect condition could not be satisfied.'),\n" +"\n" +" 500: ('Internal Server Error', 'Server got itself in trouble'),\n" +" 501: ('Not Implemented',\n" +" 'Server does not support this operation'),\n" +" 502: ('Bad Gateway', 'Invalid responses from another server/proxy.'),\n" +" 503: ('Service Unavailable',\n" +" 'The server cannot process the request due to a high load'),\n" +" 504: ('Gateway Timeout',\n" +" 'The gateway server did not receive a timely response'),\n" +" 505: ('HTTP Version Not Supported', 'Cannot fulfill request.'),\n" +" }" +msgstr "" + #: ../../howto/urllib2.rst:319 msgid "" "When an error is raised the server responds by returning an HTTP error code " @@ -311,6 +478,24 @@ msgid "" "``urllib.response`` module::" msgstr "" +#: ../../howto/urllib2.rst:324 +msgid "" +">>> req = urllib.request.Request('http://www.python.org/fish.html')\n" +">>> try:\n" +"... urllib.request.urlopen(req)\n" +"... except urllib.error.HTTPError as e:\n" +"... print(e.code)\n" +"... print(e.read()) \n" +"...\n" +"404\n" +"b'\\n\\n\\nPage Not Found\\n\n" +" ..." +msgstr "" + #: ../../howto/urllib2.rst:339 msgid "Wrapping it Up" msgstr "" @@ -326,6 +511,23 @@ msgstr "" msgid "Number 1" msgstr "" +#: ../../howto/urllib2.rst:350 +msgid "" +"from urllib.request import Request, urlopen\n" +"from urllib.error import URLError, HTTPError\n" +"req = Request(someurl)\n" +"try:\n" +" response = urlopen(req)\n" +"except HTTPError as e:\n" +" print('The server couldn\\'t fulfill the request.')\n" +" print('Error code: ', e.code)\n" +"except URLError as e:\n" +" print('We failed to reach a server.')\n" +" print('Reason: ', e.reason)\n" +"else:\n" +" # everything is fine" +msgstr "" + #: ../../howto/urllib2.rst:367 msgid "" "The ``except HTTPError`` *must* come first, otherwise ``except URLError`` " @@ -336,6 +538,24 @@ msgstr "" msgid "Number 2" msgstr "" +#: ../../howto/urllib2.rst:375 +msgid "" +"from urllib.request import Request, urlopen\n" +"from urllib.error import URLError\n" +"req = Request(someurl)\n" +"try:\n" +" response = urlopen(req)\n" +"except URLError as e:\n" +" if hasattr(e, 'reason'):\n" +" print('We failed to reach a server.')\n" +" print('Reason: ', e.reason)\n" +" elif hasattr(e, 'code'):\n" +" print('The server couldn\\'t fulfill the request.')\n" +" print('Error code: ', e.code)\n" +"else:\n" +" # everything is fine" +msgstr "" + #: ../../howto/urllib2.rst:392 msgid "info and geturl" msgstr "" @@ -451,6 +671,10 @@ msgstr "" msgid "e.g." msgstr "" +#: ../../howto/urllib2.rst:463 +msgid "WWW-Authenticate: Basic realm=\"cPanel Users\"" +msgstr "" + #: ../../howto/urllib2.rst:468 msgid "" "The client should then retry the request with the appropriate name and " @@ -478,6 +702,29 @@ msgid "" "\"deeper\" than the URL you pass to .add_password() will also match. ::" msgstr "" +#: ../../howto/urllib2.rst:486 +msgid "" +"# create a password manager\n" +"password_mgr = urllib.request.HTTPPasswordMgrWithDefaultRealm()\n" +"\n" +"# Add the username and password.\n" +"# If we knew the realm, we could use it instead of None.\n" +"top_level_url = \"http://example.com/foo/\"\n" +"password_mgr.add_password(None, top_level_url, username, password)\n" +"\n" +"handler = urllib.request.HTTPBasicAuthHandler(password_mgr)\n" +"\n" +"# create \"opener\" (OpenerDirector instance)\n" +"opener = urllib.request.build_opener(handler)\n" +"\n" +"# use the opener to fetch a URL\n" +"opener.open(a_url)\n" +"\n" +"# Install the opener.\n" +"# Now all calls to urllib.request.urlopen use our opener.\n" +"urllib.request.install_opener(opener)" +msgstr "" + #: ../../howto/urllib2.rst:508 msgid "" "In the above example we only supplied our ``HTTPBasicAuthHandler`` to " @@ -513,6 +760,13 @@ msgid "" "similar steps to setting up a `Basic Authentication`_ handler: ::" msgstr "" +#: ../../howto/urllib2.rst:534 +msgid "" +">>> proxy_support = urllib.request.ProxyHandler({})\n" +">>> opener = urllib.request.build_opener(proxy_support)\n" +">>> urllib.request.install_opener(opener)" +msgstr "" + #: ../../howto/urllib2.rst:540 msgid "" "Currently ``urllib.request`` *does not* support fetching of ``https`` " @@ -546,6 +800,21 @@ msgid "" "sockets using ::" msgstr "" +#: ../../howto/urllib2.rst:562 +msgid "" +"import socket\n" +"import urllib.request\n" +"\n" +"# timeout in seconds\n" +"timeout = 10\n" +"socket.setdefaulttimeout(timeout)\n" +"\n" +"# this call to urllib.request.urlopen now uses the default timeout\n" +"# we have set in the socket module\n" +"req = urllib.request.Request('http://www.voidspace.org.uk')\n" +"response = urllib.request.urlopen(req)" +msgstr "" + #: ../../howto/urllib2.rst:579 msgid "Footnotes" msgstr "註解" diff --git a/library/__main__.po b/library/__main__.po index 7742bbf409..a5b9d746d8 100644 --- a/library/__main__.po +++ b/library/__main__.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-07-05 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2023-12-21 14:49+0800\n" "Last-Translator: Liang-Bo Wang \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -64,6 +64,13 @@ msgstr "" "當引入 Python 模組或套件時,``__name__`` 設定為模組的名稱。通常來說,這是 " "Python 檔案本身的名稱,且不含 .py 副檔名: ::" +#: ../../library/__main__.rst:31 +msgid "" +">>> import configparser\n" +">>> configparser.__name__\n" +"'configparser'" +msgstr "" + #: ../../library/__main__.rst:35 msgid "" "If the file is part of a package, ``__name__`` will also include the parent " @@ -72,6 +79,13 @@ msgstr "" "如果檔案是套件的一部分,則 ``__name__`` 也會包含父套件 (parent package) 的路" "徑: ::" +#: ../../library/__main__.rst:38 +msgid "" +">>> from concurrent.futures import process\n" +">>> process.__name__\n" +"'concurrent.futures.process'" +msgstr "" + #: ../../library/__main__.rst:42 msgid "" "However, if the module is executed in the top-level code environment, its " @@ -104,25 +118,64 @@ msgstr "頂層程式碼環境可以是:" msgid "the scope of an interactive prompt::" msgstr "互動式提示字元的作用域: ::" +#: ../../library/__main__.rst:57 +#, fuzzy +msgid "" +">>> __name__\n" +"'__main__'" +msgstr "``__name__ == '__main__'``" + #: ../../library/__main__.rst:60 msgid "the Python module passed to the Python interpreter as a file argument:" msgstr "將 Python 模組作為檔案引數傳遞給 Python 直譯器:" +#: ../../library/__main__.rst:62 +msgid "" +"$ python helloworld.py\n" +"Hello, world!" +msgstr "" + #: ../../library/__main__.rst:67 msgid "" "the Python module or package passed to the Python interpreter with the :" "option:`-m` argument:" msgstr "使用 :option:`-m` 引數傳遞給 Python 直譯器的 Python 模組或套件:" +#: ../../library/__main__.rst:70 +msgid "" +"$ python -m tarfile\n" +"usage: tarfile.py [-h] [-v] (...)" +msgstr "" + #: ../../library/__main__.rst:75 msgid "Python code read by the Python interpreter from standard input:" msgstr "Python 直譯器從標準輸入讀取 Python 程式碼:" +#: ../../library/__main__.rst:77 +msgid "" +"$ echo \"import this\" | python\n" +"The Zen of Python, by Tim Peters\n" +"\n" +"Beautiful is better than ugly.\n" +"Explicit is better than implicit.\n" +"..." +msgstr "" + #: ../../library/__main__.rst:86 msgid "" "Python code passed to the Python interpreter with the :option:`-c` argument:" msgstr "使用 :option:`-c` 引數傳遞給 Python 直譯器的 Python 程式碼:" +#: ../../library/__main__.rst:88 +msgid "" +"$ python -c \"import this\"\n" +"The Zen of Python, by Tim Peters\n" +"\n" +"Beautiful is better than ugly.\n" +"Explicit is better than implicit.\n" +"..." +msgstr "" + #: ../../library/__main__.rst:97 msgid "" "In each of these situations, the top-level module's ``__name__`` is set to " @@ -140,6 +193,13 @@ msgstr "" "許當模組未從 import 陳述式初始化時,使用常見的慣用語法 (idiom) 來有條件地執行" "程式碼: ::" +#: ../../library/__main__.rst:105 +msgid "" +"if __name__ == '__main__':\n" +" # Execute when the module is not initialized from an import statement.\n" +" ..." +msgstr "" + #: ../../library/__main__.rst:111 msgid "" "For a more detailed look at how ``__name__`` is set in all situations, see " @@ -182,6 +242,29 @@ msgstr "" "碼的清晰度和正確性。大多數情況下,名為 ``main`` 的函式封裝 (encapsulate) 了程" "式的主要行為: ::" +#: ../../library/__main__.rst:131 +msgid "" +"# echo.py\n" +"\n" +"import shlex\n" +"import sys\n" +"\n" +"def echo(phrase: str) -> None:\n" +" \"\"\"A dummy wrapper around print.\"\"\"\n" +" # for demonstration purposes, you can imagine that there is some\n" +" # valuable and reusable logic inside this function\n" +" print(phrase)\n" +"\n" +"def main() -> int:\n" +" \"\"\"Echo the input arguments to standard output\"\"\"\n" +" phrase = shlex.join(sys.argv)\n" +" echo(phrase)\n" +" return 0\n" +"\n" +"if __name__ == '__main__':\n" +" sys.exit(main()) # next section explains the use of sys.exit" +msgstr "" + #: ../../library/__main__.rst:151 msgid "" "Note that if the module didn't encapsulate code inside the ``main`` function " @@ -222,6 +305,10 @@ msgstr "" "後,`pip `_ 將函式呼叫插入到模板腳本中,其中 ``main`` " "的回傳值被傳遞到 :func:`sys.exit` 中。例如: ::" +#: ../../library/__main__.rst:173 +msgid "sys.exit(main())" +msgstr "" + #: ../../library/__main__.rst:175 msgid "" "Since the call to ``main`` is wrapped in :func:`sys.exit`, the expectation " @@ -281,6 +368,14 @@ msgstr "" "``__main__.py`` 檔案用於為套件提供命令列介面。假設下面有虛構的套件 " "\"bandclass\":" +#: ../../library/__main__.rst:206 +msgid "" +"bandclass\n" +" ├── __init__.py\n" +" ├── __main__.py\n" +" └── student.py" +msgstr "" + #: ../../library/__main__.rst:213 msgid "" "``__main__.py`` will be executed when the package itself is invoked directly " @@ -289,6 +384,10 @@ msgstr "" "當使用 :option:`-m` 旗標 (flag) 直接從命令列呼叫套件本身時,將執行 " "``__main__.py``。例如:" +#: ../../library/__main__.rst:216 +msgid "$ python -m bandclass" +msgstr "" + #: ../../library/__main__.rst:220 msgid "" "This command will cause ``__main__.py`` to run. How you utilize this " @@ -299,6 +398,17 @@ msgstr "" "該命令將導致 ``__main__.py`` 執行。如何利用此機制將取決於你正在編寫的套件的性" "質,但在這種虛構的情況下,允許教師搜尋學生可能是有意義的: ::" +#: ../../library/__main__.rst:225 +msgid "" +"# bandclass/__main__.py\n" +"\n" +"import sys\n" +"from .student import search_students\n" +"\n" +"student_name = sys.argv[1] if len(sys.argv) >= 2 else ''\n" +"print(f'Found student: {search_students(student_name)}')" +msgstr "" + #: ../../library/__main__.rst:233 msgid "" "Note that ``from .student import search_students`` is an example of a " @@ -331,6 +441,13 @@ msgstr "" "塊,它依然會如預期般地運作。因為當引入套件,其 ``__name__`` 屬性將會包含套件" "的路徑: ::" +#: ../../library/__main__.rst:250 +msgid "" +">>> import asyncio.__main__\n" +">>> asyncio.__main__.__name__\n" +"'asyncio.__main__'" +msgstr "" + #: ../../library/__main__.rst:254 msgid "" "This won't work for ``__main__.py`` files in the root directory of a ``." @@ -387,14 +504,59 @@ msgstr "" msgid "Here is an example module that consumes the ``__main__`` namespace::" msgstr "這是一個使用 ``__main__`` 命名空間的範例模組:" +#: ../../library/__main__.rst:284 +msgid "" +"# namely.py\n" +"\n" +"import __main__\n" +"\n" +"def did_user_define_their_name():\n" +" return 'my_name' in dir(__main__)\n" +"\n" +"def print_user_name():\n" +" if not did_user_define_their_name():\n" +" raise ValueError('Define the variable `my_name`!')\n" +"\n" +" if '__file__' in dir(__main__):\n" +" print(__main__.my_name, \"found in file\", __main__.__file__)\n" +" else:\n" +" print(__main__.my_name)" +msgstr "" + #: ../../library/__main__.rst:300 msgid "Example usage of this module could be as follows::" msgstr "該模組的範例用法如下: ::" +#: ../../library/__main__.rst:302 +msgid "" +"# start.py\n" +"\n" +"import sys\n" +"\n" +"from namely import print_user_name\n" +"\n" +"# my_name = \"Dinsdale\"\n" +"\n" +"def main():\n" +" try:\n" +" print_user_name()\n" +" except ValueError as ve:\n" +" return str(ve)\n" +"\n" +"if __name__ == \"__main__\":\n" +" sys.exit(main())" +msgstr "" + #: ../../library/__main__.rst:319 msgid "Now, if we started our program, the result would look like this:" msgstr "現在,如果我們啟動程式,結果將如下所示:" +#: ../../library/__main__.rst:321 +msgid "" +"$ python start.py\n" +"Define the variable `my_name`!" +msgstr "" + #: ../../library/__main__.rst:326 msgid "" "The exit code of the program would be 1, indicating an error. Uncommenting " @@ -404,6 +566,12 @@ msgstr "" "程式的結束代碼將為 1,表示出現錯誤。取消註解 ``my_name = \"Dinsdale\"`` 而修" "復程式後,現在它以狀態碼 0 結束,表示成功:" +#: ../../library/__main__.rst:330 +msgid "" +"$ python start.py\n" +"Dinsdale found in file /path/to/start.py" +msgstr "" + #: ../../library/__main__.rst:335 msgid "" "Note that importing ``__main__`` doesn't cause any issues with " @@ -443,6 +611,22 @@ msgstr "" "Python REPL 是「頂層環境」的另一個範例,因此 REPL 中定義的任何內容都成為 作域" "的一部分: ::" +#: ../../library/__main__.rst:351 +msgid "" +">>> import namely\n" +">>> namely.did_user_define_their_name()\n" +"False\n" +">>> namely.print_user_name()\n" +"Traceback (most recent call last):\n" +"...\n" +"ValueError: Define the variable `my_name`!\n" +">>> my_name = 'Jabberwocky'\n" +">>> namely.did_user_define_their_name()\n" +"True\n" +">>> namely.print_user_name()\n" +"Jabberwocky" +msgstr "" + #: ../../library/__main__.rst:364 msgid "" "Note that in this case the ``__main__`` scope doesn't contain a ``__file__`` " diff --git a/library/argparse.po b/library/argparse.po index 01c35dd98c..c5e8ebcd5e 100644 --- a/library/argparse.po +++ b/library/argparse.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-05-09 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2018-05-23 14:38+0000\n" "Last-Translator: Adrian Liaw \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -61,6 +61,14 @@ msgid "" "whole::" msgstr "" +#: ../../library/argparse.rst:36 +msgid "" +"parser = argparse.ArgumentParser(\n" +" prog='ProgramName',\n" +" description='What the program does',\n" +" epilog='Text at the bottom of help')" +msgstr "" + #: ../../library/argparse.rst:41 msgid "" "The :meth:`ArgumentParser.add_argument` method attaches individual argument " @@ -68,12 +76,26 @@ msgid "" "that accept values, and on/off flags::" msgstr "" +#: ../../library/argparse.rst:45 +msgid "" +"parser.add_argument('filename') # positional argument\n" +"parser.add_argument('-c', '--count') # option that takes a value\n" +"parser.add_argument('-v', '--verbose',\n" +" action='store_true') # on/off flag" +msgstr "" + #: ../../library/argparse.rst:50 msgid "" "The :meth:`ArgumentParser.parse_args` method runs the parser and places the " "extracted data in a :class:`argparse.Namespace` object::" msgstr "" +#: ../../library/argparse.rst:53 +msgid "" +"args = parser.parse_args()\n" +"print(args.filename, args.count, args.verbose)" +msgstr "" + #: ../../library/argparse.rst:58 msgid "Quick Links for add_argument()" msgstr "" @@ -213,22 +235,68 @@ msgid "" "produces either the sum or the max::" msgstr "" +#: ../../library/argparse.rst:82 +msgid "" +"import argparse\n" +"\n" +"parser = argparse.ArgumentParser(description='Process some integers.')\n" +"parser.add_argument('integers', metavar='N', type=int, nargs='+',\n" +" help='an integer for the accumulator')\n" +"parser.add_argument('--sum', dest='accumulate', action='store_const',\n" +" const=sum, default=max,\n" +" help='sum the integers (default: find the max)')\n" +"\n" +"args = parser.parse_args()\n" +"print(args.accumulate(args.integers))" +msgstr "" + #: ../../library/argparse.rst:94 msgid "" "Assuming the above Python code is saved into a file called ``prog.py``, it " "can be run at the command line and it provides useful help messages:" msgstr "" +#: ../../library/argparse.rst:97 +msgid "" +"$ python prog.py -h\n" +"usage: prog.py [-h] [--sum] N [N ...]\n" +"\n" +"Process some integers.\n" +"\n" +"positional arguments:\n" +" N an integer for the accumulator\n" +"\n" +"options:\n" +" -h, --help show this help message and exit\n" +" --sum sum the integers (default: find the max)" +msgstr "" + #: ../../library/argparse.rst:111 msgid "" "When run with the appropriate arguments, it prints either the sum or the max " "of the command-line integers:" msgstr "" +#: ../../library/argparse.rst:114 +msgid "" +"$ python prog.py 1 2 3 4\n" +"4\n" +"\n" +"$ python prog.py 1 2 3 4 --sum\n" +"10" +msgstr "" + #: ../../library/argparse.rst:122 msgid "If invalid arguments are passed in, an error will be displayed:" msgstr "" +#: ../../library/argparse.rst:124 +msgid "" +"$ python prog.py a b c\n" +"usage: prog.py [-h] [--sum] N [N ...]\n" +"prog.py: error: argument N: invalid int value: 'a'" +msgstr "" + #: ../../library/argparse.rst:130 msgid "The following sections walk you through this example." msgstr "" @@ -243,6 +311,11 @@ msgid "" "`ArgumentParser` object::" msgstr "" +#: ../../library/argparse.rst:139 +msgid "" +">>> parser = argparse.ArgumentParser(description='Process some integers.')" +msgstr "" + #: ../../library/argparse.rst:141 msgid "" "The :class:`ArgumentParser` object will hold all the information necessary " @@ -263,6 +336,15 @@ msgid "" "example::" msgstr "" +#: ../../library/argparse.rst:154 +msgid "" +">>> parser.add_argument('integers', metavar='N', type=int, nargs='+',\n" +"... help='an integer for the accumulator')\n" +">>> parser.add_argument('--sum', dest='accumulate', action='store_const',\n" +"... const=sum, default=max,\n" +"... help='sum the integers (default: find the max)')" +msgstr "" + #: ../../library/argparse.rst:160 msgid "" "Later, calling :meth:`~ArgumentParser.parse_args` will return an object with " @@ -285,6 +367,12 @@ msgid "" "from attributes parsed out of the command line::" msgstr "" +#: ../../library/argparse.rst:176 +msgid "" +">>> parser.parse_args(['--sum', '7', '-1', '42'])\n" +"Namespace(accumulate=, integers=[7, -1, 42])" +msgstr "" + #: ../../library/argparse.rst:179 msgid "" "In a script, :meth:`~ArgumentParser.parse_args` will typically be called " @@ -405,18 +493,53 @@ msgid "" "``myprogram.py`` with the following code::" msgstr "" +#: ../../library/argparse.rst:258 ../../library/argparse.rst:678 +msgid "" +"import argparse\n" +"parser = argparse.ArgumentParser()\n" +"parser.add_argument('--foo', help='foo help')\n" +"args = parser.parse_args()" +msgstr "" + #: ../../library/argparse.rst:263 msgid "" "The help for this program will display ``myprogram.py`` as the program name " "(regardless of where the program was invoked from):" msgstr "" +#: ../../library/argparse.rst:266 +msgid "" +"$ python myprogram.py --help\n" +"usage: myprogram.py [-h] [--foo FOO]\n" +"\n" +"options:\n" +" -h, --help show this help message and exit\n" +" --foo FOO foo help\n" +"$ cd ..\n" +"$ python subdir/myprogram.py --help\n" +"usage: myprogram.py [-h] [--foo FOO]\n" +"\n" +"options:\n" +" -h, --help show this help message and exit\n" +" --foo FOO foo help" +msgstr "" + #: ../../library/argparse.rst:282 msgid "" "To change this default behavior, another value can be supplied using the " "``prog=`` argument to :class:`ArgumentParser`::" msgstr "" +#: ../../library/argparse.rst:285 +msgid "" +">>> parser = argparse.ArgumentParser(prog='myprogram')\n" +">>> parser.print_help()\n" +"usage: myprogram [-h]\n" +"\n" +"options:\n" +" -h, --help show this help message and exit" +msgstr "" + #: ../../library/argparse.rst:292 msgid "" "Note that the program name, whether determined from ``sys.argv[0]`` or from " @@ -424,6 +547,18 @@ msgid "" "format specifier." msgstr "" +#: ../../library/argparse.rst:298 +msgid "" +">>> parser = argparse.ArgumentParser(prog='myprogram')\n" +">>> parser.add_argument('--foo', help='foo of the %(prog)s program')\n" +">>> parser.print_help()\n" +"usage: myprogram [-h] [--foo FOO]\n" +"\n" +"options:\n" +" -h, --help show this help message and exit\n" +" --foo FOO foo of the myprogram program" +msgstr "" + #: ../../library/argparse.rst:309 msgid "usage" msgstr "" @@ -434,11 +569,44 @@ msgid "" "arguments it contains::" msgstr "" +#: ../../library/argparse.rst:314 +msgid "" +">>> parser = argparse.ArgumentParser(prog='PROG')\n" +">>> parser.add_argument('--foo', nargs='?', help='foo help')\n" +">>> parser.add_argument('bar', nargs='+', help='bar help')\n" +">>> parser.print_help()\n" +"usage: PROG [-h] [--foo [FOO]] bar [bar ...]\n" +"\n" +"positional arguments:\n" +" bar bar help\n" +"\n" +"options:\n" +" -h, --help show this help message and exit\n" +" --foo [FOO] foo help" +msgstr "" + #: ../../library/argparse.rst:327 msgid "" "The default message can be overridden with the ``usage=`` keyword argument::" msgstr "" +#: ../../library/argparse.rst:329 +msgid "" +">>> parser = argparse.ArgumentParser(prog='PROG', usage='%(prog)s " +"[options]')\n" +">>> parser.add_argument('--foo', nargs='?', help='foo help')\n" +">>> parser.add_argument('bar', nargs='+', help='bar help')\n" +">>> parser.print_help()\n" +"usage: PROG [options]\n" +"\n" +"positional arguments:\n" +" bar bar help\n" +"\n" +"options:\n" +" -h, --help show this help message and exit\n" +" --foo [FOO] foo help" +msgstr "" + #: ../../library/argparse.rst:342 msgid "" "The ``%(prog)s`` format specifier is available to fill in the program name " @@ -458,6 +626,18 @@ msgid "" "messages for the various arguments::" msgstr "" +#: ../../library/argparse.rst:357 +msgid "" +">>> parser = argparse.ArgumentParser(description='A foo that bars')\n" +">>> parser.print_help()\n" +"usage: argparse.py [-h]\n" +"\n" +"A foo that bars\n" +"\n" +"options:\n" +" -h, --help show this help message and exit" +msgstr "" + #: ../../library/argparse.rst:366 msgid "" "By default, the description will be line-wrapped so that it fits within the " @@ -475,6 +655,22 @@ msgid "" "``epilog=`` argument to :class:`ArgumentParser`::" msgstr "" +#: ../../library/argparse.rst:377 +msgid "" +">>> parser = argparse.ArgumentParser(\n" +"... description='A foo that bars',\n" +"... epilog=\"And that's how you'd foo a bar\")\n" +">>> parser.print_help()\n" +"usage: argparse.py [-h]\n" +"\n" +"A foo that bars\n" +"\n" +"options:\n" +" -h, --help show this help message and exit\n" +"\n" +"And that's how you'd foo a bar" +msgstr "" + #: ../../library/argparse.rst:390 msgid "" "As with the description_ argument, the ``epilog=`` text is by default line-" @@ -497,6 +693,22 @@ msgid "" "object being constructed::" msgstr "" +#: ../../library/argparse.rst:405 +msgid "" +">>> parent_parser = argparse.ArgumentParser(add_help=False)\n" +">>> parent_parser.add_argument('--parent', type=int)\n" +"\n" +">>> foo_parser = argparse.ArgumentParser(parents=[parent_parser])\n" +">>> foo_parser.add_argument('foo')\n" +">>> foo_parser.parse_args(['--parent', '2', 'XXX'])\n" +"Namespace(foo='XXX', parent=2)\n" +"\n" +">>> bar_parser = argparse.ArgumentParser(parents=[parent_parser])\n" +">>> bar_parser.add_argument('--bar')\n" +">>> bar_parser.parse_args(['--bar', 'YYY'])\n" +"Namespace(bar='YYY', parent=None)" +msgstr "" + #: ../../library/argparse.rst:418 msgid "" "Note that most parent parsers will specify ``add_help=False``. Otherwise, " @@ -530,6 +742,30 @@ msgid "" "command-line help messages::" msgstr "" +#: ../../library/argparse.rst:447 +msgid "" +">>> parser = argparse.ArgumentParser(\n" +"... prog='PROG',\n" +"... description='''this description\n" +"... was indented weird\n" +"... but that is okay''',\n" +"... epilog='''\n" +"... likewise for this epilog whose whitespace will\n" +"... be cleaned up and whose words will be wrapped\n" +"... across a couple lines''')\n" +">>> parser.print_help()\n" +"usage: PROG [-h]\n" +"\n" +"this description was indented weird but that is okay\n" +"\n" +"options:\n" +" -h, --help show this help message and exit\n" +"\n" +"likewise for this epilog whose whitespace will be cleaned up and whose " +"words\n" +"will be wrapped across a couple lines" +msgstr "" + #: ../../library/argparse.rst:467 msgid "" "Passing :class:`RawDescriptionHelpFormatter` as ``formatter_class=`` " @@ -537,6 +773,31 @@ msgid "" "should not be line-wrapped::" msgstr "" +#: ../../library/argparse.rst:471 +msgid "" +">>> parser = argparse.ArgumentParser(\n" +"... prog='PROG',\n" +"... formatter_class=argparse.RawDescriptionHelpFormatter,\n" +"... description=textwrap.dedent('''\\\n" +"... Please do not mess up this text!\n" +"... --------------------------------\n" +"... I have indented it\n" +"... exactly the way\n" +"... I want it\n" +"... '''))\n" +">>> parser.print_help()\n" +"usage: PROG [-h]\n" +"\n" +"Please do not mess up this text!\n" +"--------------------------------\n" +" I have indented it\n" +" exactly the way\n" +" I want it\n" +"\n" +"options:\n" +" -h, --help show this help message and exit" +msgstr "" + #: ../../library/argparse.rst:493 msgid "" ":class:`RawTextHelpFormatter` maintains whitespace for all sorts of help " @@ -551,6 +812,24 @@ msgid "" "default values to each of the argument help messages::" msgstr "" +#: ../../library/argparse.rst:501 +msgid "" +">>> parser = argparse.ArgumentParser(\n" +"... prog='PROG',\n" +"... formatter_class=argparse.ArgumentDefaultsHelpFormatter)\n" +">>> parser.add_argument('--foo', type=int, default=42, help='FOO!')\n" +">>> parser.add_argument('bar', nargs='*', default=[1, 2, 3], help='BAR!')\n" +">>> parser.print_help()\n" +"usage: PROG [-h] [--foo FOO] [bar ...]\n" +"\n" +"positional arguments:\n" +" bar BAR! (default: [1, 2, 3])\n" +"\n" +"options:\n" +" -h, --help show this help message and exit\n" +" --foo FOO FOO! (default: 42)" +msgstr "" + #: ../../library/argparse.rst:516 msgid "" ":class:`MetavarTypeHelpFormatter` uses the name of the type_ argument for " @@ -558,6 +837,24 @@ msgid "" "dest_ as the regular formatter does)::" msgstr "" +#: ../../library/argparse.rst:520 +msgid "" +">>> parser = argparse.ArgumentParser(\n" +"... prog='PROG',\n" +"... formatter_class=argparse.MetavarTypeHelpFormatter)\n" +">>> parser.add_argument('--foo', type=int)\n" +">>> parser.add_argument('bar', type=float)\n" +">>> parser.print_help()\n" +"usage: PROG [-h] [--foo int] float\n" +"\n" +"positional arguments:\n" +" float\n" +"\n" +"options:\n" +" -h, --help show this help message and exit\n" +" --foo int" +msgstr "" + #: ../../library/argparse.rst:537 msgid "prefix_chars" msgstr "prefix_chars" @@ -570,6 +867,15 @@ msgid "" "``prefix_chars=`` argument to the ArgumentParser constructor::" msgstr "" +#: ../../library/argparse.rst:545 +msgid "" +">>> parser = argparse.ArgumentParser(prog='PROG', prefix_chars='-+')\n" +">>> parser.add_argument('+f')\n" +">>> parser.add_argument('++bar')\n" +">>> parser.parse_args('+f X ++bar Y'.split())\n" +"Namespace(bar='Y', f='X')" +msgstr "" + #: ../../library/argparse.rst:551 msgid "" "The ``prefix_chars=`` argument defaults to ``'-'``. Supplying a set of " @@ -591,6 +897,17 @@ msgid "" "by the arguments they contain. For example::" msgstr "" +#: ../../library/argparse.rst:566 +msgid "" +">>> with open('args.txt', 'w', encoding=sys.getfilesystemencoding()) as fp:\n" +"... fp.write('-f\\nbar')\n" +"...\n" +">>> parser = argparse.ArgumentParser(fromfile_prefix_chars='@')\n" +">>> parser.add_argument('-f')\n" +">>> parser.parse_args(['-f', 'foo', '@args.txt'])\n" +"Namespace(f='bar')" +msgstr "" + #: ../../library/argparse.rst:574 msgid "" "Arguments read from a file must by default be one per line (but see also :" @@ -638,6 +955,17 @@ msgid "" "supply ``argument_default=SUPPRESS``::" msgstr "" +#: ../../library/argparse.rst:605 +msgid "" +">>> parser = argparse.ArgumentParser(argument_default=argparse.SUPPRESS)\n" +">>> parser.add_argument('--foo')\n" +">>> parser.add_argument('bar', nargs='?')\n" +">>> parser.parse_args(['--foo', '1', 'BAR'])\n" +"Namespace(bar='BAR', foo='1')\n" +">>> parser.parse_args([])\n" +"Namespace()" +msgstr "" + #: ../../library/argparse.rst:616 msgid "allow_abbrev" msgstr "allow_abbrev" @@ -653,6 +981,16 @@ msgstr "" msgid "This feature can be disabled by setting ``allow_abbrev`` to ``False``::" msgstr "" +#: ../../library/argparse.rst:624 +msgid "" +">>> parser = argparse.ArgumentParser(prog='PROG', allow_abbrev=False)\n" +">>> parser.add_argument('--foobar', action='store_true')\n" +">>> parser.add_argument('--foonley', action='store_false')\n" +">>> parser.parse_args(['--foon'])\n" +"usage: PROG [-h] [--foobar] [--foonley]\n" +"PROG: error: unrecognized arguments: --foon" +msgstr "" + #: ../../library/argparse.rst:635 msgid "conflict_handler" msgstr "conflict_handler" @@ -665,6 +1003,16 @@ msgid "" "that is already in use::" msgstr "" +#: ../../library/argparse.rst:642 +msgid "" +">>> parser = argparse.ArgumentParser(prog='PROG')\n" +">>> parser.add_argument('-f', '--foo', help='old foo help')\n" +">>> parser.add_argument('--foo', help='new foo help')\n" +"Traceback (most recent call last):\n" +" ..\n" +"ArgumentError: argument --foo: conflicting option string(s): --foo" +msgstr "" + #: ../../library/argparse.rst:649 msgid "" "Sometimes (e.g. when using parents_) it may be useful to simply override any " @@ -673,6 +1021,21 @@ msgid "" "of :class:`ArgumentParser`::" msgstr "" +#: ../../library/argparse.rst:654 +msgid "" +">>> parser = argparse.ArgumentParser(prog='PROG', " +"conflict_handler='resolve')\n" +">>> parser.add_argument('-f', '--foo', help='old foo help')\n" +">>> parser.add_argument('--foo', help='new foo help')\n" +">>> parser.print_help()\n" +"usage: PROG [-h] [-f FOO] [--foo FOO]\n" +"\n" +"options:\n" +" -h, --help show this help message and exit\n" +" -f FOO old foo help\n" +" --foo FOO new foo help" +msgstr "" + #: ../../library/argparse.rst:665 msgid "" "Note that :class:`ArgumentParser` objects only remove an action if all of " @@ -698,6 +1061,16 @@ msgid "" "help will be printed:" msgstr "" +#: ../../library/argparse.rst:686 +msgid "" +"$ python myprogram.py --help\n" +"usage: myprogram.py [-h] [--foo FOO]\n" +"\n" +"options:\n" +" -h, --help show this help message and exit\n" +" --foo FOO foo help" +msgstr "" + #: ../../library/argparse.rst:695 msgid "" "Occasionally, it may be useful to disable the addition of this help option. " @@ -705,6 +1078,17 @@ msgid "" "class:`ArgumentParser`::" msgstr "" +#: ../../library/argparse.rst:699 +msgid "" +">>> parser = argparse.ArgumentParser(prog='PROG', add_help=False)\n" +">>> parser.add_argument('--foo', help='foo help')\n" +">>> parser.print_help()\n" +"usage: PROG [--foo FOO]\n" +"\n" +"options:\n" +" --foo FOO foo help" +msgstr "" + #: ../../library/argparse.rst:707 msgid "" "The help option is typically ``-h/--help``. The exception to this is if the " @@ -713,6 +1097,16 @@ msgid "" "in ``prefix_chars`` is used to prefix the help options::" msgstr "" +#: ../../library/argparse.rst:713 +msgid "" +">>> parser = argparse.ArgumentParser(prog='PROG', prefix_chars='+/')\n" +">>> parser.print_help()\n" +"usage: PROG [+h]\n" +"\n" +"options:\n" +" +h, ++help show this help message and exit" +msgstr "" + #: ../../library/argparse.rst:722 msgid "exit_on_error" msgstr "exit_on_error" @@ -730,6 +1124,21 @@ msgid "" "by setting ``exit_on_error`` to ``False``::" msgstr "" +#: ../../library/argparse.rst:730 +msgid "" +">>> parser = argparse.ArgumentParser(exit_on_error=False)\n" +">>> parser.add_argument('--integers', type=int)\n" +"_StoreAction(option_strings=['--integers'], dest='integers', nargs=None, " +"const=None, default=None, type=, choices=None, help=None, " +"metavar=None)\n" +">>> try:\n" +"... parser.parse_args('--integers a'.split())\n" +"... except argparse.ArgumentError:\n" +"... print('Catching an argumentError')\n" +"...\n" +"Catching an argumentError" +msgstr "" + #: ../../library/argparse.rst:744 msgid "The add_argument() method" msgstr "" @@ -813,10 +1222,18 @@ msgstr "" msgid "For example, an optional argument could be created like::" msgstr "" +#: ../../library/argparse.rst:796 +msgid ">>> parser.add_argument('-f', '--foo')" +msgstr "" + #: ../../library/argparse.rst:798 msgid "while a positional argument could be created like::" msgstr "" +#: ../../library/argparse.rst:800 +msgid ">>> parser.add_argument('bar')" +msgstr "" + #: ../../library/argparse.rst:802 msgid "" "When :meth:`~ArgumentParser.parse_args` is called, optional arguments will " @@ -824,6 +1241,20 @@ msgid "" "assumed to be positional::" msgstr "" +#: ../../library/argparse.rst:806 +msgid "" +">>> parser = argparse.ArgumentParser(prog='PROG')\n" +">>> parser.add_argument('-f', '--foo')\n" +">>> parser.add_argument('bar')\n" +">>> parser.parse_args(['BAR'])\n" +"Namespace(bar='BAR', foo=None)\n" +">>> parser.parse_args(['BAR', '--foo', 'FOO'])\n" +"Namespace(bar='BAR', foo='FOO')\n" +">>> parser.parse_args(['--foo', 'FOO'])\n" +"usage: PROG [-h] [-f FOO] bar\n" +"PROG: error: the following arguments are required: bar" +msgstr "" + #: ../../library/argparse.rst:821 msgid "action" msgstr "" @@ -844,6 +1275,14 @@ msgid "" "action. For example::" msgstr "" +#: ../../library/argparse.rst:832 +msgid "" +">>> parser = argparse.ArgumentParser()\n" +">>> parser.add_argument('--foo')\n" +">>> parser.parse_args('--foo 1'.split())\n" +"Namespace(foo='1')" +msgstr "" + #: ../../library/argparse.rst:837 msgid "" "``'store_const'`` - This stores the value specified by the const_ keyword " @@ -852,6 +1291,14 @@ msgid "" "specify some sort of flag. For example::" msgstr "" +#: ../../library/argparse.rst:842 +msgid "" +">>> parser = argparse.ArgumentParser()\n" +">>> parser.add_argument('--foo', action='store_const', const=42)\n" +">>> parser.parse_args(['--foo'])\n" +"Namespace(foo=42)" +msgstr "" + #: ../../library/argparse.rst:847 msgid "" "``'store_true'`` and ``'store_false'`` - These are special cases of " @@ -860,6 +1307,16 @@ msgid "" "``True`` respectively. For example::" msgstr "" +#: ../../library/argparse.rst:852 +msgid "" +">>> parser = argparse.ArgumentParser()\n" +">>> parser.add_argument('--foo', action='store_true')\n" +">>> parser.add_argument('--bar', action='store_false')\n" +">>> parser.add_argument('--baz', action='store_false')\n" +">>> parser.parse_args('--foo --bar'.split())\n" +"Namespace(foo=True, bar=False, baz=True)" +msgstr "" + #: ../../library/argparse.rst:859 msgid "" "``'append'`` - This stores a list, and appends each argument value to the " @@ -869,6 +1326,14 @@ msgid "" "after those default values. Example usage::" msgstr "" +#: ../../library/argparse.rst:865 +msgid "" +">>> parser = argparse.ArgumentParser()\n" +">>> parser.add_argument('--foo', action='append')\n" +">>> parser.parse_args('--foo 1 --foo 2'.split())\n" +"Namespace(foo=['1', '2'])" +msgstr "" + #: ../../library/argparse.rst:870 msgid "" "``'append_const'`` - This stores a list, and appends the value specified by " @@ -878,12 +1343,31 @@ msgid "" "example::" msgstr "" +#: ../../library/argparse.rst:876 +msgid "" +">>> parser = argparse.ArgumentParser()\n" +">>> parser.add_argument('--str', dest='types', action='append_const', " +"const=str)\n" +">>> parser.add_argument('--int', dest='types', action='append_const', " +"const=int)\n" +">>> parser.parse_args('--str --int'.split())\n" +"Namespace(types=[, ])" +msgstr "" + #: ../../library/argparse.rst:882 msgid "" "``'count'`` - This counts the number of times a keyword argument occurs. For " "example, this is useful for increasing verbosity levels::" msgstr "" +#: ../../library/argparse.rst:885 +msgid "" +">>> parser = argparse.ArgumentParser()\n" +">>> parser.add_argument('--verbose', '-v', action='count', default=0)\n" +">>> parser.parse_args(['-vvv'])\n" +"Namespace(verbose=3)" +msgstr "" + #: ../../library/argparse.rst:890 msgid "Note, the *default* will be ``None`` unless explicitly set to *0*." msgstr "" @@ -903,12 +1387,32 @@ msgid "" "exits when invoked::" msgstr "" +#: ../../library/argparse.rst:901 +msgid "" +">>> import argparse\n" +">>> parser = argparse.ArgumentParser(prog='PROG')\n" +">>> parser.add_argument('--version', action='version', version='%(prog)s " +"2.0')\n" +">>> parser.parse_args(['--version'])\n" +"PROG 2.0" +msgstr "" + #: ../../library/argparse.rst:907 msgid "" "``'extend'`` - This stores a list, and extends each argument value to the " "list. Example usage::" msgstr "" +#: ../../library/argparse.rst:911 +msgid "" +">>> parser = argparse.ArgumentParser()\n" +">>> parser.add_argument(\"--foo\", action=\"extend\", nargs=\"+\", " +"type=str)\n" +">>> parser.parse_args([\"--foo\", \"f1\", \"--foo\", \"f2\", \"f3\", " +"\"f4\"])\n" +"Namespace(foo=['f1', 'f2', 'f3', 'f4'])" +msgstr "" + #: ../../library/argparse.rst:918 msgid "" "You may also specify an arbitrary action by passing an Action subclass or " @@ -917,6 +1421,15 @@ msgid "" "boolean actions such as ``--foo`` and ``--no-foo``::" msgstr "" +#: ../../library/argparse.rst:923 +msgid "" +">>> import argparse\n" +">>> parser = argparse.ArgumentParser()\n" +">>> parser.add_argument('--foo', action=argparse.BooleanOptionalAction)\n" +">>> parser.parse_args(['--no-foo'])\n" +"Namespace(foo=False)" +msgstr "" + #: ../../library/argparse.rst:931 msgid "" "The recommended way to create a custom action is to extend :class:`Action`, " @@ -928,6 +1441,27 @@ msgstr "" msgid "An example of a custom action::" msgstr "" +#: ../../library/argparse.rst:937 +msgid "" +">>> class FooAction(argparse.Action):\n" +"... def __init__(self, option_strings, dest, nargs=None, **kwargs):\n" +"... if nargs is not None:\n" +"... raise ValueError(\"nargs not allowed\")\n" +"... super().__init__(option_strings, dest, **kwargs)\n" +"... def __call__(self, parser, namespace, values, option_string=None):\n" +"... print('%r %r %r' % (namespace, values, option_string))\n" +"... setattr(namespace, self.dest, values)\n" +"...\n" +">>> parser = argparse.ArgumentParser()\n" +">>> parser.add_argument('--foo', action=FooAction)\n" +">>> parser.add_argument('bar', action=FooAction)\n" +">>> args = parser.parse_args('1 --foo 2'.split())\n" +"Namespace(bar=None, foo=None) '1' None\n" +"Namespace(bar='1', foo=None) '2' '--foo'\n" +">>> args\n" +"Namespace(bar='1', foo='2')" +msgstr "" + #: ../../library/argparse.rst:955 msgid "For more details, see :class:`Action`." msgstr "" @@ -950,6 +1484,15 @@ msgid "" "together into a list. For example::" msgstr "" +#: ../../library/argparse.rst:971 +msgid "" +">>> parser = argparse.ArgumentParser()\n" +">>> parser.add_argument('--foo', nargs=2)\n" +">>> parser.add_argument('bar', nargs=1)\n" +">>> parser.parse_args('c --foo a b'.split())\n" +"Namespace(bar=['c'], foo=['a', 'b'])" +msgstr "" + #: ../../library/argparse.rst:977 msgid "" "Note that ``nargs=1`` produces a list of one item. This is different from " @@ -966,12 +1509,40 @@ msgid "" "produced. Some examples to illustrate this::" msgstr "" +#: ../../library/argparse.rst:989 +msgid "" +">>> parser = argparse.ArgumentParser()\n" +">>> parser.add_argument('--foo', nargs='?', const='c', default='d')\n" +">>> parser.add_argument('bar', nargs='?', default='d')\n" +">>> parser.parse_args(['XX', '--foo', 'YY'])\n" +"Namespace(bar='XX', foo='YY')\n" +">>> parser.parse_args(['XX', '--foo'])\n" +"Namespace(bar='XX', foo='c')\n" +">>> parser.parse_args([])\n" +"Namespace(bar='d', foo='d')" +msgstr "" + #: ../../library/argparse.rst:999 msgid "" "One of the more common uses of ``nargs='?'`` is to allow optional input and " "output files::" msgstr "" +#: ../../library/argparse.rst:1002 +msgid "" +">>> parser = argparse.ArgumentParser()\n" +">>> parser.add_argument('infile', nargs='?', type=argparse.FileType('r'),\n" +"... default=sys.stdin)\n" +">>> parser.add_argument('outfile', nargs='?', type=argparse.FileType('w'),\n" +"... default=sys.stdout)\n" +">>> parser.parse_args(['input.txt', 'output.txt'])\n" +"Namespace(infile=<_io.TextIOWrapper name='input.txt' encoding='UTF-8'>,\n" +" outfile=<_io.TextIOWrapper name='output.txt' encoding='UTF-8'>)\n" +">>> parser.parse_args([])\n" +"Namespace(infile=<_io.TextIOWrapper name='' encoding='UTF-8'>,\n" +" outfile=<_io.TextIOWrapper name='' encoding='UTF-8'>)" +msgstr "" + #: ../../library/argparse.rst:1016 msgid "" "``'*'``. All command-line arguments present are gathered into a list. Note " @@ -980,6 +1551,16 @@ msgid "" "``nargs='*'`` is possible. For example::" msgstr "" +#: ../../library/argparse.rst:1021 +msgid "" +">>> parser = argparse.ArgumentParser()\n" +">>> parser.add_argument('--foo', nargs='*')\n" +">>> parser.add_argument('--bar', nargs='*')\n" +">>> parser.add_argument('baz', nargs='*')\n" +">>> parser.parse_args('a b --foo x y --bar 1 2'.split())\n" +"Namespace(bar=['1', '2'], baz=['a', 'b'], foo=['x', 'y'])" +msgstr "" + #: ../../library/argparse.rst:1030 msgid "" "``'+'``. Just like ``'*'``, all command-line args present are gathered into " @@ -987,6 +1568,17 @@ msgid "" "least one command-line argument present. For example::" msgstr "" +#: ../../library/argparse.rst:1034 +msgid "" +">>> parser = argparse.ArgumentParser(prog='PROG')\n" +">>> parser.add_argument('foo', nargs='+')\n" +">>> parser.parse_args(['a', 'b'])\n" +"Namespace(foo=['a', 'b'])\n" +">>> parser.parse_args([])\n" +"usage: PROG [-h] foo [foo ...]\n" +"PROG: error: the following arguments are required: foo" +msgstr "" + #: ../../library/argparse.rst:1042 msgid "" "If the ``nargs`` keyword argument is not provided, the number of arguments " @@ -1047,12 +1639,30 @@ msgid "" "command line::" msgstr "" +#: ../../library/argparse.rst:1087 +msgid "" +">>> parser = argparse.ArgumentParser()\n" +">>> parser.add_argument('--foo', default=42)\n" +">>> parser.parse_args(['--foo', '2'])\n" +"Namespace(foo='2')\n" +">>> parser.parse_args([])\n" +"Namespace(foo=42)" +msgstr "" + #: ../../library/argparse.rst:1094 msgid "" "If the target namespace already has an attribute set, the action *default* " "will not over write it::" msgstr "" +#: ../../library/argparse.rst:1097 +msgid "" +">>> parser = argparse.ArgumentParser()\n" +">>> parser.add_argument('--foo', default=42)\n" +">>> parser.parse_args([], namespace=argparse.Namespace(foo=101))\n" +"Namespace(foo=101)" +msgstr "" + #: ../../library/argparse.rst:1102 msgid "" "If the ``default`` value is a string, the parser parses the value as if it " @@ -1061,18 +1671,47 @@ msgid "" "`Namespace` return value. Otherwise, the parser uses the value as is::" msgstr "" +#: ../../library/argparse.rst:1107 +msgid "" +">>> parser = argparse.ArgumentParser()\n" +">>> parser.add_argument('--length', default='10', type=int)\n" +">>> parser.add_argument('--width', default=10.5, type=int)\n" +">>> parser.parse_args()\n" +"Namespace(length=10, width=10.5)" +msgstr "" + #: ../../library/argparse.rst:1113 msgid "" "For positional arguments with nargs_ equal to ``?`` or ``*``, the " "``default`` value is used when no command-line argument was present::" msgstr "" +#: ../../library/argparse.rst:1116 +msgid "" +">>> parser = argparse.ArgumentParser()\n" +">>> parser.add_argument('foo', nargs='?', default=42)\n" +">>> parser.parse_args(['a'])\n" +"Namespace(foo='a')\n" +">>> parser.parse_args([])\n" +"Namespace(foo=42)" +msgstr "" + #: ../../library/argparse.rst:1124 msgid "" "Providing ``default=argparse.SUPPRESS`` causes no attribute to be added if " "the command-line argument was not present::" msgstr "" +#: ../../library/argparse.rst:1127 +msgid "" +">>> parser = argparse.ArgumentParser()\n" +">>> parser.add_argument('--foo', default=argparse.SUPPRESS)\n" +">>> parser.parse_args([])\n" +"Namespace()\n" +">>> parser.parse_args(['--foo', '1'])\n" +"Namespace(foo='1')" +msgstr "" + #: ../../library/argparse.rst:1138 msgid "type" msgstr "" @@ -1104,10 +1743,37 @@ msgstr "" msgid "Common built-in types and functions can be used as type converters:" msgstr "" +#: ../../library/argparse.rst:1156 +msgid "" +"import argparse\n" +"import pathlib\n" +"\n" +"parser = argparse.ArgumentParser()\n" +"parser.add_argument('count', type=int)\n" +"parser.add_argument('distance', type=float)\n" +"parser.add_argument('street', type=ascii)\n" +"parser.add_argument('code_point', type=ord)\n" +"parser.add_argument('source_file', type=open)\n" +"parser.add_argument('dest_file', type=argparse.FileType('w', " +"encoding='latin-1'))\n" +"parser.add_argument('datapath', type=pathlib.Path)" +msgstr "" + #: ../../library/argparse.rst:1170 msgid "User defined functions can be used as well:" msgstr "" +#: ../../library/argparse.rst:1172 +msgid "" +">>> def hyphenated(string):\n" +"... return '-'.join([word[:4] for word in string.casefold().split()])\n" +"...\n" +">>> parser = argparse.ArgumentParser()\n" +">>> _ = parser.add_argument('short_title', type=hyphenated)\n" +">>> parser.parse_args(['\"The Tale of Two Cities\"'])\n" +"Namespace(short_title='\"the-tale-of-two-citi')" +msgstr "" + #: ../../library/argparse.rst:1182 msgid "" "The :func:`bool` function is not recommended as a type converter. All it " @@ -1159,6 +1825,18 @@ msgid "" "be displayed if the argument was not one of the acceptable values::" msgstr "" +#: ../../library/argparse.rst:1217 +msgid "" +">>> parser = argparse.ArgumentParser(prog='game.py')\n" +">>> parser.add_argument('move', choices=['rock', 'paper', 'scissors'])\n" +">>> parser.parse_args(['rock'])\n" +"Namespace(move='rock')\n" +">>> parser.parse_args(['fire'])\n" +"usage: game.py [-h] {rock,paper,scissors}\n" +"game.py: error: argument move: invalid choice: 'fire' (choose from 'rock',\n" +"'paper', 'scissors')" +msgstr "" + #: ../../library/argparse.rst:1226 msgid "" "Note that inclusion in the *choices* sequence is checked after any type_ " @@ -1166,6 +1844,17 @@ msgid "" "sequence should match the type_ specified::" msgstr "" +#: ../../library/argparse.rst:1230 +msgid "" +">>> parser = argparse.ArgumentParser(prog='doors.py')\n" +">>> parser.add_argument('door', type=int, choices=range(1, 4))\n" +">>> print(parser.parse_args(['3']))\n" +"Namespace(door=3)\n" +">>> parser.parse_args(['4'])\n" +"usage: doors.py [-h] {1,2,3}\n" +"doors.py: error: argument door: invalid choice: 4 (choose from 1, 2, 3)" +msgstr "" + #: ../../library/argparse.rst:1238 msgid "" "Any sequence can be passed as the *choices* value, so :class:`list` " @@ -1198,6 +1887,17 @@ msgid "" "the ``required=`` keyword argument to :meth:`~ArgumentParser.add_argument`::" msgstr "" +#: ../../library/argparse.rst:1260 +msgid "" +">>> parser = argparse.ArgumentParser()\n" +">>> parser.add_argument('--foo', required=True)\n" +">>> parser.parse_args(['--foo', 'BAR'])\n" +"Namespace(foo='BAR')\n" +">>> parser.parse_args([])\n" +"usage: [-h] --foo FOO\n" +": error: the following arguments are required: --foo" +msgstr "" + #: ../../library/argparse.rst:1268 msgid "" "As the example shows, if an option is marked as ``required``, :meth:" @@ -1223,6 +1923,24 @@ msgid "" "each argument::" msgstr "" +#: ../../library/argparse.rst:1288 +msgid "" +">>> parser = argparse.ArgumentParser(prog='frobble')\n" +">>> parser.add_argument('--foo', action='store_true',\n" +"... help='foo the bars before frobbling')\n" +">>> parser.add_argument('bar', nargs='+',\n" +"... help='one of the bars to be frobbled')\n" +">>> parser.parse_args(['-h'])\n" +"usage: frobble [-h] [--foo] bar [bar ...]\n" +"\n" +"positional arguments:\n" +" bar one of the bars to be frobbled\n" +"\n" +"options:\n" +" -h, --help show this help message and exit\n" +" --foo foo the bars before frobbling" +msgstr "" + #: ../../library/argparse.rst:1303 msgid "" "The ``help`` strings can include various format specifiers to avoid " @@ -1232,6 +1950,21 @@ msgid "" "``%(type)s``, etc.::" msgstr "" +#: ../../library/argparse.rst:1308 +msgid "" +">>> parser = argparse.ArgumentParser(prog='frobble')\n" +">>> parser.add_argument('bar', nargs='?', type=int, default=42,\n" +"... help='the bar to %(prog)s (default: %(default)s)')\n" +">>> parser.print_help()\n" +"usage: frobble [-h] [bar]\n" +"\n" +"positional arguments:\n" +" bar the bar to frobble (default: 42)\n" +"\n" +"options:\n" +" -h, --help show this help message and exit" +msgstr "" + #: ../../library/argparse.rst:1320 msgid "" "As the help string supports %-formatting, if you want a literal ``%`` to " @@ -1244,6 +1977,17 @@ msgid "" "setting the ``help`` value to ``argparse.SUPPRESS``::" msgstr "" +#: ../../library/argparse.rst:1326 +msgid "" +">>> parser = argparse.ArgumentParser(prog='frobble')\n" +">>> parser.add_argument('--foo', help=argparse.SUPPRESS)\n" +">>> parser.print_help()\n" +"usage: frobble [-h]\n" +"\n" +"options:\n" +" -h, --help show this help message and exit" +msgstr "" + #: ../../library/argparse.rst:1338 msgid "metavar" msgstr "" @@ -1260,10 +2004,46 @@ msgid "" "argument will be referred to as ``FOO``. An example::" msgstr "" +#: ../../library/argparse.rst:1349 +msgid "" +">>> parser = argparse.ArgumentParser()\n" +">>> parser.add_argument('--foo')\n" +">>> parser.add_argument('bar')\n" +">>> parser.parse_args('X --foo Y'.split())\n" +"Namespace(bar='X', foo='Y')\n" +">>> parser.print_help()\n" +"usage: [-h] [--foo FOO] bar\n" +"\n" +"positional arguments:\n" +" bar\n" +"\n" +"options:\n" +" -h, --help show this help message and exit\n" +" --foo FOO" +msgstr "" + #: ../../library/argparse.rst:1364 msgid "An alternative name can be specified with ``metavar``::" msgstr "" +#: ../../library/argparse.rst:1366 +msgid "" +">>> parser = argparse.ArgumentParser()\n" +">>> parser.add_argument('--foo', metavar='YYY')\n" +">>> parser.add_argument('bar', metavar='XXX')\n" +">>> parser.parse_args('X --foo Y'.split())\n" +"Namespace(bar='X', foo='Y')\n" +">>> parser.print_help()\n" +"usage: [-h] [--foo YYY] XXX\n" +"\n" +"positional arguments:\n" +" XXX\n" +"\n" +"options:\n" +" -h, --help show this help message and exit\n" +" --foo YYY" +msgstr "" + #: ../../library/argparse.rst:1381 msgid "" "Note that ``metavar`` only changes the *displayed* name - the name of the " @@ -1278,6 +2058,20 @@ msgid "" "each of the arguments::" msgstr "" +#: ../../library/argparse.rst:1389 +msgid "" +">>> parser = argparse.ArgumentParser(prog='PROG')\n" +">>> parser.add_argument('-x', nargs=2)\n" +">>> parser.add_argument('--foo', nargs=2, metavar=('bar', 'baz'))\n" +">>> parser.print_help()\n" +"usage: PROG [-h] [-x X X] [--foo bar baz]\n" +"\n" +"options:\n" +" -h, --help show this help message and exit\n" +" -x X X\n" +" --foo bar baz" +msgstr "" + #: ../../library/argparse.rst:1404 msgid "dest" msgstr "" @@ -1292,6 +2086,14 @@ msgid "" "add_argument`::" msgstr "" +#: ../../library/argparse.rst:1413 +msgid "" +">>> parser = argparse.ArgumentParser()\n" +">>> parser.add_argument('bar')\n" +">>> parser.parse_args(['XXX'])\n" +"Namespace(bar='XXX')" +msgstr "" + #: ../../library/argparse.rst:1418 msgid "" "For optional argument actions, the value of ``dest`` is normally inferred " @@ -1304,10 +2106,29 @@ msgid "" "below illustrate this behavior::" msgstr "" +#: ../../library/argparse.rst:1427 +msgid "" +">>> parser = argparse.ArgumentParser()\n" +">>> parser.add_argument('-f', '--foo-bar', '--foo')\n" +">>> parser.add_argument('-x', '-y')\n" +">>> parser.parse_args('-f 1 -x 2'.split())\n" +"Namespace(foo_bar='1', x='2')\n" +">>> parser.parse_args('--foo 1 -y 2'.split())\n" +"Namespace(foo_bar='1', x='2')" +msgstr "" + #: ../../library/argparse.rst:1435 msgid "``dest`` allows a custom attribute name to be provided::" msgstr "" +#: ../../library/argparse.rst:1437 +msgid "" +">>> parser = argparse.ArgumentParser()\n" +">>> parser.add_argument('--foo', dest='bar')\n" +">>> parser.parse_args('--foo XXX'.split())\n" +"Namespace(bar='XXX')" +msgstr "" + #: ../../library/argparse.rst:1443 msgid "Action classes" msgstr "" @@ -1421,6 +2242,17 @@ msgid "" "the option and its value are passed as two separate arguments::" msgstr "" +#: ../../library/argparse.rst:1515 +msgid "" +">>> parser = argparse.ArgumentParser(prog='PROG')\n" +">>> parser.add_argument('-x')\n" +">>> parser.add_argument('--foo')\n" +">>> parser.parse_args(['-x', 'X'])\n" +"Namespace(foo=None, x='X')\n" +">>> parser.parse_args(['--foo', 'FOO'])\n" +"Namespace(foo='FOO', x=None)" +msgstr "" + #: ../../library/argparse.rst:1523 msgid "" "For long options (options with names longer than a single character), the " @@ -1428,18 +2260,40 @@ msgid "" "``=`` to separate them::" msgstr "" +#: ../../library/argparse.rst:1527 +msgid "" +">>> parser.parse_args(['--foo=FOO'])\n" +"Namespace(foo='FOO', x=None)" +msgstr "" + #: ../../library/argparse.rst:1530 msgid "" "For short options (options only one character long), the option and its " "value can be concatenated::" msgstr "" +#: ../../library/argparse.rst:1533 +msgid "" +">>> parser.parse_args(['-xX'])\n" +"Namespace(foo=None, x='X')" +msgstr "" + #: ../../library/argparse.rst:1536 msgid "" "Several short options can be joined together, using only a single ``-`` " "prefix, as long as only the last option (or none of them) requires a value::" msgstr "" +#: ../../library/argparse.rst:1539 +msgid "" +">>> parser = argparse.ArgumentParser(prog='PROG')\n" +">>> parser.add_argument('-x', action='store_true')\n" +">>> parser.add_argument('-y', action='store_true')\n" +">>> parser.add_argument('-z')\n" +">>> parser.parse_args(['-xyzZ'])\n" +"Namespace(x=True, y=True, z='Z')" +msgstr "" + #: ../../library/argparse.rst:1548 msgid "Invalid arguments" msgstr "" @@ -1452,6 +2306,28 @@ msgid "" "an error, it exits and prints the error along with a usage message::" msgstr "" +#: ../../library/argparse.rst:1555 +msgid "" +">>> parser = argparse.ArgumentParser(prog='PROG')\n" +">>> parser.add_argument('--foo', type=int)\n" +">>> parser.add_argument('bar', nargs='?')\n" +"\n" +">>> # invalid type\n" +">>> parser.parse_args(['--foo', 'spam'])\n" +"usage: PROG [-h] [--foo FOO] [bar]\n" +"PROG: error: argument --foo: invalid int value: 'spam'\n" +"\n" +">>> # invalid option\n" +">>> parser.parse_args(['--bar'])\n" +"usage: PROG [-h] [--foo FOO] [bar]\n" +"PROG: error: no such option: --bar\n" +"\n" +">>> # wrong number of arguments\n" +">>> parser.parse_args(['spam', 'badger'])\n" +"usage: PROG [-h] [--foo FOO] [bar]\n" +"PROG: error: extra arguments found: badger" +msgstr "" + #: ../../library/argparse.rst:1576 msgid "Arguments containing ``-``" msgstr "" @@ -1468,6 +2344,39 @@ msgid "" "negative numbers::" msgstr "" +#: ../../library/argparse.rst:1586 +msgid "" +">>> parser = argparse.ArgumentParser(prog='PROG')\n" +">>> parser.add_argument('-x')\n" +">>> parser.add_argument('foo', nargs='?')\n" +"\n" +">>> # no negative number options, so -1 is a positional argument\n" +">>> parser.parse_args(['-x', '-1'])\n" +"Namespace(foo=None, x='-1')\n" +"\n" +">>> # no negative number options, so -1 and -5 are positional arguments\n" +">>> parser.parse_args(['-x', '-1', '-5'])\n" +"Namespace(foo='-5', x='-1')\n" +"\n" +">>> parser = argparse.ArgumentParser(prog='PROG')\n" +">>> parser.add_argument('-1', dest='one')\n" +">>> parser.add_argument('foo', nargs='?')\n" +"\n" +">>> # negative number options present, so -1 is an option\n" +">>> parser.parse_args(['-1', 'X'])\n" +"Namespace(foo=None, one='X')\n" +"\n" +">>> # negative number options present, so -2 is an option\n" +">>> parser.parse_args(['-2'])\n" +"usage: PROG [-h] [-1 ONE] [foo]\n" +"PROG: error: no such option: -2\n" +"\n" +">>> # negative number options present, so both -1s are options\n" +">>> parser.parse_args(['-1', '-1'])\n" +"usage: PROG [-h] [-1 ONE] [foo]\n" +"PROG: error: argument -1: expected one argument" +msgstr "" + #: ../../library/argparse.rst:1616 msgid "" "If you have positional arguments that must begin with ``-`` and don't look " @@ -1476,6 +2385,12 @@ msgid "" "positional argument::" msgstr "" +#: ../../library/argparse.rst:1621 +msgid "" +">>> parser.parse_args(['--', '-f'])\n" +"Namespace(foo='-f', one=None)" +msgstr "" + #: ../../library/argparse.rst:1624 msgid "" "See also :ref:`the argparse howto on ambiguous arguments >> parser = argparse.ArgumentParser(prog='PROG')\n" +">>> parser.add_argument('-bacon')\n" +">>> parser.add_argument('-badger')\n" +">>> parser.parse_args('-bac MMM'.split())\n" +"Namespace(bacon='MMM', badger=None)\n" +">>> parser.parse_args('-bad WOOD'.split())\n" +"Namespace(bacon=None, badger='WOOD')\n" +">>> parser.parse_args('-ba BA'.split())\n" +"usage: PROG [-h] [-bacon BACON] [-badger BADGER]\n" +"PROG: error: ambiguous option: -ba could match -badger, -bacon" +msgstr "" + #: ../../library/argparse.rst:1647 msgid "" "An error is produced for arguments that could produce more than one options. " @@ -1511,6 +2440,21 @@ msgid "" "testing at the interactive prompt::" msgstr "" +#: ../../library/argparse.rst:1660 +msgid "" +">>> parser = argparse.ArgumentParser()\n" +">>> parser.add_argument(\n" +"... 'integers', metavar='int', type=int, choices=range(10),\n" +"... nargs='+', help='an integer in the range 0..9')\n" +">>> parser.add_argument(\n" +"... '--sum', dest='accumulate', action='store_const', const=sum,\n" +"... default=max, help='sum the integers (default: find the max)')\n" +">>> parser.parse_args(['1', '2', '3', '4'])\n" +"Namespace(accumulate=, integers=[1, 2, 3, 4])\n" +">>> parser.parse_args(['1', '2', '3', '4', '--sum'])\n" +"Namespace(accumulate=, integers=[1, 2, 3, 4])" +msgstr "" + #: ../../library/argparse.rst:1675 msgid "The Namespace object" msgstr "" @@ -1528,6 +2472,15 @@ msgid "" "attributes, you can use the standard Python idiom, :func:`vars`::" msgstr "" +#: ../../library/argparse.rst:1686 +msgid "" +">>> parser = argparse.ArgumentParser()\n" +">>> parser.add_argument('--foo')\n" +">>> args = parser.parse_args(['--foo', 'BAR'])\n" +">>> vars(args)\n" +"{'foo': 'BAR'}" +msgstr "" + #: ../../library/argparse.rst:1692 msgid "" "It may also be useful to have an :class:`ArgumentParser` assign attributes " @@ -1535,6 +2488,19 @@ msgid "" "This can be achieved by specifying the ``namespace=`` keyword argument::" msgstr "" +#: ../../library/argparse.rst:1696 +msgid "" +">>> class C:\n" +"... pass\n" +"...\n" +">>> c = C()\n" +">>> parser = argparse.ArgumentParser()\n" +">>> parser.add_argument('--foo')\n" +">>> parser.parse_args(args=['--foo', 'BAR'], namespace=c)\n" +">>> c.foo\n" +"'BAR'" +msgstr "" + #: ../../library/argparse.rst:1708 msgid "Other utilities" msgstr "" @@ -1621,6 +2587,28 @@ msgstr "" msgid "Some example usage::" msgstr "一些使用範例: ::" +#: ../../library/argparse.rst:1762 +msgid "" +">>> # create the top-level parser\n" +">>> parser = argparse.ArgumentParser(prog='PROG')\n" +">>> parser.add_argument('--foo', action='store_true', help='foo help')\n" +">>> subparsers = parser.add_subparsers(help='sub-command help')\n" +">>>\n" +">>> # create the parser for the \"a\" command\n" +">>> parser_a = subparsers.add_parser('a', help='a help')\n" +">>> parser_a.add_argument('bar', type=int, help='bar help')\n" +">>>\n" +">>> # create the parser for the \"b\" command\n" +">>> parser_b = subparsers.add_parser('b', help='b help')\n" +">>> parser_b.add_argument('--baz', choices='XYZ', help='baz help')\n" +">>>\n" +">>> # parse some argument lists\n" +">>> parser.parse_args(['a', '12'])\n" +"Namespace(bar=12, foo=False)\n" +">>> parser.parse_args(['--foo', 'b', '--baz', 'Z'])\n" +"Namespace(baz='Z', foo=True)" +msgstr "" + #: ../../library/argparse.rst:1781 msgid "" "Note that the object returned by :meth:`parse_args` will only contain " @@ -1640,6 +2628,37 @@ msgid "" "to :meth:`~_SubParsersAction.add_parser` as above.)" msgstr "" +#: ../../library/argparse.rst:1796 +msgid "" +">>> parser.parse_args(['--help'])\n" +"usage: PROG [-h] [--foo] {a,b} ...\n" +"\n" +"positional arguments:\n" +" {a,b} sub-command help\n" +" a a help\n" +" b b help\n" +"\n" +"options:\n" +" -h, --help show this help message and exit\n" +" --foo foo help\n" +"\n" +">>> parser.parse_args(['a', '--help'])\n" +"usage: PROG a [-h] bar\n" +"\n" +"positional arguments:\n" +" bar bar help\n" +"\n" +"options:\n" +" -h, --help show this help message and exit\n" +"\n" +">>> parser.parse_args(['b', '--help'])\n" +"usage: PROG b [-h] [--baz {X,Y,Z}]\n" +"\n" +"options:\n" +" -h, --help show this help message and exit\n" +" --baz {X,Y,Z} baz help" +msgstr "" + #: ../../library/argparse.rst:1824 msgid "" "The :meth:`add_subparsers` method also supports ``title`` and " @@ -1647,6 +2666,26 @@ msgid "" "commands will appear in their own group in the help output. For example::" msgstr "" +#: ../../library/argparse.rst:1828 +msgid "" +">>> parser = argparse.ArgumentParser()\n" +">>> subparsers = parser.add_subparsers(title='subcommands',\n" +"... description='valid subcommands',\n" +"... help='additional help')\n" +">>> subparsers.add_parser('foo')\n" +">>> subparsers.add_parser('bar')\n" +">>> parser.parse_args(['-h'])\n" +"usage: [-h] {foo,bar} ...\n" +"\n" +"options:\n" +" -h, --help show this help message and exit\n" +"\n" +"subcommands:\n" +" valid subcommands\n" +"\n" +" {foo,bar} additional help" +msgstr "" + #: ../../library/argparse.rst:1845 msgid "" "Furthermore, ``add_parser`` supports an additional ``aliases`` argument, " @@ -1654,6 +2693,16 @@ msgid "" "like ``svn``, aliases ``co`` as a shorthand for ``checkout``::" msgstr "" +#: ../../library/argparse.rst:1849 +msgid "" +">>> parser = argparse.ArgumentParser()\n" +">>> subparsers = parser.add_subparsers()\n" +">>> checkout = subparsers.add_parser('checkout', aliases=['co'])\n" +">>> checkout.add_argument('foo')\n" +">>> parser.parse_args(['co', 'bar'])\n" +"Namespace(foo='bar')" +msgstr "" + #: ../../library/argparse.rst:1856 msgid "" "One particularly effective way of handling sub-commands is to combine the " @@ -1662,6 +2711,41 @@ msgid "" "example::" msgstr "" +#: ../../library/argparse.rst:1861 +msgid "" +">>> # sub-command functions\n" +">>> def foo(args):\n" +"... print(args.x * args.y)\n" +"...\n" +">>> def bar(args):\n" +"... print('((%s))' % args.z)\n" +"...\n" +">>> # create the top-level parser\n" +">>> parser = argparse.ArgumentParser()\n" +">>> subparsers = parser.add_subparsers(required=True)\n" +">>>\n" +">>> # create the parser for the \"foo\" command\n" +">>> parser_foo = subparsers.add_parser('foo')\n" +">>> parser_foo.add_argument('-x', type=int, default=1)\n" +">>> parser_foo.add_argument('y', type=float)\n" +">>> parser_foo.set_defaults(func=foo)\n" +">>>\n" +">>> # create the parser for the \"bar\" command\n" +">>> parser_bar = subparsers.add_parser('bar')\n" +">>> parser_bar.add_argument('z')\n" +">>> parser_bar.set_defaults(func=bar)\n" +">>>\n" +">>> # parse the args and call whatever function was selected\n" +">>> args = parser.parse_args('foo 1 -x 2'.split())\n" +">>> args.func(args)\n" +"2.0\n" +">>>\n" +">>> # parse the args and call whatever function was selected\n" +">>> args = parser.parse_args('bar XYZYX'.split())\n" +">>> args.func(args)\n" +"((XYZYX))" +msgstr "" + #: ../../library/argparse.rst:1893 msgid "" "This way, you can let :meth:`parse_args` do the job of calling the " @@ -1672,6 +2756,18 @@ msgid "" "argument to the :meth:`add_subparsers` call will work::" msgstr "" +#: ../../library/argparse.rst:1900 +msgid "" +">>> parser = argparse.ArgumentParser()\n" +">>> subparsers = parser.add_subparsers(dest='subparser_name')\n" +">>> subparser1 = subparsers.add_parser('1')\n" +">>> subparser1.add_argument('-x')\n" +">>> subparser2 = subparsers.add_parser('2')\n" +">>> subparser2.add_argument('y')\n" +">>> parser.parse_args(['2', 'frobble'])\n" +"Namespace(subparser_name='2', y='frobble')" +msgstr "" + #: ../../library/argparse.rst:1909 msgid "New *required* keyword argument." msgstr "" @@ -1689,6 +2785,17 @@ msgid "" "the :func:`open` function for more details)::" msgstr "" +#: ../../library/argparse.rst:1924 +msgid "" +">>> parser = argparse.ArgumentParser()\n" +">>> parser.add_argument('--raw', type=argparse.FileType('wb', 0))\n" +">>> parser.add_argument('out', type=argparse.FileType('w', " +"encoding='UTF-8'))\n" +">>> parser.parse_args(['--raw', 'raw.dat', 'file.txt'])\n" +"Namespace(out=<_io.TextIOWrapper name='file.txt' mode='w' encoding='UTF-8'>, " +"raw=<_io.FileIO name='raw.dat' mode='wb'>)" +msgstr "" + #: ../../library/argparse.rst:1930 msgid "" "FileType objects understand the pseudo-argument ``'-'`` and automatically " @@ -1696,6 +2803,14 @@ msgid "" "and :data:`sys.stdout` for writable :class:`FileType` objects::" msgstr "" +#: ../../library/argparse.rst:1934 +msgid "" +">>> parser = argparse.ArgumentParser()\n" +">>> parser.add_argument('infile', type=argparse.FileType('r'))\n" +">>> parser.parse_args(['-'])\n" +"Namespace(infile=<_io.TextIOWrapper name='' encoding='UTF-8'>)" +msgstr "" + #: ../../library/argparse.rst:1939 msgid "Added the *encodings* and *errors* parameters." msgstr "" @@ -1713,6 +2828,20 @@ msgid "" "method::" msgstr "" +#: ../../library/argparse.rst:1954 +msgid "" +">>> parser = argparse.ArgumentParser(prog='PROG', add_help=False)\n" +">>> group = parser.add_argument_group('group')\n" +">>> group.add_argument('--foo', help='foo help')\n" +">>> group.add_argument('bar', help='bar help')\n" +">>> parser.print_help()\n" +"usage: PROG [--foo FOO] bar\n" +"\n" +"group:\n" +" bar bar help\n" +" --foo FOO foo help" +msgstr "" + #: ../../library/argparse.rst:1965 msgid "" "The :meth:`add_argument_group` method returns an argument group object which " @@ -1724,6 +2853,27 @@ msgid "" "this display::" msgstr "" +#: ../../library/argparse.rst:1973 +msgid "" +">>> parser = argparse.ArgumentParser(prog='PROG', add_help=False)\n" +">>> group1 = parser.add_argument_group('group1', 'group1 description')\n" +">>> group1.add_argument('foo', help='foo help')\n" +">>> group2 = parser.add_argument_group('group2', 'group2 description')\n" +">>> group2.add_argument('--bar', help='bar help')\n" +">>> parser.print_help()\n" +"usage: PROG [--bar BAR] foo\n" +"\n" +"group1:\n" +" group1 description\n" +"\n" +" foo foo help\n" +"\n" +"group2:\n" +" group2 description\n" +"\n" +" --bar BAR bar help" +msgstr "" + #: ../../library/argparse.rst:1991 msgid "" "Note that any arguments not in your user-defined groups will end up back in " @@ -1749,6 +2899,21 @@ msgid "" "command line::" msgstr "" +#: ../../library/argparse.rst:2010 +msgid "" +">>> parser = argparse.ArgumentParser(prog='PROG')\n" +">>> group = parser.add_mutually_exclusive_group()\n" +">>> group.add_argument('--foo', action='store_true')\n" +">>> group.add_argument('--bar', action='store_false')\n" +">>> parser.parse_args(['--foo'])\n" +"Namespace(bar=True, foo=True)\n" +">>> parser.parse_args(['--bar'])\n" +"Namespace(bar=False, foo=False)\n" +">>> parser.parse_args(['--foo', '--bar'])\n" +"usage: PROG [-h] [--foo | --bar]\n" +"PROG: error: argument --bar: not allowed with argument --foo" +msgstr "" + #: ../../library/argparse.rst:2022 msgid "" "The :meth:`add_mutually_exclusive_group` method also accepts a *required* " @@ -1756,6 +2921,17 @@ msgid "" "is required::" msgstr "" +#: ../../library/argparse.rst:2026 +msgid "" +">>> parser = argparse.ArgumentParser(prog='PROG')\n" +">>> group = parser.add_mutually_exclusive_group(required=True)\n" +">>> group.add_argument('--foo', action='store_true')\n" +">>> group.add_argument('--bar', action='store_false')\n" +">>> parser.parse_args([])\n" +"usage: PROG [-h] (--foo | --bar)\n" +"PROG: error: one of the arguments --foo --bar is required" +msgstr "" + #: ../../library/argparse.rst:2034 msgid "" "Note that currently mutually exclusive argument groups do not support the " @@ -1764,6 +2940,26 @@ msgid "" "argument group that has a title and description. For example::" msgstr "" +#: ../../library/argparse.rst:2040 +msgid "" +">>> parser = argparse.ArgumentParser(prog='PROG')\n" +">>> group = parser.add_argument_group('Group title', 'Group description')\n" +">>> exclusive_group = group.add_mutually_exclusive_group(required=True)\n" +">>> exclusive_group.add_argument('--foo', help='foo help')\n" +">>> exclusive_group.add_argument('--bar', help='bar help')\n" +">>> parser.print_help()\n" +"usage: PROG [-h] (--foo FOO | --bar BAR)\n" +"\n" +"options:\n" +" -h, --help show this help message and exit\n" +"\n" +"Group title:\n" +" Group description\n" +"\n" +" --foo FOO foo help\n" +" --bar BAR bar help" +msgstr "" + #: ../../library/argparse.rst:2057 msgid "" "Calling :meth:`add_argument_group` or :meth:`add_mutually_exclusive_group` " @@ -1785,11 +2981,29 @@ msgid "" "command line to be added::" msgstr "" +#: ../../library/argparse.rst:2075 +msgid "" +">>> parser = argparse.ArgumentParser()\n" +">>> parser.add_argument('foo', type=int)\n" +">>> parser.set_defaults(bar=42, baz='badger')\n" +">>> parser.parse_args(['736'])\n" +"Namespace(bar=42, baz='badger', foo=736)" +msgstr "" + #: ../../library/argparse.rst:2081 msgid "" "Note that parser-level defaults always override argument-level defaults::" msgstr "" +#: ../../library/argparse.rst:2083 +msgid "" +">>> parser = argparse.ArgumentParser()\n" +">>> parser.add_argument('--foo', default='bar')\n" +">>> parser.set_defaults(foo='spam')\n" +">>> parser.parse_args([])\n" +"Namespace(foo='spam')" +msgstr "" + #: ../../library/argparse.rst:2089 msgid "" "Parser-level defaults can be particularly useful when working with multiple " @@ -1803,6 +3017,14 @@ msgid "" "`~ArgumentParser.add_argument` or by :meth:`~ArgumentParser.set_defaults`::" msgstr "" +#: ../../library/argparse.rst:2099 +msgid "" +">>> parser = argparse.ArgumentParser()\n" +">>> parser.add_argument('--foo', default='badger')\n" +">>> parser.get_default('foo')\n" +"'badger'" +msgstr "" + #: ../../library/argparse.rst:2106 msgid "Printing help" msgstr "" @@ -1861,6 +3083,15 @@ msgid "" "remaining argument strings." msgstr "" +#: ../../library/argparse.rst:2152 +msgid "" +">>> parser = argparse.ArgumentParser()\n" +">>> parser.add_argument('--foo', action='store_true')\n" +">>> parser.add_argument('bar')\n" +">>> parser.parse_known_args(['--foo', '--badger', 'BAR', 'spam'])\n" +"(Namespace(bar='BAR', foo=True), ['--badger', 'spam'])" +msgstr "" + #: ../../library/argparse.rst:2159 msgid "" ":ref:`Prefix matching ` rules apply to :meth:" @@ -1894,6 +3125,13 @@ msgid "" "word as an argument. The following example demonstrates how to do this::" msgstr "" +#: ../../library/argparse.rst:2182 +msgid "" +"class MyArgumentParser(argparse.ArgumentParser):\n" +" def convert_arg_line_to_args(self, arg_line):\n" +" return arg_line.split()" +msgstr "" + #: ../../library/argparse.rst:2188 msgid "Exiting methods" msgstr "" @@ -1905,6 +3143,15 @@ msgid "" "method to handle these steps differently::" msgstr "" +#: ../../library/argparse.rst:2196 +msgid "" +"class ErrorCatchingArgumentParser(argparse.ArgumentParser):\n" +" def exit(self, status=0, message=None):\n" +" if status:\n" +" raise Exception(f'Exiting because of an error: {message}')\n" +" exit(status)" +msgstr "" + #: ../../library/argparse.rst:2204 msgid "" "This method prints a usage message including the *message* to the standard " @@ -1939,6 +3186,18 @@ msgid "" "collects all the positionals into ``rest``. ::" msgstr "" +#: ../../library/argparse.rst:2230 +msgid "" +">>> parser = argparse.ArgumentParser()\n" +">>> parser.add_argument('--foo')\n" +">>> parser.add_argument('cmd')\n" +">>> parser.add_argument('rest', nargs='*', type=int)\n" +">>> parser.parse_known_args('doit 1 --foo bar 2 3'.split())\n" +"(Namespace(cmd='doit', foo='bar', rest=[1]), ['2', '3'])\n" +">>> parser.parse_intermixed_args('doit 1 --foo bar 2 3'.split())\n" +"Namespace(cmd='doit', foo='bar', rest=[1, 2, 3])" +msgstr "" + #: ../../library/argparse.rst:2239 msgid "" ":meth:`~ArgumentParser.parse_known_intermixed_args` returns a two item tuple " diff --git a/library/asyncio-dev.po b/library/asyncio-dev.po index bd3b23dc6b..742120c3a2 100644 --- a/library/asyncio-dev.po +++ b/library/asyncio-dev.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-08-22 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2023-02-18 14:17+0800\n" "Last-Translator: Matt Wang \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -82,6 +82,10 @@ msgstr "" "將 :ref:`asyncio logger(日誌記錄器) `\\ 的日誌級别設置為 :" "py:const:`logging.DEBUG`,例如下面的程式片段可以在應用程式啟動時運行: ::" +#: ../../library/asyncio-dev.rst:40 +msgid "logging.basicConfig(level=logging.DEBUG)" +msgstr "" + #: ../../library/asyncio-dev.rst:42 msgid "" "configuring the :mod:`warnings` module to display :exc:`ResourceWarning` " @@ -157,6 +161,10 @@ msgstr "" "要從不同的 OS 執行緒為一個 :term:`callback` 排程,應該使用 :meth:`loop." "call_soon_threadsafe` 方法。例如: ::" +#: ../../library/asyncio-dev.rst:79 +msgid "loop.call_soon_threadsafe(callback, *args)" +msgstr "" + #: ../../library/asyncio-dev.rst:81 msgid "" "Almost all asyncio objects are not thread safe, which is typically not a " @@ -168,6 +176,10 @@ msgstr "" "在 Task 或回呼函式之外有程式需要和它們一起運作。如果需要這樣的程式來呼叫低階 " "asyncio API,應該使用 :meth:`loop.call_soon_threadsafe` 方法,例如: ::" +#: ../../library/asyncio-dev.rst:87 +msgid "loop.call_soon_threadsafe(fut.cancel)" +msgstr "" + #: ../../library/asyncio-dev.rst:89 msgid "" "To schedule a coroutine object from a different OS thread, the :func:" @@ -178,6 +190,18 @@ msgstr "" "`run_coroutine_threadsafe` 函式。它會回傳一個 :class:`concurrent.futures." "Future` 以存取結果: ::" +#: ../../library/asyncio-dev.rst:93 +msgid "" +"async def coro_func():\n" +" return await asyncio.sleep(1, 42)\n" +"\n" +"# Later in another OS thread:\n" +"\n" +"future = asyncio.run_coroutine_threadsafe(coro_func(), loop)\n" +"# Wait for the result:\n" +"result = future.result()" +msgstr "" + #: ../../library/asyncio-dev.rst:102 msgid "To handle signals the event loop must be run in the main thread." msgstr "為了能夠處理訊號,事件迴圈必須於主執行緒中運行。" @@ -254,6 +278,10 @@ msgid "" "adjusted::" msgstr "日誌級別被預設為 :py:const:`logging.INFO`,它可以很容易地被調整: ::" +#: ../../library/asyncio-dev.rst:148 +msgid "logging.getLogger(\"asyncio\").setLevel(logging.WARNING)" +msgstr "" + #: ../../library/asyncio-dev.rst:151 msgid "" "Network logging can block the event loop. It is recommended to use a " @@ -277,14 +305,47 @@ msgstr "" "者協程沒有透過 :meth:`asyncio.create_task` 被排程,asyncio 將會發出 :exc:" "`RuntimeWarning`: ::" +#: ../../library/asyncio-dev.rst:166 +msgid "" +"import asyncio\n" +"\n" +"async def test():\n" +" print(\"never scheduled\")\n" +"\n" +"async def main():\n" +" test()\n" +"\n" +"asyncio.run(main())" +msgstr "" + #: ../../library/asyncio-dev.rst:176 ../../library/asyncio-dev.rst:221 msgid "Output::" msgstr "輸出: ::" +#: ../../library/asyncio-dev.rst:178 +msgid "" +"test.py:7: RuntimeWarning: coroutine 'test' was never awaited\n" +" test()" +msgstr "" + #: ../../library/asyncio-dev.rst:181 ../../library/asyncio-dev.rst:237 msgid "Output in debug mode::" msgstr "除錯模式中的輸出: ::" +#: ../../library/asyncio-dev.rst:183 +msgid "" +"test.py:7: RuntimeWarning: coroutine 'test' was never awaited\n" +"Coroutine created at (most recent call last)\n" +" File \"../t.py\", line 9, in \n" +" asyncio.run(main(), debug=True)\n" +"\n" +" < .. >\n" +"\n" +" File \"../t.py\", line 7, in main\n" +" test()\n" +" test()" +msgstr "" + #: ../../library/asyncio-dev.rst:194 msgid "" "The usual fix is to either await the coroutine or call the :meth:`asyncio." @@ -292,6 +353,12 @@ msgid "" msgstr "" "常用的修復方法是去等待協程或者呼叫 :meth:`asyncio.create_task` 函式: ::" +#: ../../library/asyncio-dev.rst:197 +msgid "" +"async def main():\n" +" await test()" +msgstr "" + #: ../../library/asyncio-dev.rst:202 msgid "Detect never-retrieved exceptions" msgstr "偵測從未被獲取的 (never-retrieved) 例外" @@ -311,6 +378,31 @@ msgstr "" msgid "Example of an unhandled exception::" msgstr "未處理例外的例子: ::" +#: ../../library/asyncio-dev.rst:211 +msgid "" +"import asyncio\n" +"\n" +"async def bug():\n" +" raise Exception(\"not consumed\")\n" +"\n" +"async def main():\n" +" asyncio.create_task(bug())\n" +"\n" +"asyncio.run(main())" +msgstr "" + +#: ../../library/asyncio-dev.rst:223 +msgid "" +"Task exception was never retrieved\n" +"future: \n" +" exception=Exception('not consumed')>\n" +"\n" +"Traceback (most recent call last):\n" +" File \"test.py\", line 4, in bug\n" +" raise Exception(\"not consumed\")\n" +"Exception: not consumed" +msgstr "" + #: ../../library/asyncio-dev.rst:232 msgid "" ":ref:`Enable the debug mode ` to get the traceback where " @@ -318,3 +410,25 @@ msgid "" msgstr "" ":ref:`啟用除錯模式 `\\ 以取得任務建立處的追蹤資訊 " "(traceback): ::" + +#: ../../library/asyncio-dev.rst:235 +msgid "asyncio.run(main(), debug=True)" +msgstr "" + +#: ../../library/asyncio-dev.rst:239 +msgid "" +"Task exception was never retrieved\n" +"future: \n" +" exception=Exception('not consumed') created at asyncio/tasks.py:321>\n" +"\n" +"source_traceback: Object created at (most recent call last):\n" +" File \"../t.py\", line 9, in \n" +" asyncio.run(main(), debug=True)\n" +"\n" +"< .. >\n" +"\n" +"Traceback (most recent call last):\n" +" File \"../t.py\", line 4, in bug\n" +" raise Exception(\"not consumed\")\n" +"Exception: not consumed" +msgstr "" diff --git a/library/asyncio-eventloop.po b/library/asyncio-eventloop.po index 803e712a6b..b08290d5c1 100644 --- a/library/asyncio-eventloop.po +++ b/library/asyncio-eventloop.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-04-18 00:04+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2022-02-20 12:36+0800\n" "Last-Translator: Adrian Liaw \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -296,11 +296,20 @@ msgid "" msgstr "請注意,使用 :func:`asyncio.run` 時不需要呼叫此函式。" #: ../../library/asyncio-eventloop.rst:176 -#: ../../library/asyncio-eventloop.rst:1242 -#: ../../library/asyncio-eventloop.rst:1660 +#: ../../library/asyncio-eventloop.rst:1253 +#: ../../library/asyncio-eventloop.rst:1671 msgid "Example::" msgstr "範例: ::" +#: ../../library/asyncio-eventloop.rst:178 +msgid "" +"try:\n" +" loop.run_forever()\n" +"finally:\n" +" loop.run_until_complete(loop.shutdown_asyncgens())\n" +" loop.close()" +msgstr "" + #: ../../library/asyncio-eventloop.rst:188 msgid "" "Schedule the closure of the default executor and wait for it to join all of " @@ -417,6 +426,13 @@ msgstr "" "大多數 :mod:`asyncio` 排程函式不允許傳遞關鍵字引數。要傳遞關鍵字引數,請使" "用 :func:`functools.partial`: ::" +#: ../../library/asyncio-eventloop.rst:257 +msgid "" +"# will schedule \"print(\"Hello\", flush=True)\"\n" +"loop.call_soon(\n" +" functools.partial(print, \"Hello\", flush=True))" +msgstr "" + #: ../../library/asyncio-eventloop.rst:261 msgid "" "Using partial objects is usually more convenient than using lambdas, as " @@ -626,8 +642,8 @@ msgid "The socket type will be :py:const:`~socket.SOCK_STREAM`." msgstr "Socket 類型將為 :py:const:`~socket.SOCK_STREAM`。" #: ../../library/asyncio-eventloop.rst:412 -#: ../../library/asyncio-eventloop.rst:1156 -#: ../../library/asyncio-eventloop.rst:1172 +#: ../../library/asyncio-eventloop.rst:1164 +#: ../../library/asyncio-eventloop.rst:1180 msgid "" "*protocol_factory* must be a callable returning an :ref:`asyncio protocol " "` implementation." @@ -1065,7 +1081,7 @@ msgstr "" #: ../../library/asyncio-eventloop.rst:652 #: ../../library/asyncio-eventloop.rst:794 -#: ../../library/asyncio-eventloop.rst:1225 +#: ../../library/asyncio-eventloop.rst:1233 msgid ":ref:`Availability `: Unix." msgstr ":ref:`適用 `:Unix。" @@ -1450,7 +1466,7 @@ msgstr "" "*callback*。" #: ../../library/asyncio-eventloop.rst:955 -#: ../../library/asyncio-eventloop.rst:1212 +#: ../../library/asyncio-eventloop.rst:1220 msgid "" "Use :func:`functools.partial` :ref:`to pass keyword arguments ` to *callback*." @@ -1704,7 +1720,17 @@ msgstr ":meth:`socket.getaddrinfo` 的非同步版本。" msgid "Asynchronous version of :meth:`socket.getnameinfo`." msgstr ":meth:`socket.getnameinfo` 的非同步版本。" -#: ../../library/asyncio-eventloop.rst:1142 +#: ../../library/asyncio-eventloop.rst:1143 +msgid "" +"Both *getaddrinfo* and *getnameinfo* internally utilize their synchronous " +"versions through the loop's default thread pool executor. When this executor " +"is saturated, these methods may experience delays, which higher-level " +"networking libraries may report as increased timeouts. To mitigate this, " +"consider using a custom executor for other user tasks, or setting a default " +"executor with a larger number of workers." +msgstr "" + +#: ../../library/asyncio-eventloop.rst:1150 msgid "" "Both *getaddrinfo* and *getnameinfo* methods were always documented to " "return a coroutine, but prior to Python 3.7 they were, in fact, returning :" @@ -1715,19 +1741,19 @@ msgstr "" "它們實際上回傳 :class:`asyncio.Future` 物件。從 Python 3.7 開始,兩個方法都是" "協程。" -#: ../../library/asyncio-eventloop.rst:1150 +#: ../../library/asyncio-eventloop.rst:1158 msgid "Working with pipes" msgstr "使用管道" -#: ../../library/asyncio-eventloop.rst:1154 +#: ../../library/asyncio-eventloop.rst:1162 msgid "Register the read end of *pipe* in the event loop." msgstr "在事件迴圈中註冊 *pipe* 的讀取端。" -#: ../../library/asyncio-eventloop.rst:1159 +#: ../../library/asyncio-eventloop.rst:1167 msgid "*pipe* is a :term:`file-like object `." msgstr "*pipe* 是 :term:`類檔案物件 `。" -#: ../../library/asyncio-eventloop.rst:1161 +#: ../../library/asyncio-eventloop.rst:1169 msgid "" "Return pair ``(transport, protocol)``, where *transport* supports the :class:" "`ReadTransport` interface and *protocol* is an object instantiated by the " @@ -1736,22 +1762,22 @@ msgstr "" "回傳 ``(transport, protocol)`` 對,其中 *transport* 支援 :class:" "`ReadTransport` 介面,*protocol* 是由 *protocol_factory* 實例化的物件。" -#: ../../library/asyncio-eventloop.rst:1165 -#: ../../library/asyncio-eventloop.rst:1181 +#: ../../library/asyncio-eventloop.rst:1173 +#: ../../library/asyncio-eventloop.rst:1189 msgid "" "With :class:`SelectorEventLoop` event loop, the *pipe* is set to non-" "blocking mode." msgstr "使用 :class:`SelectorEventLoop` 事件迴圈時,*pipe* 設置為非阻塞模式。" -#: ../../library/asyncio-eventloop.rst:1170 +#: ../../library/asyncio-eventloop.rst:1178 msgid "Register the write end of *pipe* in the event loop." msgstr "在事件迴圈中註冊 *pipe* 的寫入端。" -#: ../../library/asyncio-eventloop.rst:1175 +#: ../../library/asyncio-eventloop.rst:1183 msgid "*pipe* is :term:`file-like object `." msgstr "*pipe* 是 :term:`file-like object `。" -#: ../../library/asyncio-eventloop.rst:1177 +#: ../../library/asyncio-eventloop.rst:1185 msgid "" "Return pair ``(transport, protocol)``, where *transport* supports :class:" "`WriteTransport` interface and *protocol* is an object instantiated by the " @@ -1760,7 +1786,7 @@ msgstr "" "回傳 ``(transport, protocol)`` 對,其中 *transport* 支援 :class:" "`WriteTransport` 介面,*protocol* 是由 *protocol_factory* 實例化的物件。" -#: ../../library/asyncio-eventloop.rst:1186 +#: ../../library/asyncio-eventloop.rst:1194 msgid "" ":class:`SelectorEventLoop` does not support the above methods on Windows. " "Use :class:`ProactorEventLoop` instead for Windows." @@ -1768,20 +1794,20 @@ msgstr "" ":class:`SelectorEventLoop` 在 Windows 上不支援上述方法。對於 Windows 請使用 :" "class:`ProactorEventLoop`。" -#: ../../library/asyncio-eventloop.rst:1191 +#: ../../library/asyncio-eventloop.rst:1199 msgid "" "The :meth:`loop.subprocess_exec` and :meth:`loop.subprocess_shell` methods." msgstr ":meth:`loop.subprocess_exec` 和 :meth:`loop.subprocess_shell` 方法。" -#: ../../library/asyncio-eventloop.rst:1196 +#: ../../library/asyncio-eventloop.rst:1204 msgid "Unix signals" msgstr "Unix 訊號" -#: ../../library/asyncio-eventloop.rst:1202 +#: ../../library/asyncio-eventloop.rst:1210 msgid "Set *callback* as the handler for the *signum* signal." msgstr "將 *callback* 設置為 *signum* 訊號的處理程式。" -#: ../../library/asyncio-eventloop.rst:1204 +#: ../../library/asyncio-eventloop.rst:1212 msgid "" "The callback will be invoked by *loop*, along with other queued callbacks " "and runnable coroutines of that event loop. Unlike signal handlers " @@ -1792,7 +1818,7 @@ msgstr "" "用 :func:`signal.signal` 註冊的訊號處理程式不同,使用此函式註冊的回呼允許與事" "件迴圈進行互動。" -#: ../../library/asyncio-eventloop.rst:1209 +#: ../../library/asyncio-eventloop.rst:1217 msgid "" "Raise :exc:`ValueError` if the signal number is invalid or uncatchable. " "Raise :exc:`RuntimeError` if there is a problem setting up the handler." @@ -1800,16 +1826,16 @@ msgstr "" "如果訊號號無效或不可捕獲,引發 :exc:`ValueError`。如果設定處理程序有問題,拋" "出 :exc:`RuntimeError`。" -#: ../../library/asyncio-eventloop.rst:1215 +#: ../../library/asyncio-eventloop.rst:1223 msgid "" "Like :func:`signal.signal`, this function must be invoked in the main thread." msgstr "像 :func:`signal.signal` 一樣,此函式必須在主執行緒中呼叫。" -#: ../../library/asyncio-eventloop.rst:1220 +#: ../../library/asyncio-eventloop.rst:1228 msgid "Remove the handler for the *sig* signal." msgstr "移除 *sig* 訊號的處理程式。" -#: ../../library/asyncio-eventloop.rst:1222 +#: ../../library/asyncio-eventloop.rst:1230 msgid "" "Return ``True`` if the signal handler was removed, or ``False`` if no " "handler was set for the given signal." @@ -1817,27 +1843,71 @@ msgstr "" "如果訊號處理程式被移除,回傳 ``True``;如果給定訊號沒有設置處理程式,回傳 " "``False``。" -#: ../../library/asyncio-eventloop.rst:1229 +#: ../../library/asyncio-eventloop.rst:1237 msgid "The :mod:`signal` module." msgstr ":mod:`signal` 模組。" -#: ../../library/asyncio-eventloop.rst:1233 +#: ../../library/asyncio-eventloop.rst:1241 msgid "Executing code in thread or process pools" msgstr "在執行緒池或行程池中執行程式碼" -#: ../../library/asyncio-eventloop.rst:1237 +#: ../../library/asyncio-eventloop.rst:1245 msgid "Arrange for *func* to be called in the specified executor." msgstr "安排在指定的執行器中呼叫 *func*。" -#: ../../library/asyncio-eventloop.rst:1239 +#: ../../library/asyncio-eventloop.rst:1247 msgid "" "The *executor* argument should be an :class:`concurrent.futures.Executor` " -"instance. The default executor is used if *executor* is ``None``." -msgstr "" -"*executor* 引數應該是 :class:`concurrent.futures.Executor` 實例。如果 " -"*executor* 為 ``None``,則使用預設執行器。" - -#: ../../library/asyncio-eventloop.rst:1284 +"instance. The default executor is used if *executor* is ``None``. The " +"default executor can be set by :meth:`loop.set_default_executor`, otherwise, " +"a :class:`concurrent.futures.ThreadPoolExecutor` will be lazy-initialized " +"and used by :func:`run_in_executor` if needed." +msgstr "" + +#: ../../library/asyncio-eventloop.rst:1255 +msgid "" +"import asyncio\n" +"import concurrent.futures\n" +"\n" +"def blocking_io():\n" +" # File operations (such as logging) can block the\n" +" # event loop: run them in a thread pool.\n" +" with open('/dev/urandom', 'rb') as f:\n" +" return f.read(100)\n" +"\n" +"def cpu_bound():\n" +" # CPU-bound operations will block the event loop:\n" +" # in general it is preferable to run them in a\n" +" # process pool.\n" +" return sum(i * i for i in range(10 ** 7))\n" +"\n" +"async def main():\n" +" loop = asyncio.get_running_loop()\n" +"\n" +" ## Options:\n" +"\n" +" # 1. Run in the default loop's executor:\n" +" result = await loop.run_in_executor(\n" +" None, blocking_io)\n" +" print('default thread pool', result)\n" +"\n" +" # 2. Run in a custom thread pool:\n" +" with concurrent.futures.ThreadPoolExecutor() as pool:\n" +" result = await loop.run_in_executor(\n" +" pool, blocking_io)\n" +" print('custom thread pool', result)\n" +"\n" +" # 3. Run in a custom process pool:\n" +" with concurrent.futures.ProcessPoolExecutor() as pool:\n" +" result = await loop.run_in_executor(\n" +" pool, cpu_bound)\n" +" print('custom process pool', result)\n" +"\n" +"if __name__ == '__main__':\n" +" asyncio.run(main())" +msgstr "" + +#: ../../library/asyncio-eventloop.rst:1295 msgid "" "Note that the entry point guard (``if __name__ == '__main__'``) is required " "for option 3 due to the peculiarities of :mod:`multiprocessing`, which is " @@ -1849,11 +1919,11 @@ msgstr "" "== '__main__'``\\ )。請參閱\\ :ref:`主模組的安全引入 `。" -#: ../../library/asyncio-eventloop.rst:1289 +#: ../../library/asyncio-eventloop.rst:1300 msgid "This method returns a :class:`asyncio.Future` object." msgstr "此方法回傳 :class:`asyncio.Future` 物件。" -#: ../../library/asyncio-eventloop.rst:1291 +#: ../../library/asyncio-eventloop.rst:1302 msgid "" "Use :func:`functools.partial` :ref:`to pass keyword arguments ` to *func*." @@ -1861,7 +1931,7 @@ msgstr "" "使用 :func:`functools.partial` 將來\\ :ref:`關鍵字引數傳遞 `\\ 給 *func*。" -#: ../../library/asyncio-eventloop.rst:1294 +#: ../../library/asyncio-eventloop.rst:1305 msgid "" ":meth:`loop.run_in_executor` no longer configures the ``max_workers`` of the " "thread pool executor it creates, instead leaving it up to the thread pool " @@ -1872,7 +1942,7 @@ msgstr "" "``max_workers``,而是讓執行緒池執行器(\\ :class:`~concurrent.futures." "ThreadPoolExecutor`)設定預設值。" -#: ../../library/asyncio-eventloop.rst:1303 +#: ../../library/asyncio-eventloop.rst:1314 msgid "" "Set *executor* as the default executor used by :meth:`run_in_executor`. " "*executor* must be an instance of :class:`~concurrent.futures." @@ -1881,26 +1951,26 @@ msgstr "" "將 *executor* 設置為 :meth:`run_in_executor` 使用的預設執行器。*executor* 必" "須是 :class:`~concurrent.futures.ThreadPoolExecutor` 的實例。" -#: ../../library/asyncio-eventloop.rst:1307 +#: ../../library/asyncio-eventloop.rst:1318 msgid "" "*executor* must be an instance of :class:`~concurrent.futures." "ThreadPoolExecutor`." msgstr "" "*executor* 必須是 :class:`~concurrent.futures.ThreadPoolExecutor` 的實例。" -#: ../../library/asyncio-eventloop.rst:1313 +#: ../../library/asyncio-eventloop.rst:1324 msgid "Error Handling API" msgstr "錯誤處理 API" -#: ../../library/asyncio-eventloop.rst:1315 +#: ../../library/asyncio-eventloop.rst:1326 msgid "Allows customizing how exceptions are handled in the event loop." msgstr "允許自定義事件迴圈中的例外處理方式。" -#: ../../library/asyncio-eventloop.rst:1319 +#: ../../library/asyncio-eventloop.rst:1330 msgid "Set *handler* as the new event loop exception handler." msgstr "將 *handler* 設定為新的事件迴圈例外處理程式。" -#: ../../library/asyncio-eventloop.rst:1321 +#: ../../library/asyncio-eventloop.rst:1332 msgid "" "If *handler* is ``None``, the default exception handler will be set. " "Otherwise, *handler* must be a callable with the signature matching ``(loop, " @@ -1913,7 +1983,7 @@ msgstr "" "圈的,``context`` 是包含例外詳細資訊的 ``dict`` 物件(有關情境的詳細資訊,請" "參閱 :meth:`call_exception_handler` 文件)。" -#: ../../library/asyncio-eventloop.rst:1329 +#: ../../library/asyncio-eventloop.rst:1340 msgid "" "If the handler is called on behalf of a :class:`~asyncio.Task` or :class:" "`~asyncio.Handle`, it is run in the :class:`contextvars.Context` of that " @@ -1922,7 +1992,7 @@ msgstr "" "如果代表 :class:`~asyncio.Task` 或 :class:`~asyncio.Handle` 呼叫處理程式,它" "將在該任務或回呼處理程式的 :class:`contextvars.Context` 中運行。" -#: ../../library/asyncio-eventloop.rst:1335 +#: ../../library/asyncio-eventloop.rst:1346 msgid "" "The handler may be called in the :class:`~contextvars.Context` of the task " "or handle where the exception originated." @@ -1930,18 +2000,18 @@ msgstr "" "處理程式可能在引發例外的任務或處理程式的 :class:`~contextvars.Context` 中被呼" "叫。" -#: ../../library/asyncio-eventloop.rst:1340 +#: ../../library/asyncio-eventloop.rst:1351 msgid "" "Return the current exception handler, or ``None`` if no custom exception " "handler was set." msgstr "" "回傳當前的例外處理程式,如果未設置自定義例外處理程式,則回傳 ``None``。" -#: ../../library/asyncio-eventloop.rst:1347 +#: ../../library/asyncio-eventloop.rst:1358 msgid "Default exception handler." msgstr "預設例外處理程式。" -#: ../../library/asyncio-eventloop.rst:1349 +#: ../../library/asyncio-eventloop.rst:1360 msgid "" "This is called when an exception occurs and no exception handler is set. " "This can be called by a custom exception handler that wants to defer to the " @@ -1950,17 +2020,17 @@ msgstr "" "當發生例外且未設置例外處理程式時呼叫此函式。自定義例外處理程式可以呼叫此函式" "以轉由預設處理程式處理。" -#: ../../library/asyncio-eventloop.rst:1353 +#: ../../library/asyncio-eventloop.rst:1364 msgid "" "*context* parameter has the same meaning as in :meth:" "`call_exception_handler`." msgstr "*context* 參數與 :meth:`call_exception_handler` 中的意思相同。" -#: ../../library/asyncio-eventloop.rst:1358 +#: ../../library/asyncio-eventloop.rst:1369 msgid "Call the current event loop exception handler." msgstr "呼叫當前事件迴圈例外處理程式。" -#: ../../library/asyncio-eventloop.rst:1360 +#: ../../library/asyncio-eventloop.rst:1371 msgid "" "*context* is a ``dict`` object containing the following keys (new keys may " "be introduced in future Python versions):" @@ -1968,47 +2038,47 @@ msgstr "" "*context* 是一個包含以下鍵的 ``dict`` 物件(未來的 Python 版本中可能會引入新" "的鍵):" -#: ../../library/asyncio-eventloop.rst:1363 +#: ../../library/asyncio-eventloop.rst:1374 msgid "'message': Error message;" msgstr "'message':錯誤訊息;" -#: ../../library/asyncio-eventloop.rst:1364 +#: ../../library/asyncio-eventloop.rst:1375 msgid "'exception' (optional): Exception object;" msgstr "'exception'(可選):例外物件;" -#: ../../library/asyncio-eventloop.rst:1365 +#: ../../library/asyncio-eventloop.rst:1376 msgid "'future' (optional): :class:`asyncio.Future` instance;" msgstr "'future'(可選): :class:`asyncio.Future` 實例;" -#: ../../library/asyncio-eventloop.rst:1366 +#: ../../library/asyncio-eventloop.rst:1377 msgid "'task' (optional): :class:`asyncio.Task` instance;" msgstr "'task'(可選): :class:`asyncio.Task` 實例;" -#: ../../library/asyncio-eventloop.rst:1367 +#: ../../library/asyncio-eventloop.rst:1378 msgid "'handle' (optional): :class:`asyncio.Handle` instance;" msgstr "'handle'(可選): :class:`asyncio.Handle` 實例;" -#: ../../library/asyncio-eventloop.rst:1368 +#: ../../library/asyncio-eventloop.rst:1379 msgid "'protocol' (optional): :ref:`Protocol ` instance;" msgstr "'protocol'(可選): :ref:`Protocol ` 實例;" -#: ../../library/asyncio-eventloop.rst:1369 +#: ../../library/asyncio-eventloop.rst:1380 msgid "'transport' (optional): :ref:`Transport ` instance;" msgstr "'transport'(可選): :ref:`Transport ` 實例;" -#: ../../library/asyncio-eventloop.rst:1370 +#: ../../library/asyncio-eventloop.rst:1381 msgid "'socket' (optional): :class:`socket.socket` instance;" msgstr "'socket'(可選): :class:`socket.socket` 實例;" -#: ../../library/asyncio-eventloop.rst:1371 +#: ../../library/asyncio-eventloop.rst:1382 msgid "'asyncgen' (optional): Asynchronous generator that caused" msgstr "'asyncgen'(可選): 非同步產生器引發" -#: ../../library/asyncio-eventloop.rst:1372 +#: ../../library/asyncio-eventloop.rst:1383 msgid "the exception." msgstr "例外。" -#: ../../library/asyncio-eventloop.rst:1376 +#: ../../library/asyncio-eventloop.rst:1387 msgid "" "This method should not be overloaded in subclassed event loops. For custom " "exception handling, use the :meth:`set_exception_handler` method." @@ -2016,15 +2086,15 @@ msgstr "" "此方法不應在子類別事件迴圈中被覆寫。為了自定義例外處理,請使用 :meth:" "`set_exception_handler` 方法。" -#: ../../library/asyncio-eventloop.rst:1381 +#: ../../library/asyncio-eventloop.rst:1392 msgid "Enabling debug mode" msgstr "啟用除錯模式" -#: ../../library/asyncio-eventloop.rst:1385 +#: ../../library/asyncio-eventloop.rst:1396 msgid "Get the debug mode (:class:`bool`) of the event loop." msgstr "取得事件迴圈的除錯模式(\\ :class:`bool`\\ )。" -#: ../../library/asyncio-eventloop.rst:1387 +#: ../../library/asyncio-eventloop.rst:1398 msgid "" "The default value is ``True`` if the environment variable :envvar:" "`PYTHONASYNCIODEBUG` is set to a non-empty string, ``False`` otherwise." @@ -2032,17 +2102,17 @@ msgstr "" "如果環境變數 :envvar:`PYTHONASYNCIODEBUG` 被設定為非空字串,則預設值為 " "``True``,否則為 ``False``。" -#: ../../library/asyncio-eventloop.rst:1393 +#: ../../library/asyncio-eventloop.rst:1404 msgid "Set the debug mode of the event loop." msgstr "設定事件迴圈的除錯模式。" -#: ../../library/asyncio-eventloop.rst:1397 +#: ../../library/asyncio-eventloop.rst:1408 msgid "" "The new :ref:`Python Development Mode ` can now also be used to " "enable the debug mode." msgstr "現在也可以使用新的 :ref:`Python 開發模式 ` 啟用除錯模式。" -#: ../../library/asyncio-eventloop.rst:1402 +#: ../../library/asyncio-eventloop.rst:1413 msgid "" "This attribute can be used to set the minimum execution duration in seconds " "that is considered \"slow\". When debug mode is enabled, \"slow\" callbacks " @@ -2051,19 +2121,19 @@ msgstr "" "此屬性可用於設定被視為\"慢\"的最短執行時間(以秒為單位)。啟用偵錯模式" "後,\"慢\"回呼將被記錄。" -#: ../../library/asyncio-eventloop.rst:1406 +#: ../../library/asyncio-eventloop.rst:1417 msgid "Default value is 100 milliseconds." msgstr "預設值為 100 毫秒" -#: ../../library/asyncio-eventloop.rst:1410 +#: ../../library/asyncio-eventloop.rst:1421 msgid "The :ref:`debug mode of asyncio `." msgstr ":ref:`asyncio 的除錯模式 `。" -#: ../../library/asyncio-eventloop.rst:1414 +#: ../../library/asyncio-eventloop.rst:1425 msgid "Running Subprocesses" msgstr "運行子行程" -#: ../../library/asyncio-eventloop.rst:1416 +#: ../../library/asyncio-eventloop.rst:1427 msgid "" "Methods described in this subsections are low-level. In regular async/await " "code consider using the high-level :func:`asyncio.create_subprocess_shell` " @@ -2073,7 +2143,7 @@ msgstr "" "func:`asyncio.create_subprocess_shell` 和 :func:`asyncio." "create_subprocess_exec` 輔助功能而不是。" -#: ../../library/asyncio-eventloop.rst:1423 +#: ../../library/asyncio-eventloop.rst:1434 msgid "" "On Windows, the default event loop :class:`ProactorEventLoop` supports " "subprocesses, whereas :class:`SelectorEventLoop` does not. See :ref:" @@ -2083,26 +2153,26 @@ msgstr "" "`SelectorEventLoop` 不支援。詳細資訊請參見 :ref:`Windows 上對於子行程的支援 " "`。" -#: ../../library/asyncio-eventloop.rst:1434 +#: ../../library/asyncio-eventloop.rst:1445 msgid "" "Create a subprocess from one or more string arguments specified by *args*." msgstr "從 *args* 指定的一個或多個字串引數建立子行程。" -#: ../../library/asyncio-eventloop.rst:1437 +#: ../../library/asyncio-eventloop.rst:1448 msgid "*args* must be a list of strings represented by:" msgstr "*args* 必須是由以下項表示的字串串列:" -#: ../../library/asyncio-eventloop.rst:1439 +#: ../../library/asyncio-eventloop.rst:1450 msgid ":class:`str`;" msgstr ":class:`str`;" -#: ../../library/asyncio-eventloop.rst:1440 +#: ../../library/asyncio-eventloop.rst:1451 msgid "" "or :class:`bytes`, encoded to the :ref:`filesystem encoding `." msgstr "或 :class:`bytes`,編碼為 :ref:`檔案系統編碼 `。" -#: ../../library/asyncio-eventloop.rst:1443 +#: ../../library/asyncio-eventloop.rst:1454 msgid "" "The first string specifies the program executable, and the remaining strings " "specify the arguments. Together, string arguments form the ``argv`` of the " @@ -2111,7 +2181,7 @@ msgstr "" "第一個字串指定程序可執行檔案,其餘字串指定引數。字串引數一起組成程序的 " "``argv``。" -#: ../../library/asyncio-eventloop.rst:1447 +#: ../../library/asyncio-eventloop.rst:1458 msgid "" "This is similar to the standard library :class:`subprocess.Popen` class " "called with ``shell=False`` and the list of strings passed as the first " @@ -2122,7 +2192,7 @@ msgstr "" "字串串列作為第一個引數傳遞;然而,:class:`~subprocess.Popen` 接受單個字串串列" "引數,*subprocess_exec* 接受多個字串引數。" -#: ../../library/asyncio-eventloop.rst:1453 +#: ../../library/asyncio-eventloop.rst:1464 msgid "" "The *protocol_factory* must be a callable returning a subclass of the :class:" "`asyncio.SubprocessProtocol` class." @@ -2130,67 +2200,67 @@ msgstr "" "*protocol_factory* 必須是回傳 :class:`asyncio.SubprocessProtocol` 子類別的可" "呼叫物件。" -#: ../../library/asyncio-eventloop.rst:1456 +#: ../../library/asyncio-eventloop.rst:1467 msgid "Other parameters:" msgstr "其他參數:" -#: ../../library/asyncio-eventloop.rst:1458 +#: ../../library/asyncio-eventloop.rst:1469 msgid "*stdin* can be any of these:" msgstr "*stdin* 可以是以下任意一個:" -#: ../../library/asyncio-eventloop.rst:1460 #: ../../library/asyncio-eventloop.rst:1471 -#: ../../library/asyncio-eventloop.rst:1481 +#: ../../library/asyncio-eventloop.rst:1482 +#: ../../library/asyncio-eventloop.rst:1492 msgid "a file-like object" msgstr "類檔案物件" -#: ../../library/asyncio-eventloop.rst:1461 +#: ../../library/asyncio-eventloop.rst:1472 msgid "" "an existing file descriptor (a positive integer), for example those created " "with :meth:`os.pipe`" msgstr "現有的檔案描述器(正整數),例如用 :meth:`os.pipe` 建立的" -#: ../../library/asyncio-eventloop.rst:1462 -#: ../../library/asyncio-eventloop.rst:1472 -#: ../../library/asyncio-eventloop.rst:1482 +#: ../../library/asyncio-eventloop.rst:1473 +#: ../../library/asyncio-eventloop.rst:1483 +#: ../../library/asyncio-eventloop.rst:1493 msgid "" "the :const:`subprocess.PIPE` constant (default) which will create a new pipe " "and connect it," msgstr ":const:`subprocess.PIPE` 常數(預設),它將建立一個新的管道並連線," -#: ../../library/asyncio-eventloop.rst:1464 -#: ../../library/asyncio-eventloop.rst:1474 -#: ../../library/asyncio-eventloop.rst:1484 +#: ../../library/asyncio-eventloop.rst:1475 +#: ../../library/asyncio-eventloop.rst:1485 +#: ../../library/asyncio-eventloop.rst:1495 msgid "" "the value ``None`` which will make the subprocess inherit the file " "descriptor from this process" msgstr "值 ``None`` 將使子行程從此行程繼承檔案描述器" -#: ../../library/asyncio-eventloop.rst:1466 -#: ../../library/asyncio-eventloop.rst:1476 -#: ../../library/asyncio-eventloop.rst:1486 +#: ../../library/asyncio-eventloop.rst:1477 +#: ../../library/asyncio-eventloop.rst:1487 +#: ../../library/asyncio-eventloop.rst:1497 msgid "" "the :const:`subprocess.DEVNULL` constant which indicates that the special :" "data:`os.devnull` file will be used" msgstr "" ":const:`subprocess.DEVNULL` 常數,表示將使用特殊的 :data:`os.devnull` 檔案" -#: ../../library/asyncio-eventloop.rst:1469 +#: ../../library/asyncio-eventloop.rst:1480 msgid "*stdout* can be any of these:" msgstr "*stdout* 可以是以下任意一個:" -#: ../../library/asyncio-eventloop.rst:1479 +#: ../../library/asyncio-eventloop.rst:1490 msgid "*stderr* can be any of these:" msgstr "*stderr* 可以是以下任意一個:" -#: ../../library/asyncio-eventloop.rst:1488 +#: ../../library/asyncio-eventloop.rst:1499 msgid "" "the :const:`subprocess.STDOUT` constant which will connect the standard " "error stream to the process' standard output stream" msgstr "" ":const:`subprocess.STDOUT` 常數,它將標準錯誤串流連線到行程的標準輸出串流" -#: ../../library/asyncio-eventloop.rst:1491 +#: ../../library/asyncio-eventloop.rst:1502 msgid "" "All other keyword arguments are passed to :class:`subprocess.Popen` without " "interpretation, except for *bufsize*, *universal_newlines*, *shell*, *text*, " @@ -2200,7 +2270,7 @@ msgstr "" "*bufsize*、*universal_newlines*、*shell*、*text*、*encoding* 和 *errors* 除" "外,這些不應該指定。" -#: ../../library/asyncio-eventloop.rst:1496 +#: ../../library/asyncio-eventloop.rst:1507 msgid "" "The ``asyncio`` subprocess API does not support decoding the streams as " "text. :func:`bytes.decode` can be used to convert the bytes returned from " @@ -2209,7 +2279,7 @@ msgstr "" "``asyncio`` 子行程 API 不支援將串流解碼為文本。可以使用 :func:`bytes.decode` " "將從串流回傳的位元組轉換為文本。" -#: ../../library/asyncio-eventloop.rst:1500 +#: ../../library/asyncio-eventloop.rst:1511 msgid "" "If a file-like object passed as *stdin*, *stdout* or *stderr* represents a " "pipe, then the other side of this pipe should be registered with :meth:" @@ -2220,13 +2290,13 @@ msgstr "" "端應該使用 :meth:`~loop.connect_write_pipe` 或 :meth:`~loop." "connect_read_pipe` 註冊到事件迴圈中。" -#: ../../library/asyncio-eventloop.rst:1505 +#: ../../library/asyncio-eventloop.rst:1516 msgid "" "See the constructor of the :class:`subprocess.Popen` class for documentation " "on other arguments." msgstr "有關其他引數的文件,請參閱 :class:`subprocess.Popen` 類別的建構函式。" -#: ../../library/asyncio-eventloop.rst:1508 +#: ../../library/asyncio-eventloop.rst:1519 msgid "" "Returns a pair of ``(transport, protocol)``, where *transport* conforms to " "the :class:`asyncio.SubprocessTransport` base class and *protocol* is an " @@ -2236,7 +2306,7 @@ msgstr "" "SubprocessTransport` 基底類別,*protocol* 是由 *protocol_factory* 實例化的物" "件。" -#: ../../library/asyncio-eventloop.rst:1516 +#: ../../library/asyncio-eventloop.rst:1527 msgid "" "Create a subprocess from *cmd*, which can be a :class:`str` or a :class:" "`bytes` string encoded to the :ref:`filesystem encoding ` 的 :class:`bytes` 字串。" -#: ../../library/asyncio-eventloop.rst:1521 +#: ../../library/asyncio-eventloop.rst:1532 msgid "" "This is similar to the standard library :class:`subprocess.Popen` class " "called with ``shell=True``." @@ -2253,7 +2323,7 @@ msgstr "" "這類似於標準函式庫中的 :class:`subprocess.Popen` 類別,使用 ``shell=True`` 呼" "叫。" -#: ../../library/asyncio-eventloop.rst:1524 +#: ../../library/asyncio-eventloop.rst:1535 msgid "" "The *protocol_factory* must be a callable returning a subclass of the :class:" "`SubprocessProtocol` class." @@ -2261,13 +2331,13 @@ msgstr "" "*protocol_factory* 必須是回傳 :class:`SubprocessProtocol` 子類別的可呼叫物" "件。" -#: ../../library/asyncio-eventloop.rst:1527 +#: ../../library/asyncio-eventloop.rst:1538 msgid "" "See :meth:`~loop.subprocess_exec` for more details about the remaining " "arguments." msgstr "有關其餘引數的更多詳細資訊,請參閱 :meth:`~loop.subprocess_exec`。" -#: ../../library/asyncio-eventloop.rst:1530 +#: ../../library/asyncio-eventloop.rst:1541 msgid "" "Returns a pair of ``(transport, protocol)``, where *transport* conforms to " "the :class:`SubprocessTransport` base class and *protocol* is an object " @@ -2277,7 +2347,7 @@ msgstr "" "`SubprocessTransport` 基底類別,而 *protocol* 是由 *protocol_factory* 實例化" "的物件。" -#: ../../library/asyncio-eventloop.rst:1535 +#: ../../library/asyncio-eventloop.rst:1546 msgid "" "It is the application's responsibility to ensure that all whitespace and " "special characters are quoted appropriately to avoid `shell injection " @@ -2290,11 +2360,11 @@ msgstr "" "wikipedia.org/wiki/Shell_injection#Shell_injection>`_\\ 風險。可以使用 :func:" "`shlex.quote` 函式來正確跳脫用於構建 shell 命令的字串中的空白和特殊字元。" -#: ../../library/asyncio-eventloop.rst:1544 +#: ../../library/asyncio-eventloop.rst:1555 msgid "Callback Handles" msgstr "回呼處理" -#: ../../library/asyncio-eventloop.rst:1548 +#: ../../library/asyncio-eventloop.rst:1559 msgid "" "A callback wrapper object returned by :meth:`loop.call_soon`, :meth:`loop." "call_soon_threadsafe`." @@ -2302,46 +2372,46 @@ msgstr "" "由 :meth:`loop.call_soon` 和 :meth:`loop.call_soon_threadsafe` 回傳的回呼包裝" "器。" -#: ../../library/asyncio-eventloop.rst:1553 +#: ../../library/asyncio-eventloop.rst:1564 msgid "" "Return the :class:`contextvars.Context` object associated with the handle." msgstr "回傳與處理相關聯的 :class:`contextvars.Context` 物件。" -#: ../../library/asyncio-eventloop.rst:1560 +#: ../../library/asyncio-eventloop.rst:1571 msgid "" "Cancel the callback. If the callback has already been canceled or executed, " "this method has no effect." msgstr "取消回呼。如果回呼已被取消或執行,此方法將不起作用。" -#: ../../library/asyncio-eventloop.rst:1565 +#: ../../library/asyncio-eventloop.rst:1576 msgid "Return ``True`` if the callback was cancelled." msgstr "如果回呼已被取消,回傳 ``True``。" -#: ../../library/asyncio-eventloop.rst:1571 +#: ../../library/asyncio-eventloop.rst:1582 msgid "" "A callback wrapper object returned by :meth:`loop.call_later`, and :meth:" "`loop.call_at`." msgstr "由 :meth:`loop.call_later` 和 :meth:`loop.call_at` 回傳的回呼包裝器。" -#: ../../library/asyncio-eventloop.rst:1574 +#: ../../library/asyncio-eventloop.rst:1585 msgid "This class is a subclass of :class:`Handle`." msgstr "這個類別是 :class:`Handle` 的子類別。" -#: ../../library/asyncio-eventloop.rst:1578 +#: ../../library/asyncio-eventloop.rst:1589 msgid "Return a scheduled callback time as :class:`float` seconds." msgstr "回傳預定的回呼時間,以 :class:`float` 秒為單位。" -#: ../../library/asyncio-eventloop.rst:1580 +#: ../../library/asyncio-eventloop.rst:1591 msgid "" "The time is an absolute timestamp, using the same time reference as :meth:" "`loop.time`." msgstr "時間是一個絕對的時間戳,使用與 :meth:`loop.time` 相同的時間參照。" -#: ../../library/asyncio-eventloop.rst:1587 +#: ../../library/asyncio-eventloop.rst:1598 msgid "Server Objects" msgstr "Server 物件" -#: ../../library/asyncio-eventloop.rst:1589 +#: ../../library/asyncio-eventloop.rst:1600 msgid "" "Server objects are created by :meth:`loop.create_server`, :meth:`loop." "create_unix_server`, :func:`start_server`, and :func:`start_unix_server` " @@ -2351,11 +2421,11 @@ msgstr "" "create_unix_server`、:func:`start_server` 和 :func:`start_unix_server` 函式所" "建立。" -#: ../../library/asyncio-eventloop.rst:1593 +#: ../../library/asyncio-eventloop.rst:1604 msgid "Do not instantiate the :class:`Server` class directly." msgstr "請勿直接實例化 :class:`Server` 類別。" -#: ../../library/asyncio-eventloop.rst:1597 +#: ../../library/asyncio-eventloop.rst:1608 msgid "" "*Server* objects are asynchronous context managers. When used in an ``async " "with`` statement, it's guaranteed that the Server object is closed and not " @@ -2364,30 +2434,40 @@ msgstr "" "*Server* 物件是非同步情境管理器。當在 ``async with`` 陳述中使用時,可以保證在" "完成 ``async with`` 陳述時,Server 物件將會關閉並停止接受新的連線: ::" -#: ../../library/asyncio-eventloop.rst:1610 +#: ../../library/asyncio-eventloop.rst:1613 +msgid "" +"srv = await loop.create_server(...)\n" +"\n" +"async with srv:\n" +" # some code\n" +"\n" +"# At this point, srv is closed and no longer accepts new connections." +msgstr "" + +#: ../../library/asyncio-eventloop.rst:1621 msgid "Server object is an asynchronous context manager since Python 3.7." msgstr "自 Python 3.7 起,Server 物件是非同步情境管理器。" -#: ../../library/asyncio-eventloop.rst:1613 +#: ../../library/asyncio-eventloop.rst:1624 msgid "" "This class was exposed publicly as ``asyncio.Server`` in Python 3.9.11, " "3.10.3 and 3.11." msgstr "" "此類別在 Python 3.9.11、3.10.3 和 3.11 中以 ``asyncio.Server`` 的形式被公開。" -#: ../../library/asyncio-eventloop.rst:1618 +#: ../../library/asyncio-eventloop.rst:1629 msgid "" "Stop serving: close listening sockets and set the :attr:`sockets` attribute " "to ``None``." msgstr "停止服務:關閉監聽的 sockets 並將 :attr:`sockets` 屬性設為 ``None``。" -#: ../../library/asyncio-eventloop.rst:1621 +#: ../../library/asyncio-eventloop.rst:1632 msgid "" "The sockets that represent existing incoming client connections are left " "open." msgstr "代表現有傳入用戶端連線的 sockets 仍然保持開啟。" -#: ../../library/asyncio-eventloop.rst:1624 +#: ../../library/asyncio-eventloop.rst:1635 msgid "" "The server is closed asynchronously; use the :meth:`wait_closed` coroutine " "to wait until the server is closed (and no more connections are active)." @@ -2395,21 +2475,21 @@ msgstr "" "伺服器以非同步方式關閉;使用 :meth:`wait_close` 協程等待伺服器關閉(不再有活" "躍連線)。" -#: ../../library/asyncio-eventloop.rst:1630 +#: ../../library/asyncio-eventloop.rst:1641 msgid "Return the event loop associated with the server object." msgstr "回傳與伺服器物件關聯的事件迴圈。" -#: ../../library/asyncio-eventloop.rst:1636 +#: ../../library/asyncio-eventloop.rst:1647 msgid "Start accepting connections." msgstr "開始接受連線。" -#: ../../library/asyncio-eventloop.rst:1638 +#: ../../library/asyncio-eventloop.rst:1649 msgid "" "This method is idempotent, so it can be called when the server is already " "serving." msgstr "此方法是幂等的,因此可以在伺服器已經運行時呼叫。" -#: ../../library/asyncio-eventloop.rst:1641 +#: ../../library/asyncio-eventloop.rst:1652 msgid "" "The *start_serving* keyword-only parameter to :meth:`loop.create_server` " "and :meth:`asyncio.start_server` allows creating a Server object that is not " @@ -2422,14 +2502,14 @@ msgstr "" "種情況下,可以使用 ``Server.start_serving()`` 或 :meth:`Server." "serve_forever` 來使 Server 開始接受連線。" -#: ../../library/asyncio-eventloop.rst:1652 +#: ../../library/asyncio-eventloop.rst:1663 msgid "" "Start accepting connections until the coroutine is cancelled. Cancellation " "of ``serve_forever`` task causes the server to be closed." msgstr "" "開始接受連線,直到協程被取消。取消 ``serve_forever`` 任務會導致伺服器關閉。" -#: ../../library/asyncio-eventloop.rst:1656 +#: ../../library/asyncio-eventloop.rst:1667 msgid "" "This method can be called if the server is already accepting connections. " "Only one ``serve_forever`` task can exist per one *Server* object." @@ -2437,24 +2517,39 @@ msgstr "" "如果伺服器已經接受連線,則可以呼叫此方法。每個 *Server* 物件只能存在一個 " "``serve_forever`` 任務。" -#: ../../library/asyncio-eventloop.rst:1678 +#: ../../library/asyncio-eventloop.rst:1673 +msgid "" +"async def client_connected(reader, writer):\n" +" # Communicate with the client with\n" +" # reader/writer streams. For example:\n" +" await reader.readline()\n" +"\n" +"async def main(host, port):\n" +" srv = await asyncio.start_server(\n" +" client_connected, host, port)\n" +" await srv.serve_forever()\n" +"\n" +"asyncio.run(main('127.0.0.1', 0))" +msgstr "" + +#: ../../library/asyncio-eventloop.rst:1689 msgid "Return ``True`` if the server is accepting new connections." msgstr "如果伺服器正在接受新連線,則回傳 ``True``。" -#: ../../library/asyncio-eventloop.rst:1684 +#: ../../library/asyncio-eventloop.rst:1695 msgid "" "Wait until the :meth:`close` method completes and all active connections " "have finished." msgstr "等待 :meth:`close` 方法完成且所有活動連線都已結束。" -#: ../../library/asyncio-eventloop.rst:1689 +#: ../../library/asyncio-eventloop.rst:1700 msgid "" "List of socket-like objects, ``asyncio.trsock.TransportSocket``, which the " "server is listening on." msgstr "" "伺服器正在監聽的類似 socket 的物件串列,``asyncio.trsock.TransportSocket``。" -#: ../../library/asyncio-eventloop.rst:1692 +#: ../../library/asyncio-eventloop.rst:1703 msgid "" "Prior to Python 3.7 ``Server.sockets`` used to return an internal list of " "server sockets directly. In 3.7 a copy of that list is returned." @@ -2462,11 +2557,11 @@ msgstr "" "在 Python 3.7 之前,``Server.sockets`` 曾經直接回傳內部伺服器 sockets 的串" "列。在 3.7 中回傳了該串列的副本。" -#: ../../library/asyncio-eventloop.rst:1702 +#: ../../library/asyncio-eventloop.rst:1713 msgid "Event Loop Implementations" msgstr "事件迴圈實作" -#: ../../library/asyncio-eventloop.rst:1704 +#: ../../library/asyncio-eventloop.rst:1715 msgid "" "asyncio ships with two different event loop implementations: :class:" "`SelectorEventLoop` and :class:`ProactorEventLoop`." @@ -2474,7 +2569,7 @@ msgstr "" "asyncio 內附兩個不同的事件迴圈實作::class:`SelectorEventLoop` 和 :class:" "`ProactorEventLoop`。" -#: ../../library/asyncio-eventloop.rst:1707 +#: ../../library/asyncio-eventloop.rst:1718 msgid "" "By default asyncio is configured to use :class:`SelectorEventLoop` on Unix " "and :class:`ProactorEventLoop` on Windows." @@ -2482,11 +2577,11 @@ msgstr "" "預設情況下,asyncio 配置為在 Unix 上使用 :class:`SelectorEventLoop`,在 " "Windows 上使用 :class:`ProactorEventLoop`。" -#: ../../library/asyncio-eventloop.rst:1713 +#: ../../library/asyncio-eventloop.rst:1724 msgid "An event loop based on the :mod:`selectors` module." msgstr "基於 :mod:`selectors` 模組的事件迴圈。" -#: ../../library/asyncio-eventloop.rst:1715 +#: ../../library/asyncio-eventloop.rst:1726 msgid "" "Uses the most efficient *selector* available for the given platform. It is " "also possible to manually configure the exact selector implementation to be " @@ -2496,18 +2591,31 @@ msgstr "" "作: ::" #: ../../library/asyncio-eventloop.rst:1730 +msgid "" +"import asyncio\n" +"import selectors\n" +"\n" +"class MyPolicy(asyncio.DefaultEventLoopPolicy):\n" +" def new_event_loop(self):\n" +" selector = selectors.SelectSelector()\n" +" return asyncio.SelectorEventLoop(selector)\n" +"\n" +"asyncio.set_event_loop_policy(MyPolicy())" +msgstr "" + +#: ../../library/asyncio-eventloop.rst:1741 msgid ":ref:`Availability `: Unix, Windows." msgstr ":ref:`適用 `:Unix、Windows。" -#: ../../library/asyncio-eventloop.rst:1735 +#: ../../library/asyncio-eventloop.rst:1746 msgid "An event loop for Windows that uses \"I/O Completion Ports\" (IOCP)." msgstr "用於 Windows 的事件迴圈,使用\"I/O 完成埠\"(IOCP)。" -#: ../../library/asyncio-eventloop.rst:1737 +#: ../../library/asyncio-eventloop.rst:1748 msgid ":ref:`Availability `: Windows." msgstr ":ref:`適用 `:Windows。" -#: ../../library/asyncio-eventloop.rst:1741 +#: ../../library/asyncio-eventloop.rst:1752 msgid "" "`MSDN documentation on I/O Completion Ports `_." @@ -2515,11 +2623,11 @@ msgstr "" "`I/O 完成埠(I/O Completion Ports)的 MSDN 文件 `_。" -#: ../../library/asyncio-eventloop.rst:1747 +#: ../../library/asyncio-eventloop.rst:1758 msgid "Abstract base class for asyncio-compliant event loops." msgstr "為符合 asyncio 標準的事件迴圈的抽象基礎類別。" -#: ../../library/asyncio-eventloop.rst:1749 +#: ../../library/asyncio-eventloop.rst:1760 msgid "" "The :ref:`asyncio-event-loop-methods` section lists all methods that an " "alternative implementation of ``AbstractEventLoop`` should have defined." @@ -2527,11 +2635,11 @@ msgstr "" ":ref:`asyncio-event-loop-methods` 部分列出了替代 ``AbstractEventLoop`` 實作應" "該定義的所有方法。" -#: ../../library/asyncio-eventloop.rst:1755 +#: ../../library/asyncio-eventloop.rst:1766 msgid "Examples" msgstr "範例" -#: ../../library/asyncio-eventloop.rst:1757 +#: ../../library/asyncio-eventloop.rst:1768 msgid "" "Note that all examples in this section **purposefully** show how to use the " "low-level event loop APIs, such as :meth:`loop.run_forever` and :meth:`loop." @@ -2542,11 +2650,11 @@ msgstr "" "`loop.run_forever` 和 :meth:`loop.call_soon`。現代 asyncio 應用程式很少需要這" "種方式撰寫;請考慮使用高階的函式,如 :func:`asyncio.run`。" -#: ../../library/asyncio-eventloop.rst:1767 +#: ../../library/asyncio-eventloop.rst:1778 msgid "Hello World with call_soon()" msgstr "使用 call_soon() 的 Hello World 範例" -#: ../../library/asyncio-eventloop.rst:1769 +#: ../../library/asyncio-eventloop.rst:1780 msgid "" "An example using the :meth:`loop.call_soon` method to schedule a callback. " "The callback displays ``\"Hello World\"`` and then stops the event loop::" @@ -2554,18 +2662,39 @@ msgstr "" "使用 :meth:`loop.call_soon` 方法排程回呼的範例。回呼會顯示 ``\"Hello " "World\"``,然後停止事件迴圈: ::" -#: ../../library/asyncio-eventloop.rst:1793 +#: ../../library/asyncio-eventloop.rst:1784 +msgid "" +"import asyncio\n" +"\n" +"def hello_world(loop):\n" +" \"\"\"A callback to print 'Hello World' and stop the event loop\"\"\"\n" +" print('Hello World')\n" +" loop.stop()\n" +"\n" +"loop = asyncio.new_event_loop()\n" +"\n" +"# Schedule a call to hello_world()\n" +"loop.call_soon(hello_world, loop)\n" +"\n" +"# Blocking call interrupted by loop.stop()\n" +"try:\n" +" loop.run_forever()\n" +"finally:\n" +" loop.close()" +msgstr "" + +#: ../../library/asyncio-eventloop.rst:1804 msgid "" "A similar :ref:`Hello World ` example created with a coroutine " "and the :func:`run` function." msgstr "" "使用協程和 :func:`run` 函式建立的類似 :ref:`Hello World ` 範例。" -#: ../../library/asyncio-eventloop.rst:1800 +#: ../../library/asyncio-eventloop.rst:1811 msgid "Display the current date with call_later()" msgstr "使用 call_later() 顯示目前日期" -#: ../../library/asyncio-eventloop.rst:1802 +#: ../../library/asyncio-eventloop.rst:1813 msgid "" "An example of a callback displaying the current date every second. The " "callback uses the :meth:`loop.call_later` method to reschedule itself after " @@ -2574,7 +2703,32 @@ msgstr "" "一個回呼的範例,每秒顯示目前日期。回呼使用 :meth:`loop.call_later` 方法在 5 " "秒後重新排程自己,然後停止事件迴圈: ::" -#: ../../library/asyncio-eventloop.rst:1830 +#: ../../library/asyncio-eventloop.rst:1817 +msgid "" +"import asyncio\n" +"import datetime\n" +"\n" +"def display_date(end_time, loop):\n" +" print(datetime.datetime.now())\n" +" if (loop.time() + 1.0) < end_time:\n" +" loop.call_later(1, display_date, end_time, loop)\n" +" else:\n" +" loop.stop()\n" +"\n" +"loop = asyncio.new_event_loop()\n" +"\n" +"# Schedule the first call to display_date()\n" +"end_time = loop.time() + 5.0\n" +"loop.call_soon(display_date, end_time, loop)\n" +"\n" +"# Blocking call interrupted by loop.stop()\n" +"try:\n" +" loop.run_forever()\n" +"finally:\n" +" loop.close()" +msgstr "" + +#: ../../library/asyncio-eventloop.rst:1841 msgid "" "A similar :ref:`current date ` example created with a " "coroutine and the :func:`run` function." @@ -2582,11 +2736,11 @@ msgstr "" "使用協程和 :func:`run` 函式建立的類似 :ref:`current date " "` 範例。" -#: ../../library/asyncio-eventloop.rst:1837 +#: ../../library/asyncio-eventloop.rst:1848 msgid "Watch a file descriptor for read events" msgstr "監聽檔案描述器以進行讀取事件" -#: ../../library/asyncio-eventloop.rst:1839 +#: ../../library/asyncio-eventloop.rst:1850 msgid "" "Wait until a file descriptor received some data using the :meth:`loop." "add_reader` method and then close the event loop::" @@ -2594,7 +2748,43 @@ msgstr "" "使用 :meth:`loop.add_reader` 方法等待檔案描述器接收到某些資料,然後關閉事件迴" "圈: ::" -#: ../../library/asyncio-eventloop.rst:1877 +#: ../../library/asyncio-eventloop.rst:1853 +msgid "" +"import asyncio\n" +"from socket import socketpair\n" +"\n" +"# Create a pair of connected file descriptors\n" +"rsock, wsock = socketpair()\n" +"\n" +"loop = asyncio.new_event_loop()\n" +"\n" +"def reader():\n" +" data = rsock.recv(100)\n" +" print(\"Received:\", data.decode())\n" +"\n" +" # We are done: unregister the file descriptor\n" +" loop.remove_reader(rsock)\n" +"\n" +" # Stop the event loop\n" +" loop.stop()\n" +"\n" +"# Register the file descriptor for read event\n" +"loop.add_reader(rsock, reader)\n" +"\n" +"# Simulate the reception of data from the network\n" +"loop.call_soon(wsock.send, 'abc'.encode())\n" +"\n" +"try:\n" +" # Run the event loop\n" +" loop.run_forever()\n" +"finally:\n" +" # We are done. Close sockets and the event loop.\n" +" rsock.close()\n" +" wsock.close()\n" +" loop.close()" +msgstr "" + +#: ../../library/asyncio-eventloop.rst:1888 msgid "" "A similar :ref:`example ` using " "transports, protocols, and the :meth:`loop.create_connection` method." @@ -2602,7 +2792,7 @@ msgstr "" "使用傳輸、協定和 :meth:`loop.create_connection` 方法的類似 :ref:`範例 " "`。" -#: ../../library/asyncio-eventloop.rst:1881 +#: ../../library/asyncio-eventloop.rst:1892 msgid "" "Another similar :ref:`example ` " "using the high-level :func:`asyncio.open_connection` function and streams." @@ -2610,18 +2800,52 @@ msgstr "" "另一個使用高階 :func:`asyncio.open_connection` 函式和串流的類似 :ref:`範例 " "`。" -#: ../../library/asyncio-eventloop.rst:1889 +#: ../../library/asyncio-eventloop.rst:1900 msgid "Set signal handlers for SIGINT and SIGTERM" msgstr "設定 SIGINT 和 SIGTERM 的訊號處理程式" -#: ../../library/asyncio-eventloop.rst:1891 +#: ../../library/asyncio-eventloop.rst:1902 msgid "(This ``signals`` example only works on Unix.)" msgstr "(此 ``signals`` 範例僅在 Unix 上運作。)" -#: ../../library/asyncio-eventloop.rst:1893 +#: ../../library/asyncio-eventloop.rst:1904 msgid "" "Register handlers for signals :const:`~signal.SIGINT` and :const:`~signal." "SIGTERM` using the :meth:`loop.add_signal_handler` method::" msgstr "" "使用 :meth:`loop.add_signal_handler` 方法註冊訊號 :py:data:`SIGINT` 和 :py:" "data:`SIGTERM` 的處理程式: ::" + +#: ../../library/asyncio-eventloop.rst:1907 +msgid "" +"import asyncio\n" +"import functools\n" +"import os\n" +"import signal\n" +"\n" +"def ask_exit(signame, loop):\n" +" print(\"got signal %s: exit\" % signame)\n" +" loop.stop()\n" +"\n" +"async def main():\n" +" loop = asyncio.get_running_loop()\n" +"\n" +" for signame in {'SIGINT', 'SIGTERM'}:\n" +" loop.add_signal_handler(\n" +" getattr(signal, signame),\n" +" functools.partial(ask_exit, signame, loop))\n" +"\n" +" await asyncio.sleep(3600)\n" +"\n" +"print(\"Event loop running for 1 hour, press Ctrl+C to interrupt.\")\n" +"print(f\"pid {os.getpid()}: send SIGINT or SIGTERM to exit.\")\n" +"\n" +"asyncio.run(main())" +msgstr "" + +#~ msgid "" +#~ "The *executor* argument should be an :class:`concurrent.futures.Executor` " +#~ "instance. The default executor is used if *executor* is ``None``." +#~ msgstr "" +#~ "*executor* 引數應該是 :class:`concurrent.futures.Executor` 實例。如果 " +#~ "*executor* 為 ``None``,則使用預設執行器。" diff --git a/library/asyncio-platforms.po b/library/asyncio-platforms.po index f501b2bf97..6663d56256 100644 --- a/library/asyncio-platforms.po +++ b/library/asyncio-platforms.po @@ -10,7 +10,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-07-22 00:04+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2022-01-17 11:37+0800\n" "Last-Translator: Matt Wang \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -188,3 +188,13 @@ msgstr "" "設置 :class:`SelectorEventLoop` 來使用 :class:`~selectors.SelectSelector` " "或 :class:`~selectors.PollSelector` 以在這些舊版 macOS 上支援字元裝置。例" "如: ::" + +#: ../../library/asyncio-platforms.rst:100 +msgid "" +"import asyncio\n" +"import selectors\n" +"\n" +"selector = selectors.SelectSelector()\n" +"loop = asyncio.SelectorEventLoop(selector)\n" +"asyncio.set_event_loop(loop)" +msgstr "" diff --git a/library/asyncio-policy.po b/library/asyncio-policy.po index e1847c9ed4..bd297aae3e 100644 --- a/library/asyncio-policy.po +++ b/library/asyncio-policy.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-01-11 00:04+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -385,3 +385,19 @@ msgid "" "`DefaultEventLoopPolicy` and override the methods for which custom behavior " "is wanted, e.g.::" msgstr "" + +#: ../../library/asyncio-policy.rst:317 +msgid "" +"class MyEventLoopPolicy(asyncio.DefaultEventLoopPolicy):\n" +"\n" +" def get_event_loop(self):\n" +" \"\"\"Get the event loop.\n" +"\n" +" This may be None or an instance of EventLoop.\n" +" \"\"\"\n" +" loop = super().get_event_loop()\n" +" # Do something with loop ...\n" +" return loop\n" +"\n" +"asyncio.set_event_loop_policy(MyEventLoopPolicy())" +msgstr "" diff --git a/library/asyncio-protocol.po b/library/asyncio-protocol.po index ab5b077f76..cbe162fcad 100644 --- a/library/asyncio-protocol.po +++ b/library/asyncio-protocol.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-13 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2018-05-23 14:39+0000\n" "Last-Translator: Adrian Liaw \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -261,6 +261,13 @@ msgid "" "of the transport::" msgstr "" +#: ../../library/asyncio-protocol.rst:182 +msgid "" +"sock = transport.get_extra_info('socket')\n" +"if sock is not None:\n" +" print(sock.getsockopt(...))" +msgstr "" + #: ../../library/asyncio-protocol.rst:186 msgid "Categories of information that can be queried on some transports:" msgstr "" @@ -784,6 +791,14 @@ msgstr "" msgid "State machine:" msgstr "" +#: ../../library/asyncio-protocol.rst:580 +msgid "" +"start -> connection_made\n" +" [-> data_received]*\n" +" [-> eof_received]?\n" +"-> connection_lost -> end" +msgstr "" + #: ../../library/asyncio-protocol.rst:589 msgid "Buffered Streaming Protocols" msgstr "" @@ -850,6 +865,16 @@ msgid "" "won't be called after it." msgstr "" +#: ../../library/asyncio-protocol.rst:638 +msgid "" +"start -> connection_made\n" +" [-> get_buffer\n" +" [-> buffer_updated]?\n" +" ]*\n" +" [-> eof_received]?\n" +"-> connection_lost -> end" +msgstr "" + #: ../../library/asyncio-protocol.rst:649 msgid "Datagram Protocols" msgstr "" @@ -952,6 +977,44 @@ msgid "" "back received data, and close the connection::" msgstr "" +#: ../../library/asyncio-protocol.rst:726 +msgid "" +"import asyncio\n" +"\n" +"\n" +"class EchoServerProtocol(asyncio.Protocol):\n" +" def connection_made(self, transport):\n" +" peername = transport.get_extra_info('peername')\n" +" print('Connection from {}'.format(peername))\n" +" self.transport = transport\n" +"\n" +" def data_received(self, data):\n" +" message = data.decode()\n" +" print('Data received: {!r}'.format(message))\n" +"\n" +" print('Send: {!r}'.format(message))\n" +" self.transport.write(data)\n" +"\n" +" print('Close the client socket')\n" +" self.transport.close()\n" +"\n" +"\n" +"async def main():\n" +" # Get a reference to the event loop as we plan to use\n" +" # low-level APIs.\n" +" loop = asyncio.get_running_loop()\n" +"\n" +" server = await loop.create_server(\n" +" lambda: EchoServerProtocol(),\n" +" '127.0.0.1', 8888)\n" +"\n" +" async with server:\n" +" await server.serve_forever()\n" +"\n" +"\n" +"asyncio.run(main())" +msgstr "" + #: ../../library/asyncio-protocol.rst:764 msgid "" "The :ref:`TCP echo server using streams ` " @@ -968,6 +1031,51 @@ msgid "" "data, and waits until the connection is closed::" msgstr "" +#: ../../library/asyncio-protocol.rst:775 +msgid "" +"import asyncio\n" +"\n" +"\n" +"class EchoClientProtocol(asyncio.Protocol):\n" +" def __init__(self, message, on_con_lost):\n" +" self.message = message\n" +" self.on_con_lost = on_con_lost\n" +"\n" +" def connection_made(self, transport):\n" +" transport.write(self.message.encode())\n" +" print('Data sent: {!r}'.format(self.message))\n" +"\n" +" def data_received(self, data):\n" +" print('Data received: {!r}'.format(data.decode()))\n" +"\n" +" def connection_lost(self, exc):\n" +" print('The server closed the connection')\n" +" self.on_con_lost.set_result(True)\n" +"\n" +"\n" +"async def main():\n" +" # Get a reference to the event loop as we plan to use\n" +" # low-level APIs.\n" +" loop = asyncio.get_running_loop()\n" +"\n" +" on_con_lost = loop.create_future()\n" +" message = 'Hello World!'\n" +"\n" +" transport, protocol = await loop.create_connection(\n" +" lambda: EchoClientProtocol(message, on_con_lost),\n" +" '127.0.0.1', 8888)\n" +"\n" +" # Wait until the protocol signals that the connection\n" +" # is lost and close the transport.\n" +" try:\n" +" await on_con_lost\n" +" finally:\n" +" transport.close()\n" +"\n" +"\n" +"asyncio.run(main())" +msgstr "" + #: ../../library/asyncio-protocol.rst:820 msgid "" "The :ref:`TCP echo client using streams ` " @@ -984,6 +1092,44 @@ msgid "" "sends back received data::" msgstr "" +#: ../../library/asyncio-protocol.rst:832 +msgid "" +"import asyncio\n" +"\n" +"\n" +"class EchoServerProtocol:\n" +" def connection_made(self, transport):\n" +" self.transport = transport\n" +"\n" +" def datagram_received(self, data, addr):\n" +" message = data.decode()\n" +" print('Received %r from %s' % (message, addr))\n" +" print('Send %r to %s' % (message, addr))\n" +" self.transport.sendto(data, addr)\n" +"\n" +"\n" +"async def main():\n" +" print(\"Starting UDP server\")\n" +"\n" +" # Get a reference to the event loop as we plan to use\n" +" # low-level APIs.\n" +" loop = asyncio.get_running_loop()\n" +"\n" +" # One protocol instance will be created to serve all\n" +" # client requests.\n" +" transport, protocol = await loop.create_datagram_endpoint(\n" +" lambda: EchoServerProtocol(),\n" +" local_addr=('127.0.0.1', 9999))\n" +"\n" +" try:\n" +" await asyncio.sleep(3600) # Serve for 1 hour.\n" +" finally:\n" +" transport.close()\n" +"\n" +"\n" +"asyncio.run(main())" +msgstr "" + #: ../../library/asyncio-protocol.rst:871 msgid "UDP Echo Client" msgstr "" @@ -994,6 +1140,57 @@ msgid "" "sends data and closes the transport when it receives the answer::" msgstr "" +#: ../../library/asyncio-protocol.rst:876 +msgid "" +"import asyncio\n" +"\n" +"\n" +"class EchoClientProtocol:\n" +" def __init__(self, message, on_con_lost):\n" +" self.message = message\n" +" self.on_con_lost = on_con_lost\n" +" self.transport = None\n" +"\n" +" def connection_made(self, transport):\n" +" self.transport = transport\n" +" print('Send:', self.message)\n" +" self.transport.sendto(self.message.encode())\n" +"\n" +" def datagram_received(self, data, addr):\n" +" print(\"Received:\", data.decode())\n" +"\n" +" print(\"Close the socket\")\n" +" self.transport.close()\n" +"\n" +" def error_received(self, exc):\n" +" print('Error received:', exc)\n" +"\n" +" def connection_lost(self, exc):\n" +" print(\"Connection closed\")\n" +" self.on_con_lost.set_result(True)\n" +"\n" +"\n" +"async def main():\n" +" # Get a reference to the event loop as we plan to use\n" +" # low-level APIs.\n" +" loop = asyncio.get_running_loop()\n" +"\n" +" on_con_lost = loop.create_future()\n" +" message = \"Hello World!\"\n" +"\n" +" transport, protocol = await loop.create_datagram_endpoint(\n" +" lambda: EchoClientProtocol(message, on_con_lost),\n" +" remote_addr=('127.0.0.1', 9999))\n" +"\n" +" try:\n" +" await on_con_lost\n" +" finally:\n" +" transport.close()\n" +"\n" +"\n" +"asyncio.run(main())" +msgstr "" + #: ../../library/asyncio-protocol.rst:928 msgid "Connecting Existing Sockets" msgstr "" @@ -1004,6 +1201,58 @@ msgid "" "method with a protocol::" msgstr "" +#: ../../library/asyncio-protocol.rst:933 +msgid "" +"import asyncio\n" +"import socket\n" +"\n" +"\n" +"class MyProtocol(asyncio.Protocol):\n" +"\n" +" def __init__(self, on_con_lost):\n" +" self.transport = None\n" +" self.on_con_lost = on_con_lost\n" +"\n" +" def connection_made(self, transport):\n" +" self.transport = transport\n" +"\n" +" def data_received(self, data):\n" +" print(\"Received:\", data.decode())\n" +"\n" +" # We are done: close the transport;\n" +" # connection_lost() will be called automatically.\n" +" self.transport.close()\n" +"\n" +" def connection_lost(self, exc):\n" +" # The socket has been closed\n" +" self.on_con_lost.set_result(True)\n" +"\n" +"\n" +"async def main():\n" +" # Get a reference to the event loop as we plan to use\n" +" # low-level APIs.\n" +" loop = asyncio.get_running_loop()\n" +" on_con_lost = loop.create_future()\n" +"\n" +" # Create a pair of connected sockets\n" +" rsock, wsock = socket.socketpair()\n" +"\n" +" # Register the socket to wait for data.\n" +" transport, protocol = await loop.create_connection(\n" +" lambda: MyProtocol(on_con_lost), sock=rsock)\n" +"\n" +" # Simulate the reception of data from the network.\n" +" loop.call_soon(wsock.send, 'abc'.encode())\n" +"\n" +" try:\n" +" await protocol.on_con_lost\n" +" finally:\n" +" transport.close()\n" +" wsock.close()\n" +"\n" +"asyncio.run(main())" +msgstr "" + #: ../../library/asyncio-protocol.rst:984 msgid "" "The :ref:`watch a file descriptor for read events " @@ -1032,6 +1281,67 @@ msgstr "" msgid "The subprocess is created by the :meth:`loop.subprocess_exec` method::" msgstr "" +#: ../../library/asyncio-protocol.rst:1002 +msgid "" +"import asyncio\n" +"import sys\n" +"\n" +"class DateProtocol(asyncio.SubprocessProtocol):\n" +" def __init__(self, exit_future):\n" +" self.exit_future = exit_future\n" +" self.output = bytearray()\n" +" self.pipe_closed = False\n" +" self.exited = False\n" +"\n" +" def pipe_connection_lost(self, fd, exc):\n" +" self.pipe_closed = True\n" +" self.check_for_exit()\n" +"\n" +" def pipe_data_received(self, fd, data):\n" +" self.output.extend(data)\n" +"\n" +" def process_exited(self):\n" +" self.exited = True\n" +" # process_exited() method can be called before\n" +" # pipe_connection_lost() method: wait until both methods are\n" +" # called.\n" +" self.check_for_exit()\n" +"\n" +" def check_for_exit(self):\n" +" if self.pipe_closed and self.exited:\n" +" self.exit_future.set_result(True)\n" +"\n" +"async def get_date():\n" +" # Get a reference to the event loop as we plan to use\n" +" # low-level APIs.\n" +" loop = asyncio.get_running_loop()\n" +"\n" +" code = 'import datetime; print(datetime.datetime.now())'\n" +" exit_future = asyncio.Future(loop=loop)\n" +"\n" +" # Create the subprocess controlled by DateProtocol;\n" +" # redirect the standard output into a pipe.\n" +" transport, protocol = await loop.subprocess_exec(\n" +" lambda: DateProtocol(exit_future),\n" +" sys.executable, '-c', code,\n" +" stdin=None, stderr=None)\n" +"\n" +" # Wait for the subprocess exit using the process_exited()\n" +" # method of the protocol.\n" +" await exit_future\n" +"\n" +" # Close the stdout pipe.\n" +" transport.close()\n" +"\n" +" # Read the output which was collected by the\n" +" # pipe_data_received() method of the protocol.\n" +" data = bytes(protocol.output)\n" +" return data.decode('ascii').rstrip()\n" +"\n" +"date = asyncio.run(get_date())\n" +"print(f\"Current date: {date}\")" +msgstr "" + #: ../../library/asyncio-protocol.rst:1060 msgid "" "See also the :ref:`same example ` " diff --git a/library/asyncio-runner.po b/library/asyncio-runner.po index 80ebb00865..f77d368b39 100644 --- a/library/asyncio-runner.po +++ b/library/asyncio-runner.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-08-30 18:24+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -94,6 +94,15 @@ msgstr "" msgid "Example::" msgstr "範例: ::" +#: ../../library/asyncio-runner.rst:52 +msgid "" +"async def main():\n" +" await asyncio.sleep(1)\n" +" print('hello')\n" +"\n" +"asyncio.run(main())" +msgstr "" + #: ../../library/asyncio-runner.rst:60 msgid "Updated to use :meth:`loop.shutdown_default_executor`." msgstr "" @@ -137,6 +146,16 @@ msgid "" "usage::" msgstr "" +#: ../../library/asyncio-runner.rst:94 +msgid "" +"async def main():\n" +" await asyncio.sleep(1)\n" +" print('hello')\n" +"\n" +"with asyncio.Runner() as runner:\n" +" runner.run(main())" +msgstr "" + #: ../../library/asyncio-runner.rst:105 msgid "Run a :term:`coroutine ` *coro* in the embedded loop." msgstr "" diff --git a/library/asyncio-stream.po b/library/asyncio-stream.po index 2ee50e7d8c..677c05150a 100644 --- a/library/asyncio-stream.po +++ b/library/asyncio-stream.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-01-24 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2022-10-31 16:28+0800\n" "Last-Translator: Matt Wang \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -42,6 +42,28 @@ msgstr "" msgid "Here is an example of a TCP echo client written using asyncio streams::" msgstr "這是一個使用 asyncio 串流編寫的 TCP echo 客戶端範例: ::" +#: ../../library/asyncio-stream.rst:22 ../../library/asyncio-stream.rst:404 +msgid "" +"import asyncio\n" +"\n" +"async def tcp_echo_client(message):\n" +" reader, writer = await asyncio.open_connection(\n" +" '127.0.0.1', 8888)\n" +"\n" +" print(f'Send: {message!r}')\n" +" writer.write(message.encode())\n" +" await writer.drain()\n" +"\n" +" data = await reader.read(100)\n" +" print(f'Received: {data.decode()!r}')\n" +"\n" +" print('Close the connection')\n" +" writer.close()\n" +" await writer.wait_closed()\n" +"\n" +"asyncio.run(tcp_echo_client('Hello World!'))" +msgstr "" + #: ../../library/asyncio-stream.rst:42 msgid "See also the `Examples`_ section below." msgstr "另請參閱下方 `Examples`_ 段落。" @@ -346,6 +368,12 @@ msgstr "" msgid "The method should be used along with the ``drain()`` method::" msgstr "此方法應當與 ``drain()`` 方法一起使用: ::" +#: ../../library/asyncio-stream.rst:291 +msgid "" +"stream.write(data)\n" +"await stream.drain()" +msgstr "" + #: ../../library/asyncio-stream.rst:296 msgid "" "The method writes a list (or any iterable) of bytes to the underlying socket " @@ -355,6 +383,12 @@ msgstr "" "此方法會立即嘗試將一個位元組 list(或任何可疊代物件 (iterable))寫入到底層的 " "socket。如果失敗,資料會被放到內部寫入緩衝中排隊等待,直到它可被發送。" +#: ../../library/asyncio-stream.rst:303 +msgid "" +"stream.writelines(lines)\n" +"await stream.drain()" +msgstr "" + #: ../../library/asyncio-stream.rst:308 msgid "The method closes the stream and the underlying socket." msgstr "此方法會關閉串流以及底層的 socket。" @@ -365,6 +399,12 @@ msgid "" "``wait_closed()`` method::" msgstr "此方法應與 ``wait_closed()`` 方法一起使用,但並非強制: ::" +#: ../../library/asyncio-stream.rst:313 +msgid "" +"stream.close()\n" +"await stream.wait_closed()" +msgstr "" + #: ../../library/asyncio-stream.rst:318 msgid "" "Return ``True`` if the underlying transport supports the :meth:`write_eof` " @@ -392,6 +432,12 @@ msgstr "存取可選的傳輸資訊;詳情請見 :meth:`BaseTransport.get_extr msgid "Wait until it is appropriate to resume writing to the stream. Example::" msgstr "等待直到可以繼續寫入到串流。範例: ::" +#: ../../library/asyncio-stream.rst:340 +msgid "" +"writer.write(data)\n" +"await writer.drain()" +msgstr "" + #: ../../library/asyncio-stream.rst:343 msgid "" "This is a flow control method that interacts with the underlying IO write " @@ -483,6 +529,38 @@ msgstr "使用串流的 TCP echo 伺服器" msgid "TCP echo server using the :func:`asyncio.start_server` function::" msgstr "TCP echo 伺服器使用 :func:`asyncio.start_server` 函式: ::" +#: ../../library/asyncio-stream.rst:437 +msgid "" +"import asyncio\n" +"\n" +"async def handle_echo(reader, writer):\n" +" data = await reader.read(100)\n" +" message = data.decode()\n" +" addr = writer.get_extra_info('peername')\n" +"\n" +" print(f\"Received {message!r} from {addr!r}\")\n" +"\n" +" print(f\"Send: {message!r}\")\n" +" writer.write(data)\n" +" await writer.drain()\n" +"\n" +" print(\"Close the connection\")\n" +" writer.close()\n" +" await writer.wait_closed()\n" +"\n" +"async def main():\n" +" server = await asyncio.start_server(\n" +" handle_echo, '127.0.0.1', 8888)\n" +"\n" +" addrs = ', '.join(str(sock.getsockname()) for sock in server.sockets)\n" +" print(f'Serving on {addrs}')\n" +"\n" +" async with server:\n" +" await server.serve_forever()\n" +"\n" +"asyncio.run(main())" +msgstr "" + #: ../../library/asyncio-stream.rst:469 msgid "" "The :ref:`TCP echo server protocol " @@ -501,14 +579,61 @@ msgid "" "Simple example querying HTTP headers of the URL passed on the command line::" msgstr "查詢自命令列傳入之 URL 所帶有 HTTP 標頭的簡單範例: ::" +#: ../../library/asyncio-stream.rst:478 +msgid "" +"import asyncio\n" +"import urllib.parse\n" +"import sys\n" +"\n" +"async def print_http_headers(url):\n" +" url = urllib.parse.urlsplit(url)\n" +" if url.scheme == 'https':\n" +" reader, writer = await asyncio.open_connection(\n" +" url.hostname, 443, ssl=True)\n" +" else:\n" +" reader, writer = await asyncio.open_connection(\n" +" url.hostname, 80)\n" +"\n" +" query = (\n" +" f\"HEAD {url.path or '/'} HTTP/1.0\\r\\n\"\n" +" f\"Host: {url.hostname}\\r\\n\"\n" +" f\"\\r\\n\"\n" +" )\n" +"\n" +" writer.write(query.encode('latin-1'))\n" +" while True:\n" +" line = await reader.readline()\n" +" if not line:\n" +" break\n" +"\n" +" line = line.decode('latin1').rstrip()\n" +" if line:\n" +" print(f'HTTP header> {line}')\n" +"\n" +" # Ignore the body, close the socket\n" +" writer.close()\n" +" await writer.wait_closed()\n" +"\n" +"url = sys.argv[1]\n" +"asyncio.run(print_http_headers(url))" +msgstr "" + #: ../../library/asyncio-stream.rst:515 msgid "Usage::" msgstr "用法: ::" +#: ../../library/asyncio-stream.rst:517 +msgid "python example.py http://example.com/path/page.html" +msgstr "" + #: ../../library/asyncio-stream.rst:519 msgid "or with HTTPS::" msgstr "或使用 HTTPS: ::" +#: ../../library/asyncio-stream.rst:521 +msgid "python example.py https://example.com/path/page.html" +msgstr "" + #: ../../library/asyncio-stream.rst:527 msgid "Register an open socket to wait for data using streams" msgstr "註冊一個使用串流來等待資料的開放 socket" @@ -520,6 +645,39 @@ msgid "" msgstr "" "等待直到 socket 透過使用 :func:`open_connection` 函式接收到資料的協程: ::" +#: ../../library/asyncio-stream.rst:532 +msgid "" +"import asyncio\n" +"import socket\n" +"\n" +"async def wait_for_data():\n" +" # Get a reference to the current event loop because\n" +" # we want to access low-level APIs.\n" +" loop = asyncio.get_running_loop()\n" +"\n" +" # Create a pair of connected sockets.\n" +" rsock, wsock = socket.socketpair()\n" +"\n" +" # Register the open socket to wait for data.\n" +" reader, writer = await asyncio.open_connection(sock=rsock)\n" +"\n" +" # Simulate the reception of data from the network\n" +" loop.call_soon(wsock.send, 'abc'.encode())\n" +"\n" +" # Wait for data\n" +" data = await reader.read(100)\n" +"\n" +" # Got data, we are done: close the socket\n" +" print(\"Received:\", data.decode())\n" +" writer.close()\n" +" await writer.wait_closed()\n" +"\n" +" # Close the second socket\n" +" wsock.close()\n" +"\n" +"asyncio.run(wait_for_data())" +msgstr "" + #: ../../library/asyncio-stream.rst:564 msgid "" "The :ref:`register an open socket to wait for data using a protocol " diff --git a/library/asyncio-subprocess.po b/library/asyncio-subprocess.po index c6edc40a89..3570d604ed 100644 --- a/library/asyncio-subprocess.po +++ b/library/asyncio-subprocess.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-13 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2018-05-23 14:39+0000\n" "Last-Translator: Adrian Liaw \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -43,10 +43,38 @@ msgid "" "result::" msgstr "" +#: ../../library/asyncio-subprocess.rst:22 +msgid "" +"import asyncio\n" +"\n" +"async def run(cmd):\n" +" proc = await asyncio.create_subprocess_shell(\n" +" cmd,\n" +" stdout=asyncio.subprocess.PIPE,\n" +" stderr=asyncio.subprocess.PIPE)\n" +"\n" +" stdout, stderr = await proc.communicate()\n" +"\n" +" print(f'[{cmd!r} exited with {proc.returncode}]')\n" +" if stdout:\n" +" print(f'[stdout]\\n{stdout.decode()}')\n" +" if stderr:\n" +" print(f'[stderr]\\n{stderr.decode()}')\n" +"\n" +"asyncio.run(run('ls /zzz'))" +msgstr "" + #: ../../library/asyncio-subprocess.rst:40 msgid "will print::" msgstr "" +#: ../../library/asyncio-subprocess.rst:42 +msgid "" +"['ls /zzz' exited with 1]\n" +"[stderr]\n" +"ls: /zzz: No such file or directory" +msgstr "" + #: ../../library/asyncio-subprocess.rst:46 msgid "" "Because all asyncio subprocess functions are asynchronous and asyncio " @@ -55,6 +83,16 @@ msgid "" "the above example to run several commands simultaneously::" msgstr "" +#: ../../library/asyncio-subprocess.rst:51 +msgid "" +"async def main():\n" +" await asyncio.gather(\n" +" run('ls /zzz'),\n" +" run('sleep 1; echo \"hello\"'))\n" +"\n" +"asyncio.run(main())" +msgstr "" + #: ../../library/asyncio-subprocess.rst:58 msgid "See also the `Examples`_ subsection." msgstr "另請參閱\\ `Examples`_。" @@ -443,6 +481,32 @@ msgid "" "The subprocess is created by the :func:`create_subprocess_exec` function::" msgstr "" +#: ../../library/asyncio-subprocess.rst:352 +msgid "" +"import asyncio\n" +"import sys\n" +"\n" +"async def get_date():\n" +" code = 'import datetime; print(datetime.datetime.now())'\n" +"\n" +" # Create the subprocess; redirect the standard output\n" +" # into a pipe.\n" +" proc = await asyncio.create_subprocess_exec(\n" +" sys.executable, '-c', code,\n" +" stdout=asyncio.subprocess.PIPE)\n" +"\n" +" # Read one line of output.\n" +" data = await proc.stdout.readline()\n" +" line = data.decode('ascii').rstrip()\n" +"\n" +" # Wait for the subprocess exit.\n" +" await proc.wait()\n" +" return line\n" +"\n" +"date = asyncio.run(get_date())\n" +"print(f\"Current date: {date}\")" +msgstr "" + #: ../../library/asyncio-subprocess.rst:376 msgid "" "See also the :ref:`same example ` written " diff --git a/library/asyncio-sync.po b/library/asyncio-sync.po index 1aafed5bf7..ef094386b7 100644 --- a/library/asyncio-sync.po +++ b/library/asyncio-sync.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-10-15 20:43+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2022-02-09 19:27+0800\n" "Last-Translator: Adrian Liaw \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -99,11 +99,32 @@ msgstr "一個 asyncio 的鎖可以用來確保一個共享資源的存取權被 msgid "The preferred way to use a Lock is an :keyword:`async with` statement::" msgstr "使用 Lock 的推薦方式是透過 :keyword:`async with` 陳述式: ::" +#: ../../library/asyncio-sync.rst:50 +msgid "" +"lock = asyncio.Lock()\n" +"\n" +"# ... later\n" +"async with lock:\n" +" # access shared state" +msgstr "" + #: ../../library/asyncio-sync.rst:56 ../../library/asyncio-sync.rst:199 #: ../../library/asyncio-sync.rst:298 msgid "which is equivalent to::" msgstr "這等價於: ::" +#: ../../library/asyncio-sync.rst:58 +msgid "" +"lock = asyncio.Lock()\n" +"\n" +"# ... later\n" +"await lock.acquire()\n" +"try:\n" +" # access shared state\n" +"finally:\n" +" lock.release()" +msgstr "" + #: ../../library/asyncio-sync.rst:67 ../../library/asyncio-sync.rst:112 #: ../../library/asyncio-sync.rst:187 ../../library/asyncio-sync.rst:286 #: ../../library/asyncio-sync.rst:341 @@ -184,6 +205,30 @@ msgstr "" msgid "Example::" msgstr "範例: ::" +#: ../../library/asyncio-sync.rst:119 +msgid "" +"async def waiter(event):\n" +" print('waiting for it ...')\n" +" await event.wait()\n" +" print('... got it!')\n" +"\n" +"async def main():\n" +" # Create an Event object.\n" +" event = asyncio.Event()\n" +"\n" +" # Spawn a Task to wait until 'event' is set.\n" +" waiter_task = asyncio.create_task(waiter(event))\n" +"\n" +" # Sleep for 1 second and set the event.\n" +" await asyncio.sleep(1)\n" +" event.set()\n" +"\n" +" # Wait until the waiter task is finished.\n" +" await waiter_task\n" +"\n" +"asyncio.run(main())" +msgstr "" + #: ../../library/asyncio-sync.rst:142 msgid "Wait until the event is set." msgstr "持續等待直到事件被設置。" @@ -261,6 +306,27 @@ msgid "" "The preferred way to use a Condition is an :keyword:`async with` statement::" msgstr "使用 Condition 的推薦方式是透過 :keyword:`async with` 陳述式: ::" +#: ../../library/asyncio-sync.rst:193 +msgid "" +"cond = asyncio.Condition()\n" +"\n" +"# ... later\n" +"async with cond:\n" +" await cond.wait()" +msgstr "" + +#: ../../library/asyncio-sync.rst:201 +msgid "" +"cond = asyncio.Condition()\n" +"\n" +"# ... later\n" +"await cond.acquire()\n" +"try:\n" +" await cond.wait()\n" +"finally:\n" +" cond.release()" +msgstr "" + #: ../../library/asyncio-sync.rst:212 msgid "Acquire the underlying lock." msgstr "獲取底層的鎖。" @@ -377,6 +443,27 @@ msgid "" "The preferred way to use a Semaphore is an :keyword:`async with` statement::" msgstr "使用 Semaphore 的推薦方式是透過 :keyword:`async with` 陳述式: ::" +#: ../../library/asyncio-sync.rst:292 +msgid "" +"sem = asyncio.Semaphore(10)\n" +"\n" +"# ... later\n" +"async with sem:\n" +" # work with shared resource" +msgstr "" + +#: ../../library/asyncio-sync.rst:300 +msgid "" +"sem = asyncio.Semaphore(10)\n" +"\n" +"# ... later\n" +"await sem.acquire()\n" +"try:\n" +" # work with shared resource\n" +"finally:\n" +" sem.release()" +msgstr "" + #: ../../library/asyncio-sync.rst:311 msgid "Acquire a semaphore." msgstr "獲取一個旗號。" @@ -455,10 +542,42 @@ msgstr "" msgid "The barrier can be reused any number of times." msgstr "" +#: ../../library/asyncio-sync.rst:367 +msgid "" +"async def example_barrier():\n" +" # barrier with 3 parties\n" +" b = asyncio.Barrier(3)\n" +"\n" +" # create 2 new waiting tasks\n" +" asyncio.create_task(b.wait())\n" +" asyncio.create_task(b.wait())\n" +"\n" +" await asyncio.sleep(0)\n" +" print(b)\n" +"\n" +" # The third .wait() call passes the barrier\n" +" await b.wait()\n" +" print(b)\n" +" print(\"barrier passed\")\n" +"\n" +" await asyncio.sleep(0)\n" +" print(b)\n" +"\n" +"asyncio.run(example_barrier())" +msgstr "" + #: ../../library/asyncio-sync.rst:388 msgid "Result of this example is::" msgstr "" +#: ../../library/asyncio-sync.rst:390 +msgid "" +"\n" +"\n" +"barrier passed\n" +"" +msgstr "" + #: ../../library/asyncio-sync.rst:399 msgid "" "Pass the barrier. When all the tasks party to the barrier have called this " @@ -479,6 +598,15 @@ msgid "" "housekeeping, e.g.::" msgstr "" +#: ../../library/asyncio-sync.rst:411 +msgid "" +"...\n" +"async with barrier as position:\n" +" if position == 0:\n" +" # Only one task prints this\n" +" print('End of *draining phase*')" +msgstr "" + #: ../../library/asyncio-sync.rst:417 msgid "" "This method may raise a :class:`BrokenBarrierError` exception if the barrier " diff --git a/library/asyncio-task.po b/library/asyncio-task.po index f6b59716e5..8f85387645 100644 --- a/library/asyncio-task.po +++ b/library/asyncio-task.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-07-23 00:04+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2018-05-23 14:39+0000\n" "Last-Translator: Adrian Liaw \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -42,11 +42,31 @@ msgid "" "snippet of code prints \"hello\", waits 1 second, and then prints \"world\"::" msgstr "" +#: ../../library/asyncio-task.rst:30 +msgid "" +">>> import asyncio\n" +"\n" +">>> async def main():\n" +"... print('hello')\n" +"... await asyncio.sleep(1)\n" +"... print('world')\n" +"\n" +">>> asyncio.run(main())\n" +"hello\n" +"world" +msgstr "" + #: ../../library/asyncio-task.rst:41 msgid "" "Note that simply calling a coroutine will not schedule it to be executed::" msgstr "" +#: ../../library/asyncio-task.rst:44 +msgid "" +">>> main()\n" +"" +msgstr "" + #: ../../library/asyncio-task.rst:47 msgid "To actually run a coroutine, asyncio provides the following mechanisms:" msgstr "" @@ -64,10 +84,38 @@ msgid "" "*another* 2 seconds::" msgstr "" +#: ../../library/asyncio-task.rst:56 +msgid "" +"import asyncio\n" +"import time\n" +"\n" +"async def say_after(delay, what):\n" +" await asyncio.sleep(delay)\n" +" print(what)\n" +"\n" +"async def main():\n" +" print(f\"started at {time.strftime('%X')}\")\n" +"\n" +" await say_after(1, 'hello')\n" +" await say_after(2, 'world')\n" +"\n" +" print(f\"finished at {time.strftime('%X')}\")\n" +"\n" +"asyncio.run(main())" +msgstr "" + #: ../../library/asyncio-task.rst:73 msgid "Expected output::" msgstr "" +#: ../../library/asyncio-task.rst:75 +msgid "" +"started at 17:13:52\n" +"hello\n" +"world\n" +"finished at 17:13:55" +msgstr "" + #: ../../library/asyncio-task.rst:80 msgid "" "The :func:`asyncio.create_task` function to run coroutines concurrently as " @@ -80,18 +128,62 @@ msgid "" "*concurrently*::" msgstr "" +#: ../../library/asyncio-task.rst:86 +msgid "" +"async def main():\n" +" task1 = asyncio.create_task(\n" +" say_after(1, 'hello'))\n" +"\n" +" task2 = asyncio.create_task(\n" +" say_after(2, 'world'))\n" +"\n" +" print(f\"started at {time.strftime('%X')}\")\n" +"\n" +" # Wait until both tasks are completed (should take\n" +" # around 2 seconds.)\n" +" await task1\n" +" await task2\n" +"\n" +" print(f\"finished at {time.strftime('%X')}\")" +msgstr "" + #: ../../library/asyncio-task.rst:102 msgid "" "Note that expected output now shows that the snippet runs 1 second faster " "than before::" msgstr "" +#: ../../library/asyncio-task.rst:105 +msgid "" +"started at 17:14:32\n" +"hello\n" +"world\n" +"finished at 17:14:34" +msgstr "" + #: ../../library/asyncio-task.rst:110 msgid "" "The :class:`asyncio.TaskGroup` class provides a more modern alternative to :" "func:`create_task`. Using this API, the last example becomes::" msgstr "" +#: ../../library/asyncio-task.rst:114 +msgid "" +"async def main():\n" +" async with asyncio.TaskGroup() as tg:\n" +" task1 = tg.create_task(\n" +" say_after(1, 'hello'))\n" +"\n" +" task2 = tg.create_task(\n" +" say_after(2, 'world'))\n" +"\n" +" print(f\"started at {time.strftime('%X')}\")\n" +"\n" +" # The await is implicit when the context manager exits.\n" +"\n" +" print(f\"finished at {time.strftime('%X')}\")" +msgstr "" + #: ../../library/asyncio-task.rst:128 msgid "The timing and output should be the same as for the previous version." msgstr "" @@ -123,6 +215,25 @@ msgid "" "coroutines::" msgstr "" +#: ../../library/asyncio-task.rst:152 +msgid "" +"import asyncio\n" +"\n" +"async def nested():\n" +" return 42\n" +"\n" +"async def main():\n" +" # Nothing happens if we just call \"nested()\".\n" +" # A coroutine object is created but not awaited,\n" +" # so it *won't run at all*.\n" +" nested()\n" +"\n" +" # Let's do it differently now and await it:\n" +" print(await nested()) # will print \"42\".\n" +"\n" +"asyncio.run(main())" +msgstr "" + #: ../../library/asyncio-task.rst:170 msgid "" "In this documentation the term \"coroutine\" can be used for two closely " @@ -152,6 +263,25 @@ msgid "" "create_task` the coroutine is automatically scheduled to run soon::" msgstr "" +#: ../../library/asyncio-task.rst:187 +msgid "" +"import asyncio\n" +"\n" +"async def nested():\n" +" return 42\n" +"\n" +"async def main():\n" +" # Schedule nested() to run soon concurrently\n" +" # with \"main()\".\n" +" task = asyncio.create_task(nested())\n" +"\n" +" # \"task\" can now be used to cancel \"nested()\", or\n" +" # can simply be awaited to wait until it is complete:\n" +" await task\n" +"\n" +"asyncio.run(main())" +msgstr "" + #: ../../library/asyncio-task.rst:205 msgid "Futures" msgstr "" @@ -186,6 +316,18 @@ msgid "" "awaited::" msgstr "" +#: ../../library/asyncio-task.rst:221 +msgid "" +"async def main():\n" +" await function_that_returns_a_future_object()\n" +"\n" +" # this is also valid:\n" +" await asyncio.gather(\n" +" function_that_returns_a_future_object(),\n" +" some_python_coroutine()\n" +" )" +msgstr "" + #: ../../library/asyncio-task.rst:230 msgid "" "A good example of a low-level function that returns a Future object is :meth:" @@ -241,6 +383,22 @@ msgid "" "tasks, gather them in a collection::" msgstr "" +#: ../../library/asyncio-task.rst:272 +msgid "" +"background_tasks = set()\n" +"\n" +"for i in range(10):\n" +" task = asyncio.create_task(some_coro(param=i))\n" +"\n" +" # Add task to the set. This creates a strong reference.\n" +" background_tasks.add(task)\n" +"\n" +" # To prevent keeping references to finished tasks forever,\n" +" # make each task remove its own reference from the set after\n" +" # completion:\n" +" task.add_done_callback(background_tasks.discard)" +msgstr "" + #: ../../library/asyncio-task.rst:287 ../../library/asyncio-task.rst:1075 msgid "Added the *name* parameter." msgstr "新增 *name* 參數。" @@ -309,6 +467,16 @@ msgstr "" msgid "Example::" msgstr "範例: ::" +#: ../../library/asyncio-task.rst:340 +msgid "" +"async def main():\n" +" async with asyncio.TaskGroup() as tg:\n" +" task1 = tg.create_task(some_coro(...))\n" +" task2 = tg.create_task(another_coro(...))\n" +" print(f\"Both tasks have completed now: {task1.result()}, {task2." +"result()}\")" +msgstr "" + #: ../../library/asyncio-task.rst:346 msgid "" "The ``async with`` statement will wait for all tasks in the group to finish. " @@ -390,6 +558,23 @@ msgid "" "Example of coroutine displaying the current date every second for 5 seconds::" msgstr "" +#: ../../library/asyncio-task.rst:411 +msgid "" +"import asyncio\n" +"import datetime\n" +"\n" +"async def display_date():\n" +" loop = asyncio.get_running_loop()\n" +" end_time = loop.time() + 5.0\n" +" while True:\n" +" print(datetime.datetime.now())\n" +" if (loop.time() + 1.0) >= end_time:\n" +" break\n" +" await asyncio.sleep(1)\n" +"\n" +"asyncio.run(display_date())" +msgstr "" + #: ../../library/asyncio-task.rst:426 ../../library/asyncio-task.rst:521 #: ../../library/asyncio-task.rst:620 ../../library/asyncio-task.rst:794 #: ../../library/asyncio-task.rst:848 ../../library/asyncio-task.rst:874 @@ -457,6 +642,45 @@ msgid "" "tasks)." msgstr "" +#: ../../library/asyncio-task.rst:474 +msgid "" +"import asyncio\n" +"\n" +"async def factorial(name, number):\n" +" f = 1\n" +" for i in range(2, number + 1):\n" +" print(f\"Task {name}: Compute factorial({number}), currently i={i}..." +"\")\n" +" await asyncio.sleep(1)\n" +" f *= i\n" +" print(f\"Task {name}: factorial({number}) = {f}\")\n" +" return f\n" +"\n" +"async def main():\n" +" # Schedule three calls *concurrently*:\n" +" L = await asyncio.gather(\n" +" factorial(\"A\", 2),\n" +" factorial(\"B\", 3),\n" +" factorial(\"C\", 4),\n" +" )\n" +" print(L)\n" +"\n" +"asyncio.run(main())\n" +"\n" +"# Expected output:\n" +"#\n" +"# Task A: Compute factorial(2), currently i=2...\n" +"# Task B: Compute factorial(3), currently i=2...\n" +"# Task C: Compute factorial(4), currently i=2...\n" +"# Task A: factorial(2) = 2\n" +"# Task B: Compute factorial(3), currently i=3...\n" +"# Task C: Compute factorial(4), currently i=3...\n" +"# Task B: factorial(3) = 6\n" +"# Task C: Compute factorial(4), currently i=4...\n" +"# Task C: factorial(4) = 24\n" +"# [2, 6, 24]" +msgstr "" + #: ../../library/asyncio-task.rst:510 msgid "" "If *return_exceptions* is false, cancelling gather() after it has been " @@ -551,10 +775,20 @@ msgstr "" msgid "The statement::" msgstr "" +#: ../../library/asyncio-task.rst:587 +msgid "" +"task = asyncio.create_task(something())\n" +"res = await shield(task)" +msgstr "" + #: ../../library/asyncio-task.rst:590 msgid "is equivalent to::" msgstr "" +#: ../../library/asyncio-task.rst:592 +msgid "res = await something()" +msgstr "" + #: ../../library/asyncio-task.rst:594 msgid "" "*except* that if the coroutine containing it is cancelled, the Task running " @@ -577,6 +811,15 @@ msgid "" "follows::" msgstr "" +#: ../../library/asyncio-task.rst:607 +msgid "" +"task = asyncio.create_task(something())\n" +"try:\n" +" res = await shield(task)\n" +"except CancelledError:\n" +" res = None" +msgstr "" + #: ../../library/asyncio-task.rst:615 msgid "" "Save a reference to tasks passed to this function, to avoid a task " @@ -614,6 +857,13 @@ msgid "" "meth:`Timeout.reschedule`." msgstr "" +#: ../../library/asyncio-task.rst:647 +msgid "" +"async def main():\n" +" async with asyncio.timeout(10):\n" +" await long_running_task()" +msgstr "" + #: ../../library/asyncio-task.rst:651 msgid "" "If ``long_running_task`` takes more than 10 seconds to complete, the context " @@ -633,6 +883,18 @@ msgstr "" msgid "Example of catching :exc:`TimeoutError`::" msgstr "" +#: ../../library/asyncio-task.rst:665 +msgid "" +"async def main():\n" +" try:\n" +" async with asyncio.timeout(10):\n" +" await long_running_task()\n" +" except TimeoutError:\n" +" print(\"The long operation timed out, but we've handled it.\")\n" +"\n" +" print(\"This statement will run regardless.\")" +msgstr "" + #: ../../library/asyncio-task.rst:674 msgid "" "The context manager produced by :func:`asyncio.timeout` can be rescheduled " @@ -674,6 +936,24 @@ msgstr "" msgid "Return whether the context manager has exceeded its deadline (expired)." msgstr "" +#: ../../library/asyncio-task.rst:705 +msgid "" +"async def main():\n" +" try:\n" +" # We do not know the timeout when starting, so we pass ``None``.\n" +" async with asyncio.timeout(None) as cm:\n" +" # We know the timeout now, so we reschedule it.\n" +" new_deadline = get_running_loop().time() + 10\n" +" cm.reschedule(new_deadline)\n" +"\n" +" await long_running_task()\n" +" except TimeoutError:\n" +" pass\n" +"\n" +" if cm.expired():\n" +" print(\"Looks like we haven't finished on time.\")" +msgstr "" + #: ../../library/asyncio-task.rst:720 msgid "Timeout context managers can be safely nested." msgstr "" @@ -684,6 +964,20 @@ msgid "" "stop waiting, or ``None``." msgstr "" +#: ../../library/asyncio-task.rst:731 +msgid "" +"async def main():\n" +" loop = get_running_loop()\n" +" deadline = loop.time() + 20\n" +" try:\n" +" async with asyncio.timeout_at(deadline):\n" +" await long_running_task()\n" +" except TimeoutError:\n" +" print(\"The long operation timed out, but we've handled it.\")\n" +"\n" +" print(\"This statement will run regardless.\")" +msgstr "" + #: ../../library/asyncio-task.rst:746 msgid "" "Wait for the *aw* :ref:`awaitable ` to complete with a " @@ -718,6 +1012,27 @@ msgstr "" msgid "If the wait is cancelled, the future *aw* is also cancelled." msgstr "" +#: ../../library/asyncio-task.rst:771 +msgid "" +"async def eternity():\n" +" # Sleep for one hour\n" +" await asyncio.sleep(3600)\n" +" print('yay!')\n" +"\n" +"async def main():\n" +" # Wait for at most 1 second\n" +" try:\n" +" await asyncio.wait_for(eternity(), timeout=1.0)\n" +" except TimeoutError:\n" +" print('timeout!')\n" +"\n" +"asyncio.run(main())\n" +"\n" +"# Expected output:\n" +"#\n" +"# timeout!" +msgstr "" + #: ../../library/asyncio-task.rst:789 msgid "" "When *aw* is cancelled due to a timeout, ``wait_for`` waits for *aw* to be " @@ -751,6 +1066,10 @@ msgstr "" msgid "Usage::" msgstr "用法: ::" +#: ../../library/asyncio-task.rst:816 +msgid "done, pending = await asyncio.wait(aws)" +msgstr "" + #: ../../library/asyncio-task.rst:818 msgid "" "*timeout* (a float or int), if specified, can be used to control the maximum " @@ -820,6 +1139,13 @@ msgid "" "Raises :exc:`TimeoutError` if the timeout occurs before all Futures are done." msgstr "" +#: ../../library/asyncio-task.rst:870 +msgid "" +"for coro in as_completed(aws):\n" +" earliest_result = await coro\n" +" # ..." +msgstr "" + #: ../../library/asyncio-task.rst:877 msgid "" "Deprecation warning is emitted if not all awaitable objects in the *aws* " @@ -854,6 +1180,35 @@ msgid "" "were run in the main thread. For example::" msgstr "" +#: ../../library/asyncio-task.rst:903 +msgid "" +"def blocking_io():\n" +" print(f\"start blocking_io at {time.strftime('%X')}\")\n" +" # Note that time.sleep() can be replaced with any blocking\n" +" # IO-bound operation, such as file operations.\n" +" time.sleep(1)\n" +" print(f\"blocking_io complete at {time.strftime('%X')}\")\n" +"\n" +"async def main():\n" +" print(f\"started main at {time.strftime('%X')}\")\n" +"\n" +" await asyncio.gather(\n" +" asyncio.to_thread(blocking_io),\n" +" asyncio.sleep(1))\n" +"\n" +" print(f\"finished main at {time.strftime('%X')}\")\n" +"\n" +"\n" +"asyncio.run(main())\n" +"\n" +"# Expected output:\n" +"#\n" +"# started main at 19:50:53\n" +"# start blocking_io at 19:50:53\n" +"# blocking_io complete at 19:50:54\n" +"# finished main at 19:50:54" +msgstr "" + #: ../../library/asyncio-task.rst:929 msgid "" "Directly calling ``blocking_io()`` in any coroutine would block the event " @@ -890,12 +1245,37 @@ msgid "" "where the event loop is running. Example::" msgstr "" +#: ../../library/asyncio-task.rst:957 +msgid "" +"# Create a coroutine\n" +"coro = asyncio.sleep(1, result=3)\n" +"\n" +"# Submit the coroutine to a given loop\n" +"future = asyncio.run_coroutine_threadsafe(coro, loop)\n" +"\n" +"# Wait for the result with an optional timeout argument\n" +"assert future.result(timeout) == 3" +msgstr "" + #: ../../library/asyncio-task.rst:966 msgid "" "If an exception is raised in the coroutine, the returned Future will be " "notified. It can also be used to cancel the task in the event loop::" msgstr "" +#: ../../library/asyncio-task.rst:970 +msgid "" +"try:\n" +" result = future.result(timeout)\n" +"except TimeoutError:\n" +" print('The coroutine took too long, cancelling the task...')\n" +" future.cancel()\n" +"except Exception as exc:\n" +" print(f'The coroutine raised an exception: {exc!r}')\n" +"else:\n" +" print(f'The coroutine returned: {result!r}')" +msgstr "" + #: ../../library/asyncio-task.rst:980 msgid "" "See the :ref:`concurrency and multithreading ` " @@ -1223,6 +1603,43 @@ msgid "" "cancellation request::" msgstr "" +#: ../../library/asyncio-task.rst:1246 +msgid "" +"async def cancel_me():\n" +" print('cancel_me(): before sleep')\n" +"\n" +" try:\n" +" # Wait for 1 hour\n" +" await asyncio.sleep(3600)\n" +" except asyncio.CancelledError:\n" +" print('cancel_me(): cancel sleep')\n" +" raise\n" +" finally:\n" +" print('cancel_me(): after sleep')\n" +"\n" +"async def main():\n" +" # Create a \"cancel_me\" Task\n" +" task = asyncio.create_task(cancel_me())\n" +"\n" +" # Wait for 1 second\n" +" await asyncio.sleep(1)\n" +"\n" +" task.cancel()\n" +" try:\n" +" await task\n" +" except asyncio.CancelledError:\n" +" print(\"main(): cancel_me is cancelled now\")\n" +"\n" +"asyncio.run(main())\n" +"\n" +"# Expected output:\n" +"#\n" +"# cancel_me(): before sleep\n" +"# cancel_me(): cancel sleep\n" +"# cancel_me(): after sleep\n" +"# main(): cancel_me is cancelled now" +msgstr "" + #: ../../library/asyncio-task.rst:1282 msgid "Return ``True`` if the Task is *cancelled*." msgstr "" @@ -1257,6 +1674,20 @@ msgid "" "respective structured block. For example::" msgstr "" +#: ../../library/asyncio-task.rst:1306 +msgid "" +"async def make_request_with_timeout():\n" +" try:\n" +" async with asyncio.timeout(1):\n" +" # Structured block affected by the timeout:\n" +" await make_request()\n" +" await make_another_request()\n" +" except TimeoutError:\n" +" log(\"There was a timeout\")\n" +" # Outer code not affected by the timeout:\n" +" await unrelated_code()" +msgstr "" + #: ../../library/asyncio-task.rst:1317 msgid "" "While the block with ``make_request()`` and ``make_another_request()`` might " diff --git a/library/asyncio.po b/library/asyncio.po index 197d9dca7a..41e4d52ec1 100644 --- a/library/asyncio.po +++ b/library/asyncio.po @@ -9,7 +9,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-08-04 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2021-11-23 12:40+0800\n" "Last-Translator: Matt Wang \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -41,6 +41,18 @@ msgstr ":mod:`!asyncio` --- 非同步 I/O" msgid "Hello World!" msgstr "Hello World!" +#: ../../library/asyncio.rst:13 +msgid "" +"import asyncio\n" +"\n" +"async def main():\n" +" print('Hello ...')\n" +" await asyncio.sleep(1)\n" +" print('... World!')\n" +"\n" +"asyncio.run(main())" +msgstr "" + #: ../../library/asyncio.rst:22 msgid "" "asyncio is a library to write **concurrent** code using the **async/await** " @@ -148,6 +160,18 @@ msgstr "" msgid "You can experiment with an ``asyncio`` concurrent context in the REPL:" msgstr "你能在 REPL 中對一個 ``asyncio`` 的並行情境 (context) 進行實驗:" +#: ../../library/asyncio.rst:67 +msgid "" +"$ python -m asyncio\n" +"asyncio REPL ...\n" +"Use \"await\" directly instead of \"asyncio.run()\".\n" +"Type \"help\", \"copyright\", \"credits\" or \"license\" for more " +"information.\n" +">>> import asyncio\n" +">>> await asyncio.sleep(10, result='hello')\n" +"'hello'" +msgstr "" + #: ../../library/asyncio.rst:77 msgid "" "Raises an :ref:`auditing event ` ``cpython.run_stdin`` with no " diff --git a/library/atexit.po b/library/atexit.po index 1a51c54ab8..6ce7c45d8b 100644 --- a/library/atexit.po +++ b/library/atexit.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-04-30 00:04+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2016-01-31 07:13+0000\n" "Last-Translator: Matt Wang \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -42,8 +42,8 @@ msgid "" "program is killed by a signal not handled by Python, when a Python fatal " "internal error is detected, or when :func:`os._exit` is called." msgstr "" -"**注意:**\\ 當程式被一個不是來自 Python 的訊號終止、偵測到有 Python 嚴重內" -"部錯誤時或者 :func:`os._exit` 被呼叫時,透過此模組註冊的函式就不會被呼叫。" +"**注意:**\\ 當程式被一個不是來自 Python 的訊號終止、偵測到有 Python 嚴重內部" +"錯誤時或者 :func:`os._exit` 被呼叫時,透過此模組註冊的函式就不會被呼叫。" #: ../../library/atexit.rst:23 msgid "" @@ -89,8 +89,8 @@ msgid "" "last exception to be raised is re-raised." msgstr "" "如果在執行退出處理函式期間引發例外,則會列印回溯 (traceback)(除非引發 :exc:" -"`SystemExit`)並儲存例外資訊。在所有退出處理函式都有嘗試運作過後,將重新引發最後一" -"個引發的例外。" +"`SystemExit`)並儲存例外資訊。在所有退出處理函式都有嘗試運作過後,將重新引發" +"最後一個引發的例外。" #: ../../library/atexit.rst:48 msgid "" @@ -157,6 +157,27 @@ msgstr "" "以下的簡單範例示範了模組如何在被引入時以檔案來初始化計數器,並在程式終止時自" "動儲存計數器的更新值,而不需要仰賴應用程式在終止時明確呼叫該模組。 ::" +#: ../../library/atexit.rst:89 +msgid "" +"try:\n" +" with open('counterfile') as infile:\n" +" _count = int(infile.read())\n" +"except FileNotFoundError:\n" +" _count = 0\n" +"\n" +"def incrcounter(n):\n" +" global _count\n" +" _count = _count + n\n" +"\n" +"def savecounter():\n" +" with open('counterfile', 'w') as outfile:\n" +" outfile.write('%d' % _count)\n" +"\n" +"import atexit\n" +"\n" +"atexit.register(savecounter)" +msgstr "" + #: ../../library/atexit.rst:107 msgid "" "Positional and keyword arguments may also be passed to :func:`register` to " @@ -165,10 +186,31 @@ msgstr "" "位置引數和關鍵字引數也可以被傳遞給 :func:`register`,以便在呼叫時也傳遞給已註" "冊函式: ::" +#: ../../library/atexit.rst:110 +msgid "" +"def goodbye(name, adjective):\n" +" print('Goodbye %s, it was %s to meet you.' % (name, adjective))\n" +"\n" +"import atexit\n" +"\n" +"atexit.register(goodbye, 'Donny', 'nice')\n" +"# or:\n" +"atexit.register(goodbye, adjective='nice', name='Donny')" +msgstr "" + #: ../../library/atexit.rst:119 msgid "Usage as a :term:`decorator`::" msgstr "作為\\ :term:`裝飾器 `\\ 使用: ::" +#: ../../library/atexit.rst:121 +msgid "" +"import atexit\n" +"\n" +"@atexit.register\n" +"def goodbye():\n" +" print('You are now leaving the Python sector.')" +msgstr "" + #: ../../library/atexit.rst:127 msgid "This only works with functions that can be called without arguments." msgstr "這只適用於可以不帶引數呼叫的函式。" diff --git a/library/audioop.po b/library/audioop.po index 331d6daf61..e7ce6f704f 100644 --- a/library/audioop.po +++ b/library/audioop.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-07-20 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2022-05-22 02:00+0800\n" "Last-Translator: Liang-Bo Wang \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -192,6 +192,12 @@ msgid "" "samples for these formats, you need to also add 128 to the result::" msgstr "" +#: ../../library/audioop.rst:163 +msgid "" +"new_frames = audioop.lin2lin(frames, old_width, 1)\n" +"new_frames = audioop.bias(new_frames, 1, 128)" +msgstr "" + #: ../../library/audioop.rst:166 msgid "" "The same, in reverse, has to be applied when converting from 8 to 16, 24 or " @@ -289,6 +295,18 @@ msgid "" "that::" msgstr "" +#: ../../library/audioop.rst:249 +msgid "" +"def mul_stereo(sample, width, lfactor, rfactor):\n" +" lsample = audioop.tomono(sample, width, 1, 0)\n" +" rsample = audioop.tomono(sample, width, 0, 1)\n" +" lsample = audioop.mul(lsample, width, lfactor)\n" +" rsample = audioop.mul(rsample, width, rfactor)\n" +" lsample = audioop.tostereo(lsample, width, 1, 0)\n" +" rsample = audioop.tostereo(rsample, width, 0, 1)\n" +" return audioop.add(lsample, rsample, width)" +msgstr "" + #: ../../library/audioop.rst:258 msgid "" "If you use the ADPCM coder to build network packets and you want your " @@ -316,6 +334,22 @@ msgid "" "input sample and subtract the whole output sample from the input sample::" msgstr "" +#: ../../library/audioop.rst:275 +msgid "" +"def echocancel(outputdata, inputdata):\n" +" pos = audioop.findmax(outputdata, 800) # one tenth second\n" +" out_test = outputdata[pos*2:]\n" +" in_test = inputdata[pos*2:]\n" +" ipos, factor = audioop.findfit(in_test, out_test)\n" +" # Optional (for better cancellation):\n" +" # factor = audioop.findfactor(in_test[ipos*2:ipos*2+len(out_test)],\n" +" # out_test)\n" +" prefill = '\\0'*(pos+ipos)*2\n" +" postfill = '\\0'*(len(inputdata)-len(prefill)-len(outputdata))\n" +" outputdata = prefill + audioop.mul(outputdata, 2, -factor) + postfill\n" +" return audioop.add(inputdata, outputdata, 2)" +msgstr "" + #: ../../library/audioop.rst:24 msgid "Intel/DVI ADPCM" msgstr "Intel/DVI ADPCM" diff --git a/library/binascii.po b/library/binascii.po index 8409c34971..77622c04e6 100644 --- a/library/binascii.po +++ b/library/binascii.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-05-09 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2018-05-23 14:39+0000\n" "Last-Translator: Adrian Liaw \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -153,6 +153,15 @@ msgid "" "algorithm. Use as follows::" msgstr "" +#: ../../library/binascii.rst:117 +msgid "" +"print(binascii.crc32(b\"hello world\"))\n" +"# Or, in two pieces:\n" +"crc = binascii.crc32(b\"hello\")\n" +"crc = binascii.crc32(b\" world\", crc)\n" +"print('crc32 = {:#010x}'.format(crc))" +msgstr "" + #: ../../library/binascii.rst:123 msgid "The result is always unsigned." msgstr "" diff --git a/library/builtins.po b/library/builtins.po index 4605aa63de..9cb00dccd0 100644 --- a/library/builtins.po +++ b/library/builtins.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-05-09 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2022-02-15 20:55+0800\n" "Last-Translator: Matt Wang \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -47,6 +47,26 @@ msgstr "" "能很有用,不過其中還會需要內建該名稱。例如,在一個將內建 :func:`open` 包裝起" "來以實現另一版本 :func:`open` 函式的模組中,這個模組可以直接被使用: ::" +#: ../../library/builtins.rst:21 +msgid "" +"import builtins\n" +"\n" +"def open(path):\n" +" f = builtins.open(path, 'r')\n" +" return UpperCaser(f)\n" +"\n" +"class UpperCaser:\n" +" '''Wrapper around a file that converts output to uppercase.'''\n" +"\n" +" def __init__(self, f):\n" +" self._f = f\n" +"\n" +" def read(self, count=-1):\n" +" return self._f.read(count).upper()\n" +"\n" +" # ..." +msgstr "" + #: ../../library/builtins.rst:38 msgid "" "As an implementation detail, most modules have the name ``__builtins__`` " diff --git a/library/calendar.po b/library/calendar.po index 5ec1ad23cd..4d6af52202 100644 --- a/library/calendar.po +++ b/library/calendar.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-05-09 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2018-05-23 14:40+0000\n" "Last-Translator: Adrian Liaw \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -293,10 +293,21 @@ msgid "" "A list of CSS classes used for each weekday. The default class list is::" msgstr "對應一週每一天 CSS 類別的串列。預設的串列內容為: ::" +#: ../../library/calendar.rst:213 +msgid "" +"cssclasses = [\"mon\", \"tue\", \"wed\", \"thu\", \"fri\", \"sat\", \"sun\"]" +msgstr "" + #: ../../library/calendar.rst:215 msgid "more styles can be added for each day::" msgstr "可以針對每一天增加更多樣式: ::" +#: ../../library/calendar.rst:217 +msgid "" +"cssclasses = [\"mon text-bold\", \"tue\", \"wed\", \"thu\", \"fri\", " +"\"sat\", \"sun red\"]" +msgstr "" + #: ../../library/calendar.rst:219 msgid "Note that the length of this list must be seven items." msgstr "注意這個串列的長度必須是七個項目。" @@ -354,10 +365,24 @@ msgstr "" "``cssclass_noday``),你可以使用多個以空格隔開的 CSS 類別取代單一 CSS 類別," "例如: ::" +#: ../../library/calendar.rst:273 +msgid "\"text-bold text-red\"" +msgstr "" + #: ../../library/calendar.rst:275 msgid "Here is an example how :class:`!HTMLCalendar` can be customized::" msgstr "以下是客製化 :class:`!HTMLCalendar` 的範例: ::" +#: ../../library/calendar.rst:277 +msgid "" +"class CustomHTMLCal(calendar.HTMLCalendar):\n" +" cssclasses = [style + \" text-nowrap\" for style in\n" +" calendar.HTMLCalendar.cssclasses]\n" +" cssclass_month_head = \"text-center month-head\"\n" +" cssclass_month = \"text-center month\"\n" +" cssclass_year = \"text-italic lead\"" +msgstr "" + #: ../../library/calendar.rst:287 msgid "" "This subclass of :class:`TextCalendar` can be passed a locale name in the " @@ -400,6 +425,12 @@ msgstr "" "`TUESDAY`、:const:`WEDNESDAY`、:const:`THURSDAY`、:const:`FRIDAY`、:const:" "`SATURDAY` 及 :const:`SUNDAY` 可以方便設定。例如設定一週的第一天為週日: ::" +#: ../../library/calendar.rst:314 +msgid "" +"import calendar\n" +"calendar.setfirstweekday(calendar.SUNDAY)" +msgstr "" + #: ../../library/calendar.rst:320 msgid "Returns the current setting for the weekday to start each week." msgstr "回傳目前設定的一週的第一天。" @@ -603,10 +634,58 @@ msgid "" "to interactively print a calendar." msgstr ":mod:`calendar` 模組可以作為腳本從命令列執行,並以互動方式列印日曆。" +#: ../../library/calendar.rst:511 +msgid "" +"python -m calendar [-h] [-L LOCALE] [-e ENCODING] [-t {text,html}]\n" +" [-w WIDTH] [-l LINES] [-s SPACING] [-m MONTHS] [-c CSS]\n" +" [year] [month]" +msgstr "" + #: ../../library/calendar.rst:518 msgid "For example, to print a calendar for the year 2000:" msgstr "例如,要列印 2000 年的日曆:" +#: ../../library/calendar.rst:520 +msgid "" +"$ python -m calendar 2000\n" +" 2000\n" +"\n" +" January February March\n" +"Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su\n" +" 1 2 1 2 3 4 5 6 1 2 3 4 5\n" +" 3 4 5 6 7 8 9 7 8 9 10 11 12 13 6 7 8 9 10 11 12\n" +"10 11 12 13 14 15 16 14 15 16 17 18 19 20 13 14 15 16 17 18 19\n" +"17 18 19 20 21 22 23 21 22 23 24 25 26 27 20 21 22 23 24 25 26\n" +"24 25 26 27 28 29 30 28 29 27 28 29 30 31\n" +"31\n" +"\n" +" April May June\n" +"Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su\n" +" 1 2 1 2 3 4 5 6 7 1 2 3 4\n" +" 3 4 5 6 7 8 9 8 9 10 11 12 13 14 5 6 7 8 9 10 11\n" +"10 11 12 13 14 15 16 15 16 17 18 19 20 21 12 13 14 15 16 17 18\n" +"17 18 19 20 21 22 23 22 23 24 25 26 27 28 19 20 21 22 23 24 25\n" +"24 25 26 27 28 29 30 29 30 31 26 27 28 29 30\n" +"\n" +" July August September\n" +"Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su\n" +" 1 2 1 2 3 4 5 6 1 2 3\n" +" 3 4 5 6 7 8 9 7 8 9 10 11 12 13 4 5 6 7 8 9 10\n" +"10 11 12 13 14 15 16 14 15 16 17 18 19 20 11 12 13 14 15 16 17\n" +"17 18 19 20 21 22 23 21 22 23 24 25 26 27 18 19 20 21 22 23 24\n" +"24 25 26 27 28 29 30 28 29 30 31 25 26 27 28 29 30\n" +"31\n" +"\n" +" October November December\n" +"Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su\n" +" 1 1 2 3 4 5 1 2 3\n" +" 2 3 4 5 6 7 8 6 7 8 9 10 11 12 4 5 6 7 8 9 10\n" +" 9 10 11 12 13 14 15 13 14 15 16 17 18 19 11 12 13 14 15 16 17\n" +"16 17 18 19 20 21 22 20 21 22 23 24 25 26 18 19 20 21 22 23 24\n" +"23 24 25 26 27 28 29 27 28 29 30 25 26 27 28 29 30 31\n" +"30 31" +msgstr "" + #: ../../library/calendar.rst:561 msgid "The following options are accepted:" msgstr "接受以下選項:" diff --git a/library/cgi.po b/library/cgi.po index 25de814c82..4012213a00 100644 --- a/library/cgi.po +++ b/library/cgi.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-07-20 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2022-05-22 02:01+0800\n" "Last-Translator: Adrian Liaw \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -112,6 +112,12 @@ msgid "" "header section looks like this::" msgstr "" +#: ../../library/cgi.rst:68 +msgid "" +"print(\"Content-Type: text/html\") # HTML is following\n" +"print() # blank line, end of headers" +msgstr "" + #: ../../library/cgi.rst:71 msgid "" "The second section is usually HTML, which allows the client software to " @@ -119,6 +125,13 @@ msgid "" "Python code that prints a simple piece of HTML::" msgstr "" +#: ../../library/cgi.rst:75 +msgid "" +"print(\"CGI script output\")\n" +"print(\"

This is my first CGI script

\")\n" +"print(\"Hello, world!\")" +msgstr "" + #: ../../library/cgi.rst:83 msgid "Using the cgi module" msgstr "" @@ -131,6 +144,12 @@ msgstr "" msgid "When you write a new script, consider adding these lines::" msgstr "" +#: ../../library/cgi.rst:89 ../../library/cgi.rst:505 +msgid "" +"import cgitb\n" +"cgitb.enable()" +msgstr "" + #: ../../library/cgi.rst:92 msgid "" "This activates a special exception handler that will display detailed " @@ -139,6 +158,12 @@ msgid "" "saved to files instead, with code like this::" msgstr "" +#: ../../library/cgi.rst:97 +msgid "" +"import cgitb\n" +"cgitb.enable(display=0, logdir=\"/path/to/logdir\")" +msgstr "" + #: ../../library/cgi.rst:100 msgid "" "It's very helpful to use this feature during script development. The reports " @@ -177,6 +202,18 @@ msgid "" "the fields ``name`` and ``addr`` are both set to a non-empty string::" msgstr "" +#: ../../library/cgi.rst:127 +msgid "" +"form = cgi.FieldStorage()\n" +"if \"name\" not in form or \"addr\" not in form:\n" +" print(\"

Error

\")\n" +" print(\"Please fill in the name and addr fields.\")\n" +" return\n" +"print(\"

name:\", form[\"name\"].value)\n" +"print(\"

addr:\", form[\"addr\"].value)\n" +"...further form processing here..." +msgstr "" + #: ../../library/cgi.rst:136 msgid "" "Here the fields, accessed through ``form[key]``, are themselves instances " @@ -200,6 +237,12 @@ msgid "" "username fields, separated by commas::" msgstr "" +#: ../../library/cgi.rst:153 +msgid "" +"value = form.getlist(\"username\")\n" +"usernames = \",\".join(value)" +msgstr "" + #: ../../library/cgi.rst:156 msgid "" "If a field represents an uploaded file, accessing the value via the :attr:" @@ -213,6 +256,18 @@ msgid "" "IOBase.readline` methods will return bytes)::" msgstr "" +#: ../../library/cgi.rst:167 +msgid "" +"fileitem = form[\"userfile\"]\n" +"if fileitem.file:\n" +" # It's an uploaded file; count lines\n" +" linecount = 0\n" +" while True:\n" +" line = fileitem.file.readline()\n" +" if not line: break\n" +" linecount = linecount + 1" +msgstr "" + #: ../../library/cgi.rst:176 msgid "" ":class:`FieldStorage` objects also support being used in a :keyword:`with` " @@ -292,12 +347,27 @@ msgid "" "expected a user to post more than one value under one name::" msgstr "" +#: ../../library/cgi.rst:228 +msgid "" +"item = form.getvalue(\"item\")\n" +"if isinstance(item, list):\n" +" # The user is requesting more than one item.\n" +"else:\n" +" # The user is requesting only one item." +msgstr "" + #: ../../library/cgi.rst:234 msgid "" "This situation is common for example when a form contains a group of " "multiple checkboxes with the same name::" msgstr "" +#: ../../library/cgi.rst:237 +msgid "" +"\n" +"" +msgstr "" + #: ../../library/cgi.rst:240 msgid "" "In most situations, however, there's only one form control with a particular " @@ -305,6 +375,10 @@ msgid "" "this name. So you write a script containing for example this code::" msgstr "" +#: ../../library/cgi.rst:244 +msgid "user = form.getvalue(\"user\").upper()" +msgstr "" + #: ../../library/cgi.rst:246 msgid "" "The problem with the code is that you should never expect that a client will " @@ -353,6 +427,15 @@ msgstr "" msgid "Using these methods you can write nice compact code::" msgstr "" +#: ../../library/cgi.rst:281 +msgid "" +"import cgi\n" +"form = cgi.FieldStorage()\n" +"user = form.getfirst(\"user\", \"\").upper() # This way it's safe.\n" +"for item in form.getlist(\"item\"):\n" +" do_something(item)" +msgstr "" + #: ../../library/cgi.rst:291 msgid "Functions" msgstr "函式" @@ -435,6 +518,14 @@ msgstr "" msgid "For example, with :class:`email.message.EmailMessage`::" msgstr "" +#: ../../library/cgi.rst:352 +msgid "" +"from email.message import EmailMessage\n" +"msg = EmailMessage()\n" +"msg['content-type'] = 'application/json; charset=\"utf8\"'\n" +"main, params = msg.get_content_type(), msg['content-type'].params" +msgstr "" + #: ../../library/cgi.rst:360 msgid "" "Robust test CGI script, usable as main program. Writes minimal HTTP headers " @@ -498,6 +589,10 @@ msgid "" "column 1 followed by the pathname of the Python interpreter, for instance::" msgstr "" +#: ../../library/cgi.rst:416 +msgid "#!/usr/local/bin/python" +msgstr "" + #: ../../library/cgi.rst:418 msgid "" "Make sure the Python interpreter exists and is executable by \"others\"." @@ -525,6 +620,13 @@ msgid "" "importing other modules. For example::" msgstr "" +#: ../../library/cgi.rst:435 +msgid "" +"import sys\n" +"sys.path.insert(0, \"/usr/home/joe/lib/python\")\n" +"sys.path.insert(0, \"/usr/local/lib/python\")" +msgstr "" + #: ../../library/cgi.rst:439 msgid "(This way, the directory inserted last will be searched first!)" msgstr "" @@ -572,6 +674,10 @@ msgid "" "your browser of the form:" msgstr "" +#: ../../library/cgi.rst:473 +msgid "http://yourhostname/cgi-bin/cgi.py?name=Joe+Blow&addr=At+Home" +msgstr "" + #: ../../library/cgi.rst:477 msgid "" "If this gives an error of type 404, the server cannot find the script -- " @@ -590,6 +696,10 @@ msgid "" "from your script: replace its main code with the single statement ::" msgstr "" +#: ../../library/cgi.rst:489 +msgid "cgi.test()" +msgstr "" + #: ../../library/cgi.rst:491 msgid "" "This should produce the same results as those gotten from installing the :" @@ -627,6 +737,15 @@ msgid "" "modules)::" msgstr "" +#: ../../library/cgi.rst:515 +msgid "" +"import sys\n" +"sys.stderr = sys.stdout\n" +"print(\"Content-Type: text/plain\")\n" +"print()\n" +"...your code here..." +msgstr "" + #: ../../library/cgi.rst:521 msgid "" "This relies on the Python interpreter to print the traceback. The content " diff --git a/library/cgitb.po b/library/cgitb.po index 8ae8ec4c0d..fb993dd6c0 100644 --- a/library/cgitb.po +++ b/library/cgitb.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-07-20 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2022-05-22 02:02+0800\n" "Last-Translator: Liang-Bo Wang \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -52,6 +52,12 @@ msgstr "" msgid "To enable this feature, simply add this to the top of your CGI script::" msgstr "" +#: ../../library/cgitb.rst:37 +msgid "" +"import cgitb\n" +"cgitb.enable()" +msgstr "" + #: ../../library/cgitb.rst:40 msgid "" "The options to the :func:`enable` function control whether the report is " diff --git a/library/cmath.po b/library/cmath.po index 2921911ca2..7ceb0c8bea 100644 --- a/library/cmath.po +++ b/library/cmath.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-05-31 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2024-03-14 09:26+0800\n" "Last-Translator: Enkai Huang \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -65,12 +65,24 @@ msgstr "" "``complex(-2.0, -0.0)`` 被視為位於分枝切割 *下方* 處理,因此給出的結果在負虛" "軸上: ::" +#: ../../library/cmath.rst:31 +msgid "" +">>> cmath.sqrt(complex(-2.0, -0.0))\n" +"-1.4142135623730951j" +msgstr "" + #: ../../library/cmath.rst:34 msgid "" "But an argument of ``complex(-2.0, 0.0)`` is treated as though it lies above " "the branch cut::" msgstr "但是引數 ``complex(-2.0, 0.0)`` 會被當成位於分枝切割上方處理: ::" +#: ../../library/cmath.rst:37 +msgid "" +">>> cmath.sqrt(complex(-2.0, 0.0))\n" +"1.4142135623730951j" +msgstr "" + #: ../../library/cmath.rst:42 msgid "Conversions to and from polar coordinates" msgstr "轉換到極座標和從極座標做轉換" @@ -116,6 +128,14 @@ msgstr "" "作的分枝切割將位於負實軸上。結果的符號會與 ``x.imag`` 的符號相同,即使 ``x." "imag`` 為零: ::" +#: ../../library/cmath.rst:66 +msgid "" +">>> phase(complex(-1.0, 0.0))\n" +"3.141592653589793\n" +">>> phase(complex(-1.0, -0.0))\n" +"-3.141592653589793" +msgstr "" + #: ../../library/cmath.rst:74 msgid "" "The modulus (absolute value) of a complex number *x* can be computed using " diff --git a/library/cmd.po b/library/cmd.po index 08eca711f5..a6253073b3 100644 --- a/library/cmd.po +++ b/library/cmd.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-05-09 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2018-05-23 14:40+0000\n" "Last-Translator: Adrian Liaw \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -306,6 +306,86 @@ msgid "" "attr:`~Cmd.cmdqueue` for immediate playback::" msgstr "" +#: ../../library/cmd.rst:255 +msgid "" +"import cmd, sys\n" +"from turtle import *\n" +"\n" +"class TurtleShell(cmd.Cmd):\n" +" intro = 'Welcome to the turtle shell. Type help or ? to list commands." +"\\n'\n" +" prompt = '(turtle) '\n" +" file = None\n" +"\n" +" # ----- basic turtle commands -----\n" +" def do_forward(self, arg):\n" +" 'Move the turtle forward by the specified distance: FORWARD 10'\n" +" forward(*parse(arg))\n" +" def do_right(self, arg):\n" +" 'Turn turtle right by given number of degrees: RIGHT 20'\n" +" right(*parse(arg))\n" +" def do_left(self, arg):\n" +" 'Turn turtle left by given number of degrees: LEFT 90'\n" +" left(*parse(arg))\n" +" def do_goto(self, arg):\n" +" 'Move turtle to an absolute position with changing orientation. " +"GOTO 100 200'\n" +" goto(*parse(arg))\n" +" def do_home(self, arg):\n" +" 'Return turtle to the home position: HOME'\n" +" home()\n" +" def do_circle(self, arg):\n" +" 'Draw circle with given radius an options extent and steps: CIRCLE " +"50'\n" +" circle(*parse(arg))\n" +" def do_position(self, arg):\n" +" 'Print the current turtle position: POSITION'\n" +" print('Current position is %d %d\\n' % position())\n" +" def do_heading(self, arg):\n" +" 'Print the current turtle heading in degrees: HEADING'\n" +" print('Current heading is %d\\n' % (heading(),))\n" +" def do_color(self, arg):\n" +" 'Set the color: COLOR BLUE'\n" +" color(arg.lower())\n" +" def do_undo(self, arg):\n" +" 'Undo (repeatedly) the last turtle action(s): UNDO'\n" +" def do_reset(self, arg):\n" +" 'Clear the screen and return turtle to center: RESET'\n" +" reset()\n" +" def do_bye(self, arg):\n" +" 'Stop recording, close the turtle window, and exit: BYE'\n" +" print('Thank you for using Turtle')\n" +" self.close()\n" +" bye()\n" +" return True\n" +"\n" +" # ----- record and playback -----\n" +" def do_record(self, arg):\n" +" 'Save future commands to filename: RECORD rose.cmd'\n" +" self.file = open(arg, 'w')\n" +" def do_playback(self, arg):\n" +" 'Playback commands from a file: PLAYBACK rose.cmd'\n" +" self.close()\n" +" with open(arg) as f:\n" +" self.cmdqueue.extend(f.read().splitlines())\n" +" def precmd(self, line):\n" +" line = line.lower()\n" +" if self.file and 'playback' not in line:\n" +" print(line, file=self.file)\n" +" return line\n" +" def close(self):\n" +" if self.file:\n" +" self.file.close()\n" +" self.file = None\n" +"\n" +"def parse(arg):\n" +" 'Convert a series of zero or more numbers to an argument tuple'\n" +" return tuple(map(int, arg.split()))\n" +"\n" +"if __name__ == '__main__':\n" +" TurtleShell().cmdloop()" +msgstr "" + #: ../../library/cmd.rst:330 msgid "" "Here is a sample session with the turtle shell showing the help functions, " @@ -313,6 +393,67 @@ msgid "" "facility:" msgstr "" +#: ../../library/cmd.rst:333 +msgid "" +"Welcome to the turtle shell. Type help or ? to list commands.\n" +"\n" +"(turtle) ?\n" +"\n" +"Documented commands (type help ):\n" +"========================================\n" +"bye color goto home playback record right\n" +"circle forward heading left position reset undo\n" +"\n" +"(turtle) help forward\n" +"Move the turtle forward by the specified distance: FORWARD 10\n" +"(turtle) record spiral.cmd\n" +"(turtle) position\n" +"Current position is 0 0\n" +"\n" +"(turtle) heading\n" +"Current heading is 0\n" +"\n" +"(turtle) reset\n" +"(turtle) circle 20\n" +"(turtle) right 30\n" +"(turtle) circle 40\n" +"(turtle) right 30\n" +"(turtle) circle 60\n" +"(turtle) right 30\n" +"(turtle) circle 80\n" +"(turtle) right 30\n" +"(turtle) circle 100\n" +"(turtle) right 30\n" +"(turtle) circle 120\n" +"(turtle) right 30\n" +"(turtle) circle 120\n" +"(turtle) heading\n" +"Current heading is 180\n" +"\n" +"(turtle) forward 100\n" +"(turtle)\n" +"(turtle) right 90\n" +"(turtle) forward 100\n" +"(turtle)\n" +"(turtle) right 90\n" +"(turtle) forward 400\n" +"(turtle) right 90\n" +"(turtle) forward 500\n" +"(turtle) right 90\n" +"(turtle) forward 400\n" +"(turtle) right 90\n" +"(turtle) forward 300\n" +"(turtle) playback spiral.cmd\n" +"Current position is 0 0\n" +"\n" +"Current heading is 0\n" +"\n" +"Current heading is 180\n" +"\n" +"(turtle) bye\n" +"Thank you for using Turtle" +msgstr "" + #: ../../library/cmd.rst:64 msgid "? (question mark)" msgstr "? (問號)" diff --git a/library/collections.abc.po b/library/collections.abc.po index cbc39fdca9..ac9586f521 100644 --- a/library/collections.abc.po +++ b/library/collections.abc.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-07-20 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2018-05-23 14:41+0000\n" "Last-Translator: Adrian Liaw \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -52,6 +52,24 @@ msgid "" "desired. Other methods may be added as needed:" msgstr "" +#: ../../library/collections.abc.rst:35 +msgid "" +"class C(Sequence): # Direct inheritance\n" +" def __init__(self): ... # Extra method not required by the " +"ABC\n" +" def __getitem__(self, index): ... # Required abstract method\n" +" def __len__(self): ... # Required abstract method\n" +" def count(self, value): ... # Optionally override a mixin method" +msgstr "" + +#: ../../library/collections.abc.rst:43 +msgid "" +">>> issubclass(C, Sequence)\n" +"True\n" +">>> isinstance(C(), Sequence)\n" +"True" +msgstr "" + #: ../../library/collections.abc.rst:50 msgid "" "2) Existing classes and built-in classes can be registered as \"virtual " @@ -62,6 +80,27 @@ msgid "" "rule is for methods that are automatically inferred from the rest of the API:" msgstr "" +#: ../../library/collections.abc.rst:58 +msgid "" +"class D: # No inheritance\n" +" def __init__(self): ... # Extra method not required by the " +"ABC\n" +" def __getitem__(self, index): ... # Abstract method\n" +" def __len__(self): ... # Abstract method\n" +" def count(self, value): ... # Mixin method\n" +" def index(self, value): ... # Mixin method\n" +"\n" +"Sequence.register(D) # Register instead of inherit" +msgstr "" + +#: ../../library/collections.abc.rst:69 +msgid "" +">>> issubclass(D, Sequence)\n" +"True\n" +">>> isinstance(D(), Sequence)\n" +"True" +msgstr "" + #: ../../library/collections.abc.rst:76 msgid "" "In this example, class :class:`!D` does not need to define ``__contains__``, " @@ -77,6 +116,21 @@ msgid "" "required methods (unless those methods have been set to :const:`None`):" msgstr "" +#: ../../library/collections.abc.rst:86 +msgid "" +"class E:\n" +" def __iter__(self): ...\n" +" def __next__(self): ..." +msgstr "" + +#: ../../library/collections.abc.rst:92 +msgid "" +">>> issubclass(E, Iterable)\n" +"True\n" +">>> isinstance(E(), Iterable)\n" +"True" +msgstr "" + #: ../../library/collections.abc.rst:99 msgid "" "Complex interfaces do not support this last technique because an interface " @@ -450,11 +504,17 @@ msgstr "" msgid "ABC for classes that provide the :meth:`~object.__call__` method." msgstr "" -#: ../../library/collections.abc.rst:221 +#: ../../library/collections.abc.rst:219 +msgid "" +"See :ref:`annotating-callables` for details on how to use :class:`!Callable` " +"in type annotations." +msgstr "" + +#: ../../library/collections.abc.rst:224 msgid "ABC for classes that provide the :meth:`~container.__iter__` method." msgstr "" -#: ../../library/collections.abc.rst:223 +#: ../../library/collections.abc.rst:226 msgid "" "Checking ``isinstance(obj, Iterable)`` detects classes that are registered " "as :class:`Iterable` or that have an :meth:`~container.__iter__` method, but " @@ -463,23 +523,23 @@ msgid "" "`iterable` is to call ``iter(obj)``." msgstr "" -#: ../../library/collections.abc.rst:232 +#: ../../library/collections.abc.rst:235 msgid "ABC for sized iterable container classes." msgstr "" -#: ../../library/collections.abc.rst:238 +#: ../../library/collections.abc.rst:241 msgid "" "ABC for classes that provide the :meth:`~iterator.__iter__` and :meth:" "`~iterator.__next__` methods. See also the definition of :term:`iterator`." msgstr "" -#: ../../library/collections.abc.rst:244 +#: ../../library/collections.abc.rst:247 msgid "" "ABC for iterable classes that also provide the :meth:`~object.__reversed__` " "method." msgstr "" -#: ../../library/collections.abc.rst:251 +#: ../../library/collections.abc.rst:254 msgid "" "ABC for :term:`generator` classes that implement the protocol defined in :" "pep:`342` that extends :term:`iterators ` with the :meth:" @@ -487,11 +547,17 @@ msgid "" "methods." msgstr "" -#: ../../library/collections.abc.rst:262 +#: ../../library/collections.abc.rst:259 +msgid "" +"See :ref:`annotating-generators-and-coroutines` for details on using :class:" +"`!Generator` in type annotations." +msgstr "" + +#: ../../library/collections.abc.rst:268 msgid "ABCs for read-only and mutable :term:`sequences `." msgstr "" -#: ../../library/collections.abc.rst:264 +#: ../../library/collections.abc.rst:270 msgid "" "Implementation note: Some of the mixin methods, such as :meth:`~container." "__iter__`, :meth:`~object.__reversed__` and :meth:`index`, make repeated " @@ -502,44 +568,44 @@ msgid "" "quadratic performance and will likely need to be overridden." msgstr "" -#: ../../library/collections.abc.rst:273 +#: ../../library/collections.abc.rst:279 msgid "The index() method added support for *stop* and *start* arguments." msgstr "" -#: ../../library/collections.abc.rst:277 +#: ../../library/collections.abc.rst:283 msgid "" "The :class:`ByteString` ABC has been deprecated. For use in typing, prefer a " "union, like ``bytes | bytearray``, or :class:`collections.abc.Buffer`. For " "use as an ABC, prefer :class:`Sequence` or :class:`collections.abc.Buffer`." msgstr "" -#: ../../library/collections.abc.rst:286 +#: ../../library/collections.abc.rst:292 msgid "ABCs for read-only and mutable :ref:`sets `." msgstr "" -#: ../../library/collections.abc.rst:291 +#: ../../library/collections.abc.rst:297 msgid "ABCs for read-only and mutable :term:`mappings `." msgstr "" -#: ../../library/collections.abc.rst:298 +#: ../../library/collections.abc.rst:304 msgid "" "ABCs for mapping, items, keys, and values :term:`views `." msgstr "" -#: ../../library/collections.abc.rst:302 +#: ../../library/collections.abc.rst:308 msgid "" "ABC for :term:`awaitable` objects, which can be used in :keyword:`await` " "expressions. Custom implementations must provide the :meth:`~object." "__await__` method." msgstr "" -#: ../../library/collections.abc.rst:306 +#: ../../library/collections.abc.rst:312 msgid "" ":term:`Coroutine ` objects and instances of the :class:" "`~collections.abc.Coroutine` ABC are all instances of this ABC." msgstr "" -#: ../../library/collections.abc.rst:310 +#: ../../library/collections.abc.rst:316 msgid "" "In CPython, generator-based coroutines (:term:`generators ` " "decorated with :func:`@types.coroutine `) are *awaitables*, " @@ -548,7 +614,7 @@ msgid "" "`inspect.isawaitable` to detect them." msgstr "" -#: ../../library/collections.abc.rst:320 +#: ../../library/collections.abc.rst:326 msgid "" "ABC for :term:`coroutine` compatible classes. These implement the following " "methods, defined in :ref:`coroutine-objects`: :meth:`~coroutine.send`, :meth:" @@ -557,7 +623,7 @@ msgid "" "instances are also instances of :class:`Awaitable`." msgstr "" -#: ../../library/collections.abc.rst:328 +#: ../../library/collections.abc.rst:334 msgid "" "In CPython, generator-based coroutines (:term:`generators ` " "decorated with :func:`@types.coroutine `) are *awaitables*, " @@ -566,41 +632,61 @@ msgid "" "`inspect.isawaitable` to detect them." msgstr "" -#: ../../library/collections.abc.rst:338 +#: ../../library/collections.abc.rst:340 +msgid "" +"See :ref:`annotating-generators-and-coroutines` for details on using :class:" +"`!Coroutine` in type annotations. The variance and order of type parameters " +"correspond to those of :class:`Generator`." +msgstr "" + +#: ../../library/collections.abc.rst:349 msgid "" "ABC for classes that provide an ``__aiter__`` method. See also the " "definition of :term:`asynchronous iterable`." msgstr "" -#: ../../library/collections.abc.rst:345 +#: ../../library/collections.abc.rst:356 msgid "" "ABC for classes that provide ``__aiter__`` and ``__anext__`` methods. See " "also the definition of :term:`asynchronous iterator`." msgstr "" -#: ../../library/collections.abc.rst:352 +#: ../../library/collections.abc.rst:363 msgid "" "ABC for :term:`asynchronous generator` classes that implement the protocol " "defined in :pep:`525` and :pep:`492`." msgstr "" -#: ../../library/collections.abc.rst:359 +#: ../../library/collections.abc.rst:366 +msgid "" +"See :ref:`annotating-generators-and-coroutines` for details on using :class:" +"`!AsyncGenerator` in type annotations." +msgstr "" + +#: ../../library/collections.abc.rst:373 msgid "" "ABC for classes that provide the :meth:`~object.__buffer__` method, " "implementing the :ref:`buffer protocol `. See :pep:`688`." msgstr "" -#: ../../library/collections.abc.rst:365 +#: ../../library/collections.abc.rst:379 msgid "Examples and Recipes" msgstr "" -#: ../../library/collections.abc.rst:367 +#: ../../library/collections.abc.rst:381 msgid "" "ABCs allow us to ask classes or instances if they provide particular " "functionality, for example::" msgstr "" -#: ../../library/collections.abc.rst:374 +#: ../../library/collections.abc.rst:384 +msgid "" +"size = None\n" +"if isinstance(myvar, collections.abc.Sized):\n" +" size = len(myvar)" +msgstr "" + +#: ../../library/collections.abc.rst:388 msgid "" "Several of the ABCs are also useful as mixins that make it easier to develop " "classes supporting container APIs. For example, to write a class supporting " @@ -610,11 +696,37 @@ msgid "" "methods such as :meth:`!__and__` and :meth:`~frozenset.isdisjoint`::" msgstr "" -#: ../../library/collections.abc.rst:403 +#: ../../library/collections.abc.rst:395 +msgid "" +"class ListBasedSet(collections.abc.Set):\n" +" ''' Alternate set implementation favoring space over speed\n" +" and not requiring the set elements to be hashable. '''\n" +" def __init__(self, iterable):\n" +" self.elements = lst = []\n" +" for value in iterable:\n" +" if value not in lst:\n" +" lst.append(value)\n" +"\n" +" def __iter__(self):\n" +" return iter(self.elements)\n" +"\n" +" def __contains__(self, value):\n" +" return value in self.elements\n" +"\n" +" def __len__(self):\n" +" return len(self.elements)\n" +"\n" +"s1 = ListBasedSet('abcdef')\n" +"s2 = ListBasedSet('defghi')\n" +"overlap = s1 & s2 # The __and__() method is supported " +"automatically" +msgstr "" + +#: ../../library/collections.abc.rst:417 msgid "Notes on using :class:`Set` and :class:`MutableSet` as a mixin:" msgstr "" -#: ../../library/collections.abc.rst:406 +#: ../../library/collections.abc.rst:420 msgid "" "Since some set operations create new sets, the default mixin methods need a " "way to create new instances from an :term:`iterable`. The class constructor " @@ -627,14 +739,14 @@ msgid "" "iterable argument." msgstr "" -#: ../../library/collections.abc.rst:417 +#: ../../library/collections.abc.rst:431 msgid "" "To override the comparisons (presumably for speed, as the semantics are " "fixed), redefine :meth:`~object.__le__` and :meth:`~object.__ge__`, then the " "other operations will automatically follow suit." msgstr "" -#: ../../library/collections.abc.rst:423 +#: ../../library/collections.abc.rst:437 msgid "" "The :class:`Set` mixin provides a :meth:`!_hash` method to compute a hash " "value for the set; however, :meth:`~object.__hash__` is not defined because " @@ -643,12 +755,12 @@ msgid "" "define ``__hash__ = Set._hash``." msgstr "" -#: ../../library/collections.abc.rst:431 +#: ../../library/collections.abc.rst:445 msgid "" "`OrderedSet recipe `_ for an " "example built on :class:`MutableSet`." msgstr "" -#: ../../library/collections.abc.rst:434 +#: ../../library/collections.abc.rst:448 msgid "For more about ABCs, see the :mod:`abc` module and :pep:`3119`." msgstr "關於 ABC 的更多資訊請見 :mod:`abc` module 和 :pep:`3119`。" diff --git a/library/collections.po b/library/collections.po index 7778f02885..365c724c09 100644 --- a/library/collections.po +++ b/library/collections.po @@ -10,7 +10,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-06-13 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2024-01-22 21:42+0800\n" "Last-Translator: Matt Wang \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -235,12 +235,28 @@ msgid "" "the mappings last to first::" msgstr "注意,一個 :class:`ChainMap` 的疊代順序是透過由後往前掃描對映而定: ::" +#: ../../library/collections.rst:105 +msgid "" +">>> baseline = {'music': 'bach', 'art': 'rembrandt'}\n" +">>> adjustments = {'art': 'van gogh', 'opera': 'carmen'}\n" +">>> list(ChainMap(adjustments, baseline))\n" +"['music', 'art', 'opera']" +msgstr "" + #: ../../library/collections.rst:110 msgid "" "This gives the same ordering as a series of :meth:`dict.update` calls " "starting with the last mapping::" msgstr "這和呼叫 :meth:`dict.update` 結果的順序一樣是從最後一個對映開始: ::" +#: ../../library/collections.rst:113 +msgid "" +">>> combined = baseline.copy()\n" +">>> combined.update(adjustments)\n" +">>> list(combined)\n" +"['music', 'art', 'opera']" +msgstr "" + #: ../../library/collections.rst:118 msgid "Added support for ``|`` and ``|=`` operators, specified in :pep:`584`." msgstr "支援 ``|`` 和 ``|=`` 運算子,詳見 :pep:`584`。" @@ -300,6 +316,12 @@ msgstr "此章節提供了多種操作 ChainMap 的案例。" msgid "Example of simulating Python's internal lookup chain::" msgstr "模擬 Python 內部檢索鏈結的例子: ::" +#: ../../library/collections.rst:153 +msgid "" +"import builtins\n" +"pylookup = ChainMap(locals(), globals(), vars(builtins))" +msgstr "" + #: ../../library/collections.rst:156 msgid "" "Example of letting user specified command-line arguments take precedence " @@ -307,12 +329,50 @@ msgid "" "values::" msgstr "讓使用者指定的命令列引數優先於環境變數、再優先於預設值的範例: ::" +#: ../../library/collections.rst:159 +msgid "" +"import os, argparse\n" +"\n" +"defaults = {'color': 'red', 'user': 'guest'}\n" +"\n" +"parser = argparse.ArgumentParser()\n" +"parser.add_argument('-u', '--user')\n" +"parser.add_argument('-c', '--color')\n" +"namespace = parser.parse_args()\n" +"command_line_args = {k: v for k, v in vars(namespace).items() if v is not " +"None}\n" +"\n" +"combined = ChainMap(command_line_args, os.environ, defaults)\n" +"print(combined['color'])\n" +"print(combined['user'])" +msgstr "" + #: ../../library/collections.rst:173 msgid "" "Example patterns for using the :class:`ChainMap` class to simulate nested " "contexts::" msgstr "用 :class:`ChainMap` 類別模擬巢狀上下文的範例模式: ::" +#: ../../library/collections.rst:176 +msgid "" +"c = ChainMap() # Create root context\n" +"d = c.new_child() # Create nested child context\n" +"e = c.new_child() # Child of c, independent from d\n" +"e.maps[0] # Current context dictionary -- like Python's " +"locals()\n" +"e.maps[-1] # Root context -- like Python's globals()\n" +"e.parents # Enclosing context chain -- like Python's nonlocals\n" +"\n" +"d['x'] = 1 # Set value in current context\n" +"d['x'] # Get first key in the chain of contexts\n" +"del d['x'] # Delete from current context\n" +"list(d) # All nested values\n" +"k in d # Check all nested values\n" +"len(d) # Number of nested values\n" +"d.items() # All nested items\n" +"dict(d) # Flatten into a regular dictionary" +msgstr "" + #: ../../library/collections.rst:192 msgid "" "The :class:`ChainMap` class only makes updates (writes and deletions) to the " @@ -323,6 +383,34 @@ msgstr "" ":class:`ChainMap` 類別只對鏈結中第一個對映來做寫入或刪除,但檢索則會掃過整個" "鏈結。但如果需要對更深層的鍵寫入或刪除,透過定義一個子類別來實作也不困難: ::" +#: ../../library/collections.rst:197 +msgid "" +"class DeepChainMap(ChainMap):\n" +" 'Variant of ChainMap that allows direct updates to inner scopes'\n" +"\n" +" def __setitem__(self, key, value):\n" +" for mapping in self.maps:\n" +" if key in mapping:\n" +" mapping[key] = value\n" +" return\n" +" self.maps[0][key] = value\n" +"\n" +" def __delitem__(self, key):\n" +" for mapping in self.maps:\n" +" if key in mapping:\n" +" del mapping[key]\n" +" return\n" +" raise KeyError(key)\n" +"\n" +">>> d = DeepChainMap({'zebra': 'black'}, {'elephant': 'blue'}, {'lion': " +"'yellow'})\n" +">>> d['lion'] = 'orange' # update an existing key two levels down\n" +">>> d['snake'] = 'red' # new keys get added to the topmost dict\n" +">>> del d['elephant'] # remove an existing key one level down\n" +">>> d # display result\n" +"DeepChainMap({'zebra': 'black', 'snake': 'red'}, {}, {'lion': 'orange'})" +msgstr "" + #: ../../library/collections.rst:223 msgid ":class:`Counter` objects" msgstr ":class:`Counter` 物件" @@ -333,6 +421,24 @@ msgid "" "example::" msgstr "提供一個支援方便且快速計數的計數器工具,例如: ::" +#: ../../library/collections.rst:228 +msgid "" +">>> # Tally occurrences of words in a list\n" +">>> cnt = Counter()\n" +">>> for word in ['red', 'blue', 'red', 'green', 'blue', 'blue']:\n" +"... cnt[word] += 1\n" +"...\n" +">>> cnt\n" +"Counter({'blue': 3, 'red': 2, 'green': 1})\n" +"\n" +">>> # Find the ten most common words in Hamlet\n" +">>> import re\n" +">>> words = re.findall(r'\\w+', open('hamlet.txt').read().lower())\n" +">>> Counter(words).most_common(10)\n" +"[('the', 1143), ('and', 966), ('to', 762), ('of', 669), ('i', 631),\n" +" ('you', 554), ('a', 546), ('my', 514), ('hamlet', 471), ('in', 451)]" +msgstr "" + #: ../../library/collections.rst:245 msgid "" "A :class:`Counter` is a :class:`dict` subclass for counting :term:`hashable` " @@ -475,6 +581,19 @@ msgstr "" msgid "Common patterns for working with :class:`Counter` objects::" msgstr "使用 :class:`Counter` 物件的常見使用模式: ::" +#: ../../library/collections.rst:356 +msgid "" +"c.total() # total of all counts\n" +"c.clear() # reset all counts\n" +"list(c) # list unique elements\n" +"set(c) # convert to a set\n" +"dict(c) # convert to a regular dictionary\n" +"c.items() # convert to a list of (elem, cnt) pairs\n" +"Counter(dict(list_of_pairs)) # convert from a list of (elem, cnt) pairs\n" +"c.most_common()[:-n-1:-1] # n least common elements\n" +"+c # remove zero and negative counts" +msgstr "" + #: ../../library/collections.rst:366 msgid "" "Several mathematical operations are provided for combining :class:`Counter` " @@ -491,6 +610,24 @@ msgstr "" "含性運算則會比較對應的計數。每一個操作都可以接受輸入帶有正負號的計數,但輸出" "的 Counter 則會將擁有小於或等於 0 計數的元素剔除。" +#: ../../library/collections.rst:374 +msgid "" +">>> c = Counter(a=3, b=1)\n" +">>> d = Counter(a=1, b=2)\n" +">>> c + d # add two counters together: c[x] + d[x]\n" +"Counter({'a': 4, 'b': 3})\n" +">>> c - d # subtract (keeping only positive counts)\n" +"Counter({'a': 2})\n" +">>> c & d # intersection: min(c[x], d[x])\n" +"Counter({'a': 1, 'b': 1})\n" +">>> c | d # union: max(c[x], d[x])\n" +"Counter({'a': 3, 'b': 2})\n" +">>> c == d # equality: c[x] == d[x]\n" +"False\n" +">>> c <= d # inclusion: c[x] <= d[x]\n" +"False" +msgstr "" + #: ../../library/collections.rst:391 msgid "" "Unary addition and subtraction are shortcuts for adding an empty counter or " @@ -595,6 +732,11 @@ msgstr "" "若要根據給定的元素集合來列舉出所有不重複且擁有指定元素數量的 multiset,請見 :" "func:`itertools.combinations_with_replacement`: ::" +#: ../../library/collections.rst:447 +msgid "" +"map(Counter, combinations_with_replacement('ABC', 2)) # --> AA AB AC BB BC CC" +msgstr "" + #: ../../library/collections.rst:451 msgid ":class:`deque` objects" msgstr ":class:`deque` 物件" @@ -783,6 +925,62 @@ msgstr "" msgid "Example:" msgstr "範例:" +#: ../../library/collections.rst:596 +msgid "" +">>> from collections import deque\n" +">>> d = deque('ghi') # make a new deque with three items\n" +">>> for elem in d: # iterate over the deque's elements\n" +"... print(elem.upper())\n" +"G\n" +"H\n" +"I\n" +"\n" +">>> d.append('j') # add a new entry to the right side\n" +">>> d.appendleft('f') # add a new entry to the left side\n" +">>> d # show the representation of the deque\n" +"deque(['f', 'g', 'h', 'i', 'j'])\n" +"\n" +">>> d.pop() # return and remove the rightmost item\n" +"'j'\n" +">>> d.popleft() # return and remove the leftmost item\n" +"'f'\n" +">>> list(d) # list the contents of the deque\n" +"['g', 'h', 'i']\n" +">>> d[0] # peek at leftmost item\n" +"'g'\n" +">>> d[-1] # peek at rightmost item\n" +"'i'\n" +"\n" +">>> list(reversed(d)) # list the contents of a deque in " +"reverse\n" +"['i', 'h', 'g']\n" +">>> 'h' in d # search the deque\n" +"True\n" +">>> d.extend('jkl') # add multiple elements at once\n" +">>> d\n" +"deque(['g', 'h', 'i', 'j', 'k', 'l'])\n" +">>> d.rotate(1) # right rotation\n" +">>> d\n" +"deque(['l', 'g', 'h', 'i', 'j', 'k'])\n" +">>> d.rotate(-1) # left rotation\n" +">>> d\n" +"deque(['g', 'h', 'i', 'j', 'k', 'l'])\n" +"\n" +">>> deque(reversed(d)) # make a new deque in reverse order\n" +"deque(['l', 'k', 'j', 'i', 'h', 'g'])\n" +">>> d.clear() # empty the deque\n" +">>> d.pop() # cannot pop from an empty deque\n" +"Traceback (most recent call last):\n" +" File \"\", line 1, in -toplevel-\n" +" d.pop()\n" +"IndexError: pop from an empty deque\n" +"\n" +">>> d.extendleft('abc') # extendleft() reverses the input " +"order\n" +">>> d\n" +"deque(['c', 'b', 'a'])" +msgstr "" + #: ../../library/collections.rst:651 msgid ":class:`deque` Recipes" msgstr ":class:`deque` 用法" @@ -797,12 +995,35 @@ msgid "" "in Unix::" msgstr "被限制長度的 deque 功能類似 Unix 中的 ``tail`` filter: ::" +#: ../../library/collections.rst:658 +msgid "" +"def tail(filename, n=10):\n" +" 'Return the last n lines of a file'\n" +" with open(filename) as f:\n" +" return deque(f, n)" +msgstr "" + #: ../../library/collections.rst:663 msgid "" "Another approach to using deques is to maintain a sequence of recently added " "elements by appending to the right and popping to the left::" msgstr "另一用法是透過從右邊加入、從左邊移除來維護最近加入元素的 list: ::" +#: ../../library/collections.rst:666 +msgid "" +"def moving_average(iterable, n=3):\n" +" # moving_average([40, 30, 50, 46, 39, 44]) --> 40.0 42.0 45.0 43.0\n" +" # https://en.wikipedia.org/wiki/Moving_average\n" +" it = iter(iterable)\n" +" d = deque(itertools.islice(it, n-1))\n" +" d.appendleft(0)\n" +" s = sum(d)\n" +" for elem in it:\n" +" s += elem - d.popleft()\n" +" d.append(elem)\n" +" yield s / n" +msgstr "" + #: ../../library/collections.rst:678 msgid "" "A `round-robin scheduler A D E B F C\"\n" +" iterators = deque(map(iter, iterables))\n" +" while iterators:\n" +" try:\n" +" while True:\n" +" yield next(iterators[0])\n" +" iterators.rotate(-1)\n" +" except StopIteration:\n" +" # Remove an exhausted iterator.\n" +" iterators.popleft()" +msgstr "" + #: ../../library/collections.rst:697 msgid "" "The :meth:`~deque.rotate` method provides a way to implement :class:`deque` " @@ -828,6 +1064,14 @@ msgstr "" "例來說,用純 Python 實作 ``del d[n]`` 需要用 ``rotate()`` 來定位要被移除的元" "素: ::" +#: ../../library/collections.rst:701 +msgid "" +"def delete_nth(d, n):\n" +" d.rotate(-n)\n" +" d.popleft()\n" +" d.rotate(n)" +msgstr "" + #: ../../library/collections.rst:706 msgid "" "To implement :class:`deque` slicing, use a similar approach applying :meth:" @@ -1128,6 +1372,23 @@ msgid "" "Added the *defaults* parameter and the :attr:`_field_defaults` attribute." msgstr "新增 *defaults* 參數和 :attr:`_field_defaults` 屬性。" +#: ../../library/collections.rst:903 +msgid "" +">>> # Basic example\n" +">>> Point = namedtuple('Point', ['x', 'y'])\n" +">>> p = Point(11, y=22) # instantiate with positional or keyword " +"arguments\n" +">>> p[0] + p[1] # indexable like the plain tuple (11, 22)\n" +"33\n" +">>> x, y = p # unpack like a regular tuple\n" +">>> x, y\n" +"(11, 22)\n" +">>> p.x + p.y # fields also accessible by name\n" +"33\n" +">>> p # readable __repr__ with a name=value style\n" +"Point(x=11, y=22)" +msgstr "" + #: ../../library/collections.rst:919 msgid "" "Named tuples are especially useful for assigning field names to result " @@ -1136,6 +1397,25 @@ msgstr "" "Named tuple 在賦予欄位名稱於 :mod:`csv` 或 :mod:`sqlite3` 模組回傳之 tuple 時" "相當有用: ::" +#: ../../library/collections.rst:922 +msgid "" +"EmployeeRecord = namedtuple('EmployeeRecord', 'name, age, title, department, " +"paygrade')\n" +"\n" +"import csv\n" +"for emp in map(EmployeeRecord._make, csv.reader(open(\"employees.csv\", " +"\"rb\"))):\n" +" print(emp.name, emp.title)\n" +"\n" +"import sqlite3\n" +"conn = sqlite3.connect('/companydata')\n" +"cursor = conn.cursor()\n" +"cursor.execute('SELECT name, age, title, department, paygrade FROM " +"employees')\n" +"for emp in map(EmployeeRecord._make, cursor.fetchall()):\n" +" print(emp.name, emp.title)" +msgstr "" + #: ../../library/collections.rst:935 msgid "" "In addition to the methods inherited from tuples, named tuples support three " @@ -1150,12 +1430,26 @@ msgid "" "Class method that makes a new instance from an existing sequence or iterable." msgstr "從已存在的序列或可疊代物件建立一個新實例的類別方法。" +#: ../../library/collections.rst:943 +msgid "" +">>> t = [11, 22]\n" +">>> Point._make(t)\n" +"Point(x=11, y=22)" +msgstr "" + #: ../../library/collections.rst:951 msgid "" "Return a new :class:`dict` which maps field names to their corresponding " "values:" msgstr "回傳一個將欄位名稱對映至對應值的 :class:`dict`:" +#: ../../library/collections.rst:954 +msgid "" +">>> p = Point(x=11, y=22)\n" +">>> p._asdict()\n" +"{'x': 11, 'y': 22}" +msgstr "" + #: ../../library/collections.rst:960 msgid "Returns an :class:`OrderedDict` instead of a regular :class:`dict`." msgstr "回傳一個 :class:`OrderedDict` 而非 :class:`dict`。" @@ -1177,6 +1471,17 @@ msgid "" "values::" msgstr "回傳一個新的 named tuple 實例,並將指定欄位替換為新的值: ::" +#: ../../library/collections.rst:975 +msgid "" +">>> p = Point(x=11, y=22)\n" +">>> p._replace(x=33)\n" +"Point(x=33, y=22)\n" +"\n" +">>> for partnum, record in inventory.items():\n" +"... inventory[partnum] = record._replace(price=newprices[partnum], " +"timestamp=time.now())" +msgstr "" + #: ../../library/collections.rst:984 msgid "" "Tuple of strings listing the field names. Useful for introspection and for " @@ -1185,10 +1490,30 @@ msgstr "" "列出 tuple 欄位名稱的字串,用於自我檢查或是從現有 named tuple 建立一個新的 " "named tuple 型別。" +#: ../../library/collections.rst:987 +msgid "" +">>> p._fields # view the field names\n" +"('x', 'y')\n" +"\n" +">>> Color = namedtuple('Color', 'red green blue')\n" +">>> Pixel = namedtuple('Pixel', Point._fields + Color._fields)\n" +">>> Pixel(11, 22, 128, 255, 0)\n" +"Pixel(x=11, y=22, red=128, green=255, blue=0)" +msgstr "" + #: ../../library/collections.rst:999 msgid "Dictionary mapping field names to default values." msgstr "將欄位名稱對映至預設值的字典。" +#: ../../library/collections.rst:1001 +msgid "" +">>> Account = namedtuple('Account', ['type', 'balance'], defaults=[0])\n" +">>> Account._field_defaults\n" +"{'balance': 0}\n" +">>> Account('premium')\n" +"Account(type='premium', balance=0)" +msgstr "" + #: ../../library/collections.rst:1009 msgid "" "To retrieve a field whose name is stored in a string, use the :func:" @@ -1212,6 +1537,23 @@ msgstr "" "因為一個 named tuple 是一個常規的 Python 類別,我們可以很容易的透過子類別來新" "增或更改功能,以下是如何新增一個計算得到的欄位和固定寬度的輸出列印格式:" +#: ../../library/collections.rst:1026 +msgid "" +">>> class Point(namedtuple('Point', ['x', 'y'])):\n" +"... __slots__ = ()\n" +"... @property\n" +"... def hypot(self):\n" +"... return (self.x ** 2 + self.y ** 2) ** 0.5\n" +"... def __str__(self):\n" +"... return 'Point: x=%6.3f y=%6.3f hypot=%6.3f' % (self.x, self.y, " +"self.hypot)\n" +"\n" +">>> for p in Point(3, 4), Point(14, 5/7):\n" +"... print(p)\n" +"Point: x= 3.000 y= 4.000 hypot= 5.000\n" +"Point: x=14.000 y= 0.714 hypot=14.018" +msgstr "" + #: ../../library/collections.rst:1041 msgid "" "The subclass shown above sets ``__slots__`` to an empty tuple. This helps " @@ -1249,6 +1591,14 @@ msgstr "" "關於為 named tuple 新增型別提示的方法,請參閱 :class:`typing.NamedTuple`,它" "運用 :keyword:`class` 關鍵字以提供了一個簡潔的表示法: ::" +#: ../../library/collections.rst:1067 +msgid "" +"class Component(NamedTuple):\n" +" part_number: int\n" +" weight: float\n" +" description: Optional[str] = None" +msgstr "" + #: ../../library/collections.rst:1072 msgid "" "See :meth:`types.SimpleNamespace` for a mutable namespace based on an " @@ -1410,6 +1760,17 @@ msgstr "" "設值)則將元素移至右端;如果 *last* 為假值則將元素移至左端。如果 *key* 不存在" "則會引發 :exc:`KeyError`:" +#: ../../library/collections.rst:1151 +msgid "" +">>> d = OrderedDict.fromkeys('abcde')\n" +">>> d.move_to_end('b')\n" +">>> ''.join(d)\n" +"'acdeb'\n" +">>> d.move_to_end('b', last=False)\n" +">>> ''.join(d)\n" +"'bacde'" +msgstr "" + #: ../../library/collections.rst:1163 msgid "" "In addition to the usual mapping methods, ordered dictionaries also support " @@ -1462,6 +1823,16 @@ msgstr "" "建立一個能夠記住鍵\\ *最後*\\ 插入順序的 ordered dictionary 變體很簡單。如果" "新條目覆蓋了現有條目,則原本插入位置會被更改並移動至末端: ::" +#: ../../library/collections.rst:1194 +msgid "" +"class LastUpdatedOrderedDict(OrderedDict):\n" +" 'Store items in the order the keys were last added'\n" +"\n" +" def __setitem__(self, key, value):\n" +" super().__setitem__(key, value)\n" +" self.move_to_end(key)" +msgstr "" + #: ../../library/collections.rst:1201 msgid "" "An :class:`OrderedDict` would also be useful for implementing variants of :" @@ -1470,6 +1841,71 @@ msgstr "" ":class:`OrderedDict` 在實現一個 :func:`functools.lru_cache` 的變形版本時也非" "常有用:" +#: ../../library/collections.rst:1204 +msgid "" +"from collections import OrderedDict\n" +"from time import time\n" +"\n" +"class TimeBoundedLRU:\n" +" \"LRU Cache that invalidates and refreshes old entries.\"\n" +"\n" +" def __init__(self, func, maxsize=128, maxage=30):\n" +" self.cache = OrderedDict() # { args : (timestamp, result)}\n" +" self.func = func\n" +" self.maxsize = maxsize\n" +" self.maxage = maxage\n" +"\n" +" def __call__(self, *args):\n" +" if args in self.cache:\n" +" self.cache.move_to_end(args)\n" +" timestamp, result = self.cache[args]\n" +" if time() - timestamp <= self.maxage:\n" +" return result\n" +" result = self.func(*args)\n" +" self.cache[args] = time(), result\n" +" if len(self.cache) > self.maxsize:\n" +" self.cache.popitem(0)\n" +" return result" +msgstr "" + +#: ../../library/collections.rst:1231 +msgid "" +"class MultiHitLRUCache:\n" +" \"\"\" LRU cache that defers caching a result until\n" +" it has been requested multiple times.\n" +"\n" +" To avoid flushing the LRU cache with one-time requests,\n" +" we don't cache until a request has been made more than once.\n" +"\n" +" \"\"\"\n" +"\n" +" def __init__(self, func, maxsize=128, maxrequests=4096, cache_after=1):\n" +" self.requests = OrderedDict() # { uncached_key : request_count }\n" +" self.cache = OrderedDict() # { cached_key : function_result }\n" +" self.func = func\n" +" self.maxrequests = maxrequests # max number of uncached requests\n" +" self.maxsize = maxsize # max number of stored return " +"values\n" +" self.cache_after = cache_after\n" +"\n" +" def __call__(self, *args):\n" +" if args in self.cache:\n" +" self.cache.move_to_end(args)\n" +" return self.cache[args]\n" +" result = self.func(*args)\n" +" self.requests[args] = self.requests.get(args, 0) + 1\n" +" if self.requests[args] <= self.cache_after:\n" +" self.requests.move_to_end(args)\n" +" if len(self.requests) > self.maxrequests:\n" +" self.requests.popitem(0)\n" +" else:\n" +" self.requests.pop(args, None)\n" +" self.cache[args] = result\n" +" if len(self.cache) > self.maxsize:\n" +" self.cache.popitem(0)\n" +" return result" +msgstr "" + #: ../../library/collections.rst:1300 msgid ":class:`UserDict` objects" msgstr ":class:`UserDict` 物件" diff --git a/library/colorsys.po b/library/colorsys.po index cf65fe4766..c71dd7f8e1 100644 --- a/library/colorsys.po +++ b/library/colorsys.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-07-20 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2022-02-15 20:58+0800\n" "Last-Translator: Matt Wang \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -84,3 +84,12 @@ msgstr "將顏色自 HSV 座標轉換至 RGB 座標。" #: ../../library/colorsys.rst:59 msgid "Example::" msgstr "範例: ::" + +#: ../../library/colorsys.rst:61 +msgid "" +">>> import colorsys\n" +">>> colorsys.rgb_to_hsv(0.2, 0.4, 0.4)\n" +"(0.5, 0.5, 0.4)\n" +">>> colorsys.hsv_to_rgb(0.5, 0.5, 0.4)\n" +"(0.2, 0.4, 0.4)" +msgstr "" diff --git a/library/compileall.po b/library/compileall.po index a89bfd4561..951b0a0032 100644 --- a/library/compileall.po +++ b/library/compileall.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-08-30 18:24+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2018-05-23 14:41+0000\n" "Last-Translator: Adrian Liaw \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -390,6 +390,21 @@ msgid "" "subdirectory and all its subdirectories::" msgstr "" +#: ../../library/compileall.rst:326 +msgid "" +"import compileall\n" +"\n" +"compileall.compile_dir('Lib/', force=True)\n" +"\n" +"# Perform same compilation, excluding files in .svn directories.\n" +"import re\n" +"compileall.compile_dir('Lib/', rx=re.compile(r'[/\\\\][.]svn'), force=True)\n" +"\n" +"# pathlib.Path objects can also be used.\n" +"import pathlib\n" +"compileall.compile_dir(pathlib.Path('Lib/'), force=True)" +msgstr "" + #: ../../library/compileall.rst:340 msgid "Module :mod:`py_compile`" msgstr ":mod:`py_compile` 模組" diff --git a/library/concurrent.futures.po b/library/concurrent.futures.po index d3bb977047..0b80aa4866 100644 --- a/library/concurrent.futures.po +++ b/library/concurrent.futures.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-05-09 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2023-01-24 03:33+0800\n" "Last-Translator: Matt Wang \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -86,6 +86,13 @@ msgstr "" "\n" "::" +#: ../../library/concurrent.futures.rst:38 +msgid "" +"with ThreadPoolExecutor(max_workers=1) as executor:\n" +" future = executor.submit(pow, 323, 1235)\n" +" print(future.result())" +msgstr "" + #: ../../library/concurrent.futures.rst:44 msgid "Similar to :func:`map(fn, *iterables) ` except:" msgstr "類似於 :func:`map(fn, *iterables) `,除了:" @@ -194,6 +201,16 @@ msgstr "" "閉 :class:`Executor`\\(如同呼叫 :meth:`Executor.shutdown` 時 *wait* 被設定" "為 ``True`` 般等待): ::" +#: ../../library/concurrent.futures.rst:100 +msgid "" +"import shutil\n" +"with ThreadPoolExecutor(max_workers=4) as e:\n" +" e.submit(shutil.copy, 'src1.txt', 'dest1.txt')\n" +" e.submit(shutil.copy, 'src2.txt', 'dest2.txt')\n" +" e.submit(shutil.copy, 'src3.txt', 'dest3.txt')\n" +" e.submit(shutil.copy, 'src4.txt', 'dest4.txt')" +msgstr "" + #: ../../library/concurrent.futures.rst:107 msgid "Added *cancel_futures*." msgstr "新增 *cancel_futures*。" @@ -218,10 +235,41 @@ msgstr "" "當與 :class:`Future` 關聯的可呼叫物件等待另一個 :class:`Future` 的結果時,可" "能會發生死鎖 (deadlock)。例如: ::" +#: ../../library/concurrent.futures.rst:120 +msgid "" +"import time\n" +"def wait_on_b():\n" +" time.sleep(5)\n" +" print(b.result()) # b will never complete because it is waiting on a.\n" +" return 5\n" +"\n" +"def wait_on_a():\n" +" time.sleep(5)\n" +" print(a.result()) # a will never complete because it is waiting on b.\n" +" return 6\n" +"\n" +"\n" +"executor = ThreadPoolExecutor(max_workers=2)\n" +"a = executor.submit(wait_on_b)\n" +"b = executor.submit(wait_on_a)" +msgstr "" + #: ../../library/concurrent.futures.rst:136 msgid "And::" msgstr "和: ::" +#: ../../library/concurrent.futures.rst:138 +msgid "" +"def wait_on_future():\n" +" f = executor.submit(pow, 5, 2)\n" +" # This will never complete because there is only one worker thread and\n" +" # it is executing this function.\n" +" print(f.result())\n" +"\n" +"executor = ThreadPoolExecutor(max_workers=1)\n" +"executor.submit(wait_on_future)" +msgstr "" + #: ../../library/concurrent.futures.rst:150 msgid "" "An :class:`Executor` subclass that uses a pool of at most *max_workers* " @@ -308,6 +356,37 @@ msgstr "" msgid "ThreadPoolExecutor Example" msgstr "ThreadPoolExecutor 範例" +#: ../../library/concurrent.futures.rst:198 +msgid "" +"import concurrent.futures\n" +"import urllib.request\n" +"\n" +"URLS = ['http://www.foxnews.com/',\n" +" 'http://www.cnn.com/',\n" +" 'http://europe.wsj.com/',\n" +" 'http://www.bbc.co.uk/',\n" +" 'http://nonexistant-subdomain.python.org/']\n" +"\n" +"# Retrieve a single page and report the URL and contents\n" +"def load_url(url, timeout):\n" +" with urllib.request.urlopen(url, timeout=timeout) as conn:\n" +" return conn.read()\n" +"\n" +"# We can use a with statement to ensure threads are cleaned up promptly\n" +"with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:\n" +" # Start the load operations and mark each future with its URL\n" +" future_to_url = {executor.submit(load_url, url, 60): url for url in " +"URLS}\n" +" for future in concurrent.futures.as_completed(future_to_url):\n" +" url = future_to_url[future]\n" +" try:\n" +" data = future.result()\n" +" except Exception as exc:\n" +" print('%r generated an exception: %s' % (url, exc))\n" +" else:\n" +" print('%r page is %d bytes' % (url, len(data)))" +msgstr "" + #: ../../library/concurrent.futures.rst:227 msgid "ProcessPoolExecutor" msgstr "ProcessPoolExecutor" @@ -453,6 +532,42 @@ msgstr "" msgid "ProcessPoolExecutor Example" msgstr "ProcessPoolExecutor 範例" +#: ../../library/concurrent.futures.rst:311 +msgid "" +"import concurrent.futures\n" +"import math\n" +"\n" +"PRIMES = [\n" +" 112272535095293,\n" +" 112582705942171,\n" +" 112272535095293,\n" +" 115280095190773,\n" +" 115797848077099,\n" +" 1099726899285419]\n" +"\n" +"def is_prime(n):\n" +" if n < 2:\n" +" return False\n" +" if n == 2:\n" +" return True\n" +" if n % 2 == 0:\n" +" return False\n" +"\n" +" sqrt_n = int(math.floor(math.sqrt(n)))\n" +" for i in range(3, sqrt_n + 1, 2):\n" +" if n % i == 0:\n" +" return False\n" +" return True\n" +"\n" +"def main():\n" +" with concurrent.futures.ProcessPoolExecutor() as executor:\n" +" for number, prime in zip(PRIMES, executor.map(is_prime, PRIMES)):\n" +" print('%d is prime: %s' % (number, prime))\n" +"\n" +"if __name__ == '__main__':\n" +" main()" +msgstr "" + #: ../../library/concurrent.futures.rst:346 msgid "Future Objects" msgstr "Future 物件" diff --git a/library/configparser.po b/library/configparser.po index b571b98740..0b5f73d8b5 100644 --- a/library/configparser.po +++ b/library/configparser.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-07-20 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2018-05-23 14:41+0000\n" "Last-Translator: Adrian Liaw \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -77,6 +77,22 @@ msgstr "" msgid "Let's take a very basic configuration file that looks like this:" msgstr "" +#: ../../library/configparser.rst:64 +msgid "" +"[DEFAULT]\n" +"ServerAliveInterval = 45\n" +"Compression = yes\n" +"CompressionLevel = 9\n" +"ForwardX11 = yes\n" +"\n" +"[forge.example]\n" +"User = hg\n" +"\n" +"[topsecret.server.example]\n" +"Port = 50022\n" +"ForwardX11 = no" +msgstr "" + #: ../../library/configparser.rst:79 msgid "" "The structure of INI files is described `in the following section " @@ -86,6 +102,25 @@ msgid "" "configuration file programmatically." msgstr "" +#: ../../library/configparser.rst:85 +msgid "" +">>> import configparser\n" +">>> config = configparser.ConfigParser()\n" +">>> config['DEFAULT'] = {'ServerAliveInterval': '45',\n" +"... 'Compression': 'yes',\n" +"... 'CompressionLevel': '9'}\n" +">>> config['forge.example'] = {}\n" +">>> config['forge.example']['User'] = 'hg'\n" +">>> config['topsecret.server.example'] = {}\n" +">>> topsecret = config['topsecret.server.example']\n" +">>> topsecret['Port'] = '50022' # mutates the parser\n" +">>> topsecret['ForwardX11'] = 'no' # same here\n" +">>> config['DEFAULT']['ForwardX11'] = 'yes'\n" +">>> with open('example.ini', 'w') as configfile:\n" +"... config.write(configfile)\n" +"..." +msgstr "" + #: ../../library/configparser.rst:103 msgid "" "As you can see, we can treat a config parser much like a dictionary. There " @@ -99,6 +134,39 @@ msgid "" "and explore the data it holds." msgstr "" +#: ../../library/configparser.rst:110 +msgid "" +">>> config = configparser.ConfigParser()\n" +">>> config.sections()\n" +"[]\n" +">>> config.read('example.ini')\n" +"['example.ini']\n" +">>> config.sections()\n" +"['forge.example', 'topsecret.server.example']\n" +">>> 'forge.example' in config\n" +"True\n" +">>> 'python.org' in config\n" +"False\n" +">>> config['forge.example']['User']\n" +"'hg'\n" +">>> config['DEFAULT']['Compression']\n" +"'yes'\n" +">>> topsecret = config['topsecret.server.example']\n" +">>> topsecret['ForwardX11']\n" +"'no'\n" +">>> topsecret['Port']\n" +"'50022'\n" +">>> for key in config['forge.example']: \n" +"... print(key)\n" +"user\n" +"compressionlevel\n" +"serveraliveinterval\n" +"compression\n" +"forwardx11\n" +">>> config['forge.example']['ForwardX11']\n" +"'yes'" +msgstr "" + #: ../../library/configparser.rst:142 msgid "" "As we can see above, the API is pretty straightforward. The only bit of " @@ -117,6 +185,26 @@ msgid "" "``example.ini`` file." msgstr "" +#: ../../library/configparser.rst:154 ../../library/configparser.rst:973 +msgid "" +"[DEFAULT]\n" +"ServerAliveInterval = -1" +msgstr "" + +#: ../../library/configparser.rst:159 ../../library/configparser.rst:978 +msgid "" +">>> config_override = configparser.ConfigParser()\n" +">>> config_override['DEFAULT'] = {'ServerAliveInterval': '-1'}\n" +">>> with open('override.ini', 'w') as configfile:\n" +"... config_override.write(configfile)\n" +"...\n" +">>> config_override = configparser.ConfigParser()\n" +">>> config_override.read(['example.ini', 'override.ini'])\n" +"['example.ini', 'override.ini']\n" +">>> print(config_override.get('DEFAULT', 'ServerAliveInterval'))\n" +"-1" +msgstr "" + #: ../../library/configparser.rst:173 msgid "" "This behaviour is equivalent to a :meth:`ConfigParser.read` call with " @@ -134,6 +222,14 @@ msgid "" "other datatypes, you should convert on your own:" msgstr "" +#: ../../library/configparser.rst:184 +msgid "" +">>> int(topsecret['Port'])\n" +"50022\n" +">>> float(topsecret['CompressionLevel'])\n" +"9.0" +msgstr "" + #: ../../library/configparser.rst:191 msgid "" "Since this task is so common, config parsers provide a range of handy getter " @@ -145,6 +241,16 @@ msgid "" "``'true'``/``'false'`` and ``'1'``/``'0'`` [1]_. For example:" msgstr "" +#: ../../library/configparser.rst:199 +msgid "" +">>> topsecret.getboolean('ForwardX11')\n" +"False\n" +">>> config['forge.example'].getboolean('ForwardX11')\n" +"True\n" +">>> config.getboolean('forge.example', 'Compression')\n" +"True" +msgstr "" + #: ../../library/configparser.rst:208 msgid "" "Apart from :meth:`~ConfigParser.getboolean`, config parsers also provide " @@ -163,6 +269,17 @@ msgid "" "method to provide fallback values:" msgstr "" +#: ../../library/configparser.rst:219 +msgid "" +">>> topsecret.get('Port')\n" +"'50022'\n" +">>> topsecret.get('CompressionLevel')\n" +"'9'\n" +">>> topsecret.get('Cipher')\n" +">>> topsecret.get('Cipher', '3des-cbc')\n" +"'3des-cbc'" +msgstr "" + #: ../../library/configparser.rst:229 msgid "" "Please note that default values have precedence over fallback values. For " @@ -172,6 +289,12 @@ msgid "" "specify a fallback:" msgstr "" +#: ../../library/configparser.rst:235 +msgid "" +">>> topsecret.get('CompressionLevel', '3')\n" +"'9'" +msgstr "" + #: ../../library/configparser.rst:240 msgid "" "One more thing to be aware of is that the parser-level :meth:`~ConfigParser." @@ -180,6 +303,13 @@ msgid "" "provided via the ``fallback`` keyword-only argument:" msgstr "" +#: ../../library/configparser.rst:245 +msgid "" +">>> config.get('forge.example', 'monster',\n" +"... fallback='No such things as monsters')\n" +"'No such things as monsters'" +msgstr "" + #: ../../library/configparser.rst:251 msgid "" "The same ``fallback`` argument can be used with the :meth:`~ConfigParser." @@ -187,6 +317,17 @@ msgid "" "methods, for example:" msgstr "" +#: ../../library/configparser.rst:255 +msgid "" +">>> 'BatchMode' in topsecret\n" +"False\n" +">>> topsecret.getboolean('BatchMode', fallback=True)\n" +"True\n" +">>> config['DEFAULT']['BatchMode'] = 'no'\n" +">>> topsecret.getboolean('BatchMode', fallback=True)\n" +"False" +msgstr "" + #: ../../library/configparser.rst:267 msgid "Supported INI File Structure" msgstr "" @@ -221,6 +362,51 @@ msgstr "" msgid "For example:" msgstr "" +#: ../../library/configparser.rst:288 +msgid "" +"[Simple Values]\n" +"key=value\n" +"spaces in keys=allowed\n" +"spaces in values=allowed as well\n" +"spaces around the delimiter = obviously\n" +"you can also use : to delimit keys from values\n" +"\n" +"[All Values Are Strings]\n" +"values like this: 1000000\n" +"or this: 3.14159265359\n" +"are they treated as numbers? : no\n" +"integers, floats and booleans are held as: strings\n" +"can use the API to get converted values directly: true\n" +"\n" +"[Multiline Values]\n" +"chorus: I'm a lumberjack, and I'm okay\n" +" I sleep all night and I work all day\n" +"\n" +"[No Values]\n" +"key_without_value\n" +"empty string value here =\n" +"\n" +"[You can use comments]\n" +"# like this\n" +"; or this\n" +"\n" +"# By default only in an empty line.\n" +"# Inline comments can be harmful because they prevent users\n" +"# from using the delimiting characters as parts of values.\n" +"# That being said, this can be customized.\n" +"\n" +" [Sections Can Be Indented]\n" +" can_values_be_as_well = True\n" +" does_that_mean_anything_special = False\n" +" purpose = formatting for readability\n" +" multiline_values = are\n" +" handled just fine as\n" +" long as they are indented\n" +" deeper than the first line\n" +" of a value\n" +" # Did I mention we can indent comments, too?" +msgstr "" + #: ../../library/configparser.rst:334 msgid "Interpolation of values" msgstr "" @@ -240,6 +426,19 @@ msgid "" "can be provided on initialization." msgstr "" +#: ../../library/configparser.rst:351 +msgid "" +"[Paths]\n" +"home_dir: /Users\n" +"my_dir: %(home_dir)s/lumberjack\n" +"my_pictures: %(my_dir)s/Pictures\n" +"\n" +"[Escape]\n" +"# use a %% to escape the % sign (% is the only character that needs to be " +"escaped):\n" +"gain: 80%%" +msgstr "" + #: ../../library/configparser.rst:362 msgid "" "In the example above, :class:`ConfigParser` with *interpolation* set to " @@ -273,10 +472,43 @@ msgid "" "would look like this with extended interpolation:" msgstr "" +#: ../../library/configparser.rst:387 +msgid "" +"[Paths]\n" +"home_dir: /Users\n" +"my_dir: ${home_dir}/lumberjack\n" +"my_pictures: ${my_dir}/Pictures\n" +"\n" +"[Escape]\n" +"# use a $$ to escape the $ sign ($ is the only character that needs to be " +"escaped):\n" +"cost: $$80" +msgstr "" + #: ../../library/configparser.rst:398 msgid "Values from other sections can be fetched as well:" msgstr "" +#: ../../library/configparser.rst:400 +msgid "" +"[Common]\n" +"home_dir: /Users\n" +"library_dir: /Library\n" +"system_dir: /System\n" +"macports_dir: /opt/local\n" +"\n" +"[Frameworks]\n" +"Python: 3.2\n" +"path: ${Common:system_dir}/Library/Frameworks/\n" +"\n" +"[Arthur]\n" +"nickname: Two Sheds\n" +"last_name: Jackson\n" +"my_dir: ${Common:home_dir}/twosheds\n" +"my_pictures: ${my_dir}/Pictures\n" +"python_dir: ${Frameworks:path}/Python/Versions/${Frameworks:Python}" +msgstr "" + #: ../../library/configparser.rst:420 msgid "Mapping Protocol Access" msgstr "" @@ -315,6 +547,12 @@ msgid "" "expressions return ``True``::" msgstr "" +#: ../../library/configparser.rst:445 +msgid "" +"\"a\" in parser[\"section\"]\n" +"\"A\" in parser[\"section\"]" +msgstr "" + #: ../../library/configparser.rst:448 msgid "" "All sections include ``DEFAULTSECT`` values as well which means that ``." @@ -427,6 +665,25 @@ msgid "" "of the keys will be ordered. For example:" msgstr "" +#: ../../library/configparser.rst:515 +msgid "" +">>> parser = configparser.ConfigParser()\n" +">>> parser.read_dict({'section1': {'key1': 'value1',\n" +"... 'key2': 'value2',\n" +"... 'key3': 'value3'},\n" +"... 'section2': {'keyA': 'valueA',\n" +"... 'keyB': 'valueB',\n" +"... 'keyC': 'valueC'},\n" +"... 'section3': {'foo': 'x',\n" +"... 'bar': 'y',\n" +"... 'baz': 'z'}\n" +"... })\n" +">>> parser.sections()\n" +"['section1', 'section2', 'section3']\n" +">>> [option for option in parser['section3']]\n" +"['foo', 'bar', 'baz']" +msgstr "" + #: ../../library/configparser.rst:533 msgid "*allow_no_value*, default value: ``False``" msgstr "" @@ -439,6 +696,37 @@ msgid "" "such values should be accepted:" msgstr "" +#: ../../library/configparser.rst:540 +msgid "" +">>> import configparser\n" +"\n" +">>> sample_config = \"\"\"\n" +"... [mysqld]\n" +"... user = mysql\n" +"... pid-file = /var/run/mysqld/mysqld.pid\n" +"... skip-external-locking\n" +"... old_passwords = 1\n" +"... skip-bdb\n" +"... # we don't need ACID today\n" +"... skip-innodb\n" +"... \"\"\"\n" +">>> config = configparser.ConfigParser(allow_no_value=True)\n" +">>> config.read_string(sample_config)\n" +"\n" +">>> # Settings with values are treated as before:\n" +">>> config[\"mysqld\"][\"user\"]\n" +"'mysql'\n" +"\n" +">>> # Settings without values provide None:\n" +">>> config[\"mysqld\"][\"skip-bdb\"]\n" +"\n" +">>> # Settings which aren't specified still raise an error:\n" +">>> config[\"mysqld\"][\"does-not-exist\"]\n" +"Traceback (most recent call last):\n" +" ...\n" +"KeyError: 'does-not-exist'" +msgstr "" + #: ../../library/configparser.rst:570 msgid "*delimiters*, default value: ``('=', ':')``" msgstr "" @@ -490,6 +778,48 @@ msgid "" "values is to interpolate the prefix, for example::" msgstr "" +#: ../../library/configparser.rst:601 +msgid "" +">>> from configparser import ConfigParser, ExtendedInterpolation\n" +">>> parser = ConfigParser(interpolation=ExtendedInterpolation())\n" +">>> # the default BasicInterpolation could be used as well\n" +">>> parser.read_string(\"\"\"\n" +"... [DEFAULT]\n" +"... hash = #\n" +"...\n" +"... [hashes]\n" +"... shebang =\n" +"... ${hash}!/usr/bin/env python\n" +"... ${hash} -*- coding: utf-8 -*-\n" +"...\n" +"... extensions =\n" +"... enabled_extension\n" +"... another_extension\n" +"... #disabled_by_comment\n" +"... yet_another_extension\n" +"...\n" +"... interpolation not necessary = if # is not at line start\n" +"... even in multiline values = line #1\n" +"... line #2\n" +"... line #3\n" +"... \"\"\")\n" +">>> print(parser['hashes']['shebang'])\n" +"\n" +"#!/usr/bin/env python\n" +"# -*- coding: utf-8 -*-\n" +">>> print(parser['hashes']['extensions'])\n" +"\n" +"enabled_extension\n" +"another_extension\n" +"yet_another_extension\n" +">>> print(parser['hashes']['interpolation not necessary'])\n" +"if # is not at line start\n" +">>> print(parser['hashes']['even in multiline values'])\n" +"line #1\n" +"line #2\n" +"line #3" +msgstr "" + #: ../../library/configparser.rst:640 msgid "*strict*, default value: ``True``" msgstr "" @@ -522,6 +852,15 @@ msgid "" "lose track of the file structure. Take for instance:" msgstr "" +#: ../../library/configparser.rst:660 +msgid "" +"[Section]\n" +"key = multiline\n" +" value with a gotcha\n" +"\n" +" this = is still a part of the multiline value of 'key'" +msgstr "" + #: ../../library/configparser.rst:668 msgid "" "This can be especially problematic for the user to see if she's using a " @@ -607,6 +946,19 @@ msgid "" "strings and their Boolean outcomes. For example:" msgstr "" +#: ../../library/configparser.rst:727 +msgid "" +">>> custom = configparser.ConfigParser()\n" +">>> custom['section1'] = {'funky': 'nope'}\n" +">>> custom['section1'].getboolean('funky')\n" +"Traceback (most recent call last):\n" +"...\n" +"ValueError: Not a boolean: nope\n" +">>> custom.BOOLEAN_STATES = {'sure': True, 'nope': False}\n" +">>> custom['section1'].getboolean('funky')\n" +"False" +msgstr "" + #: ../../library/configparser.rst:739 msgid "" "Other typical Boolean pairs include ``accept``/``reject`` or ``enabled``/" @@ -621,6 +973,30 @@ msgid "" "method if that's unsuitable. For example:" msgstr "" +#: ../../library/configparser.rst:751 +msgid "" +">>> config = \"\"\"\n" +"... [Section1]\n" +"... Key = Value\n" +"...\n" +"... [Section2]\n" +"... AnotherKey = Value\n" +"... \"\"\"\n" +">>> typical = configparser.ConfigParser()\n" +">>> typical.read_string(config)\n" +">>> list(typical['Section1'].keys())\n" +"['key']\n" +">>> list(typical['Section2'].keys())\n" +"['anotherkey']\n" +">>> custom = configparser.RawConfigParser()\n" +">>> custom.optionxform = lambda option: option\n" +">>> custom.read_string(config)\n" +">>> list(custom['Section1'].keys())\n" +"['Key']\n" +">>> list(custom['Section2'].keys())\n" +"['AnotherKey']" +msgstr "" + #: ../../library/configparser.rst:775 msgid "" "The optionxform function transforms option names to a canonical form. This " @@ -637,6 +1013,27 @@ msgid "" "example:" msgstr "" +#: ../../library/configparser.rst:788 +msgid "" +">>> import re\n" +">>> config = \"\"\"\n" +"... [Section 1]\n" +"... option = value\n" +"...\n" +"... [ Section 2 ]\n" +"... another = val\n" +"... \"\"\"\n" +">>> typical = configparser.ConfigParser()\n" +">>> typical.read_string(config)\n" +">>> typical.sections()\n" +"['Section 1', ' Section 2 ']\n" +">>> custom = configparser.ConfigParser()\n" +">>> custom.SECTCRE = re.compile(r\"\\[ *(?P

[^]]+?) *\\]\")\n" +">>> custom.read_string(config)\n" +">>> custom.sections()\n" +"['Section 1', 'Section 2']" +msgstr "" + #: ../../library/configparser.rst:810 msgid "" "While ConfigParser objects also use an ``OPTCRE`` attribute for recognizing " @@ -661,20 +1058,112 @@ msgstr "" msgid "An example of writing to a configuration file::" msgstr "" +#: ../../library/configparser.rst:826 +msgid "" +"import configparser\n" +"\n" +"config = configparser.RawConfigParser()\n" +"\n" +"# Please note that using RawConfigParser's set functions, you can assign\n" +"# non-string values to keys internally, but will receive an error when\n" +"# attempting to write to a file or when you get it in non-raw mode. Setting\n" +"# values using the mapping protocol or ConfigParser's set() does not allow\n" +"# such assignments to take place.\n" +"config.add_section('Section1')\n" +"config.set('Section1', 'an_int', '15')\n" +"config.set('Section1', 'a_bool', 'true')\n" +"config.set('Section1', 'a_float', '3.1415')\n" +"config.set('Section1', 'baz', 'fun')\n" +"config.set('Section1', 'bar', 'Python')\n" +"config.set('Section1', 'foo', '%(bar)s is %(baz)s!')\n" +"\n" +"# Writing our configuration file to 'example.cfg'\n" +"with open('example.cfg', 'w') as configfile:\n" +" config.write(configfile)" +msgstr "" + #: ../../library/configparser.rst:847 msgid "An example of reading the configuration file again::" msgstr "" +#: ../../library/configparser.rst:849 +msgid "" +"import configparser\n" +"\n" +"config = configparser.RawConfigParser()\n" +"config.read('example.cfg')\n" +"\n" +"# getfloat() raises an exception if the value is not a float\n" +"# getint() and getboolean() also do this for their respective types\n" +"a_float = config.getfloat('Section1', 'a_float')\n" +"an_int = config.getint('Section1', 'an_int')\n" +"print(a_float + an_int)\n" +"\n" +"# Notice that the next output does not interpolate '%(bar)s' or '%(baz)s'.\n" +"# This is because we are using a RawConfigParser().\n" +"if config.getboolean('Section1', 'a_bool'):\n" +" print(config.get('Section1', 'foo'))" +msgstr "" + #: ../../library/configparser.rst:865 msgid "To get interpolation, use :class:`ConfigParser`::" msgstr "" +#: ../../library/configparser.rst:867 +msgid "" +"import configparser\n" +"\n" +"cfg = configparser.ConfigParser()\n" +"cfg.read('example.cfg')\n" +"\n" +"# Set the optional *raw* argument of get() to True if you wish to disable\n" +"# interpolation in a single get operation.\n" +"print(cfg.get('Section1', 'foo', raw=False)) # -> \"Python is fun!\"\n" +"print(cfg.get('Section1', 'foo', raw=True)) # -> \"%(bar)s is %(baz)s!\"\n" +"\n" +"# The optional *vars* argument is a dict with members that will take\n" +"# precedence in interpolation.\n" +"print(cfg.get('Section1', 'foo', vars={'bar': 'Documentation',\n" +" 'baz': 'evil'}))\n" +"\n" +"# The optional *fallback* argument can be used to provide a fallback value\n" +"print(cfg.get('Section1', 'foo'))\n" +" # -> \"Python is fun!\"\n" +"\n" +"print(cfg.get('Section1', 'foo', fallback='Monty is not.'))\n" +" # -> \"Python is fun!\"\n" +"\n" +"print(cfg.get('Section1', 'monster', fallback='No such things as " +"monsters.'))\n" +" # -> \"No such things as monsters.\"\n" +"\n" +"# A bare print(cfg.get('Section1', 'monster')) would raise NoOptionError\n" +"# but we can also use:\n" +"\n" +"print(cfg.get('Section1', 'monster', fallback=None))\n" +" # -> None" +msgstr "" + #: ../../library/configparser.rst:898 msgid "" "Default values are available in both types of ConfigParsers. They are used " "in interpolation if an option used is not defined elsewhere. ::" msgstr "" +#: ../../library/configparser.rst:901 +msgid "" +"import configparser\n" +"\n" +"# New instance with 'bar' and 'baz' defaulting to 'Life' and 'hard' each\n" +"config = configparser.ConfigParser({'bar': 'Life', 'baz': 'hard'})\n" +"config.read('example.cfg')\n" +"\n" +"print(config.get('Section1', 'foo')) # -> \"Python is fun!\"\n" +"config.remove_option('Section1', 'bar')\n" +"config.remove_option('Section1', 'baz')\n" +"print(config.get('Section1', 'foo')) # -> \"Life is hard!\"" +msgstr "" + #: ../../library/configparser.rst:916 msgid "ConfigParser Objects" msgstr "ConfigParser 物件" @@ -837,6 +1326,16 @@ msgid "" "`read_file` before calling :meth:`read` for any optional files::" msgstr "" +#: ../../library/configparser.rst:1071 +msgid "" +"import configparser, os\n" +"\n" +"config = configparser.ConfigParser()\n" +"config.read_file(open('defaults.cfg'))\n" +"config.read(['site.cfg', os.path.expanduser('~/.myapp.cfg')],\n" +" encoding='cp1250')" +msgstr "" + #: ../../library/configparser.rst:1078 msgid "" "Added the *encoding* parameter. Previously, all files were read using the " @@ -1020,6 +1519,12 @@ msgid "" "sensitive::" msgstr "" +#: ../../library/configparser.rst:1238 +msgid "" +"cfgparser = ConfigParser()\n" +"cfgparser.optionxform = str" +msgstr "" + #: ../../library/configparser.rst:1241 msgid "" "Note that when reading configuration files, whitespace around the option " diff --git a/library/constants.po b/library/constants.po index 95f3ea1ec2..c6fbdba8e7 100644 --- a/library/constants.po +++ b/library/constants.po @@ -9,7 +9,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-03-01 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2021-11-19 23:36+0800\n" "Last-Translator: Jordan Su \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -144,11 +144,11 @@ msgstr "" "重新賦值的(任何對它們的賦值,即使是屬性的名稱,也會拋出 :exc:" "`SyntaxError`)。因此,它們可以被視為”真正的”常數。" -#: ../../library/constants.rst:83 +#: ../../library/constants.rst:85 msgid "Constants added by the :mod:`site` module" msgstr "由 :mod:`site` module(模組)所添增的常數" -#: ../../library/constants.rst:85 +#: ../../library/constants.rst:87 msgid "" "The :mod:`site` module (which is imported automatically during startup, " "except if the :option:`-S` command-line option is given) adds several " @@ -159,7 +159,7 @@ msgstr "" "指令行選項)會添增一些常數到內建命名空間 (built-in namespace) 中。它們在互動" "式直譯器中是很有幫助的,但不應該在程式 (programs) 中被使用。" -#: ../../library/constants.rst:93 +#: ../../library/constants.rst:95 msgid "" "Objects that when printed, print a message like \"Use quit() or Ctrl-D (i.e. " "EOF) to exit\", and when called, raise :exc:`SystemExit` with the specified " @@ -168,13 +168,23 @@ msgstr "" "當印出物件時,會印出一個訊息: \"Use quit() or Ctrl-D (i.e. EOF) to exit\" 。" "當被呼叫時,則會拋出 :exc:`SystemExit` 並帶有指定的返回碼(exit code)。" -#: ../../library/constants.rst:100 +#: ../../library/constants.rst:102 +#, fuzzy +msgid "" +"Object that when printed, prints the message \"Type help() for interactive " +"help, or help(object) for help about object.\", and when called, acts as " +"described :func:`elsewhere `." +msgstr "" +"當印出此物件時,會印出訊息 \"Type license() to see the full license text\" 。" +"當被呼叫時,則會以分頁形式印出完整的許可證文字(一次一整個畫面)。" + +#: ../../library/constants.rst:109 msgid "" "Objects that when printed or called, print the text of copyright or credits, " "respectively." msgstr "當印出或是呼叫此物件時,分別會印出版權與致謝的文字。" -#: ../../library/constants.rst:105 +#: ../../library/constants.rst:114 msgid "" "Object that when printed, prints the message \"Type license() to see the " "full license text\", and when called, displays the full license text in a " diff --git a/library/contextlib.po b/library/contextlib.po index 2ff04c77a8..46d1cdf53c 100644 --- a/library/contextlib.po +++ b/library/contextlib.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-07-23 00:04+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2018-05-23 14:41+0000\n" "Last-Translator: Adrian Liaw \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -82,10 +82,32 @@ msgid "" "management::" msgstr "" +#: ../../library/contextlib.rst:57 +msgid "" +"from contextlib import contextmanager\n" +"\n" +"@contextmanager\n" +"def managed_resource(*args, **kwds):\n" +" # Code to acquire resource, e.g.:\n" +" resource = acquire_resource(*args, **kwds)\n" +" try:\n" +" yield resource\n" +" finally:\n" +" # Code to release resource, e.g.:\n" +" release_resource(resource)" +msgstr "" + #: ../../library/contextlib.rst:69 msgid "The function can then be used like this::" msgstr "" +#: ../../library/contextlib.rst:71 +msgid "" +">>> with managed_resource(timeout=3600) as resource:\n" +"... # Resource is released at the end of this block,\n" +"... # even if code in the block raises an exception" +msgstr "" + #: ../../library/contextlib.rst:75 msgid "" "The function being decorated must return a :term:`generator`-iterator when " @@ -143,12 +165,47 @@ msgstr "" msgid "A simple example::" msgstr "一個簡單範例: ::" +#: ../../library/contextlib.rst:115 +msgid "" +"from contextlib import asynccontextmanager\n" +"\n" +"@asynccontextmanager\n" +"async def get_connection():\n" +" conn = await acquire_db_connection()\n" +" try:\n" +" yield conn\n" +" finally:\n" +" await release_db_connection(conn)\n" +"\n" +"async def get_all_users():\n" +" async with get_connection() as conn:\n" +" return conn.query('SELECT ...')" +msgstr "" + #: ../../library/contextlib.rst:131 msgid "" "Context managers defined with :func:`asynccontextmanager` can be used either " "as decorators or with :keyword:`async with` statements::" msgstr "" +#: ../../library/contextlib.rst:134 +msgid "" +"import time\n" +"from contextlib import asynccontextmanager\n" +"\n" +"@asynccontextmanager\n" +"async def timeit():\n" +" now = time.monotonic()\n" +" try:\n" +" yield\n" +" finally:\n" +" print(f'it took {time.monotonic() - now}s to run')\n" +"\n" +"@timeit()\n" +"async def main():\n" +" # ... async code ..." +msgstr "" + #: ../../library/contextlib.rst:149 msgid "" "When used as a decorator, a new generator instance is implicitly created on " @@ -169,10 +226,32 @@ msgid "" "This is basically equivalent to::" msgstr "" +#: ../../library/contextlib.rst:164 +msgid "" +"from contextlib import contextmanager\n" +"\n" +"@contextmanager\n" +"def closing(thing):\n" +" try:\n" +" yield thing\n" +" finally:\n" +" thing.close()" +msgstr "" + #: ../../library/contextlib.rst:173 msgid "And lets you write code like this::" msgstr "" +#: ../../library/contextlib.rst:175 +msgid "" +"from contextlib import closing\n" +"from urllib.request import urlopen\n" +"\n" +"with closing(urlopen('https://www.python.org')) as page:\n" +" for line in page:\n" +" print(line)" +msgstr "" + #: ../../library/contextlib.rst:182 msgid "" "without needing to explicitly close ``page``. Even if an error occurs, " @@ -194,6 +273,18 @@ msgid "" "*thing* upon completion of the block. This is basically equivalent to::" msgstr "" +#: ../../library/contextlib.rst:199 +msgid "" +"from contextlib import asynccontextmanager\n" +"\n" +"@asynccontextmanager\n" +"async def aclosing(thing):\n" +" try:\n" +" yield thing\n" +" finally:\n" +" await thing.aclose()" +msgstr "" + #: ../../library/contextlib.rst:208 msgid "" "Significantly, ``aclosing()`` supports deterministic cleanup of async " @@ -201,6 +292,16 @@ msgid "" "exception. For example::" msgstr "" +#: ../../library/contextlib.rst:212 +msgid "" +"from contextlib import aclosing\n" +"\n" +"async with aclosing(my_generator()) as values:\n" +" async for value in values:\n" +" if value == 42:\n" +" break" +msgstr "" + #: ../../library/contextlib.rst:219 msgid "" "This pattern ensures that the generator's async exit code is executed in the " @@ -216,16 +317,57 @@ msgid "" "optional context manager, for example::" msgstr "" +#: ../../library/contextlib.rst:235 +msgid "" +"def myfunction(arg, ignore_exceptions=False):\n" +" if ignore_exceptions:\n" +" # Use suppress to ignore all exceptions.\n" +" cm = contextlib.suppress(Exception)\n" +" else:\n" +" # Do not ignore any exceptions, cm has no effect.\n" +" cm = contextlib.nullcontext()\n" +" with cm:\n" +" # Do something" +msgstr "" + #: ../../library/contextlib.rst:245 msgid "An example using *enter_result*::" msgstr "一個使用 *enter_result* 的範例: ::" +#: ../../library/contextlib.rst:247 +msgid "" +"def process_file(file_or_path):\n" +" if isinstance(file_or_path, str):\n" +" # If string, open file\n" +" cm = open(file_or_path)\n" +" else:\n" +" # Caller is responsible for closing file\n" +" cm = nullcontext(file_or_path)\n" +"\n" +" with cm as file:\n" +" # Perform processing on the file" +msgstr "" + #: ../../library/contextlib.rst:258 msgid "" "It can also be used as a stand-in for :ref:`asynchronous context managers " "`::" msgstr "" +#: ../../library/contextlib.rst:261 +msgid "" +"async def send_http(session=None):\n" +" if not session:\n" +" # If no http session, create it with aiohttp\n" +" cm = aiohttp.ClientSession()\n" +" else:\n" +" # Caller is responsible for closing the session\n" +" cm = nullcontext(session)\n" +"\n" +" async with cm as session:\n" +" # Send http requests with session" +msgstr "" + #: ../../library/contextlib.rst:274 msgid ":term:`asynchronous context manager` support was added." msgstr "" @@ -250,10 +392,34 @@ msgstr "" msgid "For example::" msgstr "舉例來說: ::" +#: ../../library/contextlib.rst:293 +msgid "" +"from contextlib import suppress\n" +"\n" +"with suppress(FileNotFoundError):\n" +" os.remove('somefile.tmp')\n" +"\n" +"with suppress(FileNotFoundError):\n" +" os.remove('someotherfile.tmp')" +msgstr "" + #: ../../library/contextlib.rst:301 msgid "This code is equivalent to::" msgstr "" +#: ../../library/contextlib.rst:303 +msgid "" +"try:\n" +" os.remove('somefile.tmp')\n" +"except FileNotFoundError:\n" +" pass\n" +"\n" +"try:\n" +" os.remove('someotherfile.tmp')\n" +"except FileNotFoundError:\n" +" pass" +msgstr "" + #: ../../library/contextlib.rst:313 ../../library/contextlib.rst:362 #: ../../library/contextlib.rst:372 ../../library/contextlib.rst:389 msgid "This context manager is :ref:`reentrant `." @@ -295,16 +461,36 @@ msgid "" "`with` statement::" msgstr "" +#: ../../library/contextlib.rst:341 +msgid "" +"with redirect_stdout(io.StringIO()) as f:\n" +" help(pow)\n" +"s = f.getvalue()" +msgstr "" + #: ../../library/contextlib.rst:345 msgid "" "To send the output of :func:`help` to a file on disk, redirect the output to " "a regular file::" msgstr "" +#: ../../library/contextlib.rst:348 +msgid "" +"with open('help.txt', 'w') as f:\n" +" with redirect_stdout(f):\n" +" help(pow)" +msgstr "" + #: ../../library/contextlib.rst:352 msgid "To send the output of :func:`help` to *sys.stderr*::" msgstr "" +#: ../../library/contextlib.rst:354 +msgid "" +"with redirect_stdout(sys.stderr):\n" +" help(pow)" +msgstr "" + #: ../../library/contextlib.rst:357 msgid "" "Note that the global side effect on :data:`sys.stdout` means that this " @@ -357,19 +543,66 @@ msgstr "" msgid "Example of ``ContextDecorator``::" msgstr "``ContextDecorator`` 範例: ::" +#: ../../library/contextlib.rst:407 +msgid "" +"from contextlib import ContextDecorator\n" +"\n" +"class mycontext(ContextDecorator):\n" +" def __enter__(self):\n" +" print('Starting')\n" +" return self\n" +"\n" +" def __exit__(self, *exc):\n" +" print('Finishing')\n" +" return False" +msgstr "" + #: ../../library/contextlib.rst:418 ../../library/contextlib.rst:490 msgid "The class can then be used like this::" msgstr "" +#: ../../library/contextlib.rst:420 +msgid "" +">>> @mycontext()\n" +"... def function():\n" +"... print('The bit in the middle')\n" +"...\n" +">>> function()\n" +"Starting\n" +"The bit in the middle\n" +"Finishing\n" +"\n" +">>> with mycontext():\n" +"... print('The bit in the middle')\n" +"...\n" +"Starting\n" +"The bit in the middle\n" +"Finishing" +msgstr "" + #: ../../library/contextlib.rst:436 msgid "" "This change is just syntactic sugar for any construct of the following form::" msgstr "" +#: ../../library/contextlib.rst:438 +msgid "" +"def f():\n" +" with cm():\n" +" # Do stuff" +msgstr "" + #: ../../library/contextlib.rst:442 msgid "``ContextDecorator`` lets you instead write::" msgstr "" +#: ../../library/contextlib.rst:444 +msgid "" +"@cm()\n" +"def f():\n" +" # Do stuff" +msgstr "" + #: ../../library/contextlib.rst:448 msgid "" "It makes it clear that the ``cm`` applies to the whole function, rather than " @@ -382,6 +615,18 @@ msgid "" "using ``ContextDecorator`` as a mixin class::" msgstr "" +#: ../../library/contextlib.rst:454 +msgid "" +"from contextlib import ContextDecorator\n" +"\n" +"class mycontext(ContextBaseClass, ContextDecorator):\n" +" def __enter__(self):\n" +" return self\n" +"\n" +" def __exit__(self, *exc):\n" +" return False" +msgstr "" + #: ../../library/contextlib.rst:464 msgid "" "As the decorated function must be able to be called multiple times, the " @@ -399,6 +644,42 @@ msgstr "" msgid "Example of ``AsyncContextDecorator``::" msgstr "``AsyncContextDecorator`` 範例: ::" +#: ../../library/contextlib.rst:478 +msgid "" +"from asyncio import run\n" +"from contextlib import AsyncContextDecorator\n" +"\n" +"class mycontext(AsyncContextDecorator):\n" +" async def __aenter__(self):\n" +" print('Starting')\n" +" return self\n" +"\n" +" async def __aexit__(self, *exc):\n" +" print('Finishing')\n" +" return False" +msgstr "" + +#: ../../library/contextlib.rst:492 +msgid "" +">>> @mycontext()\n" +"... async def function():\n" +"... print('The bit in the middle')\n" +"...\n" +">>> run(function())\n" +"Starting\n" +"The bit in the middle\n" +"Finishing\n" +"\n" +">>> async def function():\n" +"... async with mycontext():\n" +"... print('The bit in the middle')\n" +"...\n" +">>> run(function())\n" +"Starting\n" +"The bit in the middle\n" +"Finishing" +msgstr "" + #: ../../library/contextlib.rst:515 msgid "" "A context manager that is designed to make it easy to programmatically " @@ -412,6 +693,15 @@ msgid "" "as follows::" msgstr "" +#: ../../library/contextlib.rst:522 +msgid "" +"with ExitStack() as stack:\n" +" files = [stack.enter_context(open(fname)) for fname in filenames]\n" +" # All opened files will automatically be closed at the end of\n" +" # the with statement, even if attempts to open files later\n" +" # in the list raise an exception" +msgstr "" + #: ../../library/contextlib.rst:528 msgid "" "The :meth:`~object.__enter__` method returns the :class:`ExitStack` " @@ -534,6 +824,18 @@ msgid "" "operation as follows::" msgstr "" +#: ../../library/contextlib.rst:606 +msgid "" +"with ExitStack() as stack:\n" +" files = [stack.enter_context(open(fname)) for fname in filenames]\n" +" # Hold onto the close method, but don't call it yet.\n" +" close_files = stack.pop_all().close\n" +" # If opening any file fails, all previously opened files will be\n" +" # closed automatically. If all files are opened successfully,\n" +" # they will remain open even after the with statement ends.\n" +" # close_files() can then be invoked explicitly to close them all." +msgstr "" + #: ../../library/contextlib.rst:617 msgid "" "Immediately unwinds the callback stack, invoking callbacks in the reverse " @@ -584,6 +886,16 @@ msgstr "" msgid "Continuing the example for :func:`asynccontextmanager`::" msgstr "" +#: ../../library/contextlib.rst:656 +msgid "" +"async with AsyncExitStack() as stack:\n" +" connections = [await stack.enter_async_context(get_connection())\n" +" for i in range(5)]\n" +" # All opened connections will automatically be released at the end of\n" +" # the async with statement, even if attempts to open a connection\n" +" # later in the list raise an exception." +msgstr "" + #: ../../library/contextlib.rst:666 msgid "Examples and Recipes" msgstr "" @@ -608,6 +920,17 @@ msgid "" "of the context managers being optional::" msgstr "" +#: ../../library/contextlib.rst:682 +msgid "" +"with ExitStack() as stack:\n" +" for resource in resources:\n" +" stack.enter_context(resource)\n" +" if need_special_resource():\n" +" special = acquire_special_resource()\n" +" stack.callback(release_special_resource, special)\n" +" # Perform operations that use the acquired resources" +msgstr "" + #: ../../library/contextlib.rst:690 msgid "" "As shown, :class:`ExitStack` also makes it quite easy to use :keyword:`with` " @@ -628,6 +951,18 @@ msgid "" "be separated slightly in order to allow this::" msgstr "" +#: ../../library/contextlib.rst:704 +msgid "" +"stack = ExitStack()\n" +"try:\n" +" x = stack.enter_context(cm)\n" +"except Exception:\n" +" # handle __enter__ exception\n" +"else:\n" +" with stack:\n" +" # Handle normal case" +msgstr "" + #: ../../library/contextlib.rst:713 msgid "" "Actually needing to do this is likely to indicate that the underlying API " @@ -657,6 +992,44 @@ msgid "" "function, and maps them to the context management protocol::" msgstr "" +#: ../../library/contextlib.rst:733 +msgid "" +"from contextlib import contextmanager, AbstractContextManager, ExitStack\n" +"\n" +"class ResourceManager(AbstractContextManager):\n" +"\n" +" def __init__(self, acquire_resource, release_resource, " +"check_resource_ok=None):\n" +" self.acquire_resource = acquire_resource\n" +" self.release_resource = release_resource\n" +" if check_resource_ok is None:\n" +" def check_resource_ok(resource):\n" +" return True\n" +" self.check_resource_ok = check_resource_ok\n" +"\n" +" @contextmanager\n" +" def _cleanup_on_error(self):\n" +" with ExitStack() as stack:\n" +" stack.push(self)\n" +" yield\n" +" # The validation check passed and didn't raise an exception\n" +" # Accordingly, we want to keep the resource, and pass it\n" +" # back to our caller\n" +" stack.pop_all()\n" +"\n" +" def __enter__(self):\n" +" resource = self.acquire_resource()\n" +" with self._cleanup_on_error():\n" +" if not self.check_resource_ok(resource):\n" +" msg = \"Failed validation for {!r}\"\n" +" raise RuntimeError(msg.format(resource))\n" +" return resource\n" +"\n" +" def __exit__(self, *exc_details):\n" +" # We don't need to duplicate any of our resource release logic\n" +" self.release_resource()" +msgstr "" + #: ../../library/contextlib.rst:769 msgid "Replacing any use of ``try-finally`` and flag variables" msgstr "" @@ -669,6 +1042,18 @@ msgid "" "by using an ``except`` clause instead), it looks something like this::" msgstr "" +#: ../../library/contextlib.rst:776 +msgid "" +"cleanup_needed = True\n" +"try:\n" +" result = perform_operation()\n" +" if result:\n" +" cleanup_needed = False\n" +"finally:\n" +" if cleanup_needed:\n" +" cleanup_resources()" +msgstr "" + #: ../../library/contextlib.rst:785 msgid "" "As with any ``try`` statement based code, this can cause problems for " @@ -683,6 +1068,17 @@ msgid "" "executing that callback::" msgstr "" +#: ../../library/contextlib.rst:793 +msgid "" +"from contextlib import ExitStack\n" +"\n" +"with ExitStack() as stack:\n" +" stack.callback(cleanup_resources)\n" +" result = perform_operation()\n" +" if result:\n" +" stack.pop_all()" +msgstr "" + #: ../../library/contextlib.rst:801 msgid "" "This allows the intended cleanup behaviour to be made explicit up front, " @@ -695,6 +1091,24 @@ msgid "" "even further by means of a small helper class::" msgstr "" +#: ../../library/contextlib.rst:807 +msgid "" +"from contextlib import ExitStack\n" +"\n" +"class Callback(ExitStack):\n" +" def __init__(self, callback, /, *args, **kwds):\n" +" super().__init__()\n" +" self.callback(callback, *args, **kwds)\n" +"\n" +" def cancel(self):\n" +" self.pop_all()\n" +"\n" +"with Callback(cleanup_resources) as cb:\n" +" result = perform_operation()\n" +" if result:\n" +" cb.cancel()" +msgstr "" + #: ../../library/contextlib.rst:822 msgid "" "If the resource cleanup isn't already neatly bundled into a standalone " @@ -702,6 +1116,19 @@ msgid "" "`ExitStack.callback` to declare the resource cleanup in advance::" msgstr "" +#: ../../library/contextlib.rst:827 +msgid "" +"from contextlib import ExitStack\n" +"\n" +"with ExitStack() as stack:\n" +" @stack.callback\n" +" def cleanup_resources():\n" +" ...\n" +" result = perform_operation()\n" +" if result:\n" +" stack.pop_all()" +msgstr "" + #: ../../library/contextlib.rst:837 msgid "" "Due to the way the decorator protocol works, a callback function declared " @@ -728,14 +1155,47 @@ msgid "" "in a single definition::" msgstr "" +#: ../../library/contextlib.rst:854 +msgid "" +"from contextlib import ContextDecorator\n" +"import logging\n" +"\n" +"logging.basicConfig(level=logging.INFO)\n" +"\n" +"class track_entry_and_exit(ContextDecorator):\n" +" def __init__(self, name):\n" +" self.name = name\n" +"\n" +" def __enter__(self):\n" +" logging.info('Entering: %s', self.name)\n" +"\n" +" def __exit__(self, exc_type, exc, exc_tb):\n" +" logging.info('Exiting: %s', self.name)" +msgstr "" + #: ../../library/contextlib.rst:869 msgid "Instances of this class can be used as both a context manager::" msgstr "" +#: ../../library/contextlib.rst:871 +msgid "" +"with track_entry_and_exit('widget loader'):\n" +" print('Some time consuming activity goes here')\n" +" load_widget()" +msgstr "" + #: ../../library/contextlib.rst:875 msgid "And also as a function decorator::" msgstr "" +#: ../../library/contextlib.rst:877 +msgid "" +"@track_entry_and_exit('widget loader')\n" +"def activity():\n" +" print('Some time consuming activity goes here')\n" +" load_widget()" +msgstr "" + #: ../../library/contextlib.rst:882 msgid "" "Note that there is one additional limitation when using context managers as " @@ -787,6 +1247,29 @@ msgid "" "to yield if an attempt is made to use them a second time::" msgstr "" +#: ../../library/contextlib.rst:916 +msgid "" +">>> from contextlib import contextmanager\n" +">>> @contextmanager\n" +"... def singleuse():\n" +"... print(\"Before\")\n" +"... yield\n" +"... print(\"After\")\n" +"...\n" +">>> cm = singleuse()\n" +">>> with cm:\n" +"... pass\n" +"...\n" +"Before\n" +"After\n" +">>> with cm:\n" +"... pass\n" +"...\n" +"Traceback (most recent call last):\n" +" ...\n" +"RuntimeError: generator didn't yield" +msgstr "" + #: ../../library/contextlib.rst:940 msgid "Reentrant context managers" msgstr "" @@ -806,6 +1289,24 @@ msgid "" "very simple example of reentrant use::" msgstr "" +#: ../../library/contextlib.rst:951 +msgid "" +">>> from contextlib import redirect_stdout\n" +">>> from io import StringIO\n" +">>> stream = StringIO()\n" +">>> write_to_stream = redirect_stdout(stream)\n" +">>> with write_to_stream:\n" +"... print(\"This is written to the stream rather than stdout\")\n" +"... with write_to_stream:\n" +"... print(\"This is also written to the stream\")\n" +"...\n" +">>> print(\"This is written directly to stdout\")\n" +"This is written directly to stdout\n" +">>> print(stream.getvalue())\n" +"This is written to the stream rather than stdout\n" +"This is also written to the stream" +msgstr "" + #: ../../library/contextlib.rst:966 msgid "" "Real world examples of reentrancy are more likely to involve multiple " @@ -849,6 +1350,35 @@ msgid "" "any with statement, regardless of where those callbacks were added::" msgstr "" +#: ../../library/contextlib.rst:997 +msgid "" +">>> from contextlib import ExitStack\n" +">>> stack = ExitStack()\n" +">>> with stack:\n" +"... stack.callback(print, \"Callback: from first context\")\n" +"... print(\"Leaving first context\")\n" +"...\n" +"Leaving first context\n" +"Callback: from first context\n" +">>> with stack:\n" +"... stack.callback(print, \"Callback: from second context\")\n" +"... print(\"Leaving second context\")\n" +"...\n" +"Leaving second context\n" +"Callback: from second context\n" +">>> with stack:\n" +"... stack.callback(print, \"Callback: from outer context\")\n" +"... with stack:\n" +"... stack.callback(print, \"Callback: from inner context\")\n" +"... print(\"Leaving inner context\")\n" +"... print(\"Leaving outer context\")\n" +"...\n" +"Leaving inner context\n" +"Callback: from inner context\n" +"Callback: from outer context\n" +"Leaving outer context" +msgstr "" + #: ../../library/contextlib.rst:1023 msgid "" "As the output from the example shows, reusing a single stack object across " @@ -862,3 +1392,19 @@ msgid "" "Using separate :class:`ExitStack` instances instead of reusing a single " "instance avoids that problem::" msgstr "" + +#: ../../library/contextlib.rst:1031 +msgid "" +">>> from contextlib import ExitStack\n" +">>> with ExitStack() as outer_stack:\n" +"... outer_stack.callback(print, \"Callback: from outer context\")\n" +"... with ExitStack() as inner_stack:\n" +"... inner_stack.callback(print, \"Callback: from inner context\")\n" +"... print(\"Leaving inner context\")\n" +"... print(\"Leaving outer context\")\n" +"...\n" +"Leaving inner context\n" +"Callback: from inner context\n" +"Leaving outer context\n" +"Callback: from outer context" +msgstr "" diff --git a/library/contextvars.po b/library/contextvars.po index bb81396e9c..e9e6790146 100644 --- a/library/contextvars.po +++ b/library/contextvars.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-08-30 18:24+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2018-07-15 18:56+0800\n" "Last-Translator: \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -47,6 +47,10 @@ msgstr "" msgid "This class is used to declare a new Context Variable, e.g.::" msgstr "" +#: ../../library/contextvars.rst:33 +msgid "var: ContextVar[int] = ContextVar('var', default=42)" +msgstr "" + #: ../../library/contextvars.rst:35 msgid "" "The required *name* parameter is used for introspection and debug purposes." @@ -122,6 +126,18 @@ msgstr "" msgid "For example::" msgstr "舉例來說: ::" +#: ../../library/contextvars.rst:87 +msgid "" +"var = ContextVar('var')\n" +"\n" +"token = var.set('new value')\n" +"# code that uses 'var'; var.get() returns 'new value'.\n" +"var.reset(token)\n" +"\n" +"# After the reset call the var has no value again, so\n" +"# var.get() would raise a LookupError." +msgstr "" + #: ../../library/contextvars.rst:99 msgid "" "*Token* objects are returned by the :meth:`ContextVar.set` method. They can " @@ -160,6 +176,12 @@ msgid "" "variables and their values that are set in it::" msgstr "" +#: ../../library/contextvars.rst:131 +msgid "" +"ctx: Context = copy_context()\n" +"print(list(ctx.items()))" +msgstr "" + #: ../../library/contextvars.rst:134 msgid "" "The function has an *O*\\ (1) complexity, i.e. works equally fast for " @@ -202,6 +224,35 @@ msgid "" "in the context object::" msgstr "" +#: ../../library/contextvars.rst:163 +msgid "" +"var = ContextVar('var')\n" +"var.set('spam')\n" +"\n" +"def main():\n" +" # 'var' was set to 'spam' before\n" +" # calling 'copy_context()' and 'ctx.run(main)', so:\n" +" # var.get() == ctx[var] == 'spam'\n" +"\n" +" var.set('ham')\n" +"\n" +" # Now, after setting 'var' to 'ham':\n" +" # var.get() == ctx[var] == 'ham'\n" +"\n" +"ctx = copy_context()\n" +"\n" +"# Any changes that the 'main' function makes to 'var'\n" +"# will be contained in 'ctx'.\n" +"ctx.run(main)\n" +"\n" +"# The 'main()' function was run in the 'ctx' context,\n" +"# so changes to 'var' are contained in it:\n" +"# ctx[var] == 'ham'\n" +"\n" +"# However, outside of 'ctx', 'var' is still set to 'spam':\n" +"# var.get() == 'spam'" +msgstr "" + #: ../../library/contextvars.rst:189 msgid "" "The method raises a :exc:`RuntimeError` when called on the same context " @@ -263,3 +314,47 @@ msgid "" "server, that uses a context variable to make the address of a remote client " "available in the Task that handles that client::" msgstr "" + +#: ../../library/contextvars.rst:247 +msgid "" +"import asyncio\n" +"import contextvars\n" +"\n" +"client_addr_var = contextvars.ContextVar('client_addr')\n" +"\n" +"def render_goodbye():\n" +" # The address of the currently handled client can be accessed\n" +" # without passing it explicitly to this function.\n" +"\n" +" client_addr = client_addr_var.get()\n" +" return f'Good bye, client @ {client_addr}\\n'.encode()\n" +"\n" +"async def handle_request(reader, writer):\n" +" addr = writer.transport.get_extra_info('socket').getpeername()\n" +" client_addr_var.set(addr)\n" +"\n" +" # In any code that we call is now possible to get\n" +" # client's address by calling 'client_addr_var.get()'.\n" +"\n" +" while True:\n" +" line = await reader.readline()\n" +" print(line)\n" +" if not line.strip():\n" +" break\n" +" writer.write(line)\n" +"\n" +" writer.write(render_goodbye())\n" +" writer.close()\n" +"\n" +"async def main():\n" +" srv = await asyncio.start_server(\n" +" handle_request, '127.0.0.1', 8081)\n" +"\n" +" async with srv:\n" +" await srv.serve_forever()\n" +"\n" +"asyncio.run(main())\n" +"\n" +"# To test it you can use telnet:\n" +"# telnet 127.0.0.1 8081" +msgstr "" diff --git a/library/crypt.po b/library/crypt.po index e7cd1918e2..18767bb0ee 100644 --- a/library/crypt.po +++ b/library/crypt.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-07-20 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2018-05-23 14:42+0000\n" "Last-Translator: Adrian Liaw \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -206,12 +206,42 @@ msgid "" "compare_digest` is suitable for this purpose)::" msgstr "" +#: ../../library/crypt.rst:159 +msgid "" +"import pwd\n" +"import crypt\n" +"import getpass\n" +"from hmac import compare_digest as compare_hash\n" +"\n" +"def login():\n" +" username = input('Python login: ')\n" +" cryptedpasswd = pwd.getpwnam(username)[1]\n" +" if cryptedpasswd:\n" +" if cryptedpasswd == 'x' or cryptedpasswd == '*':\n" +" raise ValueError('no support for shadow passwords')\n" +" cleartext = getpass.getpass()\n" +" return compare_hash(crypt.crypt(cleartext, cryptedpasswd), " +"cryptedpasswd)\n" +" else:\n" +" return True" +msgstr "" + #: ../../library/crypt.rst:175 msgid "" "To generate a hash of a password using the strongest available method and " "check it against the original::" msgstr "" +#: ../../library/crypt.rst:178 +msgid "" +"import crypt\n" +"from hmac import compare_digest as compare_hash\n" +"\n" +"hashed = crypt.crypt(plaintext)\n" +"if not compare_hash(hashed, crypt.crypt(plaintext, hashed)):\n" +" raise ValueError(\"hashed version doesn't validate against original\")" +msgstr "" + #: ../../library/crypt.rst:15 ../../library/crypt.rst:33 #: ../../library/crypt.rst:119 msgid "crypt(3)" diff --git a/library/csv.po b/library/csv.po index 1a829b7f8e..b6bc631061 100644 --- a/library/csv.po +++ b/library/csv.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-05-09 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2023-11-08 15:06+0800\n" "Last-Translator: RockLeon \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -128,6 +128,17 @@ msgstr "" msgid "A short usage example::" msgstr "一個簡短的用法範例: ::" +#: ../../library/csv.rst:78 +msgid "" +">>> import csv\n" +">>> with open('eggs.csv', newline='') as csvfile:\n" +"... spamreader = csv.reader(csvfile, delimiter=' ', quotechar='|')\n" +"... for row in spamreader:\n" +"... print(', '.join(row))\n" +"Spam, Spam, Spam, Spam, Spam, Baked Beans\n" +"Spam, Lovely Spam, Wonderful Spam" +msgstr "" + #: ../../library/csv.rst:89 msgid "" "Return a writer object responsible for converting the user's data into " @@ -160,6 +171,16 @@ msgstr "" "``cursor.fetch*`` 呼叫回傳的資料進行預處理 (preprocessing)。其餘非字串的資料" "則會在寫入之前用 :func:`str` 函式進行字串化 (stringify)。" +#: ../../library/csv.rst:108 +msgid "" +"import csv\n" +"with open('eggs.csv', 'w', newline='') as csvfile:\n" +" spamwriter = csv.writer(csvfile, delimiter=' ',\n" +" quotechar='|', quoting=csv.QUOTE_MINIMAL)\n" +" spamwriter.writerow(['Spam'] * 5 + ['Baked Beans'])\n" +" spamwriter.writerow(['Spam', 'Lovely Spam', 'Wonderful Spam'])" +msgstr "" + #: ../../library/csv.rst:118 msgid "" "Associate *dialect* with *name*. *name* must be a string. The dialect can " @@ -263,6 +284,21 @@ msgstr "回傳的列已成為型別 :class:`OrderedDict`。" msgid "Returned rows are now of type :class:`dict`." msgstr "回傳的列已成為型別 :class:`dict`。" +#: ../../library/csv.rst:183 +msgid "" +">>> import csv\n" +">>> with open('names.csv', newline='') as csvfile:\n" +"... reader = csv.DictReader(csvfile)\n" +"... for row in reader:\n" +"... print(row['first_name'], row['last_name'])\n" +"...\n" +"Eric Idle\n" +"John Cleese\n" +"\n" +">>> print(row)\n" +"{'first_name': 'John', 'last_name': 'Cleese'}" +msgstr "" + #: ../../library/csv.rst:199 msgid "" "Create an object which operates like a regular writer but maps dictionaries " @@ -296,6 +332,20 @@ msgstr "" "請記得這不像類別 :class:`DictReader`,在類別 :class:`DictWriter` 中,參數 " "*fieldnames* 並不是選填的。" +#: ../../library/csv.rst:221 +msgid "" +"import csv\n" +"\n" +"with open('names.csv', 'w', newline='') as csvfile:\n" +" fieldnames = ['first_name', 'last_name']\n" +" writer = csv.DictWriter(csvfile, fieldnames=fieldnames)\n" +"\n" +" writer.writeheader()\n" +" writer.writerow({'first_name': 'Baked', 'last_name': 'Beans'})\n" +" writer.writerow({'first_name': 'Lovely', 'last_name': 'Spam'})\n" +" writer.writerow({'first_name': 'Wonderful', 'last_name': 'Spam'})" +msgstr "" + #: ../../library/csv.rst:235 msgid "" "The :class:`Dialect` class is a container class whose attributes contain " @@ -319,6 +369,14 @@ msgstr "" "透過特定 :class:`reader` 及 :class:`writer` 類別的初始器 (initializer, " "``__init__``) 函式進行註冊,就像這樣: ::" +#: ../../library/csv.rst:245 +msgid "" +"import csv\n" +"\n" +"with open('students.csv', 'w', newline='') as csvfile:\n" +" writer = csv.writer(csvfile, dialect='unix')" +msgstr "" + #: ../../library/csv.rst:253 msgid "" "The :class:`excel` class defines the usual properties of an Excel-generated " @@ -406,6 +464,15 @@ msgstr "" msgid "An example for :class:`Sniffer` use::" msgstr "一個 :class:`Sniffer` 的使用範例: ::" +#: ../../library/csv.rst:307 +msgid "" +"with open('example.csv', newline='') as csvfile:\n" +" dialect = csv.Sniffer().sniff(csvfile.read(1024))\n" +" csvfile.seek(0)\n" +" reader = csv.reader(csvfile, dialect)\n" +" # ... process CSV file contents here ..." +msgstr "" + #: ../../library/csv.rst:316 msgid "The :mod:`csv` module defines the following constants:" msgstr ":mod:`csv` 模組定義了以下常數:" @@ -744,14 +811,40 @@ msgstr "範例" msgid "The simplest example of reading a CSV file::" msgstr "最簡單的讀取 CSV 檔案範例: ::" +#: ../../library/csv.rst:554 +msgid "" +"import csv\n" +"with open('some.csv', newline='') as f:\n" +" reader = csv.reader(f)\n" +" for row in reader:\n" +" print(row)" +msgstr "" + #: ../../library/csv.rst:560 msgid "Reading a file with an alternate format::" msgstr "讀取一個其他格式的檔案: ::" +#: ../../library/csv.rst:562 +msgid "" +"import csv\n" +"with open('passwd', newline='') as f:\n" +" reader = csv.reader(f, delimiter=':', quoting=csv.QUOTE_NONE)\n" +" for row in reader:\n" +" print(row)" +msgstr "" + #: ../../library/csv.rst:568 msgid "The corresponding simplest possible writing example is::" msgstr "相對最簡單、可行的寫入範例為: ::" +#: ../../library/csv.rst:570 +msgid "" +"import csv\n" +"with open('some.csv', 'w', newline='') as f:\n" +" writer = csv.writer(f)\n" +" writer.writerows(someiterable)" +msgstr "" + #: ../../library/csv.rst:575 msgid "" "Since :func:`open` is used to open a CSV file for reading, the file will by " @@ -763,6 +856,15 @@ msgstr "" "碼格式(請見 :func:`locale.getencoding`),並解碼為 unicode。若要使用不同編碼" "格式進行檔案解碼,請使用 open 函式的 ``encoding`` 引數: ::" +#: ../../library/csv.rst:580 +msgid "" +"import csv\n" +"with open('some.csv', newline='', encoding='utf-8') as f:\n" +" reader = csv.reader(f)\n" +" for row in reader:\n" +" print(row)" +msgstr "" + #: ../../library/csv.rst:586 msgid "" "The same applies to writing in something other than the system default " @@ -775,18 +877,46 @@ msgstr "" msgid "Registering a new dialect::" msgstr "註冊一個新的 dialect : ::" +#: ../../library/csv.rst:591 +msgid "" +"import csv\n" +"csv.register_dialect('unixpwd', delimiter=':', quoting=csv.QUOTE_NONE)\n" +"with open('passwd', newline='') as f:\n" +" reader = csv.reader(f, 'unixpwd')" +msgstr "" + #: ../../library/csv.rst:596 msgid "" "A slightly more advanced use of the reader --- catching and reporting " "errors::" msgstr "稍微進階的讀取器用法 -- 擷取及回報錯誤: ::" +#: ../../library/csv.rst:598 +msgid "" +"import csv, sys\n" +"filename = 'some.csv'\n" +"with open(filename, newline='') as f:\n" +" reader = csv.reader(f)\n" +" try:\n" +" for row in reader:\n" +" print(row)\n" +" except csv.Error as e:\n" +" sys.exit('file {}, line {}: {}'.format(filename, reader.line_num, e))" +msgstr "" + #: ../../library/csv.rst:608 msgid "" "And while the module doesn't directly support parsing strings, it can easily " "be done::" msgstr "而當模組無法直接支援剖析字串時,仍可以輕鬆的解決: ::" +#: ../../library/csv.rst:611 +msgid "" +"import csv\n" +"for row in csv.reader(['one,two,three']):\n" +" print(row)" +msgstr "" + #: ../../library/csv.rst:617 msgid "Footnotes" msgstr "註解" diff --git a/library/ctypes.po b/library/ctypes.po index 302fd410fb..3ff6929a26 100644 --- a/library/ctypes.po +++ b/library/ctypes.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-08-04 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2023-04-26 02:59+0800\n" "Last-Translator: Adrian Liaw \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -87,6 +87,17 @@ msgid "" "convention::" msgstr "" +#: ../../library/ctypes.rst:57 +msgid "" +">>> from ctypes import *\n" +">>> print(windll.kernel32) \n" +"\n" +">>> print(cdll.msvcrt) \n" +"\n" +">>> libc = cdll.msvcrt \n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:65 msgid "Windows appends the usual ``.dll`` file suffix automatically." msgstr "" @@ -108,6 +119,16 @@ msgid "" "CDLL by calling the constructor::" msgstr "" +#: ../../library/ctypes.rst:79 +msgid "" +">>> cdll.LoadLibrary(\"libc.so.6\") \n" +"\n" +">>> libc = CDLL(\"libc.so.6\") \n" +">>> libc \n" +"\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:92 msgid "Accessing functions from loaded dlls" msgstr "" @@ -116,6 +137,21 @@ msgstr "" msgid "Functions are accessed as attributes of dll objects::" msgstr "" +#: ../../library/ctypes.rst:96 +msgid "" +">>> libc.printf\n" +"<_FuncPtr object at 0x...>\n" +">>> print(windll.kernel32.GetModuleHandleA) \n" +"<_FuncPtr object at 0x...>\n" +">>> print(windll.kernel32.MyOwnFunction) \n" +"Traceback (most recent call last):\n" +" File \"\", line 1, in \n" +" File \"ctypes.py\", line 239, in __getattr__\n" +" func = _StdcallFuncPtr(name, self)\n" +"AttributeError: function 'MyOwnFunction' not found\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:108 msgid "" "Note that win32 system dlls like ``kernel32`` and ``user32`` often export " @@ -127,6 +163,14 @@ msgid "" "``GetModuleHandle`` depending on whether UNICODE is defined or not::" msgstr "" +#: ../../library/ctypes.rst:116 +msgid "" +"/* ANSI version */\n" +"HMODULE GetModuleHandleA(LPCSTR lpModuleName);\n" +"/* UNICODE version */\n" +"HMODULE GetModuleHandleW(LPCWSTR lpModuleName);" +msgstr "" + #: ../../library/ctypes.rst:121 msgid "" "*windll* does not try to select one of them by magic, you must access the " @@ -141,6 +185,13 @@ msgid "" "`getattr` to retrieve the function::" msgstr "" +#: ../../library/ctypes.rst:129 +msgid "" +">>> getattr(cdll.msvcrt, \"??2@YAPAXI@Z\") \n" +"<_FuncPtr object at 0x...>\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:133 msgid "" "On Windows, some dlls export functions not by name but by ordinal. These " @@ -148,6 +199,19 @@ msgid "" "number::" msgstr "" +#: ../../library/ctypes.rst:136 +msgid "" +">>> cdll.kernel32[1] \n" +"<_FuncPtr object at 0x...>\n" +">>> cdll.kernel32[0] \n" +"Traceback (most recent call last):\n" +" File \"\", line 1, in \n" +" File \"ctypes.py\", line 310, in __getitem__\n" +" func = _StdcallFuncPtr(name, self)\n" +"AttributeError: function ordinal 0 not found\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:150 msgid "Calling functions" msgstr "" @@ -159,6 +223,12 @@ msgid "" "random integer::" msgstr "" +#: ../../library/ctypes.rst:155 +msgid "" +">>> print(libc.rand()) \n" +"1804289383" +msgstr "" + #: ../../library/ctypes.rst:158 msgid "" "On Windows, you can call the ``GetModuleHandleA()`` function, which returns " @@ -166,12 +236,36 @@ msgid "" "``NULL`` pointer)::" msgstr "" +#: ../../library/ctypes.rst:161 +msgid "" +">>> print(hex(windll.kernel32.GetModuleHandleA(None))) \n" +"0x1d000000\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:165 msgid "" ":exc:`ValueError` is raised when you call an ``stdcall`` function with the " "``cdecl`` calling convention, or vice versa::" msgstr "" +#: ../../library/ctypes.rst:168 +msgid "" +">>> cdll.kernel32.GetModuleHandleA(None) \n" +"Traceback (most recent call last):\n" +" File \"\", line 1, in \n" +"ValueError: Procedure probably called with not enough arguments (4 bytes " +"missing)\n" +">>>\n" +"\n" +">>> windll.msvcrt.printf(b\"spam\") \n" +"Traceback (most recent call last):\n" +" File \"\", line 1, in \n" +"ValueError: Procedure probably called with too many arguments (4 bytes in " +"excess)\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:180 msgid "" "To find out the correct calling convention you have to look into the C " @@ -185,6 +279,15 @@ msgid "" "with invalid argument values::" msgstr "" +#: ../../library/ctypes.rst:187 +msgid "" +">>> windll.kernel32.GetModuleHandleA(32) \n" +"Traceback (most recent call last):\n" +" File \"\", line 1, in \n" +"OSError: exception: access violation reading 0x00000020\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:193 msgid "" "There are, however, enough ways to crash Python with :mod:`ctypes`, so you " @@ -451,11 +554,35 @@ msgid "" "of the correct type and value::" msgstr "" +#: ../../library/ctypes.rst:272 +msgid "" +">>> c_int()\n" +"c_long(0)\n" +">>> c_wchar_p(\"Hello, World\")\n" +"c_wchar_p(140018365411392)\n" +">>> c_ushort(-3)\n" +"c_ushort(65533)\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:280 msgid "" "Since these types are mutable, their value can also be changed afterwards::" msgstr "" +#: ../../library/ctypes.rst:282 +msgid "" +">>> i = c_int(42)\n" +">>> print(i)\n" +"c_long(42)\n" +">>> print(i.value)\n" +"42\n" +">>> i.value = -99\n" +">>> print(i.value)\n" +"-99\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:292 msgid "" "Assigning a new value to instances of the pointer types :class:`c_char_p`, :" @@ -464,6 +591,24 @@ msgid "" "Python bytes objects are immutable)::" msgstr "" +#: ../../library/ctypes.rst:297 +msgid "" +">>> s = \"Hello, World\"\n" +">>> c_s = c_wchar_p(s)\n" +">>> print(c_s)\n" +"c_wchar_p(139966785747344)\n" +">>> print(c_s.value)\n" +"Hello World\n" +">>> c_s.value = \"Hi, there\"\n" +">>> print(c_s) # the memory location has changed\n" +"c_wchar_p(139966783348904)\n" +">>> print(c_s.value)\n" +"Hi, there\n" +">>> print(s) # first object is unchanged\n" +"Hello, World\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:312 msgid "" "You should be careful, however, not to pass them to functions expecting " @@ -474,6 +619,28 @@ msgid "" "``value`` property::" msgstr "" +#: ../../library/ctypes.rst:319 +msgid "" +">>> from ctypes import *\n" +">>> p = create_string_buffer(3) # create a 3 byte buffer, " +"initialized to NUL bytes\n" +">>> print(sizeof(p), repr(p.raw))\n" +"3 b'\\x00\\x00\\x00'\n" +">>> p = create_string_buffer(b\"Hello\") # create a buffer containing a " +"NUL terminated string\n" +">>> print(sizeof(p), repr(p.raw))\n" +"6 b'Hello\\x00'\n" +">>> print(repr(p.value))\n" +"b'Hello'\n" +">>> p = create_string_buffer(b\"Hello\", 10) # create a 10 byte buffer\n" +">>> print(sizeof(p), repr(p.raw))\n" +"10 b'Hello\\x00\\x00\\x00\\x00\\x00'\n" +">>> p.value = b\"Hi\"\n" +">>> print(sizeof(p), repr(p.raw))\n" +"10 b'Hi\\x00lo\\x00\\x00\\x00\\x00\\x00'\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:336 msgid "" "The :func:`create_string_buffer` function replaces the old :func:`!c_buffer` " @@ -493,6 +660,25 @@ msgid "" "from within *IDLE* or *PythonWin*::" msgstr "" +#: ../../library/ctypes.rst:351 +msgid "" +">>> printf = libc.printf\n" +">>> printf(b\"Hello, %s\\n\", b\"World!\")\n" +"Hello, World!\n" +"14\n" +">>> printf(b\"Hello, %S\\n\", \"World!\")\n" +"Hello, World!\n" +"14\n" +">>> printf(b\"%d bottles of beer\\n\", 42)\n" +"42 bottles of beer\n" +"19\n" +">>> printf(b\"%f bottles of beer\\n\", 42.5)\n" +"Traceback (most recent call last):\n" +" File \"\", line 1, in \n" +"ArgumentError: argument 2: TypeError: Don't know how to convert parameter 2\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:367 msgid "" "As has been mentioned before, all Python types except integers, strings, and " @@ -500,6 +686,14 @@ msgid "" "so that they can be converted to the required C data type::" msgstr "" +#: ../../library/ctypes.rst:371 +msgid "" +">>> printf(b\"An int %d, a double %f\\n\", 1234, c_double(3.14))\n" +"An int 1234, a double 3.140000\n" +"31\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:379 msgid "Calling variadic functions" msgstr "" @@ -519,6 +713,10 @@ msgid "" "attribute for the regular, non-variadic, function arguments:" msgstr "" +#: ../../library/ctypes.rst:389 +msgid "libc.printf.argtypes = [ctypes.c_char_p]" +msgstr "" + #: ../../library/ctypes.rst:393 msgid "" "Because specifying the attribute does not inhibit portability it is advised " @@ -538,6 +736,19 @@ msgid "" "or an object with an :attr:`!_as_parameter_` attribute::" msgstr "" +#: ../../library/ctypes.rst:408 +msgid "" +">>> class Bottles:\n" +"... def __init__(self, number):\n" +"... self._as_parameter_ = number\n" +"...\n" +">>> bottles = Bottles(42)\n" +">>> printf(b\"%d bottles of beer\\n\", bottles)\n" +"42 bottles of beer\n" +"19\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:418 msgid "" "If you don't want to store the instance's data in the :attr:`!" @@ -564,6 +775,15 @@ msgid "" "feature)::" msgstr "" +#: ../../library/ctypes.rst:436 +msgid "" +">>> printf.argtypes = [c_char_p, c_char_p, c_int, c_double]\n" +">>> printf(b\"String '%s', Int %d, Double %f\\n\", b\"Hi\", 10, 2.2)\n" +"String 'Hi', Int 10, Double 2.200000\n" +"37\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:442 msgid "" "Specifying a format protects against incompatible argument types (just as a " @@ -571,6 +791,18 @@ msgid "" "types::" msgstr "" +#: ../../library/ctypes.rst:445 +msgid "" +">>> printf(b\"%d %d %d\", 1, 2, 3)\n" +"Traceback (most recent call last):\n" +" File \"\", line 1, in \n" +"ArgumentError: argument 2: TypeError: wrong type\n" +">>> printf(b\"%s %d %f\\n\", b\"X\", 2, 3)\n" +"X 2 3.000000\n" +"13\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:454 msgid "" "If you have defined your own classes which you pass to function calls, you " @@ -603,22 +835,49 @@ msgid "" "expr:`int`, you should specify the :attr:`!restype` attribute::" msgstr "" +#: ../../library/ctypes.rst:486 +msgid ">>> libc.time.restype = c_time_t" +msgstr "" + #: ../../library/ctypes.rst:488 msgid "The argument types can be specified using :attr:`~_FuncPtr.argtypes`::" msgstr "" +#: ../../library/ctypes.rst:490 +msgid ">>> libc.time.argtypes = (POINTER(c_time_t),)" +msgstr "" + #: ../../library/ctypes.rst:492 msgid "" "To call the function with a ``NULL`` pointer as first argument, use " "``None``::" msgstr "" +#: ../../library/ctypes.rst:494 +msgid "" +">>> print(libc.time(None)) \n" +"1150640792" +msgstr "" + #: ../../library/ctypes.rst:497 msgid "" "Here is a more advanced example, it uses the :func:`!strchr` function, which " "expects a string pointer and a char, and returns a pointer to a string::" msgstr "" +#: ../../library/ctypes.rst:500 +msgid "" +">>> strchr = libc.strchr\n" +">>> strchr(b\"abcdef\", ord(\"d\")) \n" +"8059983\n" +">>> strchr.restype = c_char_p # c_char_p is a pointer to a string\n" +">>> strchr(b\"abcdef\", ord(\"d\"))\n" +"b'def'\n" +">>> print(strchr(b\"abcdef\", ord(\"x\")))\n" +"None\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:510 msgid "" "If you want to avoid the :func:`ord(\"x\") ` calls above, you can set " @@ -626,6 +885,23 @@ msgid "" "converted from a single character Python bytes object into a C char:" msgstr "" +#: ../../library/ctypes.rst:514 +msgid "" +">>> strchr.restype = c_char_p\n" +">>> strchr.argtypes = [c_char_p, c_char]\n" +">>> strchr(b\"abcdef\", b\"d\")\n" +"b'def'\n" +">>> strchr(b\"abcdef\", b\"def\")\n" +"Traceback (most recent call last):\n" +"ctypes.ArgumentError: argument 2: TypeError: one character bytes, bytearray " +"or integer expected\n" +">>> print(strchr(b\"abcdef\", b\"x\"))\n" +"None\n" +">>> strchr(b\"abcdef\", b\"d\")\n" +"b'def'\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:529 msgid "" "You can also use a callable Python object (a function or a class for " @@ -636,6 +912,26 @@ msgid "" "automatically raise an exception::" msgstr "" +#: ../../library/ctypes.rst:535 +msgid "" +">>> GetModuleHandle = windll.kernel32.GetModuleHandleA \n" +">>> def ValidHandle(value):\n" +"... if value == 0:\n" +"... raise WinError()\n" +"... return value\n" +"...\n" +">>>\n" +">>> GetModuleHandle.restype = ValidHandle \n" +">>> GetModuleHandle(None) \n" +"486539264\n" +">>> GetModuleHandle(\"something silly\") \n" +"Traceback (most recent call last):\n" +" File \"\", line 1, in \n" +" File \"\", line 3, in ValidHandle\n" +"OSError: [Errno 126] The specified module could not be found.\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:552 msgid "" "``WinError`` is a function which will call Windows ``FormatMessage()`` api " @@ -672,6 +968,21 @@ msgid "" "you don't need the pointer object in Python itself::" msgstr "" +#: ../../library/ctypes.rst:577 +msgid "" +">>> i = c_int()\n" +">>> f = c_float()\n" +">>> s = create_string_buffer(b'\\000' * 32)\n" +">>> print(i.value, f.value, repr(s.value))\n" +"0 0.0 b''\n" +">>> libc.sscanf(b\"1 3.14 Hello\", b\"%d %f %s\",\n" +"... byref(i), byref(f), s)\n" +"3\n" +">>> print(i.value, f.value, repr(s.value))\n" +"1 3.1400001049 b'Hello'\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:593 msgid "Structures and unions" msgstr "" @@ -698,6 +1009,26 @@ msgid "" "constructor::" msgstr "" +#: ../../library/ctypes.rst:606 +msgid "" +">>> from ctypes import *\n" +">>> class POINT(Structure):\n" +"... _fields_ = [(\"x\", c_int),\n" +"... (\"y\", c_int)]\n" +"...\n" +">>> point = POINT(10, 20)\n" +">>> print(point.x, point.y)\n" +"10 20\n" +">>> point = POINT(y=5)\n" +">>> print(point.x, point.y)\n" +"0 5\n" +">>> POINT(1, 2, 3)\n" +"Traceback (most recent call last):\n" +" File \"\", line 1, in \n" +"TypeError: too many initializers\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:623 msgid "" "You can, however, build much more complicated structures. A structure can " @@ -710,18 +1041,47 @@ msgid "" "*lowerright*::" msgstr "" +#: ../../library/ctypes.rst:629 +msgid "" +">>> class RECT(Structure):\n" +"... _fields_ = [(\"upperleft\", POINT),\n" +"... (\"lowerright\", POINT)]\n" +"...\n" +">>> rc = RECT(point)\n" +">>> print(rc.upperleft.x, rc.upperleft.y)\n" +"0 5\n" +">>> print(rc.lowerright.x, rc.lowerright.y)\n" +"0 0\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:640 msgid "" "Nested structures can also be initialized in the constructor in several " "ways::" msgstr "" +#: ../../library/ctypes.rst:642 +msgid "" +">>> r = RECT(POINT(1, 2), POINT(3, 4))\n" +">>> r = RECT((1, 2), (3, 4))" +msgstr "" + #: ../../library/ctypes.rst:645 msgid "" "Field :term:`descriptor`\\s can be retrieved from the *class*, they are " "useful for debugging because they can provide useful information::" msgstr "" +#: ../../library/ctypes.rst:648 +msgid "" +">>> print(POINT.x)\n" +"\n" +">>> print(POINT.y)\n" +"\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:659 msgid "" ":mod:`ctypes` does not support passing unions or structures with bit-fields " @@ -763,6 +1123,19 @@ msgid "" "the third item in the :attr:`~Structure._fields_` tuples::" msgstr "" +#: ../../library/ctypes.rst:689 +msgid "" +">>> class Int(Structure):\n" +"... _fields_ = [(\"first_16\", c_int, 16),\n" +"... (\"second_16\", c_int, 16)]\n" +"...\n" +">>> print(Int.first_16)\n" +"\n" +">>> print(Int.second_16)\n" +"\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:703 msgid "Arrays" msgstr "" @@ -779,16 +1152,43 @@ msgid "" "a positive integer::" msgstr "" +#: ../../library/ctypes.rst:710 +msgid "TenPointsArrayType = POINT * 10" +msgstr "" + #: ../../library/ctypes.rst:712 msgid "" "Here is an example of a somewhat artificial data type, a structure " "containing 4 POINTs among other stuff::" msgstr "" +#: ../../library/ctypes.rst:715 +msgid "" +">>> from ctypes import *\n" +">>> class POINT(Structure):\n" +"... _fields_ = (\"x\", c_int), (\"y\", c_int)\n" +"...\n" +">>> class MyStruct(Structure):\n" +"... _fields_ = [(\"a\", c_int),\n" +"... (\"b\", c_float),\n" +"... (\"point_array\", POINT * 4)]\n" +">>>\n" +">>> print(len(MyStruct().point_array))\n" +"4\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:728 msgid "Instances are created in the usual way, by calling the class::" msgstr "" +#: ../../library/ctypes.rst:730 +msgid "" +"arr = TenPointsArrayType()\n" +"for pt in arr:\n" +" print(pt.x, pt.y)" +msgstr "" + #: ../../library/ctypes.rst:734 msgid "" "The above code print a series of ``0 0`` lines, because the array contents " @@ -799,6 +1199,19 @@ msgstr "" msgid "Initializers of the correct type can also be specified::" msgstr "" +#: ../../library/ctypes.rst:739 +msgid "" +">>> from ctypes import *\n" +">>> TenIntegers = c_int * 10\n" +">>> ii = TenIntegers(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)\n" +">>> print(ii)\n" +"\n" +">>> for i in ii: print(i, end=\" \")\n" +"...\n" +"1 2 3 4 5 6 7 8 9 10\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:753 msgid "Pointers" msgstr "" @@ -809,18 +1222,42 @@ msgid "" "mod:`ctypes` type::" msgstr "" +#: ../../library/ctypes.rst:758 +msgid "" +">>> from ctypes import *\n" +">>> i = c_int(42)\n" +">>> pi = pointer(i)\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:763 msgid "" "Pointer instances have a :attr:`~_Pointer.contents` attribute which returns " "the object to which the pointer points, the ``i`` object above::" msgstr "" +#: ../../library/ctypes.rst:766 +msgid "" +">>> pi.contents\n" +"c_long(42)\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:770 msgid "" "Note that :mod:`ctypes` does not have OOR (original object return), it " "constructs a new, equivalent object each time you retrieve an attribute::" msgstr "" +#: ../../library/ctypes.rst:773 +msgid "" +">>> pi.contents is i\n" +"False\n" +">>> pi.contents is pi.contents\n" +"False\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:779 msgid "" "Assigning another :class:`c_int` instance to the pointer's contents " @@ -828,14 +1265,40 @@ msgid "" "is stored::" msgstr "" +#: ../../library/ctypes.rst:782 +msgid "" +">>> i = c_int(99)\n" +">>> pi.contents = i\n" +">>> pi.contents\n" +"c_long(99)\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:791 msgid "Pointer instances can also be indexed with integers::" msgstr "" +#: ../../library/ctypes.rst:793 +msgid "" +">>> pi[0]\n" +"99\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:797 msgid "Assigning to an integer index changes the pointed to value::" msgstr "" +#: ../../library/ctypes.rst:799 +msgid "" +">>> print(i)\n" +"c_long(99)\n" +">>> pi[0] = 22\n" +">>> print(i)\n" +"c_long(22)\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:806 msgid "" "It is also possible to use indexes different from 0, but you must know what " @@ -853,18 +1316,55 @@ msgid "" "returns a new type::" msgstr "" +#: ../../library/ctypes.rst:817 +msgid "" +">>> PI = POINTER(c_int)\n" +">>> PI\n" +"\n" +">>> PI(42)\n" +"Traceback (most recent call last):\n" +" File \"\", line 1, in \n" +"TypeError: expected c_long instead of int\n" +">>> PI(c_int(42))\n" +"\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:828 msgid "" "Calling the pointer type without an argument creates a ``NULL`` pointer. " "``NULL`` pointers have a ``False`` boolean value::" msgstr "" +#: ../../library/ctypes.rst:831 +msgid "" +">>> null_ptr = POINTER(c_int)()\n" +">>> print(bool(null_ptr))\n" +"False\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:836 msgid "" ":mod:`ctypes` checks for ``NULL`` when dereferencing pointers (but " "dereferencing invalid non-\\ ``NULL`` pointers would crash Python)::" msgstr "" +#: ../../library/ctypes.rst:839 +msgid "" +">>> null_ptr[0]\n" +"Traceback (most recent call last):\n" +" ....\n" +"ValueError: NULL pointer access\n" +">>>\n" +"\n" +">>> null_ptr[0] = 1234\n" +"Traceback (most recent call last):\n" +" ....\n" +"ValueError: NULL pointer access\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:855 msgid "Type conversions" msgstr "" @@ -880,6 +1380,23 @@ msgid "" "ctypes accepts an array of c_int::" msgstr "" +#: ../../library/ctypes.rst:864 +msgid "" +">>> class Bar(Structure):\n" +"... _fields_ = [(\"count\", c_int), (\"values\", POINTER(c_int))]\n" +"...\n" +">>> bar = Bar()\n" +">>> bar.values = (c_int * 3)(1, 2, 3)\n" +">>> bar.count = 3\n" +">>> for i in range(bar.count):\n" +"... print(bar.values[i])\n" +"...\n" +"1\n" +"2\n" +"3\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:878 msgid "" "In addition, if a function argument is explicitly declared to be a pointer " @@ -893,6 +1410,12 @@ msgstr "" msgid "To set a POINTER type field to ``NULL``, you can assign ``None``::" msgstr "" +#: ../../library/ctypes.rst:885 +msgid "" +">>> bar.values = None\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:890 msgid "" "Sometimes you have instances of incompatible types. In C, you can cast one " @@ -902,6 +1425,16 @@ msgid "" "``values`` field, but not instances of other types::" msgstr "" +#: ../../library/ctypes.rst:896 +msgid "" +">>> bar.values = (c_byte * 4)()\n" +"Traceback (most recent call last):\n" +" File \"\", line 1, in \n" +"TypeError: incompatible types, c_byte_Array_4 instance instead of LP_c_long " +"instance\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:902 msgid "For these cases, the :func:`cast` function is handy." msgstr "" @@ -915,12 +1448,29 @@ msgid "" "references the same memory block as the first argument::" msgstr "" +#: ../../library/ctypes.rst:910 +msgid "" +">>> a = (c_byte * 4)()\n" +">>> cast(a, POINTER(c_int))\n" +"\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:915 msgid "" "So, :func:`cast` can be used to assign to the ``values`` field of ``Bar`` " "the structure::" msgstr "" +#: ../../library/ctypes.rst:918 +msgid "" +">>> bar = Bar()\n" +">>> bar.values = cast((c_byte * 4)(), POINTER(c_int))\n" +">>> print(bar.values[0])\n" +"0\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:928 msgid "Incomplete Types" msgstr "" @@ -932,12 +1482,35 @@ msgid "" "defined later::" msgstr "" +#: ../../library/ctypes.rst:934 +msgid "" +"struct cell; /* forward declaration */\n" +"\n" +"struct cell {\n" +" char *name;\n" +" struct cell *next;\n" +"};" +msgstr "" + #: ../../library/ctypes.rst:941 msgid "" "The straightforward translation into ctypes code would be this, but it does " "not work::" msgstr "" +#: ../../library/ctypes.rst:944 +msgid "" +">>> class cell(Structure):\n" +"... _fields_ = [(\"name\", c_char_p),\n" +"... (\"next\", POINTER(cell))]\n" +"...\n" +"Traceback (most recent call last):\n" +" File \"\", line 1, in \n" +" File \"\", line 2, in cell\n" +"NameError: name 'cell' is not defined\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:954 msgid "" "because the new ``class cell`` is not available in the class statement " @@ -945,12 +1518,40 @@ msgid "" "`~Structure._fields_` attribute later, after the class statement::" msgstr "" +#: ../../library/ctypes.rst:958 +msgid "" +">>> from ctypes import *\n" +">>> class cell(Structure):\n" +"... pass\n" +"...\n" +">>> cell._fields_ = [(\"name\", c_char_p),\n" +"... (\"next\", POINTER(cell))]\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:966 msgid "" "Let's try it. We create two instances of ``cell``, and let them point to " "each other, and finally follow the pointer chain a few times::" msgstr "" +#: ../../library/ctypes.rst:969 +msgid "" +">>> c1 = cell()\n" +">>> c1.name = b\"foo\"\n" +">>> c2 = cell()\n" +">>> c2.name = b\"bar\"\n" +">>> c1.next = pointer(c2)\n" +">>> c2.next = pointer(c1)\n" +">>> p = c1\n" +">>> for i in range(8):\n" +"... print(p.name, end=\" \")\n" +"... p = p.next[0]\n" +"...\n" +"foo bar foo bar foo bar foo bar\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:987 msgid "Callback functions" msgstr "" @@ -990,6 +1591,15 @@ msgid "" "function. :c:func:`!qsort` will be used to sort an array of integers::" msgstr "" +#: ../../library/ctypes.rst:1009 +msgid "" +">>> IntArray5 = c_int * 5\n" +">>> ia = IntArray5(5, 1, 7, 33, 99)\n" +">>> qsort = libc.qsort\n" +">>> qsort.restype = None\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:1015 msgid "" ":func:`!qsort` must be called with a pointer to the data to sort, the number " @@ -1006,30 +1616,97 @@ msgid "" "integer. First we create the ``type`` for the callback function::" msgstr "" +#: ../../library/ctypes.rst:1024 +msgid "" +">>> CMPFUNC = CFUNCTYPE(c_int, POINTER(c_int), POINTER(c_int))\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:1027 msgid "" "To get started, here is a simple callback that shows the values it gets " "passed::" msgstr "" +#: ../../library/ctypes.rst:1030 +msgid "" +">>> def py_cmp_func(a, b):\n" +"... print(\"py_cmp_func\", a[0], b[0])\n" +"... return 0\n" +"...\n" +">>> cmp_func = CMPFUNC(py_cmp_func)\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:1037 msgid "The result::" msgstr "" +#: ../../library/ctypes.rst:1039 +msgid "" +">>> qsort(ia, len(ia), sizeof(c_int), cmp_func) \n" +"py_cmp_func 5 1\n" +"py_cmp_func 33 99\n" +"py_cmp_func 7 33\n" +"py_cmp_func 5 7\n" +"py_cmp_func 1 7\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:1047 msgid "Now we can actually compare the two items and return a useful result::" msgstr "" +#: ../../library/ctypes.rst:1049 +msgid "" +">>> def py_cmp_func(a, b):\n" +"... print(\"py_cmp_func\", a[0], b[0])\n" +"... return a[0] - b[0]\n" +"...\n" +">>>\n" +">>> qsort(ia, len(ia), sizeof(c_int), CMPFUNC(py_cmp_func)) \n" +"py_cmp_func 5 1\n" +"py_cmp_func 33 99\n" +"py_cmp_func 7 33\n" +"py_cmp_func 1 7\n" +"py_cmp_func 5 7\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:1062 msgid "As we can easily check, our array is sorted now::" msgstr "" +#: ../../library/ctypes.rst:1064 +msgid "" +">>> for i in ia: print(i, end=\" \")\n" +"...\n" +"1 5 7 33 99\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:1069 msgid "" "The function factories can be used as decorator factories, so we may as well " "write::" msgstr "" +#: ../../library/ctypes.rst:1072 +msgid "" +">>> @CFUNCTYPE(c_int, POINTER(c_int), POINTER(c_int))\n" +"... def py_cmp_func(a, b):\n" +"... print(\"py_cmp_func\", a[0], b[0])\n" +"... return a[0] - b[0]\n" +"...\n" +">>> qsort(ia, len(ia), sizeof(c_int), py_cmp_func)\n" +"py_cmp_func 5 1\n" +"py_cmp_func 33 99\n" +"py_cmp_func 7 33\n" +"py_cmp_func 1 7\n" +"py_cmp_func 5 7\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:1087 msgid "" "Make sure you keep references to :func:`CFUNCTYPE` objects as long as they " @@ -1065,6 +1742,13 @@ msgid "" "to the Python C api::" msgstr "" +#: ../../library/ctypes.rst:1111 +msgid "" +">>> version = ctypes.c_int.in_dll(ctypes.pythonapi, \"Py_Version\")\n" +">>> print(hex(version.value))\n" +"0x30c00a0" +msgstr "" + #: ../../library/ctypes.rst:1115 msgid "" "An extended example which also demonstrates the use of pointers accesses " @@ -1090,12 +1774,33 @@ msgid "" "example size, we show only how this table can be read with :mod:`ctypes`::" msgstr "" +#: ../../library/ctypes.rst:1128 +msgid "" +">>> from ctypes import *\n" +">>>\n" +">>> class struct_frozen(Structure):\n" +"... _fields_ = [(\"name\", c_char_p),\n" +"... (\"code\", POINTER(c_ubyte)),\n" +"... (\"size\", c_int),\n" +"... (\"get_code\", POINTER(c_ubyte)), # Function pointer\n" +"... ]\n" +"...\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:1139 msgid "" "We have defined the :c:struct:`_frozen` data type, so we can get the pointer " "to the table::" msgstr "" +#: ../../library/ctypes.rst:1142 +msgid "" +">>> FrozenTable = POINTER(struct_frozen)\n" +">>> table = FrozenTable.in_dll(pythonapi, \"_PyImport_FrozenBootstrap\")\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:1146 msgid "" "Since ``table`` is a ``pointer`` to the array of ``struct_frozen`` records, " @@ -1105,6 +1810,19 @@ msgid "" "the loop when we hit the ``NULL`` entry::" msgstr "" +#: ../../library/ctypes.rst:1152 +msgid "" +">>> for item in table:\n" +"... if item.name is None:\n" +"... break\n" +"... print(item.name.decode(\"ascii\"), item.size)\n" +"...\n" +"_frozen_importlib 31764\n" +"_frozen_importlib_external 41499\n" +"zipimport 12345\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:1162 msgid "" "The fact that standard Python has a frozen module and a frozen package " @@ -1126,12 +1844,41 @@ msgstr "" msgid "Consider the following example::" msgstr "" +#: ../../library/ctypes.rst:1177 +msgid "" +">>> from ctypes import *\n" +">>> class POINT(Structure):\n" +"... _fields_ = (\"x\", c_int), (\"y\", c_int)\n" +"...\n" +">>> class RECT(Structure):\n" +"... _fields_ = (\"a\", POINT), (\"b\", POINT)\n" +"...\n" +">>> p1 = POINT(1, 2)\n" +">>> p2 = POINT(3, 4)\n" +">>> rc = RECT(p1, p2)\n" +">>> print(rc.a.x, rc.a.y, rc.b.x, rc.b.y)\n" +"1 2 3 4\n" +">>> # now swap the two points\n" +">>> rc.a, rc.b = rc.b, rc.a\n" +">>> print(rc.a.x, rc.a.y, rc.b.x, rc.b.y)\n" +"3 4 3 4\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:1195 msgid "" "Hm. We certainly expected the last statement to print ``3 4 1 2``. What " "happened? Here are the steps of the ``rc.a, rc.b = rc.b, rc.a`` line above::" msgstr "" +#: ../../library/ctypes.rst:1198 +msgid "" +">>> temp0, temp1 = rc.b, rc.a\n" +">>> rc.a = temp0\n" +">>> rc.b = temp1\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:1203 msgid "" "Note that ``temp0`` and ``temp1`` are objects still using the internal " @@ -1154,6 +1901,17 @@ msgid "" "this::" msgstr "" +#: ../../library/ctypes.rst:1215 +msgid "" +">>> s = c_char_p()\n" +">>> s.value = b\"abc def ghi\"\n" +">>> s.value\n" +"b'abc def ghi'\n" +">>> s.value is s.value\n" +"False\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:1225 msgid "" "Objects instantiated from :class:`c_char_p` can only have their value set to " @@ -1187,6 +1945,23 @@ msgid "" "objects type, a :exc:`ValueError` is raised if this is tried::" msgstr "" +#: ../../library/ctypes.rst:1248 +msgid "" +">>> short_array = (c_short * 4)()\n" +">>> print(sizeof(short_array))\n" +"8\n" +">>> resize(short_array, 4)\n" +"Traceback (most recent call last):\n" +" ...\n" +"ValueError: minimum size is 8\n" +">>> resize(short_array, 32)\n" +">>> sizeof(short_array)\n" +"32\n" +">>> sizeof(type(short_array))\n" +"8\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:1262 msgid "" "This is nice and fine, but how would one access the additional elements " @@ -1194,6 +1969,17 @@ msgid "" "we get errors accessing other elements::" msgstr "" +#: ../../library/ctypes.rst:1266 +msgid "" +">>> short_array[:]\n" +"[0, 0, 0, 0]\n" +">>> short_array[7]\n" +"Traceback (most recent call last):\n" +" ...\n" +"IndexError: invalid index\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:1274 msgid "" "Another way to use variable-sized data types with :mod:`ctypes` is to use " @@ -1260,6 +2046,18 @@ msgstr "" msgid "Here are some examples::" msgstr "以下是一些範例: ::" +#: ../../library/ctypes.rst:1324 +msgid "" +">>> from ctypes.util import find_library\n" +">>> find_library(\"m\")\n" +"'libm.so.6'\n" +">>> find_library(\"c\")\n" +"'libc.so.6'\n" +">>> find_library(\"bz2\")\n" +"'libbz2.so.1.0'\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:1333 msgid "" "On macOS, :func:`~ctypes.util.find_library` tries several predefined naming " @@ -1267,6 +2065,20 @@ msgid "" "successful::" msgstr "" +#: ../../library/ctypes.rst:1336 +msgid "" +">>> from ctypes.util import find_library\n" +">>> find_library(\"c\")\n" +"'/usr/lib/libc.dylib'\n" +">>> find_library(\"m\")\n" +"'/usr/lib/libm.dylib'\n" +">>> find_library(\"bz2\")\n" +"'/usr/lib/libbz2.dylib'\n" +">>> find_library(\"AGL\")\n" +"'/System/Library/Frameworks/AGL.framework/AGL'\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:1347 msgid "" "On Windows, :func:`~ctypes.util.find_library` searches along the system " @@ -1449,6 +2261,16 @@ msgid "" "other hand, accessing it through an index returns a new object each time::" msgstr "" +#: ../../library/ctypes.rst:1502 +msgid "" +">>> from ctypes import CDLL\n" +">>> libc = CDLL(\"libc.so.6\") # On Linux\n" +">>> libc.time == libc.time\n" +"True\n" +">>> libc['time'] == libc['time']\n" +"False" +msgstr "" + #: ../../library/ctypes.rst:1509 msgid "" "The following public attributes are available, their name starts with an " @@ -1813,14 +2635,41 @@ msgid "" "declaration from the windows header file is this::" msgstr "" +#: ../../library/ctypes.rst:1803 +msgid "" +"WINUSERAPI int WINAPI\n" +"MessageBoxW(\n" +" HWND hWnd,\n" +" LPCWSTR lpText,\n" +" LPCWSTR lpCaption,\n" +" UINT uType);" +msgstr "" + #: ../../library/ctypes.rst:1810 ../../library/ctypes.rst:1833 msgid "Here is the wrapping with :mod:`ctypes`::" msgstr "" +#: ../../library/ctypes.rst:1812 +msgid "" +">>> from ctypes import c_int, WINFUNCTYPE, windll\n" +">>> from ctypes.wintypes import HWND, LPCWSTR, UINT\n" +">>> prototype = WINFUNCTYPE(c_int, HWND, LPCWSTR, LPCWSTR, UINT)\n" +">>> paramflags = (1, \"hwnd\", 0), (1, \"text\", \"Hi\"), (1, \"caption\", " +"\"Hello from ctypes\"), (1, \"flags\", 0)\n" +">>> MessageBox = prototype((\"MessageBoxW\", windll.user32), paramflags)" +msgstr "" + #: ../../library/ctypes.rst:1818 msgid "The ``MessageBox`` foreign function can now be called in these ways::" msgstr "" +#: ../../library/ctypes.rst:1820 +msgid "" +">>> MessageBox()\n" +">>> MessageBox(text=\"Spam, spam, spam\")\n" +">>> MessageBox(flags=2, text=\"foo bar\")" +msgstr "" + #: ../../library/ctypes.rst:1824 msgid "" "A second example demonstrates output parameters. The win32 " @@ -1829,6 +2678,25 @@ msgid "" "the C declaration::" msgstr "" +#: ../../library/ctypes.rst:1828 +msgid "" +"WINUSERAPI BOOL WINAPI\n" +"GetWindowRect(\n" +" HWND hWnd,\n" +" LPRECT lpRect);" +msgstr "" + +#: ../../library/ctypes.rst:1835 +msgid "" +">>> from ctypes import POINTER, WINFUNCTYPE, windll, WinError\n" +">>> from ctypes.wintypes import BOOL, HWND, RECT\n" +">>> prototype = WINFUNCTYPE(BOOL, HWND, POINTER(RECT))\n" +">>> paramflags = (1, \"hwnd\"), (2, \"lprect\")\n" +">>> GetWindowRect = prototype((\"GetWindowRect\", windll.user32), " +"paramflags)\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:1842 msgid "" "Functions with output parameters will automatically return the output " @@ -1846,6 +2714,17 @@ msgid "" "exception when the api call failed::" msgstr "" +#: ../../library/ctypes.rst:1852 +msgid "" +">>> def errcheck(result, func, args):\n" +"... if not result:\n" +"... raise WinError()\n" +"... return args\n" +"...\n" +">>> GetWindowRect.errcheck = errcheck\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:1860 msgid "" "If the :attr:`~_FuncPtr.errcheck` function returns the argument tuple it " @@ -1855,6 +2734,18 @@ msgid "" "and return them instead, the normal processing will no longer take place::" msgstr "" +#: ../../library/ctypes.rst:1866 +msgid "" +">>> def errcheck(result, func, args):\n" +"... if not result:\n" +"... raise WinError()\n" +"... rc = args[1]\n" +"... return rc.left, rc.top, rc.bottom, rc.right\n" +"...\n" +">>> GetWindowRect.errcheck = errcheck\n" +">>>" +msgstr "" + #: ../../library/ctypes.rst:1879 msgid "Utility functions" msgstr "" @@ -1890,6 +2781,10 @@ msgstr "" msgid "``byref(obj, offset)`` corresponds to this C code::" msgstr "" +#: ../../library/ctypes.rst:1903 +msgid "(((char *)&obj) + offset)" +msgstr "" + #: ../../library/ctypes.rst:1905 msgid "" "The returned object can only be used as a foreign function call parameter. " @@ -2588,6 +3483,15 @@ msgid "" "data types that directly or indirectly reference themselves::" msgstr "" +#: ../../library/ctypes.rst:2508 +msgid "" +"class List(Structure):\n" +" pass\n" +"List._fields_ = [(\"pnext\", POINTER(List)),\n" +" ...\n" +" ]" +msgstr "" + #: ../../library/ctypes.rst:2514 msgid "" "The :attr:`_fields_` class variable must, however, be defined before the " @@ -2630,6 +3534,19 @@ msgstr "" msgid "Here is an example type (Windows)::" msgstr "" +#: ../../library/ctypes.rst:2545 +msgid "" +"class _U(Union):\n" +" _fields_ = [(\"lptdesc\", POINTER(TYPEDESC)),\n" +" (\"lpadesc\", POINTER(ARRAYDESC)),\n" +" (\"hreftype\", HREFTYPE)]\n" +"\n" +"class TYPEDESC(Structure):\n" +" _anonymous_ = (\"u\",)\n" +" _fields_ = [(\"u\", _U),\n" +" (\"vt\", VARTYPE)]" +msgstr "" + #: ../../library/ctypes.rst:2556 msgid "" "The ``TYPEDESC`` structure describes a COM data type, the ``vt`` field " @@ -2640,6 +3557,14 @@ msgid "" "temporary union instance::" msgstr "" +#: ../../library/ctypes.rst:2563 +msgid "" +"td = TYPEDESC()\n" +"td.vt = VT_PTR\n" +"td.lptdesc = POINTER(some_type)\n" +"td.u.lptdesc = POINTER(some_type)" +msgstr "" + #: ../../library/ctypes.rst:2568 msgid "" "It is possible to define sub-subclasses of structures, they inherit the " diff --git a/library/dataclasses.po b/library/dataclasses.po index 6652db5131..12adf2489c 100644 --- a/library/dataclasses.po +++ b/library/dataclasses.po @@ -4,7 +4,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-05-31 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2023-02-11 15:02+0800\n" "Last-Translator: \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -44,11 +44,35 @@ msgstr "" "在這些生成的方法中使用的成員變數是使用 :pep:`526` 型別註釋定義的。例如,這段" "程式碼: ::" +#: ../../library/dataclasses.rst:22 +msgid "" +"from dataclasses import dataclass\n" +"\n" +"@dataclass\n" +"class InventoryItem:\n" +" \"\"\"Class for keeping track of an item in inventory.\"\"\"\n" +" name: str\n" +" unit_price: float\n" +" quantity_on_hand: int = 0\n" +"\n" +" def total_cost(self) -> float:\n" +" return self.unit_price * self.quantity_on_hand" +msgstr "" + #: ../../library/dataclasses.rst:34 #, fuzzy msgid "will add, among other things, a :meth:`!__init__` that looks like::" msgstr "將新增,除其他事項外,一個 :meth:`!__init__` 看起來像: ::" +#: ../../library/dataclasses.rst:36 +msgid "" +"def __init__(self, name: str, unit_price: float, quantity_on_hand: int = " +"0):\n" +" self.name = name\n" +" self.unit_price = unit_price\n" +" self.quantity_on_hand = quantity_on_hand" +msgstr "" + #: ../../library/dataclasses.rst:41 #, fuzzy msgid "" @@ -113,6 +137,23 @@ msgstr "" "如果 ``@dataclass`` 僅用作不帶參數的簡單裝飾器,它的行為就好像它具有此簽名中" "記錄的預設值一樣。也就是說,``@dataclass`` 的這三種用法是等價的: ::" +#: ../../library/dataclasses.rst:74 +msgid "" +"@dataclass\n" +"class C:\n" +" ...\n" +"\n" +"@dataclass()\n" +"class C:\n" +" ...\n" +"\n" +"@dataclass(init=True, repr=True, eq=True, order=False, unsafe_hash=False, " +"frozen=False,\n" +" match_args=True, kw_only=False, slots=False, weakref_slot=False)\n" +"class C:\n" +" ..." +msgstr "" + #: ../../library/dataclasses.rst:87 msgid "The parameters to ``@dataclass`` are:" msgstr "``@dataclass`` 的參數是:" @@ -324,17 +365,33 @@ msgid "" "*slots*: If true (the default is ``False``), :attr:`~object.__slots__` " "attribute will be generated and new class will be returned instead of the " "original one. If :attr:`!__slots__` is already defined in the class, then :" -"exc:`TypeError` is raised. Calling no-arg :func:`super` in dataclasses using " -"``slots=True`` will result in the following exception being raised: " -"``TypeError: super(type, obj): obj must be an instance or subtype of type``. " -"The two-arg :func:`super` is a valid workaround. See :gh:`90562` for full " -"details." +"exc:`TypeError` is raised." +msgstr "" +"``slots``:如果為 true(預設為 ``False``),將生成 :attr:`~object.__slots__` " +"屬性並回傳新類而不是原始類。如果 :attr:`!__slots__` 已經在類中定義,則 :exc:" +"`TypeError` 被引發。" + +#: ../../library/dataclasses.rst:191 +#, fuzzy +msgid "" +"Calling no-arg :func:`super` in dataclasses using ``slots=True`` will result " +"in the following exception being raised: ``TypeError: super(type, obj): obj " +"must be an instance or subtype of type``. The two-arg :func:`super` is a " +"valid workaround. See :gh:`90562` for full details." msgstr "" "``slots``:如果為 true(預設為 ``False``),將生成 :attr:`~object.__slots__` " "屬性並回傳新類而不是原始類。如果 :attr:`!__slots__` 已經在類中定義,則 :exc:" "`TypeError` 被引發。" -#: ../../library/dataclasses.rst:195 +#: ../../library/dataclasses.rst:198 +msgid "" +"Passing parameters to a base class :meth:`~object.__init_subclass__` when " +"using ``slots=True`` will result in a :exc:`TypeError`. Either use " +"``__init_subclass__`` with no parameters or use default values as a " +"workaround. See :gh:`91126` for full details." +msgstr "" + +#: ../../library/dataclasses.rst:206 #, fuzzy msgid "" "If a field name is already included in the :attr:`!__slots__` of a base " @@ -350,26 +407,34 @@ msgstr "" "夠確定繼承的插槽,基底類別 :attr:`!__slots__` 可以是任何可疊代的,但*不是*疊" "代器。" -#: ../../library/dataclasses.rst:205 +#: ../../library/dataclasses.rst:216 #, fuzzy msgid "" "*weakref_slot*: If true (the default is ``False``), add a slot named " -"\"__weakref__\", which is required to make an instance weakref-able. It is " -"an error to specify ``weakref_slot=True`` without also specifying " -"``slots=True``." +"\"__weakref__\", which is required to make an instance :func:`weakref-able " +"`. It is an error to specify ``weakref_slot=True`` without also " +"specifying ``slots=True``." msgstr "" "*weakref_slot*:如果為真(預設為 ``False``),新增一個名為 \"__weakref__\" 的" "插槽,這是使實例可弱引用所必需的。在沒有指定 ``slots=True`` 的情況下指定 " "``weakref_slot=True`` 是錯誤的。" -#: ../../library/dataclasses.rst:212 +#: ../../library/dataclasses.rst:224 #, fuzzy msgid "" "``field``\\s may optionally specify a default value, using normal Python " "syntax::" msgstr "``field``\\s 可以選擇指定一個預設值,使用普通的 Python 語法: ::" -#: ../../library/dataclasses.rst:220 +#: ../../library/dataclasses.rst:227 +msgid "" +"@dataclass\n" +"class C:\n" +" a: int # 'a' has no default value\n" +" b: int = 0 # assign a default value for 'b'" +msgstr "" + +#: ../../library/dataclasses.rst:232 #, fuzzy msgid "" "In this example, both :attr:`!a` and :attr:`!b` will be included in the " @@ -378,7 +443,11 @@ msgstr "" "在此示例中,:attr:`!a` 和 :attr:`!b` 都將包含在新增的 :meth:`~object." "__init__` 方法中,該方法將定義為: ::" -#: ../../library/dataclasses.rst:225 +#: ../../library/dataclasses.rst:235 +msgid "def __init__(self, a: int, b: int = 0):" +msgstr "" + +#: ../../library/dataclasses.rst:237 #, fuzzy msgid "" ":exc:`TypeError` will be raised if a field without a default value follows a " @@ -388,7 +457,7 @@ msgstr "" ":exc:`TypeError` 如果沒有預設值的欄位跟在具有預設值的欄位之後,將引發。無論這" "發生在單個類中還是作為類繼承的結果,都是如此。" -#: ../../library/dataclasses.rst:231 +#: ../../library/dataclasses.rst:243 #, fuzzy msgid "" "For common and simple use cases, no other functionality is required. There " @@ -401,7 +470,17 @@ msgstr "" "位資訊。為了滿足這種對附加資訊的需求,你可以通過呼叫提供的 :func:`!field` 函" "式來替換預設欄位值。例如: ::" -#: ../../library/dataclasses.rst:244 +#: ../../library/dataclasses.rst:249 +msgid "" +"@dataclass\n" +"class C:\n" +" mylist: list[int] = field(default_factory=list)\n" +"\n" +"c = C()\n" +"c.mylist += [1, 2, 3]" +msgstr "" + +#: ../../library/dataclasses.rst:256 #, fuzzy msgid "" "As shown above, the :const:`MISSING` value is a sentinel object used to " @@ -413,11 +492,11 @@ msgstr "" "供。使用此標記是因為“None”對於某些具有不同含義的參數是有效值。任何程式碼都不" "應直接使用 :const:`MISSING` 值。" -#: ../../library/dataclasses.rst:249 +#: ../../library/dataclasses.rst:261 msgid "The parameters to :func:`!field` are:" msgstr ":func:`!field` 的參數是:" -#: ../../library/dataclasses.rst:251 +#: ../../library/dataclasses.rst:263 #, fuzzy msgid "" "*default*: If provided, this will be the default value for this field. This " @@ -427,7 +506,7 @@ msgstr "" "*default*:如果提供,這將是該欄位的預設值。這是必需的,因為 :meth:`!field` 呼" "叫本身會替換預設值的正常位置。" -#: ../../library/dataclasses.rst:255 +#: ../../library/dataclasses.rst:267 #, fuzzy msgid "" "*default_factory*: If provided, it must be a zero-argument callable that " @@ -440,7 +519,7 @@ msgstr "" "時將被呼叫。除其他用途外,這可用於指定具有可變預設值的欄位,如下所述。同時指" "定 *default* 和 *default_factory* 是錯誤的。" -#: ../../library/dataclasses.rst:261 +#: ../../library/dataclasses.rst:273 #, fuzzy msgid "" "*init*: If true (the default), this field is included as a parameter to the " @@ -449,7 +528,7 @@ msgstr "" "*init*:如果為 true(預設值),則此欄位將作為生成的 :meth:`~object.__init__` " "方法的參數包含在內。" -#: ../../library/dataclasses.rst:264 +#: ../../library/dataclasses.rst:276 #, fuzzy msgid "" "*repr*: If true (the default), this field is included in the string returned " @@ -458,7 +537,7 @@ msgstr "" "*repr*:如果為真(預設值),則此欄位包含在生成的 :meth:`~object.__repr__` 方" "法回傳的字串中。" -#: ../../library/dataclasses.rst:267 +#: ../../library/dataclasses.rst:279 #, fuzzy msgid "" "*hash*: This can be a bool or ``None``. If true, this field is included in " @@ -472,7 +551,7 @@ msgstr "" "如果一個欄位用於比較,則應在雜湊中考慮該欄位。不鼓勵將此值設定為“無”以外的任" "何值。" -#: ../../library/dataclasses.rst:274 +#: ../../library/dataclasses.rst:286 #, fuzzy msgid "" "One possible reason to set ``hash=False`` but ``compare=True`` would be if a " @@ -485,7 +564,7 @@ msgstr "" "湊值的成本很高,則需要該欄位進行相等性測試,並且還有其他欄位有助於型別的雜湊" "值。即使一個欄位被排除在雜湊之外,它仍然會被用於比較。" -#: ../../library/dataclasses.rst:280 +#: ../../library/dataclasses.rst:292 #, fuzzy msgid "" "*compare*: If true (the default), this field is included in the generated " @@ -495,7 +574,7 @@ msgstr "" "*compare*:如果為真(預設值),則此欄位包含在生成的相等和比較方法中(:meth:" "`~object.__eq__`、:meth:`~object.__gt__` 等)。" -#: ../../library/dataclasses.rst:284 +#: ../../library/dataclasses.rst:296 #, fuzzy msgid "" "*metadata*: This can be a mapping or ``None``. ``None`` is treated as an " @@ -510,7 +589,7 @@ msgstr "" "不被資料類別使用,而是作為第三方擴充機制提供的。多個第三方可以各自擁有自己的" "密鑰,用作元資料中的命名空間。" -#: ../../library/dataclasses.rst:292 +#: ../../library/dataclasses.rst:304 #, fuzzy msgid "" "*kw_only*: If true, this field will be marked as keyword-only. This is used " @@ -519,7 +598,7 @@ msgstr "" "*kw_only*:如果為真,該欄位將被標記為僅限關鍵字。這在計算生成的 :meth:" "`~object.__init__` 方法的參數時使用。" -#: ../../library/dataclasses.rst:298 +#: ../../library/dataclasses.rst:310 #, fuzzy msgid "" "If the default value of a field is specified by a call to :func:`!field`, " @@ -535,7 +614,17 @@ msgstr "" "在 :func:`@dataclass ` 裝飾器運行後,類別屬性將全部包含欄位的預設" "值,就像預設值本身已指定一樣。例如,在: ::" -#: ../../library/dataclasses.rst:314 +#: ../../library/dataclasses.rst:319 +msgid "" +"@dataclass\n" +"class C:\n" +" x: int\n" +" y: int = field(repr=False)\n" +" z: int = field(repr=False, default=10)\n" +" t: int = 20" +msgstr "" + +#: ../../library/dataclasses.rst:326 #, fuzzy msgid "" "The class attribute :attr:`!C.z` will be ``10``, the class attribute :attr:`!" @@ -545,7 +634,7 @@ msgstr "" "類別屬性 :attr:`!C.z` 將為 ``10``,類別屬性 :attr:`!C.t` 將為 ``20``,類別屬" "性 :attr:`!C.x` 和 :attr:`!C.y` 將不會放。" -#: ../../library/dataclasses.rst:320 +#: ../../library/dataclasses.rst:332 #, fuzzy msgid "" ":class:`!Field` objects describe each defined field. These objects are " @@ -557,15 +646,15 @@ msgstr "" "`fields` 模組級方法回傳(見下文)。使用者不應該直接實例化 :class:`!Field` 物" "件。它記錄的屬性是:" -#: ../../library/dataclasses.rst:325 +#: ../../library/dataclasses.rst:337 msgid ":attr:`!name`: The name of the field." msgstr ":attr:`!name`:欄位的名稱。" -#: ../../library/dataclasses.rst:326 +#: ../../library/dataclasses.rst:338 msgid ":attr:`!type`: The type of the field." msgstr ":attr:`!type`:欄位的型別。" -#: ../../library/dataclasses.rst:327 +#: ../../library/dataclasses.rst:339 #, fuzzy msgid "" ":attr:`!default`, :attr:`!default_factory`, :attr:`!init`, :attr:`!repr`, :" @@ -576,14 +665,14 @@ msgstr "" "attr:`!hash`、:attr:`!compare`, :attr:`!metadata` 和 :attr:`!kw_only` 有與它" "們在 :func:`field` 函式中的含義和值相同。" -#: ../../library/dataclasses.rst:331 +#: ../../library/dataclasses.rst:343 #, fuzzy msgid "" "Other attributes may exist, but they are private and must not be inspected " "or relied on." msgstr "可能存在其他屬性,但它們是私有的,不得檢查或依賴。" -#: ../../library/dataclasses.rst:336 +#: ../../library/dataclasses.rst:348 #, fuzzy msgid "" "Returns a tuple of :class:`Field` objects that define the fields for this " @@ -595,7 +684,7 @@ msgstr "" "實例。如果未傳遞資料類別或其中一個實例,則引發 :exc:`TypeError`。不回傳 " "``ClassVar`` 或 ``InitVar`` 的偽欄位。" -#: ../../library/dataclasses.rst:343 +#: ../../library/dataclasses.rst:355 #, fuzzy msgid "" "Converts the dataclass *obj* to a dict (by using the factory function " @@ -607,23 +696,45 @@ msgstr "" "都被轉換為其欄位的字典,作為 ``name: value`` 對。資料類別、字典、列表和元組被" "遞迴到。其他物件使用 :func:`copy.deepcopy` 複製。" -#: ../../library/dataclasses.rst:349 +#: ../../library/dataclasses.rst:361 #, fuzzy msgid "Example of using :func:`!asdict` on nested dataclasses::" msgstr "在嵌套資料類別上使用 :func:`!asdict` 的範例: ::" -#: ../../library/dataclasses.rst:366 ../../library/dataclasses.rst:386 +#: ../../library/dataclasses.rst:363 +msgid "" +"@dataclass\n" +"class Point:\n" +" x: int\n" +" y: int\n" +"\n" +"@dataclass\n" +"class C:\n" +" mylist: list[Point]\n" +"\n" +"p = Point(10, 20)\n" +"assert asdict(p) == {'x': 10, 'y': 20}\n" +"\n" +"c = C([Point(0, 0), Point(10, 4)])\n" +"assert asdict(c) == {'mylist': [{'x': 0, 'y': 0}, {'x': 10, 'y': 4}]}" +msgstr "" + +#: ../../library/dataclasses.rst:378 ../../library/dataclasses.rst:398 #, fuzzy msgid "To create a shallow copy, the following workaround may be used::" msgstr "要建立淺複製,可以使用以下解決方法:" -#: ../../library/dataclasses.rst:370 +#: ../../library/dataclasses.rst:380 +msgid "{field.name: getattr(obj, field.name) for field in fields(obj)}" +msgstr "" + +#: ../../library/dataclasses.rst:382 #, fuzzy msgid "" ":func:`!asdict` raises :exc:`TypeError` if *obj* is not a dataclass instance." msgstr ":func:`!asdict` 如果 *obj* 不是資料類別實例,則引發 :exc:`TypeError`。" -#: ../../library/dataclasses.rst:375 +#: ../../library/dataclasses.rst:387 #, fuzzy msgid "" "Converts the dataclass *obj* to a tuple (by using the factory function " @@ -635,11 +746,21 @@ msgstr "" "都被轉換為其欄位值的元組。資料類別、字典、列表和元組被遞迴到。其他物件使用 :" "func:`copy.deepcopy` 複製。" -#: ../../library/dataclasses.rst:381 +#: ../../library/dataclasses.rst:393 msgid "Continuing from the previous example::" msgstr "從前面的例子繼續: ::" -#: ../../library/dataclasses.rst:390 +#: ../../library/dataclasses.rst:395 +msgid "" +"assert astuple(p) == (10, 20)\n" +"assert astuple(c) == ([(0, 0), (10, 4)],)" +msgstr "" + +#: ../../library/dataclasses.rst:400 +msgid "tuple(getattr(obj, field.name) for field in dataclasses.fields(obj))" +msgstr "" + +#: ../../library/dataclasses.rst:402 #, fuzzy msgid "" ":func:`!astuple` raises :exc:`TypeError` if *obj* is not a dataclass " @@ -647,7 +768,7 @@ msgid "" msgstr "" ":func:`!astuple` 如果 *obj* 不是資料類別實例,則引發 :exc:`TypeError`。" -#: ../../library/dataclasses.rst:395 +#: ../../library/dataclasses.rst:407 #, fuzzy msgid "" "Creates a new dataclass with name *cls_name*, fields as defined in *fields*, " @@ -667,13 +788,13 @@ msgstr "" "``kw_only`` 的值, ``slots`` 和 ``weakref_slot`` 與它們在 :func:`dataclass` 中" "的含義相同。" -#: ../../library/dataclasses.rst:405 +#: ../../library/dataclasses.rst:417 msgid "" "If *module* is defined, the :attr:`!__module__` attribute of the dataclass " "is set to that value. By default, it is set to the module name of the caller." msgstr "" -#: ../../library/dataclasses.rst:409 +#: ../../library/dataclasses.rst:421 #, fuzzy msgid "" "This function is not strictly required, because any Python mechanism for " @@ -685,11 +806,32 @@ msgstr "" "制都可以應用 :func:`dataclass` 函式將該類轉換為資料類別。提供此功能是為了方" "便。例如: ::" -#: ../../library/dataclasses.rst:421 +#: ../../library/dataclasses.rst:427 +msgid "" +"C = make_dataclass('C',\n" +" [('x', int),\n" +" 'y',\n" +" ('z', int, field(default=5))],\n" +" namespace={'add_one': lambda self: self.x + 1})" +msgstr "" + +#: ../../library/dataclasses.rst:433 msgid "Is equivalent to::" msgstr "相當於: ::" -#: ../../library/dataclasses.rst:434 +#: ../../library/dataclasses.rst:435 +msgid "" +"@dataclass\n" +"class C:\n" +" x: int\n" +" y: 'typing.Any'\n" +" z: int = 5\n" +"\n" +" def add_one(self):\n" +" return self.x + 1" +msgstr "" + +#: ../../library/dataclasses.rst:446 #, fuzzy msgid "" "Creates a new object of the same type as *obj*, replacing fields with values " @@ -701,7 +843,7 @@ msgstr "" "``obj`` 不是資料類別,則引發 :exc:`TypeError`。如果 ``changes`` 中的值未指定" "欄位,則引發 :exc:`TypeError`。" -#: ../../library/dataclasses.rst:439 +#: ../../library/dataclasses.rst:451 #, fuzzy msgid "" "The newly returned object is created by calling the :meth:`~object.__init__` " @@ -711,7 +853,7 @@ msgstr "" "新回傳的對像是通過呼叫資料類別的 :meth:`~object.__init__` 方法建立的。這確" "保 :meth:`__post_init__`(如果存在)也被呼叫。" -#: ../../library/dataclasses.rst:443 +#: ../../library/dataclasses.rst:455 #, fuzzy msgid "" "Init-only variables without default values, if any exist, must be specified " @@ -721,7 +863,7 @@ msgstr "" "沒有預設值的僅初始化變數(如果存在)必須在呼叫 :func:`replace` 時指定,以便它" "們可以傳遞給 :meth:`__init__` 和 :meth:`__post_init__`。" -#: ../../library/dataclasses.rst:447 +#: ../../library/dataclasses.rst:459 #, fuzzy msgid "" "It is an error for *changes* to contain any fields that are defined as " @@ -730,7 +872,7 @@ msgstr "" "*changes* 包含任何定義為具有 ``init=False`` 的欄位是錯誤的。在這種情況下將引" "發 :exc:`ValueError`。" -#: ../../library/dataclasses.rst:451 +#: ../../library/dataclasses.rst:463 #, fuzzy msgid "" "Be forewarned about how ``init=False`` fields work during a call to :func:`!" @@ -747,7 +889,7 @@ msgstr "" "造函式可能是明智的,或者可能是處理實例複製的自定義:func:`!replace` (或類似命" "名的)方法。" -#: ../../library/dataclasses.rst:462 +#: ../../library/dataclasses.rst:474 #, fuzzy msgid "" "Return ``True`` if its parameter is a dataclass (including subclasses of a " @@ -755,7 +897,7 @@ msgid "" msgstr "" "如果它的參數是一個資料類別或一個實例,則回傳 ``True``,否則回傳 ``False``。" -#: ../../library/dataclasses.rst:465 +#: ../../library/dataclasses.rst:477 #, fuzzy msgid "" "If you need to know if a class is an instance of a dataclass (and not a " @@ -765,12 +907,18 @@ msgstr "" "如果你需要知道一個類是否是資料類別的實例(而不是資料類別本身),那麼新增一個" "進一步的檢查 ``not isinstance(obj, type)``: ::" -#: ../../library/dataclasses.rst:474 +#: ../../library/dataclasses.rst:481 +msgid "" +"def is_dataclass_instance(obj):\n" +" return is_dataclass(obj) and not isinstance(obj, type)" +msgstr "" + +#: ../../library/dataclasses.rst:486 #, fuzzy msgid "A sentinel value signifying a missing default or default_factory." msgstr "表示缺少 default 或 default_factory 的標記值。" -#: ../../library/dataclasses.rst:478 +#: ../../library/dataclasses.rst:490 #, fuzzy msgid "" "A sentinel value used as a type annotation. Any fields after a pseudo-field " @@ -786,21 +934,33 @@ msgstr "" "類欄位的名稱。按照慣例,名稱 ``_`` 用於 :const:`!KW_ONLY` 欄位。僅關鍵字欄位" "表示 :meth:`~object.__init__` 參數,在實例化類時必須將其指定為關鍵字。" -#: ../../library/dataclasses.rst:487 +#: ../../library/dataclasses.rst:499 #, fuzzy msgid "" "In this example, the fields ``y`` and ``z`` will be marked as keyword-only " "fields::" msgstr "在此示例中,欄位 ``y`` 和 ``z`` 將被標記為僅關鍵字欄位: ::" -#: ../../library/dataclasses.rst:498 +#: ../../library/dataclasses.rst:501 +msgid "" +"@dataclass\n" +"class Point:\n" +" x: float\n" +" _: KW_ONLY\n" +" y: float\n" +" z: float\n" +"\n" +"p = Point(0, y=1.5, z=2.0)" +msgstr "" + +#: ../../library/dataclasses.rst:510 #, fuzzy msgid "" "In a single dataclass, it is an error to specify more than one field whose " "type is :const:`!KW_ONLY`." msgstr "在單個資料類別中,指定多個型別為 :const:`!KW_ONLY` 的欄位是錯誤的。" -#: ../../library/dataclasses.rst:505 +#: ../../library/dataclasses.rst:517 #, fuzzy msgid "" "Raised when an implicitly defined :meth:`~object.__setattr__` or :meth:" @@ -810,12 +970,12 @@ msgstr "" "當在使用 frozen=True 定義的資料類別上呼叫隱式定義的 :meth:`__setattr__` 或 :" "meth:`__delattr__` 時引發。它是 :exc:`AttributeError` 的子類別。" -#: ../../library/dataclasses.rst:512 +#: ../../library/dataclasses.rst:524 #, fuzzy msgid "Post-init processing" msgstr "初始化後處理" -#: ../../library/dataclasses.rst:516 +#: ../../library/dataclasses.rst:528 #, fuzzy msgid "" "When defined on the class, it will be called by the generated :meth:`~object." @@ -831,14 +991,26 @@ msgstr "" "按照它們在類中定義的順序傳遞給 :meth:`!__post_init__` 。如果沒有生成 :meth:`!" "__init__` 方法,那麼 :meth:`!__post_init__` 將不會被自動呼叫。" -#: ../../library/dataclasses.rst:523 +#: ../../library/dataclasses.rst:535 #, fuzzy msgid "" "Among other uses, this allows for initializing field values that depend on " "one or more other fields. For example::" msgstr "在其他用途中,這允許初始化依賴於一個或多個其他欄位的欄位值。例如: ::" -#: ../../library/dataclasses.rst:535 +#: ../../library/dataclasses.rst:538 +msgid "" +"@dataclass\n" +"class C:\n" +" a: float\n" +" b: float\n" +" c: float = field(init=False)\n" +"\n" +" def __post_init__(self):\n" +" self.c = self.a + self.b" +msgstr "" + +#: ../../library/dataclasses.rst:547 #, fuzzy msgid "" "The :meth:`~object.__init__` method generated by :func:`@dataclass " @@ -851,6 +1023,21 @@ msgstr "" "方法,通常在 :meth:`__post_init__` 方法中呼叫此方法: ::" #: ../../library/dataclasses.rst:552 +msgid "" +"class Rectangle:\n" +" def __init__(self, height, width):\n" +" self.height = height\n" +" self.width = width\n" +"\n" +"@dataclass\n" +"class Square(Rectangle):\n" +" side: float\n" +"\n" +" def __post_init__(self):\n" +" super().__init__(self.side, self.side)" +msgstr "" + +#: ../../library/dataclasses.rst:564 #, fuzzy msgid "" "Note, however, that in general the dataclass-generated :meth:`!__init__` " @@ -860,7 +1047,7 @@ msgstr "" "但是請注意,通常不需要呼叫資料類別生成的 :meth:`!__init__` 方法,因為派生資料" "類別將負責初始化作為資料類別本身的任何基底類別的所有欄位。" -#: ../../library/dataclasses.rst:556 +#: ../../library/dataclasses.rst:568 #, fuzzy msgid "" "See the section below on init-only variables for ways to pass parameters to :" @@ -870,11 +1057,11 @@ msgstr "" "請參閱下面有關僅初始化變數的部分,了解將參數傳遞給 :meth:`!__post_init__` 的" "方法。另請參閱有關 :func:`replace` 如何處理 ``init=False`` 欄位的警告。" -#: ../../library/dataclasses.rst:563 +#: ../../library/dataclasses.rst:575 msgid "Class variables" msgstr "類別變數" -#: ../../library/dataclasses.rst:565 +#: ../../library/dataclasses.rst:577 #, fuzzy msgid "" "One of the few places where :func:`@dataclass ` actually inspects " @@ -891,12 +1078,12 @@ msgstr "" "外,並被資料類別機制忽略。模組級 :func:`fields` 函式不會回傳此類別 " "``ClassVar`` 偽欄位。" -#: ../../library/dataclasses.rst:576 +#: ../../library/dataclasses.rst:588 #, fuzzy msgid "Init-only variables" msgstr "僅初始化變數" -#: ../../library/dataclasses.rst:578 +#: ../../library/dataclasses.rst:590 #, fuzzy msgid "" "Another place where :func:`@dataclass ` inspects a type " @@ -916,7 +1103,7 @@ msgstr "" "的 :meth:`~object.__init__` 方法,並傳遞給可選的 :meth:`__post_init__` 方法。" "它們不被資料類使用。" -#: ../../library/dataclasses.rst:588 +#: ../../library/dataclasses.rst:600 #, fuzzy msgid "" "For example, suppose a field will be initialized from a database, if a value " @@ -924,6 +1111,21 @@ msgid "" msgstr "例如,假設一個欄位將從資料庫中初始化,如果在建立類時沒有提供值: ::" #: ../../library/dataclasses.rst:603 +msgid "" +"@dataclass\n" +"class C:\n" +" i: int\n" +" j: int | None = None\n" +" database: InitVar[DatabaseType | None] = None\n" +"\n" +" def __post_init__(self, database):\n" +" if self.j is None and database is not None:\n" +" self.j = database.lookup('j')\n" +"\n" +"c = C(10, database=my_database)" +msgstr "" + +#: ../../library/dataclasses.rst:615 #, fuzzy msgid "" "In this case, :func:`fields` will return :class:`Field` objects for :attr:`!" @@ -932,11 +1134,11 @@ msgstr "" "在這種情況下,:func:`fields` 將為 :attr:`!i` 和 :attr:`!j` 回傳 :class:" "`Field` 物件,但不會為 :attr:`!database` 回傳。" -#: ../../library/dataclasses.rst:609 +#: ../../library/dataclasses.rst:621 msgid "Frozen instances" msgstr "凍結實例" -#: ../../library/dataclasses.rst:611 +#: ../../library/dataclasses.rst:623 #, fuzzy msgid "" "It is not possible to create truly immutable Python objects. However, by " @@ -950,7 +1152,7 @@ msgstr "" "別將向類新增 :meth:`~object.__setattr__` 和 :meth:`~object.__delattr__` 方" "法。這些方法在呼叫時會引發 :exc:`FrozenInstanceError`。" -#: ../../library/dataclasses.rst:617 +#: ../../library/dataclasses.rst:629 #, fuzzy msgid "" "There is a tiny performance penalty when using ``frozen=True``: :meth:" @@ -960,11 +1162,11 @@ msgstr "" "使用 ``frozen=True`` 時有一個微小的性能損失::meth:`~object.__init__` 不能使" "用簡單賦值來初始化欄位,必須使用 :meth:`!object.__setattr__`。" -#: ../../library/dataclasses.rst:626 +#: ../../library/dataclasses.rst:638 msgid "Inheritance" msgstr "繼承" -#: ../../library/dataclasses.rst:628 +#: ../../library/dataclasses.rst:640 #, fuzzy msgid "" "When the dataclass is being created by the :func:`@dataclass ` " @@ -982,7 +1184,20 @@ msgstr "" "將自己的欄位新增到有序映射中。所有生成的方法都將使用這種組合的、計算的有序欄" "位映射。因為欄位是按插入順序排列的,所以派生類會覆蓋基底類別。一個例子: ::" -#: ../../library/dataclasses.rst:648 +#: ../../library/dataclasses.rst:650 +msgid "" +"@dataclass\n" +"class Base:\n" +" x: Any = 15.0\n" +" y: int = 0\n" +"\n" +"@dataclass\n" +"class C(Base):\n" +" z: int = 10\n" +" x: int = 15" +msgstr "" + +#: ../../library/dataclasses.rst:660 #, fuzzy msgid "" "The final list of fields is, in order, :attr:`!x`, :attr:`!y`, :attr:`!z`. " @@ -992,19 +1207,23 @@ msgstr "" "最終的欄位列表按順序為 :attr:`!x`、:attr:`!y`、:attr:`!z`。:attr:`!x` 的最終" "型別是 :class:`int`,如類別 :class:`!C` 中指定的那樣。" -#: ../../library/dataclasses.rst:651 +#: ../../library/dataclasses.rst:663 #, fuzzy msgid "" "The generated :meth:`~object.__init__` method for :class:`!C` will look " "like::" msgstr "為 :class:`!C` 生成的 :meth:`~object.__init__` 方法將如下所示: ::" -#: ../../library/dataclasses.rst:656 +#: ../../library/dataclasses.rst:665 +msgid "def __init__(self, x: int = 15, y: int = 0, z: int = 10):" +msgstr "" + +#: ../../library/dataclasses.rst:668 #, fuzzy msgid "Re-ordering of keyword-only parameters in :meth:`!__init__`" msgstr ":meth:`!__init__` 中僅關鍵字參數的重新排序" -#: ../../library/dataclasses.rst:658 +#: ../../library/dataclasses.rst:670 #, fuzzy msgid "" "After the parameters needed for :meth:`~object.__init__` are computed, any " @@ -1016,7 +1235,7 @@ msgstr "" "僅關鍵字)參數之後。這是如何在 Python 中實作僅關鍵字參數的要求:它們必須位於" "非僅關鍵字參數之後。" -#: ../../library/dataclasses.rst:664 +#: ../../library/dataclasses.rst:676 #, fuzzy msgid "" "In this example, :attr:`!Base.y`, :attr:`!Base.w`, and :attr:`!D.t` are " @@ -1027,11 +1246,32 @@ msgstr "" "位,:attr:`!Base.x` 和 :attr:`!D.z` 是常規欄位: ::" #: ../../library/dataclasses.rst:679 +msgid "" +"@dataclass\n" +"class Base:\n" +" x: Any = 15.0\n" +" _: KW_ONLY\n" +" y: int = 0\n" +" w: int = 1\n" +"\n" +"@dataclass\n" +"class D(Base):\n" +" z: int = 10\n" +" t: int = field(kw_only=True, default=0)" +msgstr "" + +#: ../../library/dataclasses.rst:691 #, fuzzy msgid "The generated :meth:`!__init__` method for :class:`!D` will look like::" msgstr "為 :class:`!D` 生成的 :meth:`!__init__` 方法將如下所示: ::" -#: ../../library/dataclasses.rst:683 +#: ../../library/dataclasses.rst:693 +msgid "" +"def __init__(self, x: Any = 15.0, z: int = 10, *, y: int = 0, w: int = 1, t: " +"int = 0):" +msgstr "" + +#: ../../library/dataclasses.rst:695 #, fuzzy msgid "" "Note that the parameters have been re-ordered from how they appear in the " @@ -1041,18 +1281,18 @@ msgstr "" "請注意,參數已根據它們在欄位列表中的顯示方式重新排序:從常規欄位派生的參數後" "跟從僅關鍵字欄位派生的參數。" -#: ../../library/dataclasses.rst:687 +#: ../../library/dataclasses.rst:699 #, fuzzy msgid "" "The relative ordering of keyword-only parameters is maintained in the re-" "ordered :meth:`!__init__` parameter list." msgstr "僅關鍵字參數的相對順序在重新排序的 :meth:`!__init__` 參數列表中維護。" -#: ../../library/dataclasses.rst:692 +#: ../../library/dataclasses.rst:704 msgid "Default factory functions" msgstr "預設工廠函式" -#: ../../library/dataclasses.rst:694 +#: ../../library/dataclasses.rst:706 #, fuzzy msgid "" "If a :func:`field` specifies a *default_factory*, it is called with zero " @@ -1062,7 +1302,11 @@ msgstr "" "如果 :func:`field` 指定了 *default_factory*,當需要該欄位的預設值時,它會以零" "引數呼叫。例如,要建立列表的新實例,請使用: ::" -#: ../../library/dataclasses.rst:700 +#: ../../library/dataclasses.rst:710 +msgid "mylist: list = field(default_factory=list)" +msgstr "" + +#: ../../library/dataclasses.rst:712 #, fuzzy msgid "" "If a field is excluded from :meth:`~object.__init__` (using ``init=False``) " @@ -1075,11 +1319,11 @@ msgstr "" "位還指定了 ``default_factory``,那麼預設工廠函式將始終從生成的 :meth:" "`__init__ 中呼叫`功能。發生這種情況是因為沒有其他方法可以為該欄位賦予初始值。" -#: ../../library/dataclasses.rst:707 +#: ../../library/dataclasses.rst:719 msgid "Mutable default values" msgstr "可變預設值" -#: ../../library/dataclasses.rst:709 +#: ../../library/dataclasses.rst:721 #, fuzzy msgid "" "Python stores default member variable values in class attributes. Consider " @@ -1088,6 +1332,21 @@ msgstr "" "Python 將預設成員變數值存儲在類別屬性中。考慮這個例子,不使用資料類別: ::" #: ../../library/dataclasses.rst:724 +msgid "" +"class C:\n" +" x = []\n" +" def add(self, element):\n" +" self.x.append(element)\n" +"\n" +"o1 = C()\n" +"o2 = C()\n" +"o1.add(1)\n" +"o2.add(2)\n" +"assert o1.x == [1, 2]\n" +"assert o1.x is o2.x" +msgstr "" + +#: ../../library/dataclasses.rst:736 #, fuzzy msgid "" "Note that the two instances of class :class:`!C` share the same class " @@ -1096,16 +1355,37 @@ msgstr "" "請注意,類別 :class:`!C` 的兩個實例共享同一個類別變數 :attr:`!x`,正如預期的" "那樣。" -#: ../../library/dataclasses.rst:727 +#: ../../library/dataclasses.rst:739 #, fuzzy msgid "Using dataclasses, *if* this code was valid::" msgstr "使用資料類別,*如果*此程式碼有效: ::" -#: ../../library/dataclasses.rst:735 +#: ../../library/dataclasses.rst:741 +msgid "" +"@dataclass\n" +"class D:\n" +" x: list = [] # This code raises ValueError\n" +" def add(self, element):\n" +" self.x.append(element)" +msgstr "" + +#: ../../library/dataclasses.rst:747 msgid "it would generate code similar to::" msgstr "它會生成類似的程式碼: ::" -#: ../../library/dataclasses.rst:746 +#: ../../library/dataclasses.rst:749 +msgid "" +"class D:\n" +" x = []\n" +" def __init__(self, x=x):\n" +" self.x = x\n" +" def add(self, element):\n" +" self.x.append(element)\n" +"\n" +"assert D().x is D().x" +msgstr "" + +#: ../../library/dataclasses.rst:758 #, fuzzy msgid "" "This has the same issue as the original example using class :class:`!C`. " @@ -1125,14 +1405,23 @@ msgstr "" "到不可散列的預設參數,它將引發 :exc:`TypeError`。假設是如果一個值是不可散列" "的,那麼它就是可變的。這是一個部分解決方案,但它確實可以防止許多常見錯誤。" -#: ../../library/dataclasses.rst:757 +#: ../../library/dataclasses.rst:769 #, fuzzy msgid "" "Using default factory functions is a way to create new instances of mutable " "types as default values for fields::" msgstr "使用預設工廠函式是一種建立可變型別的新實例作為欄位預設值的方法: ::" -#: ../../library/dataclasses.rst:766 +#: ../../library/dataclasses.rst:772 +msgid "" +"@dataclass\n" +"class D:\n" +" x: list = field(default_factory=list)\n" +"\n" +"assert D().x is not D().x" +msgstr "" + +#: ../../library/dataclasses.rst:778 #, fuzzy msgid "" "Instead of looking for and disallowing objects of type :class:`list`, :class:" @@ -1142,12 +1431,12 @@ msgstr "" "不再查找和禁止型別為 :class:`list`、:class:`dict` 或 :class:`set` 的物件,現" "在不允許使用不可散列的對像作為預設值。不可散列性用於近似可變性。" -#: ../../library/dataclasses.rst:773 +#: ../../library/dataclasses.rst:785 #, fuzzy msgid "Descriptor-typed fields" msgstr "描述器型別的欄位" -#: ../../library/dataclasses.rst:775 +#: ../../library/dataclasses.rst:787 #, fuzzy msgid "" "Fields that are assigned :ref:`descriptor objects ` as their " @@ -1155,7 +1444,7 @@ msgid "" msgstr "" "指定為\\ :ref:`描述器物件 `\\ 作為預設值的欄位具有以下特殊行為:" -#: ../../library/dataclasses.rst:778 +#: ../../library/dataclasses.rst:790 #, fuzzy msgid "" "The value for the field passed to the dataclass's :meth:`~object.__init__` " @@ -1165,7 +1454,7 @@ msgstr "" "傳遞給資料類別的 :meth:`~object.__init__` 方法的欄位值被傳遞給描述器的 :meth:" "`~object.__set__` 方法,而不是覆蓋描述器物件。" -#: ../../library/dataclasses.rst:782 +#: ../../library/dataclasses.rst:794 #, fuzzy msgid "" "Similarly, when getting or setting the field, the descriptor's :meth:" @@ -1175,7 +1464,7 @@ msgstr "" "同樣,在獲取或設定欄位時,將呼叫描述器的 :meth:`~object.__get__` 或 :meth:`!" "__set__` 方法,而不是回傳或覆蓋描述器物件。" -#: ../../library/dataclasses.rst:786 +#: ../../library/dataclasses.rst:798 #, fuzzy msgid "" "To determine whether a field contains a default value, :func:`@dataclass " @@ -1191,7 +1480,36 @@ msgstr "" "面,如果描述器在這種情況下引發 :exc:`AttributeError`,則不會為該欄位提供預設" "值。" -#: ../../library/dataclasses.rst:821 +#: ../../library/dataclasses.rst:808 +msgid "" +"class IntConversionDescriptor:\n" +" def __init__(self, *, default):\n" +" self._default = default\n" +"\n" +" def __set_name__(self, owner, name):\n" +" self._name = \"_\" + name\n" +"\n" +" def __get__(self, obj, type):\n" +" if obj is None:\n" +" return self._default\n" +"\n" +" return getattr(obj, self._name, self._default)\n" +"\n" +" def __set__(self, obj, value):\n" +" setattr(obj, self._name, int(value))\n" +"\n" +"@dataclass\n" +"class InventoryItem:\n" +" quantity_on_hand: IntConversionDescriptor = " +"IntConversionDescriptor(default=100)\n" +"\n" +"i = InventoryItem()\n" +"print(i.quantity_on_hand) # 100\n" +"i.quantity_on_hand = 2.5 # calls __set__ with 2.5\n" +"print(i.quantity_on_hand) # 2" +msgstr "" + +#: ../../library/dataclasses.rst:833 #, fuzzy msgid "" "Note that if a field is annotated with a descriptor type, but is not " diff --git a/library/decimal.po b/library/decimal.po index 2d135597ae..5e0afdcc71 100644 --- a/library/decimal.po +++ b/library/decimal.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-07-20 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2018-05-23 14:43+0000\n" "Last-Translator: Adrian Liaw \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -156,6 +156,17 @@ msgid "" "values for precision, rounding, or enabled traps::" msgstr "" +#: ../../library/decimal.rst:131 +msgid "" +">>> from decimal import *\n" +">>> getcontext()\n" +"Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999,\n" +" capitals=1, clamp=0, flags=[], traps=[Overflow, DivisionByZero,\n" +" InvalidOperation])\n" +"\n" +">>> getcontext().prec = 7 # Set a new precision" +msgstr "" + #: ../../library/decimal.rst:139 msgid "" "Decimal instances can be constructed from integers, strings, floats, or " @@ -165,6 +176,27 @@ msgid "" "negative ``Infinity``, and ``-0``::" msgstr "" +#: ../../library/decimal.rst:145 +msgid "" +">>> getcontext().prec = 28\n" +">>> Decimal(10)\n" +"Decimal('10')\n" +">>> Decimal('3.14')\n" +"Decimal('3.14')\n" +">>> Decimal(3.14)\n" +"Decimal('3.140000000000000124344978758017532527446746826171875')\n" +">>> Decimal((0, (3, 1, 4), -2))\n" +"Decimal('3.14')\n" +">>> Decimal(str(2.0 ** 0.5))\n" +"Decimal('1.4142135623730951')\n" +">>> Decimal(2) ** Decimal('0.5')\n" +"Decimal('1.414213562373095048801688724')\n" +">>> Decimal('NaN')\n" +"Decimal('NaN')\n" +">>> Decimal('-Infinity')\n" +"Decimal('-Infinity')" +msgstr "" + #: ../../library/decimal.rst:163 msgid "" "If the :exc:`FloatOperation` signal is trapped, accidental mixing of " @@ -172,6 +204,22 @@ msgid "" "exception::" msgstr "" +#: ../../library/decimal.rst:167 +msgid "" +">>> c = getcontext()\n" +">>> c.traps[FloatOperation] = True\n" +">>> Decimal(3.14)\n" +"Traceback (most recent call last):\n" +" File \"\", line 1, in \n" +"decimal.FloatOperation: []\n" +">>> Decimal('3.5') < 3.7\n" +"Traceback (most recent call last):\n" +" File \"\", line 1, in \n" +"decimal.FloatOperation: []\n" +">>> Decimal('3.5') == 3.5\n" +"True" +msgstr "" + #: ../../library/decimal.rst:182 msgid "" "The significance of a new Decimal is determined solely by the number of " @@ -179,18 +227,69 @@ msgid "" "arithmetic operations." msgstr "" +#: ../../library/decimal.rst:186 +msgid "" +">>> getcontext().prec = 6\n" +">>> Decimal('3.0')\n" +"Decimal('3.0')\n" +">>> Decimal('3.1415926535')\n" +"Decimal('3.1415926535')\n" +">>> Decimal('3.1415926535') + Decimal('2.7182818285')\n" +"Decimal('5.85987')\n" +">>> getcontext().rounding = ROUND_UP\n" +">>> Decimal('3.1415926535') + Decimal('2.7182818285')\n" +"Decimal('5.85988')" +msgstr "" + #: ../../library/decimal.rst:199 msgid "" "If the internal limits of the C version are exceeded, constructing a decimal " "raises :class:`InvalidOperation`::" msgstr "" +#: ../../library/decimal.rst:202 +msgid "" +">>> Decimal(\"1e9999999999999999999\")\n" +"Traceback (most recent call last):\n" +" File \"\", line 1, in \n" +"decimal.InvalidOperation: []" +msgstr "" + #: ../../library/decimal.rst:209 msgid "" "Decimals interact well with much of the rest of Python. Here is a small " "decimal floating-point flying circus:" msgstr "" +#: ../../library/decimal.rst:212 +msgid "" +">>> data = list(map(Decimal, '1.34 1.87 3.45 2.35 1.00 0.03 9.25'.split()))\n" +">>> max(data)\n" +"Decimal('9.25')\n" +">>> min(data)\n" +"Decimal('0.03')\n" +">>> sorted(data)\n" +"[Decimal('0.03'), Decimal('1.00'), Decimal('1.34'), Decimal('1.87'),\n" +" Decimal('2.35'), Decimal('3.45'), Decimal('9.25')]\n" +">>> sum(data)\n" +"Decimal('19.29')\n" +">>> a,b,c = data[:3]\n" +">>> str(a)\n" +"'1.34'\n" +">>> float(a)\n" +"1.34\n" +">>> round(a, 1)\n" +"Decimal('1.3')\n" +">>> int(a)\n" +"1\n" +">>> a * 5\n" +"Decimal('6.70')\n" +">>> a * b\n" +"Decimal('2.5058')\n" +">>> c % a\n" +"Decimal('0.77')" +msgstr "" + #: ../../library/decimal.rst:241 msgid "And some mathematical functions are also available to Decimal:" msgstr "" @@ -224,6 +323,30 @@ msgid "" "many of the traps are enabled:" msgstr "" +#: ../../library/decimal.rst:275 +msgid "" +">>> myothercontext = Context(prec=60, rounding=ROUND_HALF_DOWN)\n" +">>> setcontext(myothercontext)\n" +">>> Decimal(1) / Decimal(7)\n" +"Decimal('0.142857142857142857142857142857142857142857142857142857142857')\n" +"\n" +">>> ExtendedContext\n" +"Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999,\n" +" capitals=1, clamp=0, flags=[], traps=[])\n" +">>> setcontext(ExtendedContext)\n" +">>> Decimal(1) / Decimal(7)\n" +"Decimal('0.142857143')\n" +">>> Decimal(42) / Decimal(0)\n" +"Decimal('Infinity')\n" +"\n" +">>> setcontext(BasicContext)\n" +">>> Decimal(42) / Decimal(0)\n" +"Traceback (most recent call last):\n" +" File \"\", line 1, in -toplevel-\n" +" Decimal(42) / Decimal(0)\n" +"DivisionByZero: x / 0" +msgstr "" + #: ../../library/decimal.rst:299 msgid "" "Contexts also have signal flags for monitoring exceptional conditions " @@ -232,6 +355,17 @@ msgid "" "computations by using the :meth:`~Context.clear_flags` method. ::" msgstr "" +#: ../../library/decimal.rst:304 +msgid "" +">>> setcontext(ExtendedContext)\n" +">>> getcontext().clear_flags()\n" +">>> Decimal(355) / Decimal(113)\n" +"Decimal('3.14159292')\n" +">>> getcontext()\n" +"Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999,\n" +" capitals=1, clamp=0, flags=[Inexact, Rounded], traps=[])" +msgstr "" + #: ../../library/decimal.rst:312 msgid "" "The *flags* entry shows that the rational approximation to pi was rounded " @@ -245,6 +379,19 @@ msgid "" "attribute of a context:" msgstr "" +#: ../../library/decimal.rst:319 +msgid "" +">>> setcontext(ExtendedContext)\n" +">>> Decimal(1) / Decimal(0)\n" +"Decimal('Infinity')\n" +">>> getcontext().traps[DivisionByZero] = 1\n" +">>> Decimal(1) / Decimal(0)\n" +"Traceback (most recent call last):\n" +" File \"\", line 1, in -toplevel-\n" +" Decimal(1) / Decimal(0)\n" +"DivisionByZero: x / 0" +msgstr "" + #: ../../library/decimal.rst:331 msgid "" "Most programs adjust the current context only once, at the beginning of the " @@ -271,6 +418,21 @@ msgid "" "throughout, are removed::" msgstr "" +#: ../../library/decimal.rst:355 +msgid "" +"sign ::= '+' | '-'\n" +"digit ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | " +"'9'\n" +"indicator ::= 'e' | 'E'\n" +"digits ::= digit [digit]...\n" +"decimal-part ::= digits '.' [digits] | ['.'] digits\n" +"exponent-part ::= indicator [sign] digits\n" +"infinity ::= 'Infinity' | 'Inf'\n" +"nan ::= 'NaN' [digits] | 'sNaN' [digits]\n" +"numeric-value ::= decimal-part [exponent-part] | infinity\n" +"numeric-string ::= [sign] numeric-value | [sign] nan" +msgstr "" + #: ../../library/decimal.rst:366 msgid "" "Other Unicode decimal digits are also permitted where ``digit`` appears " @@ -352,6 +514,14 @@ msgid "" "*dividend* rather than the sign of the divisor::" msgstr "" +#: ../../library/decimal.rst:418 +msgid "" +">>> (-7) % 4\n" +"1\n" +">>> Decimal(-7) % Decimal(4)\n" +"Decimal('-3')" +msgstr "" + #: ../../library/decimal.rst:423 msgid "" "The integer division operator ``//`` behaves analogously, returning the " @@ -359,6 +529,14 @@ msgid "" "floor, so as to preserve the usual identity ``x == (x // y) * y + x % y``::" msgstr "" +#: ../../library/decimal.rst:427 +msgid "" +">>> -7 // 4\n" +"-2\n" +">>> Decimal(-7) // Decimal(4)\n" +"Decimal('-1')" +msgstr "" + #: ../../library/decimal.rst:432 msgid "" "The ``%`` and ``//`` operators implement the ``remainder`` and ``divide-" @@ -403,6 +581,12 @@ msgid "" "denominator::" msgstr "" +#: ../../library/decimal.rst:465 +msgid "" +">>> Decimal('-3.14').as_integer_ratio()\n" +"(-157, 50)" +msgstr "" + #: ../../library/decimal.rst:468 msgid "" "The conversion is exact. Raise OverflowError on infinities and ValueError " @@ -428,6 +612,14 @@ msgid "" "Decimal instance, and if either operand is a NaN then the result is a NaN::" msgstr "" +#: ../../library/decimal.rst:491 +msgid "" +"a or b is a NaN ==> Decimal('NaN')\n" +"a < b ==> Decimal('-1')\n" +"a == b ==> Decimal('0')\n" +"a > b ==> Decimal('1')" +msgstr "" + #: ../../library/decimal.rst:498 msgid "" "This operation is identical to the :meth:`compare` method, except that all " @@ -522,6 +714,18 @@ msgid "" "directly from a :class:`float`." msgstr "" +#: ../../library/decimal.rst:588 +msgid "" +">>> Decimal.from_float(0.1)\n" +"Decimal('0.1000000000000000055511151231257827021181583404541015625')\n" +">>> Decimal.from_float(float('nan'))\n" +"Decimal('NaN')\n" +">>> Decimal.from_float(float('inf'))\n" +"Decimal('Infinity')\n" +">>> Decimal.from_float(float('-inf'))\n" +"Decimal('-Infinity')" +msgstr "" + #: ../../library/decimal.rst:603 msgid "" "Fused multiply-add. Return self*other+third with no rounding of the " @@ -942,6 +1146,22 @@ msgstr "" msgid "For example::" msgstr "" +#: ../../library/decimal.rst:929 +msgid "" +">>> from decimal import Decimal, getcontext, ROUND_DOWN\n" +">>> getcontext().rounding = ROUND_DOWN\n" +">>> round(Decimal('3.75')) # context rounding ignored\n" +"4\n" +">>> round(Decimal('3.5')) # round-ties-to-even\n" +"4\n" +">>> round(Decimal('3.75'), 0) # uses the context rounding\n" +"Decimal('3')\n" +">>> round(Decimal('3.75'), 1)\n" +"Decimal('3.7')\n" +">>> round(Decimal('3.75'), -1)\n" +"Decimal('0E+1')" +msgstr "" + #: ../../library/decimal.rst:946 msgid "Logical operands" msgstr "" @@ -1002,10 +1222,29 @@ msgid "" "context::" msgstr "" +#: ../../library/decimal.rst:993 +msgid "" +"from decimal import localcontext\n" +"\n" +"with localcontext() as ctx:\n" +" ctx.prec = 42 # Perform a high precision calculation\n" +" s = calculate_something()\n" +"s = +s # Round the final result back to the default precision" +msgstr "" + #: ../../library/decimal.rst:1000 msgid "Using keyword arguments, the code would be the following::" msgstr "" +#: ../../library/decimal.rst:1002 +msgid "" +"from decimal import localcontext\n" +"\n" +"with localcontext(prec=42) as ctx:\n" +" s = calculate_something()\n" +"s = +s" +msgstr "" + #: ../../library/decimal.rst:1008 msgid "" "Raises :exc:`TypeError` if *kwargs* supplies an attribute that :class:" @@ -1143,6 +1382,12 @@ msgid "" "For example::" msgstr "" +#: ../../library/decimal.rst:1101 +msgid "" +">>> Context(prec=6, Emax=999, clamp=1).create_decimal('1.23e999')\n" +"Decimal('1.23000E+999')" +msgstr "" + #: ../../library/decimal.rst:1104 msgid "" "A *clamp* value of ``1`` allows compatibility with the fixed-width decimal " @@ -1194,6 +1439,15 @@ msgid "" "sum can change the result:" msgstr "" +#: ../../library/decimal.rst:1148 +msgid "" +">>> getcontext().prec = 3\n" +">>> Decimal('3.4445') + Decimal('1.0023')\n" +"Decimal('4.45')\n" +">>> Decimal('3.4445') + Decimal(0) + Decimal('1.0023')\n" +"Decimal('4.44')" +msgstr "" + #: ../../library/decimal.rst:1156 msgid "" "This method implements the to-number operation of the IBM specification. If " @@ -1209,6 +1463,18 @@ msgid "" "conversion." msgstr "" +#: ../../library/decimal.rst:1167 +msgid "" +">>> context = Context(prec=5, rounding=ROUND_DOWN)\n" +">>> context.create_decimal_from_float(math.pi)\n" +"Decimal('3.1415')\n" +">>> context = Context(prec=5, traps=[Inexact])\n" +">>> context.create_decimal_from_float(math.pi)\n" +"Traceback (most recent call last):\n" +" ...\n" +"decimal.Inexact: None" +msgstr "" + #: ../../library/decimal.rst:1182 msgid "" "Returns a value equal to ``Emin - prec + 1`` which is the minimum exponent " @@ -1688,6 +1954,19 @@ msgid "" "trapped, returns ``NaN``. Possible causes include::" msgstr "" +#: ../../library/decimal.rst:1660 +msgid "" +"Infinity - Infinity\n" +"0 * Infinity\n" +"Infinity / Infinity\n" +"x % 0\n" +"Infinity % x\n" +"sqrt(-x) and x > 0\n" +"0 ** 0\n" +"x ** (non-integer)\n" +"x ** Infinity" +msgstr "" + #: ../../library/decimal.rst:1673 msgid "Numerical overflow." msgstr "" @@ -1758,6 +2037,21 @@ msgstr "" msgid "The following table summarizes the hierarchy of signals::" msgstr "" +#: ../../library/decimal.rst:1726 +msgid "" +"exceptions.ArithmeticError(exceptions.Exception)\n" +" DecimalException\n" +" Clamped\n" +" DivisionByZero(DecimalException, exceptions.ZeroDivisionError)\n" +" Inexact\n" +" Overflow(Inexact, Rounded)\n" +" Underflow(Inexact, Rounded, Subnormal)\n" +" InvalidOperation\n" +" Rounded\n" +" Subnormal\n" +" FloatOperation(DecimalException, exceptions.TypeError)" +msgstr "" + #: ../../library/decimal.rst:1745 msgid "Floating-Point Notes" msgstr "" @@ -1783,12 +2077,47 @@ msgid "" "of the associative and distributive properties of addition:" msgstr "" +#: ../../library/decimal.rst:1761 +msgid "" +"# Examples from Seminumerical Algorithms, Section 4.2.2.\n" +">>> from decimal import Decimal, getcontext\n" +">>> getcontext().prec = 8\n" +"\n" +">>> u, v, w = Decimal(11111113), Decimal(-11111111), Decimal('7.51111111')\n" +">>> (u + v) + w\n" +"Decimal('9.5111111')\n" +">>> u + (v + w)\n" +"Decimal('10')\n" +"\n" +">>> u, v, w = Decimal(20000), Decimal(-6), Decimal('6.0000003')\n" +">>> (u*v) + (u*w)\n" +"Decimal('0.01')\n" +">>> u * (v+w)\n" +"Decimal('0.0060000')" +msgstr "" + #: ../../library/decimal.rst:1779 msgid "" "The :mod:`decimal` module makes it possible to restore the identities by " "expanding the precision sufficiently to avoid loss of significance:" msgstr "" +#: ../../library/decimal.rst:1782 +msgid "" +">>> getcontext().prec = 20\n" +">>> u, v, w = Decimal(11111113), Decimal(-11111111), Decimal('7.51111111')\n" +">>> (u + v) + w\n" +"Decimal('9.51111111')\n" +">>> u + (v + w)\n" +"Decimal('9.51111111')\n" +">>>\n" +">>> u, v, w = Decimal(20000), Decimal(-6), Decimal('6.0000003')\n" +">>> (u*v) + (u*w)\n" +"Decimal('0.0060000')\n" +">>> u * (v+w)\n" +"Decimal('0.0060000')" +msgstr "" + #: ../../library/decimal.rst:1799 msgid "Special values" msgstr "" @@ -1902,6 +2231,22 @@ msgid "" "a race condition between threads calling :func:`getcontext`. For example::" msgstr "" +#: ../../library/decimal.rst:1878 +msgid "" +"# Set applicationwide defaults for all threads about to be launched\n" +"DefaultContext.prec = 12\n" +"DefaultContext.rounding = ROUND_DOWN\n" +"DefaultContext.traps = ExtendedContext.traps.copy()\n" +"DefaultContext.traps[InvalidOperation] = 1\n" +"setcontext(DefaultContext)\n" +"\n" +"# Afterwards, the threads can be started\n" +"t1.start()\n" +"t2.start()\n" +"t3.start()\n" +" . . ." +msgstr "" + #: ../../library/decimal.rst:1897 msgid "Recipes" msgstr "" @@ -1912,6 +2257,155 @@ msgid "" "ways to work with the :class:`Decimal` class::" msgstr "" +#: ../../library/decimal.rst:1902 +msgid "" +"def moneyfmt(value, places=2, curr='', sep=',', dp='.',\n" +" pos='', neg='-', trailneg=''):\n" +" \"\"\"Convert Decimal to a money formatted string.\n" +"\n" +" places: required number of places after the decimal point\n" +" curr: optional currency symbol before the sign (may be blank)\n" +" sep: optional grouping separator (comma, period, space, or blank)\n" +" dp: decimal point indicator (comma or period)\n" +" only specify as blank when places is zero\n" +" pos: optional sign for positive numbers: '+', space or blank\n" +" neg: optional sign for negative numbers: '-', '(', space or blank\n" +" trailneg:optional trailing minus indicator: '-', ')', space or blank\n" +"\n" +" >>> d = Decimal('-1234567.8901')\n" +" >>> moneyfmt(d, curr='$')\n" +" '-$1,234,567.89'\n" +" >>> moneyfmt(d, places=0, sep='.', dp='', neg='', trailneg='-')\n" +" '1.234.568-'\n" +" >>> moneyfmt(d, curr='$', neg='(', trailneg=')')\n" +" '($1,234,567.89)'\n" +" >>> moneyfmt(Decimal(123456789), sep=' ')\n" +" '123 456 789.00'\n" +" >>> moneyfmt(Decimal('-0.02'), neg='<', trailneg='>')\n" +" '<0.02>'\n" +"\n" +" \"\"\"\n" +" q = Decimal(10) ** -places # 2 places --> '0.01'\n" +" sign, digits, exp = value.quantize(q).as_tuple()\n" +" result = []\n" +" digits = list(map(str, digits))\n" +" build, next = result.append, digits.pop\n" +" if sign:\n" +" build(trailneg)\n" +" for i in range(places):\n" +" build(next() if digits else '0')\n" +" if places:\n" +" build(dp)\n" +" if not digits:\n" +" build('0')\n" +" i = 0\n" +" while digits:\n" +" build(next())\n" +" i += 1\n" +" if i == 3 and digits:\n" +" i = 0\n" +" build(sep)\n" +" build(curr)\n" +" build(neg if sign else pos)\n" +" return ''.join(reversed(result))\n" +"\n" +"def pi():\n" +" \"\"\"Compute Pi to the current precision.\n" +"\n" +" >>> print(pi())\n" +" 3.141592653589793238462643383\n" +"\n" +" \"\"\"\n" +" getcontext().prec += 2 # extra digits for intermediate steps\n" +" three = Decimal(3) # substitute \"three=3.0\" for regular floats\n" +" lasts, t, s, n, na, d, da = 0, three, 3, 1, 0, 0, 24\n" +" while s != lasts:\n" +" lasts = s\n" +" n, na = n+na, na+8\n" +" d, da = d+da, da+32\n" +" t = (t * n) / d\n" +" s += t\n" +" getcontext().prec -= 2\n" +" return +s # unary plus applies the new precision\n" +"\n" +"def exp(x):\n" +" \"\"\"Return e raised to the power of x. Result type matches input " +"type.\n" +"\n" +" >>> print(exp(Decimal(1)))\n" +" 2.718281828459045235360287471\n" +" >>> print(exp(Decimal(2)))\n" +" 7.389056098930650227230427461\n" +" >>> print(exp(2.0))\n" +" 7.38905609893\n" +" >>> print(exp(2+0j))\n" +" (7.38905609893+0j)\n" +"\n" +" \"\"\"\n" +" getcontext().prec += 2\n" +" i, lasts, s, fact, num = 0, 0, 1, 1, 1\n" +" while s != lasts:\n" +" lasts = s\n" +" i += 1\n" +" fact *= i\n" +" num *= x\n" +" s += num / fact\n" +" getcontext().prec -= 2\n" +" return +s\n" +"\n" +"def cos(x):\n" +" \"\"\"Return the cosine of x as measured in radians.\n" +"\n" +" The Taylor series approximation works best for a small value of x.\n" +" For larger values, first compute x = x % (2 * pi).\n" +"\n" +" >>> print(cos(Decimal('0.5')))\n" +" 0.8775825618903727161162815826\n" +" >>> print(cos(0.5))\n" +" 0.87758256189\n" +" >>> print(cos(0.5+0j))\n" +" (0.87758256189+0j)\n" +"\n" +" \"\"\"\n" +" getcontext().prec += 2\n" +" i, lasts, s, fact, num, sign = 0, 0, 1, 1, 1, 1\n" +" while s != lasts:\n" +" lasts = s\n" +" i += 2\n" +" fact *= i * (i-1)\n" +" num *= x * x\n" +" sign *= -1\n" +" s += num / fact * sign\n" +" getcontext().prec -= 2\n" +" return +s\n" +"\n" +"def sin(x):\n" +" \"\"\"Return the sine of x as measured in radians.\n" +"\n" +" The Taylor series approximation works best for a small value of x.\n" +" For larger values, first compute x = x % (2 * pi).\n" +"\n" +" >>> print(sin(Decimal('0.5')))\n" +" 0.4794255386042030002732879352\n" +" >>> print(sin(0.5))\n" +" 0.479425538604\n" +" >>> print(sin(0.5+0j))\n" +" (0.479425538604+0j)\n" +"\n" +" \"\"\"\n" +" getcontext().prec += 2\n" +" i, lasts, s, fact, num, sign = 1, 0, x, 1, x, 1\n" +" while s != lasts:\n" +" lasts = s\n" +" i += 2\n" +" fact *= i * (i-1)\n" +" num *= x * x\n" +" sign *= -1\n" +" s += num / fact * sign\n" +" getcontext().prec -= 2\n" +" return +s" +msgstr "" + #: ../../library/decimal.rst:2054 msgid "Decimal FAQ" msgstr "" @@ -1988,6 +2482,20 @@ msgid "" "computation::" msgstr "" +#: ../../library/decimal.rst:2143 +msgid "" +">>> getcontext().prec = 5\n" +">>> pi = Decimal('3.1415926535') # More than 5 digits\n" +">>> pi # All digits are retained\n" +"Decimal('3.1415926535')\n" +">>> pi + 0 # Rounded after an addition\n" +"Decimal('3.1416')\n" +">>> pi - Decimal('0.00005') # Subtract unrounded numbers, then round\n" +"Decimal('3.1415')\n" +">>> pi + 0 - Decimal('0.00005'). # Intermediate values are rounded\n" +"Decimal('3.1416')" +msgstr "" + #: ../../library/decimal.rst:2154 msgid "" "Q. Some decimal values always print with exponential notation. Is there a " @@ -2020,6 +2528,12 @@ msgid "" "would suggest:" msgstr "" +#: ../../library/decimal.rst:2178 +msgid "" +">>> Decimal(math.pi)\n" +"Decimal('3.141592653589793115997963468544185161590576171875')" +msgstr "" + #: ../../library/decimal.rst:2183 msgid "" "Q. Within a complex calculation, how can I make sure that I haven't gotten a " @@ -2050,12 +2564,28 @@ msgid "" "haven't been rounded:" msgstr "" +#: ../../library/decimal.rst:2200 +msgid "" +">>> getcontext().prec = 3\n" +">>> Decimal('3.104') + Decimal('2.104')\n" +"Decimal('5.21')\n" +">>> Decimal('3.104') + Decimal('0.000') + Decimal('2.104')\n" +"Decimal('5.20')" +msgstr "" + #: ../../library/decimal.rst:2208 msgid "" "The solution is either to increase precision or to force rounding of inputs " "using the unary plus operation:" msgstr "" +#: ../../library/decimal.rst:2211 +msgid "" +">>> getcontext().prec = 3\n" +">>> +Decimal('1.23456789') # unary plus triggers rounding\n" +"Decimal('1.23')" +msgstr "" + #: ../../library/decimal.rst:2217 msgid "" "Alternatively, inputs can be rounded upon creation using the :meth:`Context." @@ -2093,12 +2623,28 @@ msgid "" "value for :attr:`~Context.prec` as well [#]_::" msgstr "" +#: ../../library/decimal.rst:2242 +msgid "" +">>> setcontext(Context(prec=MAX_PREC, Emax=MAX_EMAX, Emin=MIN_EMIN))\n" +">>> x = Decimal(2) ** 256\n" +">>> x / 128\n" +"Decimal('904625697166532776746648320380374280103671755200316906558262375061821325312')" +msgstr "" + #: ../../library/decimal.rst:2248 msgid "" "For inexact results, :attr:`MAX_PREC` is far too large on 64-bit platforms " "and the available memory will be insufficient::" msgstr "" +#: ../../library/decimal.rst:2251 +msgid "" +">>> Decimal(1) / 3\n" +"Traceback (most recent call last):\n" +" File \"\", line 1, in \n" +"MemoryError" +msgstr "" + #: ../../library/decimal.rst:2256 msgid "" "On systems with overallocation (e.g. Linux), a more sophisticated approach " @@ -2107,6 +2653,30 @@ msgid "" "of 500MB each::" msgstr "" +#: ../../library/decimal.rst:2260 +msgid "" +">>> import sys\n" +">>>\n" +">>> # Maximum number of digits for a single operand using 500MB in 8-byte " +"words\n" +">>> # with 19 digits per word (4-byte and 9 digits for the 32-bit build):\n" +">>> maxdigits = 19 * ((500 * 1024**2) // 8)\n" +">>>\n" +">>> # Check that this works:\n" +">>> c = Context(prec=maxdigits, Emax=MAX_EMAX, Emin=MIN_EMIN)\n" +">>> c.traps[Inexact] = True\n" +">>> setcontext(c)\n" +">>>\n" +">>> # Fill the available precision with nines:\n" +">>> x = Decimal(0).logical_invert() * 9\n" +">>> sys.getsizeof(x)\n" +"524288112\n" +">>> x + 2\n" +"Traceback (most recent call last):\n" +" File \"\", line 1, in \n" +" decimal.Inexact: []" +msgstr "" + #: ../../library/decimal.rst:2280 msgid "" "In general (and especially on systems without overallocation), it is " diff --git a/library/difflib.po b/library/difflib.po index cdca4d7729..7f7ca31cfc 100644 --- a/library/difflib.po +++ b/library/difflib.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-05-09 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2016-11-19 00:29+0000\n" "Last-Translator: Liang-Bo Wang \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -432,6 +432,10 @@ msgid "" "ignored. For example, pass::" msgstr "" +#: ../../library/difflib.rst:375 +msgid "lambda x: x in \" \\t\"" +msgstr "" + #: ../../library/difflib.rst:377 msgid "" "if you're comparing lines as sequences of characters, and don't want to " @@ -554,6 +558,13 @@ msgid "" "triples always describe non-adjacent equal blocks." msgstr "" +#: ../../library/difflib.rst:479 +msgid "" +">>> s = SequenceMatcher(None, \"abxcd\", \"abcd\")\n" +">>> s.get_matching_blocks()\n" +"[Match(a=0, b=0, size=2), Match(a=3, b=2, size=2), Match(a=5, b=4, size=0)]" +msgstr "" + #: ../../library/difflib.rst:488 msgid "" "Return list of 5-tuples describing how to turn *a* into *b*. Each tuple is " @@ -608,6 +619,21 @@ msgstr "" msgid "For example::" msgstr "舉例來說: ::" +#: ../../library/difflib.rst:514 +msgid "" +">>> a = \"qabxcd\"\n" +">>> b = \"abycdf\"\n" +">>> s = SequenceMatcher(None, a, b)\n" +">>> for tag, i1, i2, j1, j2 in s.get_opcodes():\n" +"... print('{:7} a[{}:{}] --> b[{}:{}] {!r:>8} --> {!r}'.format(\n" +"... tag, i1, i2, j1, j2, a[i1:i2], b[j1:j2]))\n" +"delete a[0:1] --> b[0:0] 'q' --> ''\n" +"equal a[1:3] --> b[0:2] 'ab' --> 'ab'\n" +"replace a[3:4] --> b[2:3] 'x' --> 'y'\n" +"equal a[4:6] --> b[3:5] 'cd' --> 'cd'\n" +"insert a[6:6] --> b[5:6] '' --> 'f'" +msgstr "" + #: ../../library/difflib.rst:529 msgid "Return a :term:`generator` of groups with up to *n* lines of context." msgstr "" @@ -648,6 +674,14 @@ msgid "" "arguments. For instance::" msgstr "" +#: ../../library/difflib.rst:557 +msgid "" +">>> SequenceMatcher(None, 'tide', 'diet').ratio()\n" +"0.25\n" +">>> SequenceMatcher(None, 'diet', 'tide').ratio()\n" +"0.5" +msgstr "" + #: ../../library/difflib.rst:565 msgid "Return an upper bound on :meth:`ratio` relatively quickly." msgstr "" @@ -822,6 +856,73 @@ msgid "" "This example shows how to use difflib to create a ``diff``-like utility." msgstr "" +#: ../../library/difflib.rst:761 +msgid "" +"\"\"\" Command line interface to difflib.py providing diffs in four " +"formats:\n" +"\n" +"* ndiff: lists every line and highlights interline changes.\n" +"* context: highlights clusters of changes in a before/after format.\n" +"* unified: highlights clusters of changes in an inline format.\n" +"* html: generates side by side comparison with change highlights.\n" +"\n" +"\"\"\"\n" +"\n" +"import sys, os, difflib, argparse\n" +"from datetime import datetime, timezone\n" +"\n" +"def file_mtime(path):\n" +" t = datetime.fromtimestamp(os.stat(path).st_mtime,\n" +" timezone.utc)\n" +" return t.astimezone().isoformat()\n" +"\n" +"def main():\n" +"\n" +" parser = argparse.ArgumentParser()\n" +" parser.add_argument('-c', action='store_true', default=False,\n" +" help='Produce a context format diff (default)')\n" +" parser.add_argument('-u', action='store_true', default=False,\n" +" help='Produce a unified format diff')\n" +" parser.add_argument('-m', action='store_true', default=False,\n" +" help='Produce HTML side by side diff '\n" +" '(can use -c and -l in conjunction)')\n" +" parser.add_argument('-n', action='store_true', default=False,\n" +" help='Produce a ndiff format diff')\n" +" parser.add_argument('-l', '--lines', type=int, default=3,\n" +" help='Set number of context lines (default 3)')\n" +" parser.add_argument('fromfile')\n" +" parser.add_argument('tofile')\n" +" options = parser.parse_args()\n" +"\n" +" n = options.lines\n" +" fromfile = options.fromfile\n" +" tofile = options.tofile\n" +"\n" +" fromdate = file_mtime(fromfile)\n" +" todate = file_mtime(tofile)\n" +" with open(fromfile) as ff:\n" +" fromlines = ff.readlines()\n" +" with open(tofile) as tf:\n" +" tolines = tf.readlines()\n" +"\n" +" if options.u:\n" +" diff = difflib.unified_diff(fromlines, tolines, fromfile, tofile, " +"fromdate, todate, n=n)\n" +" elif options.n:\n" +" diff = difflib.ndiff(fromlines, tolines)\n" +" elif options.m:\n" +" diff = difflib.HtmlDiff().make_file(fromlines,tolines,fromfile," +"tofile,context=options.c,numlines=n)\n" +" else:\n" +" diff = difflib.context_diff(fromlines, tolines, fromfile, tofile, " +"fromdate, todate, n=n)\n" +"\n" +" sys.stdout.writelines(diff)\n" +"\n" +"if __name__ == '__main__':\n" +" main()\n" +msgstr "" + #: ../../library/difflib.rst:764 msgid "ndiff example" msgstr "ndiff 範例: ::" @@ -829,3 +930,120 @@ msgstr "ndiff 範例: ::" #: ../../library/difflib.rst:766 msgid "This example shows how to use :func:`difflib.ndiff`." msgstr "" + +#: ../../library/difflib.rst:768 +msgid "" +"\"\"\"ndiff [-q] file1 file2\n" +" or\n" +"ndiff (-r1 | -r2) < ndiff_output > file1_or_file2\n" +"\n" +"Print a human-friendly file difference report to stdout. Both inter-\n" +"and intra-line differences are noted. In the second form, recreate file1\n" +"(-r1) or file2 (-r2) on stdout, from an ndiff report on stdin.\n" +"\n" +"In the first form, if -q (\"quiet\") is not specified, the first two lines\n" +"of output are\n" +"\n" +"-: file1\n" +"+: file2\n" +"\n" +"Each remaining line begins with a two-letter code:\n" +"\n" +" \"- \" line unique to file1\n" +" \"+ \" line unique to file2\n" +" \" \" line common to both files\n" +" \"? \" line not present in either input file\n" +"\n" +"Lines beginning with \"? \" attempt to guide the eye to intraline\n" +"differences, and were not present in either input file. These lines can be\n" +"confusing if the source files contain tab characters.\n" +"\n" +"The first file can be recovered by retaining only lines that begin with\n" +"\" \" or \"- \", and deleting those 2-character prefixes; use ndiff with -" +"r1.\n" +"\n" +"The second file can be recovered similarly, but by retaining only \" \" " +"and\n" +"\"+ \" lines; use ndiff with -r2; or, on Unix, the second file can be\n" +"recovered by piping the output through\n" +"\n" +" sed -n '/^[+ ] /s/^..//p'\n" +"\"\"\"\n" +"\n" +"__version__ = 1, 7, 0\n" +"\n" +"import difflib, sys\n" +"\n" +"def fail(msg):\n" +" out = sys.stderr.write\n" +" out(msg + \"\\n\\n\")\n" +" out(__doc__)\n" +" return 0\n" +"\n" +"# open a file & return the file object; gripe and return 0 if it\n" +"# couldn't be opened\n" +"def fopen(fname):\n" +" try:\n" +" return open(fname)\n" +" except IOError as detail:\n" +" return fail(\"couldn't open \" + fname + \": \" + str(detail))\n" +"\n" +"# open two files & spray the diff to stdout; return false iff a problem\n" +"def fcompare(f1name, f2name):\n" +" f1 = fopen(f1name)\n" +" f2 = fopen(f2name)\n" +" if not f1 or not f2:\n" +" return 0\n" +"\n" +" a = f1.readlines(); f1.close()\n" +" b = f2.readlines(); f2.close()\n" +" for line in difflib.ndiff(a, b):\n" +" print(line, end=' ')\n" +"\n" +" return 1\n" +"\n" +"# crack args (sys.argv[1:] is normal) & compare;\n" +"# return false iff a problem\n" +"\n" +"def main(args):\n" +" import getopt\n" +" try:\n" +" opts, args = getopt.getopt(args, \"qr:\")\n" +" except getopt.error as detail:\n" +" return fail(str(detail))\n" +" noisy = 1\n" +" qseen = rseen = 0\n" +" for opt, val in opts:\n" +" if opt == \"-q\":\n" +" qseen = 1\n" +" noisy = 0\n" +" elif opt == \"-r\":\n" +" rseen = 1\n" +" whichfile = val\n" +" if qseen and rseen:\n" +" return fail(\"can't specify both -q and -r\")\n" +" if rseen:\n" +" if args:\n" +" return fail(\"no args allowed with -r option\")\n" +" if whichfile in (\"1\", \"2\"):\n" +" restore(whichfile)\n" +" return 1\n" +" return fail(\"-r value must be 1 or 2\")\n" +" if len(args) != 2:\n" +" return fail(\"need 2 filename args\")\n" +" f1name, f2name = args\n" +" if noisy:\n" +" print('-:', f1name)\n" +" print('+:', f2name)\n" +" return fcompare(f1name, f2name)\n" +"\n" +"# read ndiff output from stdin, and print file1 (which=='1') or\n" +"# file2 (which=='2') to stdout\n" +"\n" +"def restore(which):\n" +" restored = difflib.restore(sys.stdin.readlines(), which)\n" +" sys.stdout.writelines(restored)\n" +"\n" +"if __name__ == '__main__':\n" +" main(sys.argv[1:])\n" +msgstr "" diff --git a/library/dis.po b/library/dis.po index 51bc74eef7..f52708725c 100644 --- a/library/dis.po +++ b/library/dis.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-08-07 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2018-07-27 16:55+0800\n" "Last-Translator: Adrian Liaw \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -86,12 +86,29 @@ msgstr "" msgid "Example: Given the function :func:`!myfunc`::" msgstr "" +#: ../../library/dis.rst:56 +msgid "" +"def myfunc(alist):\n" +" return len(alist)" +msgstr "" + #: ../../library/dis.rst:59 msgid "" "the following command can be used to display the disassembly of :func:`!" "myfunc`:" msgstr "" +#: ../../library/dis.rst:62 +msgid "" +">>> dis.dis(myfunc)\n" +" 2 0 RESUME 0\n" +"\n" +" 3 2 LOAD_GLOBAL 1 (NULL + len)\n" +" 12 LOAD_FAST 0 (alist)\n" +" 14 CALL 1\n" +" 22 RETURN_VALUE" +msgstr "" + #: ../../library/dis.rst:72 msgid "(The \"2\" is a line number)." msgstr "" @@ -104,6 +121,10 @@ msgstr "" msgid "The :mod:`dis` module can be invoked as a script from the command line:" msgstr "" +#: ../../library/dis.rst:81 +msgid "python -m dis [-h] [infile]" +msgstr "" + #: ../../library/dis.rst:85 msgid "The following options are accepted:" msgstr "" @@ -212,6 +233,19 @@ msgstr "新增 *show_caches* 與 *adaptive* 參數。" msgid "Example:" msgstr "範例:" +#: ../../library/dis.rst:162 +msgid "" +">>> bytecode = dis.Bytecode(myfunc)\n" +">>> for instr in bytecode:\n" +"... print(instr.opname)\n" +"...\n" +"RESUME\n" +"LOAD_GLOBAL\n" +"LOAD_FAST\n" +"CALL\n" +"RETURN_VALUE" +msgstr "" + #: ../../library/dis.rst:176 msgid "Analysis functions" msgstr "" @@ -497,6 +531,10 @@ msgstr "" msgid "Removes the top-of-stack item::" msgstr "" +#: ../../library/dis.rst:451 +msgid "STACK.pop()" +msgstr "" + #: ../../library/dis.rst:456 msgid "" "Removes the top two values from the stack. Equivalent to ``POP_TOP``; " @@ -513,10 +551,20 @@ msgid "" "original location::" msgstr "" +#: ../../library/dis.rst:476 +msgid "" +"assert i > 0\n" +"STACK.append(STACK[-i])" +msgstr "" + #: ../../library/dis.rst:484 msgid "Swap the top of the stack with the i-th element::" msgstr "" +#: ../../library/dis.rst:486 +msgid "STACK[-i], STACK[-1] = STACK[-1], STACK[-i]" +msgstr "" + #: ../../library/dis.rst:493 msgid "" "Rather than being an actual instruction, this opcode is used to mark extra " @@ -595,6 +643,13 @@ msgid "" "*op*)::" msgstr "" +#: ../../library/dis.rst:558 +msgid "" +"rhs = STACK.pop()\n" +"lhs = STACK.pop()\n" +"STACK.append(lhs op rhs)" +msgstr "" + #: ../../library/dis.rst:567 ../../library/dis.rst:576 #: ../../library/dis.rst:586 ../../library/dis.rst:594 #: ../../library/dis.rst:606 ../../library/dis.rst:694 @@ -605,6 +660,45 @@ msgstr "" msgid "Implements::" msgstr "" +#: ../../library/dis.rst:569 +msgid "" +"key = STACK.pop()\n" +"container = STACK.pop()\n" +"STACK.append(container[key])" +msgstr "" + +#: ../../library/dis.rst:578 +msgid "" +"key = STACK.pop()\n" +"container = STACK.pop()\n" +"value = STACK.pop()\n" +"container[key] = value" +msgstr "" + +#: ../../library/dis.rst:588 +msgid "" +"key = STACK.pop()\n" +"container = STACK.pop()\n" +"del container[key]" +msgstr "" + +#: ../../library/dis.rst:596 +msgid "" +"end = STACK.pop()\n" +"start = STACK.pop()\n" +"container = STACK.pop()\n" +"STACK.append(container[start:end])" +msgstr "" + +#: ../../library/dis.rst:608 +msgid "" +"end = STACK.pop()\n" +"start = STACK.pop()\n" +"container = STACK.pop()\n" +"values = STACK.pop()\n" +"container[start:end] = value" +msgstr "" + #: ../../library/dis.rst:617 msgid "**Coroutine opcodes**" msgstr "" @@ -677,18 +771,41 @@ msgid "" "``__aexit__`` and result of ``__aenter__()`` to the stack::" msgstr "" +#: ../../library/dis.rst:684 +msgid "STACK.extend((__aexit__, __aenter__())" +msgstr "" + #: ../../library/dis.rst:690 msgid "**Miscellaneous opcodes**" msgstr "" +#: ../../library/dis.rst:696 +msgid "" +"item = STACK.pop()\n" +"set.add(STACK[-i], item)" +msgstr "" + #: ../../library/dis.rst:699 msgid "Used to implement set comprehensions." msgstr "" +#: ../../library/dis.rst:706 +msgid "" +"item = STACK.pop()\n" +"list.append(STACK[-i], item)" +msgstr "" + #: ../../library/dis.rst:709 msgid "Used to implement list comprehensions." msgstr "" +#: ../../library/dis.rst:716 +msgid "" +"value = STACK.pop()\n" +"key = STACK.pop()\n" +"dict.__setitem__(STACK[-i], key, value)" +msgstr "" + #: ../../library/dis.rst:720 msgid "Used to implement dict comprehensions." msgstr "" @@ -866,6 +983,12 @@ msgid "" "stack right-to-left. Require there to be exactly *count* values.::" msgstr "" +#: ../../library/dis.rst:909 +msgid "" +"assert(len(STACK[-1]) == count)\n" +"STACK.extend(STACK.pop()[:-count-1:-1])" +msgstr "" + #: ../../library/dis.rst:915 msgid "" "Implements assignment with a starred target: Unpacks an iterable in " @@ -893,12 +1016,25 @@ msgid "" "d`` will be stored after execution as ``STACK.extend((a, b, c))``." msgstr "" +#: ../../library/dis.rst:936 +msgid "" +"obj = STACK.pop()\n" +"value = STACK.pop()\n" +"obj.name = value" +msgstr "" + #: ../../library/dis.rst:940 msgid "" "where *namei* is the index of name in :attr:`~codeobject.co_names` of the :" "ref:`code object `." msgstr "" +#: ../../library/dis.rst:947 +msgid "" +"obj = STACK.pop()\n" +"del obj.name" +msgstr "" + #: ../../library/dis.rst:950 msgid "" "where *namei* is the index of name into :attr:`~codeobject.co_names` of the :" @@ -945,6 +1081,17 @@ msgid "" "resulting tuple onto the stack::" msgstr "" +#: ../../library/dis.rst:1000 +msgid "" +"if count == 0:\n" +" value = ()\n" +"else:\n" +" value = tuple(STACK[-count:])\n" +" STACK = STACK[:-count]\n" +"\n" +"STACK.append(value)" +msgstr "" + #: ../../library/dis.rst:1011 msgid "Works as :opcode:`BUILD_TUPLE`, but creates a list." msgstr "" @@ -979,14 +1126,32 @@ msgid "" "onto the stack." msgstr "" +#: ../../library/dis.rst:1051 +msgid "" +"seq = STACK.pop()\n" +"list.extend(STACK[-i], seq)" +msgstr "" + #: ../../library/dis.rst:1054 msgid "Used to build lists." msgstr "" +#: ../../library/dis.rst:1063 +msgid "" +"seq = STACK.pop()\n" +"set.update(STACK[-i], seq)" +msgstr "" + #: ../../library/dis.rst:1066 msgid "Used to build sets." msgstr "" +#: ../../library/dis.rst:1075 +msgid "" +"map = STACK.pop()\n" +"dict.update(STACK[-i], map)" +msgstr "" + #: ../../library/dis.rst:1078 msgid "Used to build dicts." msgstr "" @@ -1394,10 +1559,25 @@ msgid "" "implements::" msgstr "" +#: ../../library/dis.rst:1463 +msgid "" +"end = STACK.pop()\n" +"start = STACK.pop()\n" +"STACK.append(slice(start, end))" +msgstr "" + #: ../../library/dis.rst:1467 msgid "if it is 3, implements::" msgstr "" +#: ../../library/dis.rst:1469 +msgid "" +"step = STACK.pop()\n" +"end = STACK.pop()\n" +"start = STACK.pop()\n" +"STACK.append(slice(start, end, step))" +msgstr "" + #: ../../library/dis.rst:1474 msgid "See the :func:`slice` built-in function for more information." msgstr "" @@ -1661,6 +1841,14 @@ msgid "" "functionality that is not performance critical::" msgstr "" +#: ../../library/dis.rst:1635 +msgid "" +"arg2 = STACK.pop()\n" +"arg1 = STACK.pop()\n" +"result = intrinsic2(arg1, arg2)\n" +"STACK.push(result)" +msgstr "" + #: ../../library/dis.rst:1645 msgid "``INTRINSIC_2_INVALID``" msgstr "``INTRINSIC_2_INVALID``" diff --git a/library/doctest.po b/library/doctest.po index 480f7f16f5..330ca1915e 100644 --- a/library/doctest.po +++ b/library/doctest.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-05-09 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2018-05-23 14:43+0000\n" "Last-Translator: Adrian Liaw \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -57,12 +57,76 @@ msgstr "" msgid "Here's a complete but small example module::" msgstr "" +#: ../../library/doctest.rst:33 +msgid "" +"\"\"\"\n" +"This is the \"example\" module.\n" +"\n" +"The example module supplies one function, factorial(). For example,\n" +"\n" +">>> factorial(5)\n" +"120\n" +"\"\"\"\n" +"\n" +"def factorial(n):\n" +" \"\"\"Return the factorial of n, an exact integer >= 0.\n" +"\n" +" >>> [factorial(n) for n in range(6)]\n" +" [1, 1, 2, 6, 24, 120]\n" +" >>> factorial(30)\n" +" 265252859812191058636308480000000\n" +" >>> factorial(-1)\n" +" Traceback (most recent call last):\n" +" ...\n" +" ValueError: n must be >= 0\n" +"\n" +" Factorials of floats are OK, but the float must be an exact integer:\n" +" >>> factorial(30.1)\n" +" Traceback (most recent call last):\n" +" ...\n" +" ValueError: n must be exact integer\n" +" >>> factorial(30.0)\n" +" 265252859812191058636308480000000\n" +"\n" +" It must also not be ridiculously large:\n" +" >>> factorial(1e100)\n" +" Traceback (most recent call last):\n" +" ...\n" +" OverflowError: n too large\n" +" \"\"\"\n" +"\n" +" import math\n" +" if not n >= 0:\n" +" raise ValueError(\"n must be >= 0\")\n" +" if math.floor(n) != n:\n" +" raise ValueError(\"n must be exact integer\")\n" +" if n+1 == n: # catch a value like 1e300\n" +" raise OverflowError(\"n too large\")\n" +" result = 1\n" +" factor = 2\n" +" while factor <= n:\n" +" result *= factor\n" +" factor += 1\n" +" return result\n" +"\n" +"\n" +"if __name__ == \"__main__\":\n" +" import doctest\n" +" doctest.testmod()" +msgstr "" + #: ../../library/doctest.rst:88 msgid "" "If you run :file:`example.py` directly from the command line, :mod:`doctest` " "works its magic:" msgstr "" +#: ../../library/doctest.rst:91 +msgid "" +"$ python example.py\n" +"$" +msgstr "" + #: ../../library/doctest.rst:96 msgid "" "There's no output! That's normal, and it means all the examples worked. " @@ -70,10 +134,43 @@ msgid "" "it's trying, and prints a summary at the end:" msgstr "" +#: ../../library/doctest.rst:100 +msgid "" +"$ python example.py -v\n" +"Trying:\n" +" factorial(5)\n" +"Expecting:\n" +" 120\n" +"ok\n" +"Trying:\n" +" [factorial(n) for n in range(6)]\n" +"Expecting:\n" +" [1, 1, 2, 6, 24, 120]\n" +"ok" +msgstr "" + #: ../../library/doctest.rst:114 msgid "And so on, eventually ending with:" msgstr "" +#: ../../library/doctest.rst:116 +msgid "" +"Trying:\n" +" factorial(1e100)\n" +"Expecting:\n" +" Traceback (most recent call last):\n" +" ...\n" +" OverflowError: n too large\n" +"ok\n" +"2 items passed all tests:\n" +" 1 tests in __main__\n" +" 8 tests in __main__.factorial\n" +"9 tests in 2 items.\n" +"9 passed and 0 failed.\n" +"Test passed.\n" +"$" +msgstr "" + #: ../../library/doctest.rst:133 msgid "" "That's all you need to know to start making productive use of :mod:" @@ -93,6 +190,13 @@ msgid "" "continue to do it) is to end each module :mod:`!M` with::" msgstr "" +#: ../../library/doctest.rst:148 +msgid "" +"if __name__ == \"__main__\":\n" +" import doctest\n" +" doctest.testmod()" +msgstr "" + #: ../../library/doctest.rst:152 msgid ":mod:`!doctest` then examines docstrings in module :mod:`!M`." msgstr "" @@ -103,6 +207,10 @@ msgid "" "executed and verified::" msgstr "" +#: ../../library/doctest.rst:157 +msgid "python M.py" +msgstr "" + #: ../../library/doctest.rst:159 msgid "" "This won't display anything unless an example fails, in which case the " @@ -115,6 +223,10 @@ msgstr "" msgid "Run it with the ``-v`` switch instead::" msgstr "" +#: ../../library/doctest.rst:166 +msgid "python M.py -v" +msgstr "" + #: ../../library/doctest.rst:168 msgid "" "and a detailed report of all examples tried is printed to standard output, " @@ -136,6 +248,10 @@ msgid "" "standard library and pass the module name(s) on the command line::" msgstr "" +#: ../../library/doctest.rst:180 +msgid "python -m doctest -v example.py" +msgstr "" + #: ../../library/doctest.rst:182 msgid "" "This will import :file:`example.py` as a standalone module and run :func:" @@ -159,6 +275,12 @@ msgid "" "text file. This can be done with the :func:`testfile` function::" msgstr "" +#: ../../library/doctest.rst:197 +msgid "" +"import doctest\n" +"doctest.testfile(\"example.txt\")" +msgstr "" + #: ../../library/doctest.rst:200 msgid "" "That short script executes and verifies any interactive Python examples " @@ -167,12 +289,42 @@ msgid "" "Python program! For example, perhaps :file:`example.txt` contains this:" msgstr "" +#: ../../library/doctest.rst:205 +msgid "" +"The ``example`` module\n" +"======================\n" +"\n" +"Using ``factorial``\n" +"-------------------\n" +"\n" +"This is an example text file in reStructuredText format. First import\n" +"``factorial`` from the ``example`` module:\n" +"\n" +" >>> from example import factorial\n" +"\n" +"Now use it:\n" +"\n" +" >>> factorial(6)\n" +" 120" +msgstr "" + #: ../../library/doctest.rst:223 msgid "" "Running ``doctest.testfile(\"example.txt\")`` then finds the error in this " "documentation::" msgstr "" +#: ../../library/doctest.rst:226 +msgid "" +"File \"./example.txt\", line 14, in example.txt\n" +"Failed example:\n" +" factorial(6)\n" +"Expected:\n" +" 120\n" +"Got:\n" +" 720" +msgstr "" + #: ../../library/doctest.rst:234 msgid "" "As with :func:`testmod`, :func:`testfile` won't display anything unless an " @@ -202,6 +354,10 @@ msgid "" "standard library and pass the file name(s) on the command line::" msgstr "" +#: ../../library/doctest.rst:251 +msgid "python -m doctest -v example.txt" +msgstr "" + #: ../../library/doctest.rst:253 msgid "" "Because the file name does not end with :file:`.py`, :mod:`doctest` infers " @@ -255,6 +411,19 @@ msgstr "" msgid "For example, place this block of code at the top of :file:`example.py`:" msgstr "" +#: ../../library/doctest.rst:291 +msgid "" +"__test__ = {\n" +" 'numbers': \"\"\"\n" +">>> factorial(6)\n" +"720\n" +"\n" +">>> [factorial(n) for n in range(6)]\n" +"[1, 1, 2, 6, 24, 120]\n" +"\"\"\"\n" +"}" +msgstr "" + #: ../../library/doctest.rst:303 msgid "" "The value of ``example.__test__[\"numbers\"]`` will be treated as a " @@ -281,6 +450,25 @@ msgid "" "shell." msgstr "" +#: ../../library/doctest.rst:323 +msgid "" +">>> # comments are ignored\n" +">>> x = 12\n" +">>> x\n" +"12\n" +">>> if x == 13:\n" +"... print(\"yes\")\n" +"... else:\n" +"... print(\"no\")\n" +"... print(\"NO\")\n" +"... print(\"NO!!!\")\n" +"...\n" +"no\n" +"NO\n" +"NO!!!\n" +">>>" +msgstr "" + #: ../../library/doctest.rst:343 msgid "" "Any expected output must immediately follow the final ``'>>> '`` or ``'... " @@ -328,6 +516,15 @@ msgid "" "preserve your backslashes exactly as you type them::" msgstr "" +#: ../../library/doctest.rst:373 +msgid "" +">>> def f(x):\n" +"... r'''Backslashes in a raw docstring: m\\n'''\n" +"...\n" +">>> print(f.__doc__)\n" +"Backslashes in a raw docstring: m\\n" +msgstr "" + #: ../../library/doctest.rst:379 msgid "" "Otherwise, the backslash will be interpreted as part of the string. For " @@ -336,10 +533,27 @@ msgid "" "use a raw string)::" msgstr "" +#: ../../library/doctest.rst:383 +msgid "" +">>> def f(x):\n" +"... '''Backslashes in a raw docstring: m\\\\n'''\n" +"...\n" +">>> print(f.__doc__)\n" +"Backslashes in a raw docstring: m\\n" +msgstr "" + #: ../../library/doctest.rst:389 msgid "The starting column doesn't matter::" msgstr "" +#: ../../library/doctest.rst:391 +msgid "" +">>> assert \"Easy!\"\n" +" >>> import math\n" +" >>> math.floor(1.9)\n" +" 1" +msgstr "" + #: ../../library/doctest.rst:396 msgid "" "and as many leading whitespace characters are stripped from the expected " @@ -384,6 +598,14 @@ msgstr "" msgid "Simple example::" msgstr "簡單範例: ::" +#: ../../library/doctest.rst:430 +msgid "" +">>> [1, 2, 3].remove(42)\n" +"Traceback (most recent call last):\n" +" File \"\", line 1, in \n" +"ValueError: list.remove(x): x not in list" +msgstr "" + #: ../../library/doctest.rst:435 msgid "" "That doctest succeeds if :exc:`ValueError` is raised, with the ``list." @@ -397,6 +619,12 @@ msgid "" "first line of the example::" msgstr "" +#: ../../library/doctest.rst:442 +msgid "" +"Traceback (most recent call last):\n" +"Traceback (innermost last):" +msgstr "" + #: ../../library/doctest.rst:445 msgid "" "The traceback header is followed by an optional traceback stack, whose " @@ -412,6 +640,16 @@ msgid "" "multi-line detail::" msgstr "" +#: ../../library/doctest.rst:454 +msgid "" +">>> raise ValueError('multi\\n line\\ndetail')\n" +"Traceback (most recent call last):\n" +" File \"\", line 1, in \n" +"ValueError: multi\n" +" line\n" +"detail" +msgstr "" + #: ../../library/doctest.rst:461 msgid "" "The last three lines (starting with :exc:`ValueError`) are compared against " @@ -425,6 +663,16 @@ msgid "" "as::" msgstr "" +#: ../../library/doctest.rst:467 +msgid "" +">>> raise ValueError('multi\\n line\\ndetail')\n" +"Traceback (most recent call last):\n" +" ...\n" +"ValueError: multi\n" +" line\n" +"detail" +msgstr "" + #: ../../library/doctest.rst:474 msgid "" "Note that tracebacks are treated very specially. In particular, in the " @@ -479,6 +727,15 @@ msgid "" "markers and tildes::" msgstr "" +#: ../../library/doctest.rst:510 +msgid "" +">>> 1 + None\n" +" File \"\", line 1\n" +" 1 + None\n" +" ~~^~~~~~\n" +"TypeError: unsupported operand type(s) for +: 'int' and 'NoneType'" +msgstr "" + #: ../../library/doctest.rst:516 msgid "" "Since the lines showing the position of the error come before the exception " @@ -487,6 +744,15 @@ msgid "" "location::" msgstr "" +#: ../../library/doctest.rst:520 +msgid "" +">>> 1 + None\n" +" File \"\", line 1\n" +" 1 + None\n" +" ^~~~~~~~\n" +"TypeError: unsupported operand type(s) for +: 'int' and 'NoneType'" +msgstr "" + #: ../../library/doctest.rst:531 msgid "Option Flags" msgstr "" @@ -568,6 +834,21 @@ msgid "" "these variations will work with the flag specified:" msgstr "" +#: ../../library/doctest.rst:601 +msgid "" +">>> raise Exception('message')\n" +"Traceback (most recent call last):\n" +"Exception: message\n" +"\n" +">>> raise Exception('message')\n" +"Traceback (most recent call last):\n" +"builtins.Exception: message\n" +"\n" +">>> raise Exception('message')\n" +"Traceback (most recent call last):\n" +"__main__.Exception: message" +msgstr "" + #: ../../library/doctest.rst:615 msgid "" "Note that :const:`ELLIPSIS` can also be used to ignore the details of the " @@ -669,6 +950,10 @@ msgid "" "be called using the following idiom::" msgstr "" +#: ../../library/doctest.rst:704 +msgid "MY_FLAG = register_optionflag('MY_FLAG')" +msgstr "" + #: ../../library/doctest.rst:714 msgid "Directives" msgstr "" @@ -697,6 +982,13 @@ msgstr "" msgid "For example, this test passes:" msgstr "" +#: ../../library/doctest.rst:736 +msgid "" +">>> print(list(range(20))) # doctest: +NORMALIZE_WHITESPACE\n" +"[0, 1, 2, 3, 4, 5, 6, 7, 8, 9,\n" +"10, 11, 12, 13, 14, 15, 16, 17, 18, 19]" +msgstr "" + #: ../../library/doctest.rst:743 msgid "" "Without the directive it would fail, both because the actual output doesn't " @@ -705,18 +997,37 @@ msgid "" "a directive to do so:" msgstr "" +#: ../../library/doctest.rst:748 +msgid "" +">>> print(list(range(20))) # doctest: +ELLIPSIS\n" +"[0, 1, ..., 18, 19]" +msgstr "" + #: ../../library/doctest.rst:754 msgid "" "Multiple directives can be used on a single physical line, separated by " "commas:" msgstr "" +#: ../../library/doctest.rst:757 +msgid "" +">>> print(list(range(20))) # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE\n" +"[0, 1, ..., 18, 19]" +msgstr "" + #: ../../library/doctest.rst:763 msgid "" "If multiple directive comments are used for a single example, then they are " "combined:" msgstr "" +#: ../../library/doctest.rst:766 +msgid "" +">>> print(list(range(20))) # doctest: +ELLIPSIS\n" +"... # doctest: +NORMALIZE_WHITESPACE\n" +"[0, 1, ..., 18, 19]" +msgstr "" + #: ../../library/doctest.rst:773 msgid "" "As the previous example shows, you can add ``...`` lines to your example " @@ -724,6 +1035,13 @@ msgid "" "for a directive to comfortably fit on the same line:" msgstr "" +#: ../../library/doctest.rst:777 +msgid "" +">>> print(list(range(5)) + list(range(10, 20)) + list(range(30, 40)))\n" +"... # doctest: +ELLIPSIS\n" +"[0, ..., 4, 10, ..., 19, 30, ..., 39]" +msgstr "" + #: ../../library/doctest.rst:784 msgid "" "Note that since all options are disabled by default, and directives apply " @@ -748,14 +1066,33 @@ msgid "" "test like ::" msgstr "" +#: ../../library/doctest.rst:802 +msgid "" +">>> foo()\n" +"{\"spam\", \"eggs\"}" +msgstr "" + #: ../../library/doctest.rst:805 msgid "is vulnerable! One workaround is to do ::" msgstr "" +#: ../../library/doctest.rst:807 +msgid "" +">>> foo() == {\"spam\", \"eggs\"}\n" +"True" +msgstr "" + #: ../../library/doctest.rst:810 msgid "instead. Another is to do ::" msgstr "" +#: ../../library/doctest.rst:812 +msgid "" +">>> d = sorted(foo())\n" +">>> d\n" +"['eggs', 'spam']" +msgstr "" + #: ../../library/doctest.rst:816 msgid "There are others, but you get the idea." msgstr "" @@ -764,11 +1101,26 @@ msgstr "" msgid "Another bad idea is to print things that embed an object address, like" msgstr "" +#: ../../library/doctest.rst:820 +msgid "" +">>> id(1.0) # certain to fail some of the time \n" +"7948648\n" +">>> class C: pass\n" +">>> C() # the default repr() for instances embeds an address \n" +"" +msgstr "" + #: ../../library/doctest.rst:828 msgid "" "The :const:`ELLIPSIS` directive gives a nice approach for the last example:" msgstr "" +#: ../../library/doctest.rst:830 +msgid "" +">>> C() # doctest: +ELLIPSIS\n" +"" +msgstr "" + #: ../../library/doctest.rst:836 msgid "" "Floating-point numbers are also subject to small output variations across " @@ -776,12 +1128,28 @@ msgid "" "formatting, and C libraries vary widely in quality here. ::" msgstr "" +#: ../../library/doctest.rst:840 +msgid "" +">>> 1./7 # risky\n" +"0.14285714285714285\n" +">>> print(1./7) # safer\n" +"0.142857142857\n" +">>> print(round(1./7, 6)) # much safer\n" +"0.142857" +msgstr "" + #: ../../library/doctest.rst:847 msgid "" "Numbers of the form ``I/2.**J`` are safe across all platforms, and I often " "contrive doctest examples to produce numbers of that form::" msgstr "" +#: ../../library/doctest.rst:850 +msgid "" +">>> 3./4 # utterly safe\n" +"0.75" +msgstr "" + #: ../../library/doctest.rst:853 msgid "" "Simple fractions are also easier for people to understand, and that makes " @@ -1018,6 +1386,17 @@ msgid "" "your test module::" msgstr "" +#: ../../library/doctest.rst:1003 +msgid "" +"import unittest\n" +"import doctest\n" +"import my_module_with_doctests\n" +"\n" +"def load_tests(loader, tests, ignore):\n" +" tests.addTests(doctest.DocTestSuite(my_module_with_doctests))\n" +" return tests" +msgstr "" + #: ../../library/doctest.rst:1011 msgid "" "There are two main functions for creating :class:`unittest.TestSuite` " @@ -1306,6 +1685,18 @@ msgid "" "following diagram::" msgstr "" +#: ../../library/doctest.rst:1205 +msgid "" +" list of:\n" +"+------+ +---------+\n" +"|module| --DocTestFinder-> | DocTest | --DocTestRunner-> results\n" +"+------+ | ^ +---------+ | ^ (printed)\n" +" | | | Example | | |\n" +" v | | ... | v |\n" +" DocTestParser | Example | OutputChecker\n" +" +---------+" +msgstr "" + #: ../../library/doctest.rst:1218 msgid "DocTest Objects" msgstr "DocTest 物件" @@ -1787,10 +2178,56 @@ msgid "" "`a.py` contains just this module docstring::" msgstr "" +#: ../../library/doctest.rst:1612 +msgid "" +"\"\"\"\n" +">>> def f(x):\n" +"... g(x*2)\n" +">>> def g(x):\n" +"... print(x+3)\n" +"... import pdb; pdb.set_trace()\n" +">>> f(3)\n" +"9\n" +"\"\"\"" +msgstr "" + #: ../../library/doctest.rst:1622 msgid "Then an interactive Python session may look like this::" msgstr "" +#: ../../library/doctest.rst:1624 +msgid "" +">>> import a, doctest\n" +">>> doctest.testmod(a)\n" +"--Return--\n" +"> (3)g()->None\n" +"-> import pdb; pdb.set_trace()\n" +"(Pdb) list\n" +" 1 def g(x):\n" +" 2 print(x+3)\n" +" 3 -> import pdb; pdb.set_trace()\n" +"[EOF]\n" +"(Pdb) p x\n" +"6\n" +"(Pdb) step\n" +"--Return--\n" +"> (2)f()->None\n" +"-> g(x*2)\n" +"(Pdb) list\n" +" 1 def f(x):\n" +" 2 -> g(x*2)\n" +"[EOF]\n" +"(Pdb) p x\n" +"3\n" +"(Pdb) step\n" +"--Return--\n" +"> (1)?()->None\n" +"-> f(3)\n" +"(Pdb) cont\n" +"(0, 3)\n" +">>>" +msgstr "" + #: ../../library/doctest.rst:1655 msgid "" "Functions that convert doctests to Python code, and possibly run the " @@ -1809,10 +2246,34 @@ msgid "" "generated script is returned as a string. For example, ::" msgstr "" +#: ../../library/doctest.rst:1668 +msgid "" +"import doctest\n" +"print(doctest.script_from_examples(r\"\"\"\n" +" Set x and y to 1 and 2.\n" +" >>> x, y = 1, 2\n" +"\n" +" Print their sum:\n" +" >>> print(x+y)\n" +" 3\n" +"\"\"\"))" +msgstr "" + #: ../../library/doctest.rst:1678 msgid "displays::" msgstr "" +#: ../../library/doctest.rst:1680 +msgid "" +"# Set x and y to 1 and 2.\n" +"x, y = 1, 2\n" +"#\n" +"# Print their sum:\n" +"print(x+y)\n" +"# Expected:\n" +"## 3" +msgstr "" + #: ../../library/doctest.rst:1688 msgid "" "This function is used internally by other functions (see below), but can " @@ -1834,6 +2295,12 @@ msgid "" "module :file:`a.py` contains a top-level function :func:`!f`, then ::" msgstr "" +#: ../../library/doctest.rst:1704 +msgid "" +"import a, doctest\n" +"print(doctest.testsource(a, \"a.f\"))" +msgstr "" + #: ../../library/doctest.rst:1707 msgid "" "prints a script version of function :func:`!f`'s docstring, with doctests " @@ -2062,6 +2529,24 @@ msgid "" "example of such a test runner::" msgstr "" +#: ../../library/doctest.rst:1880 +msgid "" +"if __name__ == '__main__':\n" +" import doctest\n" +" flags = doctest.REPORT_NDIFF|doctest.FAIL_FAST\n" +" if len(sys.argv) > 1:\n" +" name = sys.argv[1]\n" +" if name in globals():\n" +" obj = globals()[name]\n" +" else:\n" +" obj = __test__[name]\n" +" doctest.run_docstring_examples(obj, globals(), name=name,\n" +" optionflags=flags)\n" +" else:\n" +" fail, total = doctest.testmod(optionflags=flags)\n" +" print(\"{} failures out of {} tests\".format(fail, total))" +msgstr "" + #: ../../library/doctest.rst:1897 msgid "Footnotes" msgstr "註解" diff --git a/library/email.compat32-message.po b/library/email.compat32-message.po index d07fff4b62..d34cd98103 100644 --- a/library/email.compat32-message.po +++ b/library/email.compat32-message.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-07-21 00:04+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2018-07-15 18:56+0800\n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" "tw)\n" @@ -128,6 +128,16 @@ msgid "" "method directly. For example::" msgstr "" +#: ../../library/email.compat32-message.rst:91 +msgid "" +"from io import StringIO\n" +"from email.generator import Generator\n" +"fp = StringIO()\n" +"g = Generator(fp, mangle_from_=True, maxheaderlen=60)\n" +"g.flatten(msg)\n" +"text = fp.getvalue()" +msgstr "" + #: ../../library/email.compat32-message.rst:98 msgid "" "If the message object contains binary data that is not encoded according to " @@ -166,6 +176,16 @@ msgid "" "flatten` method directly. For example::" msgstr "" +#: ../../library/email.compat32-message.rst:134 +msgid "" +"from io import BytesIO\n" +"from email.generator import BytesGenerator\n" +"fp = BytesIO()\n" +"g = BytesGenerator(fp, mangle_from_=True, maxheaderlen=60)\n" +"g.flatten(msg)\n" +"text = fp.getvalue()" +msgstr "" + #: ../../library/email.compat32-message.rst:146 msgid "" "Equivalent to :meth:`.as_bytes`. Allows ``bytes(msg)`` to produce a bytes " @@ -367,6 +387,12 @@ msgid "" "Used for the ``in`` operator, e.g.::" msgstr "" +#: ../../library/email.compat32-message.rst:316 +msgid "" +"if 'message-id' in myMessage:\n" +" print('Message-ID:', myMessage['message-id'])" +msgstr "" + #: ../../library/email.compat32-message.rst:322 msgid "" "Return the value of the named header field. *name* should not include the " @@ -395,6 +421,12 @@ msgid "" "present in the message with field name *name*, delete the field first, e.g.::" msgstr "" +#: ../../library/email.compat32-message.rst:341 +msgid "" +"del msg['subject']\n" +"msg['subject'] = 'Python roolz!'" +msgstr "" + #: ../../library/email.compat32-message.rst:347 msgid "" "Delete all occurrences of the field with name *name* from the message's " @@ -463,18 +495,37 @@ msgstr "" msgid "Here's an example::" msgstr "以下是個範例: ::" +#: ../../library/email.compat32-message.rst:407 +msgid "msg.add_header('Content-Disposition', 'attachment', filename='bud.gif')" +msgstr "" + #: ../../library/email.compat32-message.rst:409 msgid "This will add a header that looks like ::" msgstr "" +#: ../../library/email.compat32-message.rst:411 +msgid "Content-Disposition: attachment; filename=\"bud.gif\"" +msgstr "" + #: ../../library/email.compat32-message.rst:413 msgid "An example with non-ASCII characters::" msgstr "" +#: ../../library/email.compat32-message.rst:415 +msgid "" +"msg.add_header('Content-Disposition', 'attachment',\n" +" filename=('iso-8859-1', '', 'Fußballer.ppt'))" +msgstr "" + #: ../../library/email.compat32-message.rst:418 msgid "Which produces ::" msgstr "" +#: ../../library/email.compat32-message.rst:420 +msgid "" +"Content-Disposition: attachment; filename*=\"iso-8859-1''Fu%DFballer.ppt\"" +msgstr "" + #: ../../library/email.compat32-message.rst:425 msgid "" "Replace a header. Replace the first header found in the message that " @@ -586,6 +637,12 @@ msgid "" "value is a tuple, or the original string unquoted if it isn't. For example::" msgstr "" +#: ../../library/email.compat32-message.rst:519 +msgid "" +"rawparam = msg.get_param('foo')\n" +"param = email.utils.collapse_rfc2231_value(rawparam)" +msgstr "" + #: ../../library/email.compat32-message.rst:522 msgid "" "In any case, the parameter value (either the returned string, or the " @@ -753,6 +810,19 @@ msgid "" "message structure:" msgstr "" +#: ../../library/email.compat32-message.rst:674 +msgid "" +">>> for part in msg.walk():\n" +"... print(part.get_content_type())\n" +"multipart/report\n" +"text/plain\n" +"message/delivery-status\n" +"text/plain\n" +"text/plain\n" +"message/rfc822\n" +"text/plain" +msgstr "" + #: ../../library/email.compat32-message.rst:686 msgid "" "``walk`` iterates over the subparts of any part where :meth:`is_multipart` " @@ -761,6 +831,28 @@ msgid "" "``_structure`` debug helper function:" msgstr "" +#: ../../library/email.compat32-message.rst:692 +msgid "" +">>> for part in msg.walk():\n" +"... print(part.get_content_maintype() == 'multipart',\n" +"... part.is_multipart())\n" +"True True\n" +"False False\n" +"False True\n" +"False False\n" +"False False\n" +"False True\n" +"False False\n" +">>> _structure(msg)\n" +"multipart/report\n" +" text/plain\n" +" message/delivery-status\n" +" text/plain\n" +" text/plain\n" +" message/rfc822\n" +" text/plain" +msgstr "" + #: ../../library/email.compat32-message.rst:713 msgid "" "Here the ``message`` parts are not ``multiparts``, but they do contain " diff --git a/library/email.examples.po b/library/email.examples.po index 6a1c5ec69a..47eaf1512e 100644 --- a/library/email.examples.po +++ b/library/email.examples.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-06-26 18:54+0800\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2018-07-15 18:56+0800\n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" "tw)\n" @@ -31,30 +31,261 @@ msgid "" "content and the addresses may contain unicode characters):" msgstr "" +#: ../../library/email.examples.rst:12 +msgid "" +"# Import smtplib for the actual sending function\n" +"import smtplib\n" +"\n" +"# Import the email modules we'll need\n" +"from email.message import EmailMessage\n" +"\n" +"# Open the plain text file whose name is in textfile for reading.\n" +"with open(textfile) as fp:\n" +" # Create a text/plain message\n" +" msg = EmailMessage()\n" +" msg.set_content(fp.read())\n" +"\n" +"# me == the sender's email address\n" +"# you == the recipient's email address\n" +"msg['Subject'] = f'The contents of {textfile}'\n" +"msg['From'] = me\n" +"msg['To'] = you\n" +"\n" +"# Send the message via our own SMTP server.\n" +"s = smtplib.SMTP('localhost')\n" +"s.send_message(msg)\n" +"s.quit()\n" +msgstr "" + #: ../../library/email.examples.rst:15 msgid "" "Parsing :rfc:`822` headers can easily be done by the using the classes from " "the :mod:`~email.parser` module:" msgstr "" +#: ../../library/email.examples.rst:18 +msgid "" +"# Import the email modules we'll need\n" +"#from email.parser import BytesParser\n" +"from email.parser import Parser\n" +"from email.policy import default\n" +"\n" +"# If the e-mail headers are in a file, uncomment these two lines:\n" +"# with open(messagefile, 'rb') as fp:\n" +"# headers = BytesParser(policy=default).parse(fp)\n" +"\n" +"# Or for parsing headers in a string (this is an uncommon operation), use:\n" +"headers = Parser(policy=default).parsestr(\n" +" 'From: Foo Bar \\n'\n" +" 'To: \\n'\n" +" 'Subject: Test message\\n'\n" +" '\\n'\n" +" 'Body would go here\\n')\n" +"\n" +"# Now the header items can be accessed as a dictionary:\n" +"print('To: {}'.format(headers['to']))\n" +"print('From: {}'.format(headers['from']))\n" +"print('Subject: {}'.format(headers['subject']))\n" +"\n" +"# You can also access the parts of the addresses:\n" +"print('Recipient username: {}'.format(headers['to'].addresses[0].username))\n" +"print('Sender name: {}'.format(headers['from'].addresses[0].display_name))\n" +msgstr "" + #: ../../library/email.examples.rst:21 msgid "" "Here's an example of how to send a MIME message containing a bunch of family " "pictures that may be residing in a directory:" msgstr "" +#: ../../library/email.examples.rst:24 +msgid "" +"# Import smtplib for the actual sending function.\n" +"import smtplib\n" +"\n" +"# Here are the email package modules we'll need.\n" +"from email.message import EmailMessage\n" +"\n" +"# Create the container email message.\n" +"msg = EmailMessage()\n" +"msg['Subject'] = 'Our family reunion'\n" +"# me == the sender's email address\n" +"# family = the list of all recipients' email addresses\n" +"msg['From'] = me\n" +"msg['To'] = ', '.join(family)\n" +"msg.preamble = 'You will not see this in a MIME-aware mail reader.\\n'\n" +"\n" +"# Open the files in binary mode. You can also omit the subtype\n" +"# if you want MIMEImage to guess it.\n" +"for file in pngfiles:\n" +" with open(file, 'rb') as fp:\n" +" img_data = fp.read()\n" +" msg.add_attachment(img_data, maintype='image',\n" +" subtype='png')\n" +"\n" +"# Send the email via our own SMTP server.\n" +"with smtplib.SMTP('localhost') as s:\n" +" s.send_message(msg)\n" +msgstr "" + #: ../../library/email.examples.rst:27 msgid "" "Here's an example of how to send the entire contents of a directory as an " "email message: [1]_" msgstr "" +#: ../../library/email.examples.rst:30 +msgid "" +"#!/usr/bin/env python3\n" +"\n" +"\"\"\"Send the contents of a directory as a MIME message.\"\"\"\n" +"\n" +"import os\n" +"import smtplib\n" +"# For guessing MIME type based on file name extension\n" +"import mimetypes\n" +"\n" +"from argparse import ArgumentParser\n" +"\n" +"from email.message import EmailMessage\n" +"from email.policy import SMTP\n" +"\n" +"\n" +"def main():\n" +" parser = ArgumentParser(description=\"\"\"\\\n" +"Send the contents of a directory as a MIME message.\n" +"Unless the -o option is given, the email is sent by forwarding to your " +"local\n" +"SMTP server, which then does the normal delivery process. Your local " +"machine\n" +"must be running an SMTP server.\n" +"\"\"\")\n" +" parser.add_argument('-d', '--directory',\n" +" help=\"\"\"Mail the contents of the specified " +"directory,\n" +" otherwise use the current directory. Only the " +"regular\n" +" files in the directory are sent, and we don't " +"recurse to\n" +" subdirectories.\"\"\")\n" +" parser.add_argument('-o', '--output',\n" +" metavar='FILE',\n" +" help=\"\"\"Print the composed message to FILE " +"instead of\n" +" sending the message to the SMTP server.\"\"\")\n" +" parser.add_argument('-s', '--sender', required=True,\n" +" help='The value of the From: header (required)')\n" +" parser.add_argument('-r', '--recipient', required=True,\n" +" action='append', metavar='RECIPIENT',\n" +" default=[], dest='recipients',\n" +" help='A To: header value (at least one required)')\n" +" args = parser.parse_args()\n" +" directory = args.directory\n" +" if not directory:\n" +" directory = '.'\n" +" # Create the message\n" +" msg = EmailMessage()\n" +" msg['Subject'] = f'Contents of directory {os.path.abspath(directory)}'\n" +" msg['To'] = ', '.join(args.recipients)\n" +" msg['From'] = args.sender\n" +" msg.preamble = 'You will not see this in a MIME-aware mail reader.\\n'\n" +"\n" +" for filename in os.listdir(directory):\n" +" path = os.path.join(directory, filename)\n" +" if not os.path.isfile(path):\n" +" continue\n" +" # Guess the content type based on the file's extension. Encoding\n" +" # will be ignored, although we should check for simple things like\n" +" # gzip'd or compressed files.\n" +" ctype, encoding = mimetypes.guess_type(path)\n" +" if ctype is None or encoding is not None:\n" +" # No guess could be made, or the file is encoded (compressed), " +"so\n" +" # use a generic bag-of-bits type.\n" +" ctype = 'application/octet-stream'\n" +" maintype, subtype = ctype.split('/', 1)\n" +" with open(path, 'rb') as fp:\n" +" msg.add_attachment(fp.read(),\n" +" maintype=maintype,\n" +" subtype=subtype,\n" +" filename=filename)\n" +" # Now send or store the message\n" +" if args.output:\n" +" with open(args.output, 'wb') as fp:\n" +" fp.write(msg.as_bytes(policy=SMTP))\n" +" else:\n" +" with smtplib.SMTP('localhost') as s:\n" +" s.send_message(msg)\n" +"\n" +"\n" +"if __name__ == '__main__':\n" +" main()\n" +msgstr "" + #: ../../library/email.examples.rst:33 msgid "" "Here's an example of how to unpack a MIME message like the one above, into a " "directory of files:" msgstr "" +#: ../../library/email.examples.rst:36 +msgid "" +"#!/usr/bin/env python3\n" +"\n" +"\"\"\"Unpack a MIME message into a directory of files.\"\"\"\n" +"\n" +"import os\n" +"import email\n" +"import mimetypes\n" +"\n" +"from email.policy import default\n" +"\n" +"from argparse import ArgumentParser\n" +"\n" +"\n" +"def main():\n" +" parser = ArgumentParser(description=\"\"\"\\\n" +"Unpack a MIME message into a directory of files.\n" +"\"\"\")\n" +" parser.add_argument('-d', '--directory', required=True,\n" +" help=\"\"\"Unpack the MIME message into the named\n" +" directory, which will be created if it doesn't " +"already\n" +" exist.\"\"\")\n" +" parser.add_argument('msgfile')\n" +" args = parser.parse_args()\n" +"\n" +" with open(args.msgfile, 'rb') as fp:\n" +" msg = email.message_from_binary_file(fp, policy=default)\n" +"\n" +" try:\n" +" os.mkdir(args.directory)\n" +" except FileExistsError:\n" +" pass\n" +"\n" +" counter = 1\n" +" for part in msg.walk():\n" +" # multipart/* are just containers\n" +" if part.get_content_maintype() == 'multipart':\n" +" continue\n" +" # Applications should really sanitize the given filename so that an\n" +" # email message can't be used to overwrite important files\n" +" filename = part.get_filename()\n" +" if not filename:\n" +" ext = mimetypes.guess_extension(part.get_content_type())\n" +" if not ext:\n" +" # Use a generic bag-of-bits extension\n" +" ext = '.bin'\n" +" filename = f'part-{counter:03d}{ext}'\n" +" counter += 1\n" +" with open(os.path.join(args.directory, filename), 'wb') as fp:\n" +" fp.write(part.get_payload(decode=True))\n" +"\n" +"\n" +"if __name__ == '__main__':\n" +" main()\n" +msgstr "" + #: ../../library/email.examples.rst:39 msgid "" "Here's an example of how to create an HTML message with an alternative plain " @@ -63,16 +294,182 @@ msgid "" "disk, as well as sending it." msgstr "" +#: ../../library/email.examples.rst:44 +msgid "" +"#!/usr/bin/env python3\n" +"\n" +"import smtplib\n" +"\n" +"from email.message import EmailMessage\n" +"from email.headerregistry import Address\n" +"from email.utils import make_msgid\n" +"\n" +"# Create the base text message.\n" +"msg = EmailMessage()\n" +"msg['Subject'] = \"Ayons asperges pour le déjeuner\"\n" +"msg['From'] = Address(\"Pepé Le Pew\", \"pepe\", \"example.com\")\n" +"msg['To'] = (Address(\"Penelope Pussycat\", \"penelope\", \"example.com\"),\n" +" Address(\"Fabrette Pussycat\", \"fabrette\", \"example.com\"))\n" +"msg.set_content(\"\"\"\\\n" +"Salut!\n" +"\n" +"Cela ressemble à un excellent recipie[1] déjeuner.\n" +"\n" +"[1] http://www.yummly.com/recipe/Roasted-Asparagus-Epicurious-203718\n" +"\n" +"--Pepé\n" +"\"\"\")\n" +"\n" +"# Add the html version. This converts the message into a multipart/" +"alternative\n" +"# container, with the original text message as the first part and the new " +"html\n" +"# message as the second part.\n" +"asparagus_cid = make_msgid()\n" +"msg.add_alternative(\"\"\"\\\n" +"\n" +" \n" +" \n" +"

Salut!

\n" +"

Cela ressemble à un excellent\n" +" \n" +" recipie\n" +" déjeuner.\n" +"

\n" +" \n" +" \n" +"\n" +"\"\"\".format(asparagus_cid=asparagus_cid[1:-1]), subtype='html')\n" +"# note that we needed to peel the <> off the msgid for use in the html.\n" +"\n" +"# Now add the related image to the html part.\n" +"with open(\"roasted-asparagus.jpg\", 'rb') as img:\n" +" msg.get_payload()[1].add_related(img.read(), 'image', 'jpeg',\n" +" cid=asparagus_cid)\n" +"\n" +"# Make a local copy of what we are going to send.\n" +"with open('outgoing.msg', 'wb') as f:\n" +" f.write(bytes(msg))\n" +"\n" +"# Send the message via local SMTP server.\n" +"with smtplib.SMTP('localhost') as s:\n" +" s.send_message(msg)\n" +msgstr "" + #: ../../library/email.examples.rst:47 msgid "" "If we were sent the message from the last example, here is one way we could " "process it:" msgstr "" +#: ../../library/email.examples.rst:50 +msgid "" +"import os\n" +"import sys\n" +"import tempfile\n" +"import mimetypes\n" +"import webbrowser\n" +"\n" +"# Import the email modules we'll need\n" +"from email import policy\n" +"from email.parser import BytesParser\n" +"\n" +"\n" +"def magic_html_parser(html_text, partfiles):\n" +" \"\"\"Return safety-sanitized html linked to partfiles.\n" +"\n" +" Rewrite the href=\"cid:....\" attributes to point to the filenames in " +"partfiles.\n" +" Though not trivial, this should be possible using html.parser.\n" +" \"\"\"\n" +" raise NotImplementedError(\"Add the magic needed\")\n" +"\n" +"\n" +"# In a real program you'd get the filename from the arguments.\n" +"with open('outgoing.msg', 'rb') as fp:\n" +" msg = BytesParser(policy=policy.default).parse(fp)\n" +"\n" +"# Now the header items can be accessed as a dictionary, and any non-ASCII " +"will\n" +"# be converted to unicode:\n" +"print('To:', msg['to'])\n" +"print('From:', msg['from'])\n" +"print('Subject:', msg['subject'])\n" +"\n" +"# If we want to print a preview of the message content, we can extract " +"whatever\n" +"# the least formatted payload is and print the first three lines. Of " +"course,\n" +"# if the message has no plain text part printing the first three lines of " +"html\n" +"# is probably useless, but this is just a conceptual example.\n" +"simplest = msg.get_body(preferencelist=('plain', 'html'))\n" +"print()\n" +"print(''.join(simplest.get_content().splitlines(keepends=True)[:3]))\n" +"\n" +"ans = input(\"View full message?\")\n" +"if ans.lower()[0] == 'n':\n" +" sys.exit()\n" +"\n" +"# We can extract the richest alternative in order to display it:\n" +"richest = msg.get_body()\n" +"partfiles = {}\n" +"if richest['content-type'].maintype == 'text':\n" +" if richest['content-type'].subtype == 'plain':\n" +" for line in richest.get_content().splitlines():\n" +" print(line)\n" +" sys.exit()\n" +" elif richest['content-type'].subtype == 'html':\n" +" body = richest\n" +" else:\n" +" print(\"Don't know how to display {}\".format(richest." +"get_content_type()))\n" +" sys.exit()\n" +"elif richest['content-type'].content_type == 'multipart/related':\n" +" body = richest.get_body(preferencelist=('html'))\n" +" for part in richest.iter_attachments():\n" +" fn = part.get_filename()\n" +" if fn:\n" +" extension = os.path.splitext(part.get_filename())[1]\n" +" else:\n" +" extension = mimetypes.guess_extension(part.get_content_type())\n" +" with tempfile.NamedTemporaryFile(suffix=extension, delete=False) as " +"f:\n" +" f.write(part.get_content())\n" +" # again strip the <> to go from email form of cid to html form.\n" +" partfiles[part['content-id'][1:-1]] = f.name\n" +"else:\n" +" print(\"Don't know how to display {}\".format(richest." +"get_content_type()))\n" +" sys.exit()\n" +"with tempfile.NamedTemporaryFile(mode='w', delete=False) as f:\n" +" f.write(magic_html_parser(body.get_content(), partfiles))\n" +"webbrowser.open(f.name)\n" +"os.remove(f.name)\n" +"for fn in partfiles.values():\n" +" os.remove(fn)\n" +"\n" +"# Of course, there are lots of email messages that could break this simple\n" +"# minded program, but it will handle the most common ones.\n" +msgstr "" + #: ../../library/email.examples.rst:52 msgid "Up to the prompt, the output from the above is:" msgstr "" +#: ../../library/email.examples.rst:54 +msgid "" +"To: Penelope Pussycat , Fabrette Pussycat " +"\n" +"From: Pepé Le Pew \n" +"Subject: Ayons asperges pour le déjeuner\n" +"\n" +"Salut!\n" +"\n" +"Cela ressemble à un excellent recipie[1] déjeuner." +msgstr "" + #: ../../library/email.examples.rst:66 msgid "Footnotes" msgstr "註解" diff --git a/library/email.header.po b/library/email.header.po index 2c1a175f90..5a0c8a3a3b 100644 --- a/library/email.header.po +++ b/library/email.header.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-06-09 00:04+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2018-05-23 14:44+0000\n" "Last-Translator: Adrian Liaw \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -73,6 +73,17 @@ msgid "" "header` module. For example::" msgstr "" +#: ../../library/email.header.rst:40 +msgid "" +">>> from email.message import Message\n" +">>> from email.header import Header\n" +">>> msg = Message()\n" +">>> h = Header('p\\xf6stal', 'iso-8859-1')\n" +">>> msg['Subject'] = h\n" +">>> msg.as_string()\n" +"'Subject: =?iso-8859-1?q?p=F6stal?=\\n\\n'" +msgstr "" + #: ../../library/email.header.rst:50 msgid "" "Notice here how we wanted the :mailheader:`Subject` field to contain a non-" @@ -267,6 +278,13 @@ msgstr "" msgid "Here's an example::" msgstr "以下是個範例: ::" +#: ../../library/email.header.rst:188 +msgid "" +">>> from email.header import decode_header\n" +">>> decode_header('=?iso-8859-1?q?p=F6stal?=')\n" +"[(b'p\\xf6stal', 'iso-8859-1')]" +msgstr "" + #: ../../library/email.header.rst:195 msgid "" "Create a :class:`Header` instance from a sequence of pairs as returned by :" diff --git a/library/email.headerregistry.po b/library/email.headerregistry.po index 274ee09e6f..be96c8fe1f 100644 --- a/library/email.headerregistry.po +++ b/library/email.headerregistry.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-05-09 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2018-05-23 14:44+0000\n" "Last-Translator: Adrian Liaw \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -124,6 +124,10 @@ msgid "" "method is called as follows::" msgstr "" +#: ../../library/email.headerregistry.rst:94 +msgid "parse(string, kwds)" +msgstr "" + #: ../../library/email.headerregistry.rst:96 msgid "" "``kwds`` is a dictionary containing one pre-initialized key, ``defects``. " @@ -145,6 +149,13 @@ msgid "" "``BaseHeader`` itself. Such an ``init`` method should look like this::" msgstr "" +#: ../../library/email.headerregistry.rst:110 +msgid "" +"def init(self, /, *args, **kw):\n" +" self._myattr = kw.pop('myattr')\n" +" super().init(*args, **kw)" +msgstr "" + #: ../../library/email.headerregistry.rst:114 msgid "" "That is, anything extra that the specialized class puts in to the ``kwds`` " @@ -208,6 +219,10 @@ msgid "" "``datetime`` according to the :rfc:`5322` rules; that is, it is set to::" msgstr "" +#: ../../library/email.headerregistry.rst:163 +msgid "email.utils.format_datetime(self.datetime)" +msgstr "" + #: ../../library/email.headerregistry.rst:165 msgid "" "When creating a ``DateHeader``, *value* may be :class:`~datetime.datetime` " @@ -215,6 +230,10 @@ msgid "" "does what one would expect::" msgstr "" +#: ../../library/email.headerregistry.rst:169 +msgid "msg['Date'] = datetime(2011, 7, 15, 21)" +msgstr "" + #: ../../library/email.headerregistry.rst:171 msgid "" "Because this is a naive ``datetime`` it will be interpreted as a UTC " @@ -223,6 +242,10 @@ msgid "" "mod:`~email.utils` module::" msgstr "" +#: ../../library/email.headerregistry.rst:176 +msgid "msg['Date'] = utils.localtime()" +msgstr "" + #: ../../library/email.headerregistry.rst:178 msgid "" "This example sets the date header to the current time and date using the " @@ -545,10 +568,18 @@ msgid "" "address is::" msgstr "" +#: ../../library/email.headerregistry.rst:380 +msgid "[display_name] " +msgstr "" + #: ../../library/email.headerregistry.rst:382 msgid "or::" msgstr "或是: ::" +#: ../../library/email.headerregistry.rst:384 +msgid "username@domain" +msgstr "" + #: ../../library/email.headerregistry.rst:386 msgid "" "where each part must conform to specific syntax rules spelled out in :rfc:" @@ -606,6 +637,10 @@ msgid "" "address group is::" msgstr "" +#: ../../library/email.headerregistry.rst:432 +msgid "display_name: [address-list];" +msgstr "" + #: ../../library/email.headerregistry.rst:434 msgid "" "As a convenience for processing lists of addresses that consist of a mixture " diff --git a/library/email.iterators.po b/library/email.iterators.po index 8c949ce72b..26a3ff9e6a 100644 --- a/library/email.iterators.po +++ b/library/email.iterators.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-05-09 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2016-11-19 00:30+0000\n" "Last-Translator: Liang-Bo Wang \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -81,6 +81,27 @@ msgid "" "structure. For example:" msgstr "" +#: ../../library/email.iterators.rst:57 +msgid "" +">>> msg = email.message_from_file(somefile)\n" +">>> _structure(msg)\n" +"multipart/mixed\n" +" text/plain\n" +" text/plain\n" +" multipart/digest\n" +" message/rfc822\n" +" text/plain\n" +" message/rfc822\n" +" text/plain\n" +" message/rfc822\n" +" text/plain\n" +" message/rfc822\n" +" text/plain\n" +" message/rfc822\n" +" text/plain\n" +" text/plain" +msgstr "" + #: ../../library/email.iterators.rst:81 msgid "" "Optional *fp* is a file-like object to print the output to. It must be " diff --git a/library/email.message.po b/library/email.message.po index ba4aae722e..65bc1fce87 100644 --- a/library/email.message.po +++ b/library/email.message.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-05-09 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2018-05-23 14:44+0000\n" "Last-Translator: Adrian Liaw \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -230,6 +230,12 @@ msgid "" "Used for the ``in`` operator. For example::" msgstr "" +#: ../../library/email.message.rst:185 +msgid "" +"if 'message-id' in myMessage:\n" +" print('Message-ID:', myMessage['message-id'])" +msgstr "" + #: ../../library/email.message.rst:191 msgid "" "Return the value of the named header field. *name* does not include the " @@ -264,6 +270,12 @@ msgid "" "present in the message with field name *name*, delete the field first, e.g.::" msgstr "" +#: ../../library/email.message.rst:213 +msgid "" +"del msg['subject']\n" +"msg['subject'] = 'Python roolz!'" +msgstr "" + #: ../../library/email.message.rst:216 msgid "" "If the :mod:`policy ` defines certain headers to be unique (as " @@ -347,14 +359,28 @@ msgstr "" msgid "Here is an example::" msgstr "以下是個範例: ::" +#: ../../library/email.message.rst:289 +msgid "msg.add_header('Content-Disposition', 'attachment', filename='bud.gif')" +msgstr "" + #: ../../library/email.message.rst:291 msgid "This will add a header that looks like ::" msgstr "" +#: ../../library/email.message.rst:293 +msgid "Content-Disposition: attachment; filename=\"bud.gif\"" +msgstr "" + #: ../../library/email.message.rst:295 msgid "An example of the extended interface with non-ASCII characters::" msgstr "" +#: ../../library/email.message.rst:297 +msgid "" +"msg.add_header('Content-Disposition', 'attachment',\n" +" filename=('iso-8859-1', '', 'Fußballer.ppt'))" +msgstr "" + #: ../../library/email.message.rst:303 msgid "" "Replace a header. Replace the first header found in the message that " @@ -560,6 +586,19 @@ msgid "" "message structure:" msgstr "" +#: ../../library/email.message.rst:491 +msgid "" +">>> for part in msg.walk():\n" +"... print(part.get_content_type())\n" +"multipart/report\n" +"text/plain\n" +"message/delivery-status\n" +"text/plain\n" +"text/plain\n" +"message/rfc822\n" +"text/plain" +msgstr "" + #: ../../library/email.message.rst:503 msgid "" "``walk`` iterates over the subparts of any part where :meth:`is_multipart` " @@ -568,6 +607,29 @@ msgid "" "``_structure`` debug helper function:" msgstr "" +#: ../../library/email.message.rst:509 +msgid "" +">>> from email.iterators import _structure\n" +">>> for part in msg.walk():\n" +"... print(part.get_content_maintype() == 'multipart',\n" +"... part.is_multipart())\n" +"True True\n" +"False False\n" +"False True\n" +"False False\n" +"False False\n" +"False True\n" +"False False\n" +">>> _structure(msg)\n" +"multipart/report\n" +" text/plain\n" +" message/delivery-status\n" +" text/plain\n" +" text/plain\n" +" message/rfc822\n" +" text/plain" +msgstr "" + #: ../../library/email.message.rst:531 msgid "" "Here the ``message`` parts are not ``multiparts``, but they do contain " diff --git a/library/email.parser.po b/library/email.parser.po index 0564faea50..4225a8e604 100644 --- a/library/email.parser.po +++ b/library/email.parser.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-05-09 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2018-05-23 16:01+0000\n" "Last-Translator: Adrian Liaw \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -327,6 +327,12 @@ msgid "" "interactive Python prompt::" msgstr "" +#: ../../library/email.parser.rst:286 +msgid "" +">>> import email\n" +">>> msg = email.message_from_bytes(myBytes) " +msgstr "" + #: ../../library/email.parser.rst:291 msgid "Additional notes" msgstr "" diff --git a/library/email.policy.po b/library/email.policy.po index f3c991842c..5f6aaaf326 100644 --- a/library/email.policy.po +++ b/library/email.policy.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-08-07 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2018-05-23 16:01+0000\n" "Last-Translator: Adrian Liaw \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -122,6 +122,22 @@ msgid "" "system:" msgstr "" +#: ../../library/email.policy.rst:92 +msgid "" +">>> from email import message_from_binary_file\n" +">>> from email.generator import BytesGenerator\n" +">>> from email import policy\n" +">>> from subprocess import Popen, PIPE\n" +">>> with open('mymsg.txt', 'rb') as f:\n" +"... msg = message_from_binary_file(f, policy=policy.default)\n" +"...\n" +">>> p = Popen(['sendmail', msg['To'].addresses[0]], stdin=PIPE)\n" +">>> g = BytesGenerator(p.stdin, policy=msg.policy.clone(linesep='\\r\\n'))\n" +">>> g.flatten(msg)\n" +">>> p.stdin.close()\n" +">>> rc = p.wait()" +msgstr "" + #: ../../library/email.policy.rst:114 msgid "" "Here we are telling :class:`~email.generator.BytesGenerator` to use the RFC " @@ -139,6 +155,14 @@ msgid "" "line separators for the platform on which it is running::" msgstr "" +#: ../../library/email.policy.rst:125 +msgid "" +">>> import os\n" +">>> with open('converted.txt', 'wb') as f:\n" +"... f.write(msg.as_bytes(policy=msg.policy.clone(linesep=os.linesep)))\n" +"17" +msgstr "" + #: ../../library/email.policy.rst:130 msgid "" "Policy objects can also be combined using the addition operator, producing a " @@ -146,12 +170,31 @@ msgid "" "the summed objects::" msgstr "" +#: ../../library/email.policy.rst:134 +msgid "" +">>> compat_SMTP = policy.compat32.clone(linesep='\\r\\n')\n" +">>> compat_strict = policy.compat32.clone(raise_on_defect=True)\n" +">>> compat_strict_SMTP = compat_SMTP + compat_strict" +msgstr "" + #: ../../library/email.policy.rst:138 msgid "" "This operation is not commutative; that is, the order in which the objects " "are added matters. To illustrate::" msgstr "" +#: ../../library/email.policy.rst:141 +msgid "" +">>> policy100 = policy.compat32.clone(max_line_length=100)\n" +">>> policy80 = policy.compat32.clone(max_line_length=80)\n" +">>> apolicy = policy100 + policy80\n" +">>> apolicy.max_line_length\n" +"80\n" +">>> apolicy = policy80 + policy100\n" +">>> apolicy.max_line_length\n" +"100" +msgstr "" + #: ../../library/email.policy.rst:153 msgid "" "This is the :term:`abstract base class` for all policy classes. It provides " @@ -644,6 +687,10 @@ msgid "" "strict by writing::" msgstr "" +#: ../../library/email.policy.rst:571 +msgid "somepolicy + policy.strict" +msgstr "" + #: ../../library/email.policy.rst:574 msgid "" "With all of these :class:`EmailPolicies <.EmailPolicy>`, the effective API " diff --git a/library/email.utils.po b/library/email.utils.po index 5f859dc179..07d05d5647 100644 --- a/library/email.utils.po +++ b/library/email.utils.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-07-20 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -90,7 +90,16 @@ msgid "" "unless the parse fails, in which case a 2-tuple of ``('', '')`` is returned." msgstr "" -#: ../../library/email.utils.rst:71 +#: ../../library/email.utils.rst:68 ../../library/email.utils.rst:96 +msgid "" +"If *strict* is true, use a strict parser which rejects malformed inputs." +msgstr "" + +#: ../../library/email.utils.rst:70 ../../library/email.utils.rst:108 +msgid "Add *strict* optional parameter and reject malformed inputs by default." +msgstr "" + +#: ../../library/email.utils.rst:76 msgid "" "The inverse of :meth:`parseaddr`, this takes a 2-tuple of the form " "``(realname, email_address)`` and returns the string value suitable for a :" @@ -98,7 +107,7 @@ msgid "" "is false, then the second element is returned unmodified." msgstr "" -#: ../../library/email.utils.rst:76 +#: ../../library/email.utils.rst:81 msgid "" "Optional *charset* is the character set that will be used in the :rfc:`2047` " "encoding of the ``realname`` if the ``realname`` contains non-ASCII " @@ -106,19 +115,33 @@ msgid "" "Charset`. Defaults to ``utf-8``." msgstr "" -#: ../../library/email.utils.rst:81 +#: ../../library/email.utils.rst:86 msgid "Added the *charset* option." msgstr "新增 *charset* 選項。" -#: ../../library/email.utils.rst:87 +#: ../../library/email.utils.rst:92 msgid "" "This method returns a list of 2-tuples of the form returned by " "``parseaddr()``. *fieldvalues* is a sequence of header field values as might " -"be returned by :meth:`Message.get_all `. " -"Here's a simple example that gets all the recipients of a message::" +"be returned by :meth:`Message.get_all `." +msgstr "" + +#: ../../library/email.utils.rst:98 +msgid "Here's a simple example that gets all the recipients of a message::" +msgstr "" + +#: ../../library/email.utils.rst:100 +msgid "" +"from email.utils import getaddresses\n" +"\n" +"tos = msg.get_all('to', [])\n" +"ccs = msg.get_all('cc', [])\n" +"resent_tos = msg.get_all('resent-to', [])\n" +"resent_ccs = msg.get_all('resent-cc', [])\n" +"all_recipients = getaddresses(tos + ccs + resent_tos + resent_ccs)" msgstr "" -#: ../../library/email.utils.rst:103 +#: ../../library/email.utils.rst:114 msgid "" "Attempts to parse a date according to the rules in :rfc:`2822`. however, " "some mailers don't follow that format as specified, so :func:`parsedate` " @@ -129,7 +152,7 @@ msgid "" "returned. Note that indexes 6, 7, and 8 of the result tuple are not usable." msgstr "" -#: ../../library/email.utils.rst:114 +#: ../../library/email.utils.rst:125 msgid "" "Performs the same function as :func:`parsedate`, but returns either ``None`` " "or a 10-tuple; the first 9 elements make up a tuple that can be passed " @@ -140,7 +163,7 @@ msgid "" "the result tuple are not usable." msgstr "" -#: ../../library/email.utils.rst:124 +#: ../../library/email.utils.rst:135 msgid "" "The inverse of :func:`format_datetime`. Performs the same function as :func:" "`parsedate`, but on success returns a :mod:`~datetime.datetime`; otherwise " @@ -154,25 +177,29 @@ msgid "" "corresponding a :class:`~datetime.timezone` :class:`~datetime.tzinfo`." msgstr "" -#: ../../library/email.utils.rst:140 +#: ../../library/email.utils.rst:151 msgid "" "Turn a 10-tuple as returned by :func:`parsedate_tz` into a UTC timestamp " "(seconds since the Epoch). If the timezone item in the tuple is ``None``, " "assume local time." msgstr "" -#: ../../library/email.utils.rst:147 +#: ../../library/email.utils.rst:158 msgid "Returns a date string as per :rfc:`2822`, e.g.::" msgstr "" -#: ../../library/email.utils.rst:151 +#: ../../library/email.utils.rst:160 +msgid "Fri, 09 Nov 2001 01:08:47 -0000" +msgstr "" + +#: ../../library/email.utils.rst:162 msgid "" "Optional *timeval* if given is a floating-point time value as accepted by :" "func:`time.gmtime` and :func:`time.localtime`, otherwise the current time is " "used." msgstr "" -#: ../../library/email.utils.rst:155 +#: ../../library/email.utils.rst:166 msgid "" "Optional *localtime* is a flag that when ``True``, interprets *timeval*, and " "returns a date relative to the local timezone instead of UTC, properly " @@ -180,7 +207,7 @@ msgid "" "UTC is used." msgstr "" -#: ../../library/email.utils.rst:160 +#: ../../library/email.utils.rst:171 msgid "" "Optional *usegmt* is a flag that when ``True``, outputs a date string with " "the timezone as an ascii string ``GMT``, rather than a numeric ``-0000``. " @@ -188,7 +215,7 @@ msgid "" "*localtime* is ``False``. The default is ``False``." msgstr "" -#: ../../library/email.utils.rst:168 +#: ../../library/email.utils.rst:179 msgid "" "Like ``formatdate``, but the input is a :mod:`datetime` instance. If it is " "a naive datetime, it is assumed to be \"UTC with no information about the " @@ -200,11 +227,11 @@ msgid "" "date headers." msgstr "" -#: ../../library/email.utils.rst:182 +#: ../../library/email.utils.rst:193 msgid "Decode the string *s* according to :rfc:`2231`." msgstr "" -#: ../../library/email.utils.rst:187 +#: ../../library/email.utils.rst:198 msgid "" "Encode the string *s* according to :rfc:`2231`. Optional *charset* and " "*language*, if given is the character set name and language name to use. If " @@ -213,7 +240,7 @@ msgid "" "*language*." msgstr "" -#: ../../library/email.utils.rst:195 +#: ../../library/email.utils.rst:206 msgid "" "When a header parameter is encoded in :rfc:`2231` format, :meth:`Message." "get_param ` may return a 3-tuple containing " @@ -225,23 +252,23 @@ msgid "" "defaults to ``'us-ascii'``." msgstr "" -#: ../../library/email.utils.rst:204 +#: ../../library/email.utils.rst:215 msgid "" "For convenience, if the *value* passed to :func:`collapse_rfc2231_value` is " "not a tuple, it should be a string and it is returned unquoted." msgstr "" -#: ../../library/email.utils.rst:210 +#: ../../library/email.utils.rst:221 msgid "" "Decode parameters list according to :rfc:`2231`. *params* is a sequence of " "2-tuples containing elements of the form ``(content-type, string-value)``." msgstr "" -#: ../../library/email.utils.rst:215 +#: ../../library/email.utils.rst:226 msgid "Footnotes" msgstr "註解" -#: ../../library/email.utils.rst:216 +#: ../../library/email.utils.rst:227 msgid "" "Note that the sign of the timezone offset is the opposite of the sign of the " "``time.timezone`` variable for the same timezone; the latter variable " diff --git a/library/enum.po b/library/enum.po index b359efa937..c7582b388c 100644 --- a/library/enum.po +++ b/library/enum.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-08-15 00:04+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2023-09-11 14:08+0800\n" "Last-Translator: Adrian Liaw \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -72,6 +72,20 @@ msgid "" "using function-call syntax::" msgstr "列舉透過 :keyword:`class` 語法或函式呼叫的語法來建立: ::" +#: ../../library/enum.rst:38 +msgid "" +">>> from enum import Enum\n" +"\n" +">>> # class syntax\n" +">>> class Color(Enum):\n" +"... RED = 1\n" +"... GREEN = 2\n" +"... BLUE = 3\n" +"\n" +">>> # functional syntax\n" +">>> Color = Enum('Color', ['RED', 'GREEN', 'BLUE'])" +msgstr "" + #: ../../library/enum.rst:49 msgid "" "Even though we can use :keyword:`class` syntax to create Enums, Enums are " @@ -418,6 +432,15 @@ msgstr "在位元操作時怎麼處理範圍外的值(只有 :class:`Flag` 會 msgid "Returns ``True`` if member belongs to the ``cls``::" msgstr "如果 member 屬於 ``cls`` 則回傳 ``True``: ::" +#: ../../library/enum.rst:198 +msgid "" +">>> some_var = Color.RED\n" +">>> some_var in Color\n" +"True\n" +">>> Color.RED.value in Color\n" +"True" +msgstr "" + #: ../../library/enum.rst:206 msgid "" "Before Python 3.12, a ``TypeError`` is raised if a non-Enum-member is used " @@ -434,20 +457,46 @@ msgstr "" "回傳 ``['__class__', '__doc__', '__members__', '__module__']`` 及 *cls* 的成" "員名稱: ::" +#: ../../library/enum.rst:214 +msgid "" +">>> dir(Color)\n" +"['BLUE', 'GREEN', 'RED', '__class__', '__contains__', '__doc__', " +"'__getitem__', '__init_subclass__', '__iter__', '__len__', '__members__', " +"'__module__', '__name__', '__qualname__']" +msgstr "" + #: ../../library/enum.rst:219 msgid "" "Returns the Enum member in *cls* matching *name*, or raises a :exc:" "`KeyError`::" msgstr "回傳 *cls* 中符合 *name* 的列舉成員,或引發 :exc:`KeyError`: ::" +#: ../../library/enum.rst:221 +msgid "" +">>> Color['BLUE']\n" +"" +msgstr "" + #: ../../library/enum.rst:226 msgid "Returns each member in *cls* in definition order::" msgstr "以定義的順序回傳在 *cls* 中的每個成員: ::" +#: ../../library/enum.rst:228 +msgid "" +">>> list(Color)\n" +"[, , ]" +msgstr "" + #: ../../library/enum.rst:233 msgid "Returns the number of member in *cls*::" msgstr "回傳 *cls* 的成員數量: ::" +#: ../../library/enum.rst:235 +msgid "" +">>> len(Color)\n" +"3" +msgstr "" + #: ../../library/enum.rst:240 msgid "Returns a mapping of every enum name to its member, including aliases" msgstr "回傳每個列舉名稱到其成員的對映,包括別名" @@ -456,6 +505,12 @@ msgstr "回傳每個列舉名稱到其成員的對映,包括別名" msgid "Returns each member in *cls* in reverse definition order::" msgstr "以跟定義相反的順序回傳 *cls* 的每個成員: ::" +#: ../../library/enum.rst:246 +msgid "" +">>> list(reversed(Color))\n" +"[, , ]" +msgstr "" + #: ../../library/enum.rst:251 msgid "Before 3.11 ``enum`` used ``EnumMeta`` type, which is kept as an alias." msgstr "" @@ -469,10 +524,22 @@ msgstr "*Enum* 是所有 *enum* 列舉的基礎類別。" msgid "The name used to define the ``Enum`` member::" msgstr "用來定義 ``Enum`` 成員的名稱: ::" +#: ../../library/enum.rst:262 +msgid "" +">>> Color.BLUE.name\n" +"'BLUE'" +msgstr "" + #: ../../library/enum.rst:267 msgid "The value given to the ``Enum`` member::" msgstr "``Enum`` 成員給定的值: ::" +#: ../../library/enum.rst:269 +msgid "" +">>> Color.RED.value\n" +"1" +msgstr "" + #: ../../library/enum.rst:272 ../../library/enum.rst:292 msgid "Value of the member, can be set in :meth:`~Enum.__new__`." msgstr "成員的值,可以在 :meth:`~Enum.__new__` 設定。" @@ -532,6 +599,26 @@ msgstr "" "回傳 ``['__class__', '__doc__', '__module__', 'name', 'value']`` 及任何 " "*self.__class__* 上定義的公開方法: ::" +#: ../../library/enum.rst:313 +msgid "" +">>> from datetime import date\n" +">>> class Weekday(Enum):\n" +"... MONDAY = 1\n" +"... TUESDAY = 2\n" +"... WEDNESDAY = 3\n" +"... THURSDAY = 4\n" +"... FRIDAY = 5\n" +"... SATURDAY = 6\n" +"... SUNDAY = 7\n" +"... @classmethod\n" +"... def today(cls):\n" +"... print('today is %s' % cls(date.today().isoweekday()).name)\n" +"...\n" +">>> dir(Weekday.SATURDAY)\n" +"['__class__', '__doc__', '__eq__', '__hash__', '__module__', 'name', " +"'today', 'value']" +msgstr "" + #: ../../library/enum.rst:0 msgid "name" msgstr "name" @@ -566,6 +653,20 @@ msgid "" "`auto`::" msgstr "一個 *staticmethod*,用來決定 :class:`auto` 下一個要回傳的值的: ::" +#: ../../library/enum.rst:339 +msgid "" +">>> from enum import auto\n" +">>> class PowersOfThree(Enum):\n" +"... @staticmethod\n" +"... def _generate_next_value_(name, start, count, last_values):\n" +"... return 3 ** (count + 1)\n" +"... FIRST = auto()\n" +"... SECOND = auto()\n" +"...\n" +">>> PowersOfThree.SECOND.value\n" +"9" +msgstr "" + #: ../../library/enum.rst:352 msgid "" "By default, does nothing. If multiple values are given in the member " @@ -594,6 +695,26 @@ msgstr "" "一個 *classmethod*,用來查詢在 *cls* 裡找不到的值。預設不做任何事,但可以被覆" "寫以實作客製化的搜尋行為: ::" +#: ../../library/enum.rst:371 +msgid "" +">>> from enum import StrEnum\n" +">>> class Build(StrEnum):\n" +"... DEBUG = auto()\n" +"... OPTIMIZED = auto()\n" +"... @classmethod\n" +"... def _missing_(cls, value):\n" +"... value = value.lower()\n" +"... for member in cls:\n" +"... if member.value == value:\n" +"... return member\n" +"... return None\n" +"...\n" +">>> Build.DEBUG.value\n" +"'debug'\n" +">>> Build('deBUG')\n" +"" +msgstr "" + #: ../../library/enum.rst:390 msgid "" "By default, doesn't exist. If specified, either in the enum class " @@ -624,6 +745,21 @@ msgstr "" "回傳呼叫 *repr()* 時使用的字串。預設回傳 *Enum* 名稱、成員名稱及值,但可以被" "覆寫: ::" +#: ../../library/enum.rst:410 +msgid "" +">>> class OtherStyle(Enum):\n" +"... ALTERNATE = auto()\n" +"... OTHER = auto()\n" +"... SOMETHING_ELSE = auto()\n" +"... def __repr__(self):\n" +"... cls_name = self.__class__.__name__\n" +"... return f'{cls_name}.{self.name}'\n" +"...\n" +">>> OtherStyle.ALTERNATE, str(OtherStyle.ALTERNATE), f\"{OtherStyle." +"ALTERNATE}\"\n" +"(OtherStyle.ALTERNATE, 'OtherStyle.ALTERNATE', 'OtherStyle.ALTERNATE')" +msgstr "" + #: ../../library/enum.rst:423 msgid "" "Returns the string used for *str()* calls. By default, returns the *Enum* " @@ -632,6 +768,20 @@ msgstr "" "回傳呼叫 *str()* 時使用的字串。預設回傳 *Enum* 名稱及成員名稱,但可以被覆" "寫: ::" +#: ../../library/enum.rst:426 +msgid "" +">>> class OtherStyle(Enum):\n" +"... ALTERNATE = auto()\n" +"... OTHER = auto()\n" +"... SOMETHING_ELSE = auto()\n" +"... def __str__(self):\n" +"... return f'{self.name}'\n" +"...\n" +">>> OtherStyle.ALTERNATE, str(OtherStyle.ALTERNATE), f\"{OtherStyle." +"ALTERNATE}\"\n" +"(, 'ALTERNATE', 'ALTERNATE')" +msgstr "" + #: ../../library/enum.rst:438 msgid "" "Returns the string used for *format()* and *f-string* calls. By default, " @@ -640,6 +790,20 @@ msgstr "" "回傳呼叫 *format()* 及 *f-string* 時使用的字串。預設回傳 :meth:`__str__` 的回" "傳值,但可以被覆寫: ::" +#: ../../library/enum.rst:441 +msgid "" +">>> class OtherStyle(Enum):\n" +"... ALTERNATE = auto()\n" +"... OTHER = auto()\n" +"... SOMETHING_ELSE = auto()\n" +"... def __format__(self, spec):\n" +"... return f'{self.name}'\n" +"...\n" +">>> OtherStyle.ALTERNATE, str(OtherStyle.ALTERNATE), f\"{OtherStyle." +"ALTERNATE}\"\n" +"(, 'OtherStyle.ALTERNATE', 'ALTERNATE')" +msgstr "" + #: ../../library/enum.rst:453 msgid "" "Using :class:`auto` with :class:`Enum` results in integers of increasing " @@ -727,34 +891,113 @@ msgstr "" msgid "Returns *True* if value is in self::" msgstr "如果 value 在 self 裡則回傳 *True*: ::" +#: ../../library/enum.rst:526 +msgid "" +">>> from enum import Flag, auto\n" +">>> class Color(Flag):\n" +"... RED = auto()\n" +"... GREEN = auto()\n" +"... BLUE = auto()\n" +"...\n" +">>> purple = Color.RED | Color.BLUE\n" +">>> white = Color.RED | Color.GREEN | Color.BLUE\n" +">>> Color.GREEN in purple\n" +"False\n" +">>> Color.GREEN in white\n" +"True\n" +">>> purple in white\n" +"True\n" +">>> white in purple\n" +"False" +msgstr "" + #: ../../library/enum.rst:545 msgid "Returns all contained non-alias members::" msgstr "回傳所有包含的非別名成員: ::" +#: ../../library/enum.rst:547 +msgid "" +">>> list(Color.RED)\n" +"[]\n" +">>> list(purple)\n" +"[, ]" +msgstr "" + #: ../../library/enum.rst:556 msgid "Returns number of members in flag::" msgstr "回傳旗標裡的成員數量: ::" +#: ../../library/enum.rst:558 +msgid "" +">>> len(Color.GREEN)\n" +"1\n" +">>> len(white)\n" +"3" +msgstr "" + #: ../../library/enum.rst:567 msgid "Returns *True* if any members in flag, *False* otherwise::" msgstr "如果成員在旗標裡則回傳 *True*,否則回傳 *False*: ::" +#: ../../library/enum.rst:569 +msgid "" +">>> bool(Color.GREEN)\n" +"True\n" +">>> bool(white)\n" +"True\n" +">>> black = Color(0)\n" +">>> bool(black)\n" +"False" +msgstr "" + #: ../../library/enum.rst:579 msgid "Returns current flag binary or'ed with other::" msgstr "回傳和 other 做 OR 過後的二進位旗標: ::" +#: ../../library/enum.rst:581 +msgid "" +">>> Color.RED | Color.GREEN\n" +"" +msgstr "" + #: ../../library/enum.rst:586 msgid "Returns current flag binary and'ed with other::" msgstr "回傳和 other 做 AND 過後的二進位旗標: ::" +#: ../../library/enum.rst:588 +msgid "" +">>> purple & white\n" +"\n" +">>> purple & Color.GREEN\n" +"" +msgstr "" + #: ../../library/enum.rst:595 msgid "Returns current flag binary xor'ed with other::" msgstr "回傳和 other 做 XOR 過後的二進位旗標: ::" +#: ../../library/enum.rst:597 +msgid "" +">>> purple ^ white\n" +"\n" +">>> purple ^ Color.GREEN\n" +"" +msgstr "" + #: ../../library/enum.rst:604 msgid "Returns all the flags in *type(self)* that are not in self::" msgstr "回傳所有在 *type(self)* 但不在 self 裡的旗標: ::" +#: ../../library/enum.rst:606 +msgid "" +">>> ~white\n" +"\n" +">>> ~purple\n" +"\n" +">>> ~Color.RED\n" +"" +msgstr "" + #: ../../library/enum.rst:615 msgid "" "Function used to format any remaining unnamed numeric values. Default is " @@ -787,6 +1030,12 @@ msgid "" "is not an *IntFlag*::" msgstr "如果 *IntFlag* 成員經過任何整數運算,其結果不是 *IntFlag*: ::" +#: ../../library/enum.rst:648 +msgid "" +">>> Color.RED + 2\n" +"3" +msgstr "" + #: ../../library/enum.rst:651 msgid "If a *Flag* operation is performed with an *IntFlag* member and:" msgstr "如果 *IntFlag* 成員經過 *Flag* 操作且:" @@ -868,12 +1117,39 @@ msgstr "" msgid "Ensure that each value has only one name::" msgstr "確保每個值只有一個名稱: ::" +#: ../../library/enum.rst:700 +msgid "" +">>> from enum import Enum, verify, UNIQUE\n" +">>> @verify(UNIQUE)\n" +"... class Color(Enum):\n" +"... RED = 1\n" +"... GREEN = 2\n" +"... BLUE = 3\n" +"... CRIMSON = 1\n" +"Traceback (most recent call last):\n" +"...\n" +"ValueError: aliases found in : CRIMSON -> RED" +msgstr "" + #: ../../library/enum.rst:714 msgid "" "Ensure that there are no missing values between the lowest-valued member and " "the highest-valued member::" msgstr "確保在最小值成員跟最大值成員間沒有缺少值: ::" +#: ../../library/enum.rst:717 +msgid "" +">>> from enum import Enum, verify, CONTINUOUS\n" +">>> @verify(CONTINUOUS)\n" +"... class Color(Enum):\n" +"... RED = 1\n" +"... GREEN = 2\n" +"... BLUE = 5\n" +"Traceback (most recent call last):\n" +"...\n" +"ValueError: invalid enum 'Color': missing values 3, 4" +msgstr "" + #: ../../library/enum.rst:729 msgid "" "Ensure that any flag groups/masks contain only named flags -- useful when " @@ -882,6 +1158,22 @@ msgstr "" "確保任何旗標群組 / 遮罩只包含命名旗標 -- 當值是用指定而不是透過 :func:`auto` " "產生時是很實用的: ::" +#: ../../library/enum.rst:732 +msgid "" +">>> from enum import Flag, verify, NAMED_FLAGS\n" +">>> @verify(NAMED_FLAGS)\n" +"... class Color(Flag):\n" +"... RED = 1\n" +"... GREEN = 2\n" +"... BLUE = 4\n" +"... WHITE = 15\n" +"... NEON = 31\n" +"Traceback (most recent call last):\n" +"...\n" +"ValueError: invalid Flag 'Color': aliases WHITE and NEON are missing " +"combined values of 0x18 [use enum.show_flag_values(value) for details]" +msgstr "" + #: ../../library/enum.rst:746 msgid "" "CONTINUOUS and NAMED_FLAGS are designed to work with integer-valued members." @@ -899,12 +1191,40 @@ msgid "" "default for :class:`Flag`::" msgstr "範圍外的值會引發 :exc:`ValueError`。這是 :class:`Flag` 的預設行為: ::" +#: ../../library/enum.rst:760 +msgid "" +">>> from enum import Flag, STRICT, auto\n" +">>> class StrictFlag(Flag, boundary=STRICT):\n" +"... RED = auto()\n" +"... GREEN = auto()\n" +"... BLUE = auto()\n" +"...\n" +">>> StrictFlag(2**2 + 2**4)\n" +"Traceback (most recent call last):\n" +"...\n" +"ValueError: invalid value 20\n" +" given 0b0 10100\n" +" allowed 0b0 00111" +msgstr "" + #: ../../library/enum.rst:775 msgid "" "Out-of-range values have invalid values removed, leaving a valid *Flag* " "value::" msgstr "範圍外的值會移除非法值,留下合法的 *Flag* 值: ::" +#: ../../library/enum.rst:778 +msgid "" +">>> from enum import Flag, CONFORM, auto\n" +">>> class ConformFlag(Flag, boundary=CONFORM):\n" +"... RED = auto()\n" +"... GREEN = auto()\n" +"... BLUE = auto()\n" +"...\n" +">>> ConformFlag(2**2 + 2**4)\n" +"" +msgstr "" + #: ../../library/enum.rst:789 msgid "" "Out-of-range values lose their *Flag* membership and revert to :class:`int`." @@ -918,6 +1238,18 @@ msgstr "" "範圍外的值會被保留,*Flag* 成員資格也會被保留。這是 :class:`IntFlag` 的預設行" "為: ::" +#: ../../library/enum.rst:805 +msgid "" +">>> from enum import Flag, KEEP, auto\n" +">>> class KeepFlag(Flag, boundary=KEEP):\n" +"... RED = auto()\n" +"... GREEN = auto()\n" +"... BLUE = auto()\n" +"...\n" +">>> KeepFlag(2**2 + 2**4)\n" +"" +msgstr "" + #: ../../library/enum.rst:819 msgid "Supported ``__dunder__`` names" msgstr "支援 ``__dunder__`` 名稱" @@ -1101,6 +1433,21 @@ msgstr "" "__members__`,蒐集任何它找到的別名;如果有找到任何別名則引發 :exc:" "`ValueError` 並附上細節: ::" +#: ../../library/enum.rst:909 +msgid "" +">>> from enum import Enum, unique\n" +">>> @unique\n" +"... class Mistake(Enum):\n" +"... ONE = 1\n" +"... TWO = 2\n" +"... THREE = 3\n" +"... FOUR = 3\n" +"...\n" +"Traceback (most recent call last):\n" +"...\n" +"ValueError: duplicate values found in : FOUR -> THREE" +msgstr "" + #: ../../library/enum.rst:923 msgid "" "A :keyword:`class` decorator specifically for enumerations. Members from :" @@ -1167,10 +1514,24 @@ msgstr "" "如果你不需要或不想要這些限制,你可以透過混合 ``int`` 或 ``str`` 類型來建立自" "己的基礎類別: ::" +#: ../../library/enum.rst:975 +msgid "" +">>> from enum import Enum\n" +">>> class MyIntEnum(int, Enum):\n" +"... pass" +msgstr "" + #: ../../library/enum.rst:979 msgid "or you can reassign the appropriate :meth:`str`, etc., in your enum::" msgstr "或者你也可以在你的列舉重新給定合適的 :meth:`str`: ::" +#: ../../library/enum.rst:981 +msgid "" +">>> from enum import Enum, IntEnum\n" +">>> class MyIntEnum(IntEnum):\n" +"... __str__ = Enum.__str__" +msgstr "" + #~ msgid "call the appropriate ``__new__`` instead." #~ msgstr "而是呼叫適當的 ``__new__`` 。" diff --git a/library/exceptions.po b/library/exceptions.po index a8aa0b3b9e..d5e78edadc 100644 --- a/library/exceptions.po +++ b/library/exceptions.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-07-20 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2024-03-12 20:57+0800\n" "Last-Translator: Adrian Liaw \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -107,6 +107,10 @@ msgstr "" "這個隱含的例外情境可以透過使用 :keyword:`!from` 搭配 :keyword:`raise` 來補充" "明確的原因: ::" +#: ../../library/exceptions.rst:63 +msgid "raise new_exc from original_exc" +msgstr "" + #: ../../library/exceptions.rst:65 msgid "" "The expression following :keyword:`from` must be an exception or " @@ -227,6 +231,15 @@ msgstr "" "引發,目前的 frame 會被加進 ``OtherException`` 的回溯,就像原來 " "``SomeException`` 的回溯會發生的一樣,我們允許它被傳遞給呼叫者: ::" +#: ../../library/exceptions.rst:135 +msgid "" +"try:\n" +" ...\n" +"except SomeException:\n" +" tb = sys.exception().__traceback__\n" +" raise OtherException(...).with_traceback(tb)" +msgstr "" + #: ../../library/exceptions.rst:143 msgid "" "A writable field that holds the :ref:`traceback object ` " @@ -1214,6 +1227,35 @@ msgid "" "not need to be updated by :meth:`derive`." msgstr "" +#: ../../library/exceptions.rst:983 +msgid "" +">>> class MyGroup(ExceptionGroup):\n" +"... def derive(self, excs):\n" +"... return MyGroup(self.message, excs)\n" +"...\n" +">>> e = MyGroup(\"eg\", [ValueError(1), TypeError(2)])\n" +">>> e.add_note(\"a note\")\n" +">>> e.__context__ = Exception(\"context\")\n" +">>> e.__cause__ = Exception(\"cause\")\n" +">>> try:\n" +"... raise e\n" +"... except Exception as e:\n" +"... exc = e\n" +"...\n" +">>> match, rest = exc.split(ValueError)\n" +">>> exc, exc.__context__, exc.__cause__, exc.__notes__\n" +"(MyGroup('eg', [ValueError(1), TypeError(2)]), Exception('context'), " +"Exception('cause'), ['a note'])\n" +">>> match, match.__context__, match.__cause__, match.__notes__\n" +"(MyGroup('eg', [ValueError(1)]), Exception('context'), Exception('cause'), " +"['a note'])\n" +">>> rest, rest.__context__, rest.__cause__, rest.__notes__\n" +"(MyGroup('eg', [TypeError(2)]), Exception('context'), Exception('cause'), " +"['a note'])\n" +">>> exc.__traceback__ is match.__traceback__ is rest.__traceback__\n" +"True" +msgstr "" + #: ../../library/exceptions.rst:1009 msgid "" "Note that :exc:`BaseExceptionGroup` defines :meth:`~object.__new__`, so " @@ -1223,6 +1265,18 @@ msgid "" "group's message from it. ::" msgstr "" +#: ../../library/exceptions.rst:1015 +msgid "" +"class Errors(ExceptionGroup):\n" +" def __new__(cls, errors, exit_code):\n" +" self = super().__new__(Errors, f\"exit code: {exit_code}\", errors)\n" +" self.exit_code = exit_code\n" +" return self\n" +"\n" +" def derive(self, excs):\n" +" return Errors(excs, self.exit_code)" +msgstr "" + #: ../../library/exceptions.rst:1024 msgid "" "Like :exc:`ExceptionGroup`, any subclass of :exc:`BaseExceptionGroup` which " @@ -1238,6 +1292,77 @@ msgstr "例外階層" msgid "The class hierarchy for built-in exceptions is:" msgstr "內建例外的類別階層如下:" +#: ../../library/exceptions.rst:1036 +msgid "" +"BaseException\n" +" ├── BaseExceptionGroup\n" +" ├── GeneratorExit\n" +" ├── KeyboardInterrupt\n" +" ├── SystemExit\n" +" └── Exception\n" +" ├── ArithmeticError\n" +" │ ├── FloatingPointError\n" +" │ ├── OverflowError\n" +" │ └── ZeroDivisionError\n" +" ├── AssertionError\n" +" ├── AttributeError\n" +" ├── BufferError\n" +" ├── EOFError\n" +" ├── ExceptionGroup [BaseExceptionGroup]\n" +" ├── ImportError\n" +" │ └── ModuleNotFoundError\n" +" ├── LookupError\n" +" │ ├── IndexError\n" +" │ └── KeyError\n" +" ├── MemoryError\n" +" ├── NameError\n" +" │ └── UnboundLocalError\n" +" ├── OSError\n" +" │ ├── BlockingIOError\n" +" │ ├── ChildProcessError\n" +" │ ├── ConnectionError\n" +" │ │ ├── BrokenPipeError\n" +" │ │ ├── ConnectionAbortedError\n" +" │ │ ├── ConnectionRefusedError\n" +" │ │ └── ConnectionResetError\n" +" │ ├── FileExistsError\n" +" │ ├── FileNotFoundError\n" +" │ ├── InterruptedError\n" +" │ ├── IsADirectoryError\n" +" │ ├── NotADirectoryError\n" +" │ ├── PermissionError\n" +" │ ├── ProcessLookupError\n" +" │ └── TimeoutError\n" +" ├── ReferenceError\n" +" ├── RuntimeError\n" +" │ ├── NotImplementedError\n" +" │ └── RecursionError\n" +" ├── StopAsyncIteration\n" +" ├── StopIteration\n" +" ├── SyntaxError\n" +" │ └── IndentationError\n" +" │ └── TabError\n" +" ├── SystemError\n" +" ├── TypeError\n" +" ├── ValueError\n" +" │ └── UnicodeError\n" +" │ ├── UnicodeDecodeError\n" +" │ ├── UnicodeEncodeError\n" +" │ └── UnicodeTranslateError\n" +" └── Warning\n" +" ├── BytesWarning\n" +" ├── DeprecationWarning\n" +" ├── EncodingWarning\n" +" ├── FutureWarning\n" +" ├── ImportWarning\n" +" ├── PendingDeprecationWarning\n" +" ├── ResourceWarning\n" +" ├── RuntimeWarning\n" +" ├── SyntaxWarning\n" +" ├── UnicodeWarning\n" +" └── UserWarning\n" +msgstr "" + #: ../../library/exceptions.rst:6 ../../library/exceptions.rst:17 #: ../../library/exceptions.rst:196 msgid "statement" diff --git a/library/faulthandler.po b/library/faulthandler.po index 0d1e7a71c7..b4adcc1d42 100644 --- a/library/faulthandler.po +++ b/library/faulthandler.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-05-09 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2018-05-23 16:01+0000\n" "Last-Translator: Adrian Liaw \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -252,3 +252,20 @@ msgid "" "Example of a segmentation fault on Linux with and without enabling the fault " "handler:" msgstr "" + +#: ../../library/faulthandler.rst:178 +msgid "" +"$ python -c \"import ctypes; ctypes.string_at(0)\"\n" +"Segmentation fault\n" +"\n" +"$ python -q -X faulthandler\n" +">>> import ctypes\n" +">>> ctypes.string_at(0)\n" +"Fatal Python error: Segmentation fault\n" +"\n" +"Current thread 0x00007fb899f39700 (most recent call first):\n" +" File \"/home/python/cpython/Lib/ctypes/__init__.py\", line 486 in " +"string_at\n" +" File \"\", line 1 in \n" +"Segmentation fault" +msgstr "" diff --git a/library/fcntl.po b/library/fcntl.po index 3d3e47c648..b2676a2871 100644 --- a/library/fcntl.po +++ b/library/fcntl.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-08-04 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2017-09-22 18:26+0000\n" "Last-Translator: Liang-Bo Wang \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -182,6 +182,20 @@ msgstr "" msgid "An example::" msgstr "範例: ::" +#: ../../library/fcntl.rst:125 +msgid "" +">>> import array, fcntl, struct, termios, os\n" +">>> os.getpgrp()\n" +"13341\n" +">>> struct.unpack('h', fcntl.ioctl(0, termios.TIOCGPGRP, \" \"))[0]\n" +"13341\n" +">>> buf = array.array('h', [0])\n" +">>> fcntl.ioctl(0, termios.TIOCGPGRP, buf, 1)\n" +"0\n" +">>> buf\n" +"array('h', [13341])" +msgstr "" + #: ../../library/fcntl.rst:136 msgid "" "Raises an :ref:`auditing event ` ``fcntl.ioctl`` with arguments " @@ -285,6 +299,17 @@ msgstr "" msgid "Examples (all on a SVR4 compliant system)::" msgstr "" +#: ../../library/fcntl.rst:198 +msgid "" +"import struct, fcntl, os\n" +"\n" +"f = open(...)\n" +"rv = fcntl.fcntl(f, fcntl.F_SETFL, os.O_NDELAY)\n" +"\n" +"lockdata = struct.pack('hhllhh', fcntl.F_WRLCK, 0, 0, 0, 0, 0)\n" +"rv = fcntl.fcntl(f, fcntl.F_SETLKW, lockdata)" +msgstr "" + #: ../../library/fcntl.rst:206 msgid "" "Note that in the first example the return value variable *rv* will hold an " diff --git a/library/filecmp.po b/library/filecmp.po index db539d9d16..7c37e0ca1f 100644 --- a/library/filecmp.po +++ b/library/filecmp.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-05-09 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2015-12-09 17:51+0000\n" "Last-Translator: Liang-Bo Wang \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -236,3 +236,17 @@ msgid "" "Here is a simplified example of using the ``subdirs`` attribute to search " "recursively through two directories to show common different files::" msgstr "" + +#: ../../library/filecmp.rst:197 +msgid "" +">>> from filecmp import dircmp\n" +">>> def print_diff_files(dcmp):\n" +"... for name in dcmp.diff_files:\n" +"... print(\"diff_file %s found in %s and %s\" % (name, dcmp.left,\n" +"... dcmp.right))\n" +"... for sub_dcmp in dcmp.subdirs.values():\n" +"... print_diff_files(sub_dcmp)\n" +"...\n" +">>> dcmp = dircmp('dir1', 'dir2') \n" +">>> print_diff_files(dcmp) " +msgstr "" diff --git a/library/fnmatch.po b/library/fnmatch.po index fb99db2926..5181c3bfbe 100644 --- a/library/fnmatch.po +++ b/library/fnmatch.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-05-09 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2018-05-23 16:02+0000\n" "Last-Translator: Adrian Liaw \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -110,6 +110,16 @@ msgid "" "extension ``.txt``::" msgstr "" +#: ../../library/fnmatch.rst:64 +msgid "" +"import fnmatch\n" +"import os\n" +"\n" +"for file in os.listdir('.'):\n" +" if fnmatch.fnmatch(file, '*.txt'):\n" +" print(file)" +msgstr "" + #: ../../library/fnmatch.rst:74 msgid "" "Test whether the filename string *name* matches the pattern string *pat*, " diff --git a/library/fractions.po b/library/fractions.po index 11c2d748b5..1ca1524907 100644 --- a/library/fractions.po +++ b/library/fractions.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-07-23 00:04+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2016-01-31 07:18+0000\n" "Last-Translator: Liang-Bo Wang \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -55,6 +55,10 @@ msgid "" "instance. The usual form for this instance is::" msgstr "" +#: ../../library/fractions.rst:41 +msgid "[sign] numerator ['/' denominator]" +msgstr "" + #: ../../library/fractions.rst:43 msgid "" "where the optional ``sign`` may be either '+' or '-' and ``numerator`` and " @@ -66,6 +70,34 @@ msgid "" "whitespace. Here are some examples::" msgstr "" +#: ../../library/fractions.rst:52 +msgid "" +">>> from fractions import Fraction\n" +">>> Fraction(16, -10)\n" +"Fraction(-8, 5)\n" +">>> Fraction(123)\n" +"Fraction(123, 1)\n" +">>> Fraction()\n" +"Fraction(0, 1)\n" +">>> Fraction('3/7')\n" +"Fraction(3, 7)\n" +">>> Fraction(' -3/7 ')\n" +"Fraction(-3, 7)\n" +">>> Fraction('1.414213 \\t\\n')\n" +"Fraction(1414213, 1000000)\n" +">>> Fraction('-.125')\n" +"Fraction(-1, 8)\n" +">>> Fraction('7e-6')\n" +"Fraction(7, 1000000)\n" +">>> Fraction(2.25)\n" +"Fraction(9, 4)\n" +">>> Fraction(1.1)\n" +"Fraction(2476979795053773, 2251799813685248)\n" +">>> from decimal import Decimal\n" +">>> Fraction(Decimal('1.1'))\n" +"Fraction(11, 10)" +msgstr "" + #: ../../library/fractions.rst:78 msgid "" "The :class:`Fraction` class inherits from the abstract base class :class:" @@ -202,6 +234,20 @@ msgstr "" msgid "Here are some examples::" msgstr "" +#: ../../library/fractions.rst:214 +msgid "" +">>> from fractions import Fraction\n" +">>> format(Fraction(1, 7), '.40g')\n" +"'0.1428571428571428571428571428571428571429'\n" +">>> format(Fraction('1234567.855'), '_.2f')\n" +"'1_234_567.86'\n" +">>> f\"{Fraction(355, 113):*>20.6e}\"\n" +"'********3.141593e+00'\n" +">>> old_price, new_price = 499, 672\n" +">>> \"{:.2%} price increase\".format(Fraction(new_price, old_price) - 1)\n" +"'34.67% price increase'" +msgstr "" + #: ../../library/fractions.rst:228 msgid "Module :mod:`numbers`" msgstr ":mod:`numbers` 模組" diff --git a/library/functions.po b/library/functions.po index 297b06d5a5..5fa9962160 100644 --- a/library/functions.po +++ b/library/functions.po @@ -10,7 +10,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-08-30 18:24+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2024-05-06 17:06+0800\n" "Last-Translator: KNChiu \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -426,6 +426,15 @@ msgstr "" "如果 *iterable* 的所有元素皆為真(或 iterable 為空)則回傳 ``True``。等價" "於: ::" +#: ../../library/functions.rst:79 +msgid "" +"def all(iterable):\n" +" for element in iterable:\n" +" if not element:\n" +" return False\n" +" return True" +msgstr "" + #: ../../library/functions.rst:89 msgid "" "When awaited, return the next item from the given :term:`asynchronous " @@ -458,6 +467,15 @@ msgstr "" "如果 *iterable* 的任一元素為真,回傳 ``True``。如果 iterable 是空的,則回傳 " "``False``。等價於: ::" +#: ../../library/functions.rst:107 +msgid "" +"def any(iterable):\n" +" for element in iterable:\n" +" if element:\n" +" return True\n" +" return False" +msgstr "" + #: ../../library/functions.rst:116 msgid "" "As :func:`repr`, return a string containing a printable representation of an " @@ -687,6 +705,13 @@ msgstr "" "一個 class method 把自己的 class 作為第一個引數,就像一個實例 method 把實例自" "己作為第一個引數。請用以下慣例來宣告 class method: ::" +#: ../../library/functions.rst:265 +msgid "" +"class C:\n" +" @classmethod\n" +" def f(cls, arg1, arg2): ..." +msgstr "" + #: ../../library/functions.rst:269 msgid "" "The ``@classmethod`` form is a function :term:`decorator` -- see :ref:" @@ -898,6 +923,26 @@ msgstr "" msgid "Examples:" msgstr "例如: ::" +#: ../../library/functions.rst:384 +msgid "" +">>> complex('+1.23')\n" +"(1.23+0j)\n" +">>> complex('-4.5j')\n" +"-4.5j\n" +">>> complex('-1.23+4.5j')\n" +"(-1.23+4.5j)\n" +">>> complex('\\t( -1.23+4.5J )\\n')\n" +"(-1.23+4.5j)\n" +">>> complex('-Infinity+NaNj')\n" +"(-inf+nanj)\n" +">>> complex(1.23)\n" +"(1.23+0j)\n" +">>> complex(imag=-4.5)\n" +"-4.5j\n" +">>> complex(-1.23, 4.5)\n" +"(-1.23+4.5j)" +msgstr "" + #: ../../library/functions.rst:403 msgid "" "If the argument is a string, it must contain either a real part (in the same " @@ -1107,6 +1152,15 @@ msgstr "" msgid "Equivalent to::" msgstr "等價於: ::" +#: ../../library/functions.rst:564 +msgid "" +"def enumerate(iterable, start=0):\n" +" n = start\n" +" for elem in iterable:\n" +" yield n, elem\n" +" n += 1" +msgstr "" + #: ../../library/functions.rst:0 msgid "Parameters" msgstr "" @@ -1343,6 +1397,20 @@ msgstr "" msgid "Return a floating-point number constructed from a number or a string." msgstr "回傳從數字或字串生成的浮點數。" +#: ../../library/functions.rst:721 +msgid "" +">>> float('+1.23')\n" +"1.23\n" +">>> float(' -12345\\n')\n" +"-12345.0\n" +">>> float('1e-003')\n" +"0.001\n" +">>> float('+1E6')\n" +"1000000.0\n" +">>> float('-Infinity')\n" +"-inf" +msgstr "" + #: ../../library/functions.rst:734 msgid "" "If the argument is a string, it should contain a decimal number, optionally " @@ -1626,6 +1694,14 @@ msgstr "" "從輸入中讀取一行,將其轉換為字串(去除末尾的換行符)並回傳。當讀取到 EOF 時," "則引發 :exc:`EOFError`。例如: ::" +#: ../../library/functions.rst:940 +msgid "" +">>> s = input('--> ') \n" +"--> Monty Python's Flying Circus\n" +">>> s \n" +"\"Monty Python's Flying Circus\"" +msgstr "" + #: ../../library/functions.rst:945 msgid "" "If the :mod:`readline` module was loaded, then :func:`input` will use it to " @@ -1656,6 +1732,22 @@ msgid "" "``0`` if no arguments are given." msgstr "" +#: ../../library/functions.rst:967 +msgid "" +">>> int(123.45)\n" +"123\n" +">>> int('123')\n" +"123\n" +">>> int(' -12_345\\n')\n" +"-12345\n" +">>> int('FACE', 16)\n" +"64206\n" +">>> int('0xface', 0)\n" +"64206\n" +">>> int('01110011', base=2)\n" +"115" +msgstr "" + #: ../../library/functions.rst:982 msgid "" "If the argument defines :meth:`~object.__int__`, ``int(x)`` returns ``x." @@ -1826,6 +1918,14 @@ msgstr "" ":func:`iter` 的第二種形式有一個好用的應用,是能夠建立一個區塊閱讀器 (block-" "reader)。例如,從二進位資料庫檔案中讀取固定寬度的區塊,直到檔案的結尾: ::" +#: ../../library/functions.rst:1088 +msgid "" +"from functools import partial\n" +"with open('mydata.db', 'rb') as f:\n" +" for block in iter(partial(f.read, 64), b''):\n" +" process_block(block)" +msgstr "" + #: ../../library/functions.rst:1096 msgid "" "Return the length (the number of items) of an object. The argument may be a " @@ -2356,6 +2456,19 @@ msgstr "" "下面的範例使用 :func:`os.open` 函式回傳值當作 :ref:`dir_fd ` 的參數," "從給定的目錄中用相對路徑開啟檔案: ::" +#: ../../library/functions.rst:1408 +msgid "" +">>> import os\n" +">>> dir_fd = os.open('somedir', os.O_RDONLY)\n" +">>> def opener(path, flags):\n" +"... return os.open(path, flags, dir_fd=dir_fd)\n" +"...\n" +">>> with open('spamspam.txt', 'w', opener=opener) as f:\n" +"... print('This will be written to somedir/spamspam.txt', file=f)\n" +"...\n" +">>> os.close(dir_fd) # don't leak a file descriptor" +msgstr "" + #: ../../library/functions.rst:1418 msgid "" "The type of :term:`file object` returned by the :func:`open` function " @@ -2519,6 +2632,14 @@ msgstr "" msgid "Here's an example of computing an inverse for ``38`` modulo ``97``::" msgstr "以下是一個計算 ``38`` 對 ``97`` 取模倒數的範例: ::" +#: ../../library/functions.rst:1511 +msgid "" +">>> pow(38, -1, mod=97)\n" +"23\n" +">>> 23 * 38 % 97 == 1\n" +"True" +msgstr "" + #: ../../library/functions.rst:1516 msgid "" "For :class:`int` operands, the three-argument form of ``pow`` now allows the " @@ -2595,6 +2716,24 @@ msgstr "" msgid "A typical use is to define a managed attribute ``x``::" msgstr "一個典型的用途是定義一個受管理的屬性 ``x``: ::" +#: ../../library/functions.rst:1561 +msgid "" +"class C:\n" +" def __init__(self):\n" +" self._x = None\n" +"\n" +" def getx(self):\n" +" return self._x\n" +"\n" +" def setx(self, value):\n" +" self._x = value\n" +"\n" +" def delx(self):\n" +" del self._x\n" +"\n" +" x = property(getx, setx, delx, \"I'm the 'x' property.\")" +msgstr "" + #: ../../library/functions.rst:1576 msgid "" "If *c* is an instance of *C*, ``c.x`` will invoke the getter, ``c.x = " @@ -2614,6 +2753,18 @@ msgstr "" "*fget* 的說明字串(如果它存在的話)。這樣一來,就能夠輕鬆地使用 :func:" "`property` 作為\\ :term:`裝飾器 `\\ 來建立唯讀屬性: ::" +#: ../../library/functions.rst:1583 +msgid "" +"class Parrot:\n" +" def __init__(self):\n" +" self._voltage = 100000\n" +"\n" +" @property\n" +" def voltage(self):\n" +" \"\"\"Get the current voltage.\"\"\"\n" +" return self._voltage" +msgstr "" + #: ../../library/functions.rst:1592 msgid "" "The ``@property`` decorator turns the :meth:`!voltage` method into a " @@ -2629,6 +2780,26 @@ msgid "" "with an example:" msgstr "" +#: ../../library/functions.rst:1605 +msgid "" +"class C:\n" +" def __init__(self):\n" +" self._x = None\n" +"\n" +" @property\n" +" def x(self):\n" +" \"\"\"I'm the 'x' property.\"\"\"\n" +" return self._x\n" +"\n" +" @x.setter\n" +" def x(self, value):\n" +" self._x = value\n" +"\n" +" @x.deleter\n" +" def x(self):\n" +" del self._x" +msgstr "" + #: ../../library/functions.rst:1624 msgid "" "This code is exactly equivalent to the first example. Be sure to give the " @@ -2669,6 +2840,17 @@ msgstr "" msgid "This class has a custom representation that can be evaluated::" msgstr "" +#: ../../library/functions.rst:1659 +msgid "" +"class Person:\n" +" def __init__(self, name, age):\n" +" self.name = name\n" +" self.age = age\n" +"\n" +" def __repr__(self):\n" +" return f\"Person('{self.name}', {self.age})\"" +msgstr "" + #: ../../library/functions.rst:1670 msgid "" "Return a reverse :term:`iterator`. *seq* must be an object which has a :" @@ -2840,6 +3022,13 @@ msgid "" "static method, use this idiom::" msgstr "" +#: ../../library/functions.rst:1803 +msgid "" +"class C:\n" +" @staticmethod\n" +" def f(arg1, arg2, argN): ..." +msgstr "" + #: ../../library/functions.rst:1807 msgid "" "The ``@staticmethod`` form is a function :term:`decorator` -- see :ref:" @@ -2872,6 +3061,15 @@ msgid "" "cases, use this idiom::" msgstr "" +#: ../../library/functions.rst:1825 +msgid "" +"def regular_function():\n" +" ...\n" +"\n" +"class C:\n" +" method = staticmethod(regular_function)" +msgstr "" + #: ../../library/functions.rst:1831 msgid "For more information on static methods, see :ref:`types`." msgstr "關於 static method 的更多資訊,請參考 :ref:`types`。" @@ -2942,10 +3140,10 @@ msgstr "" #: ../../library/functions.rst:1888 msgid "" -"The :attr:`~class.__mro__` attribute of the *object_or_type* lists the " -"method resolution search order used by both :func:`getattr` and :func:" -"`super`. The attribute is dynamic and can change whenever the inheritance " -"hierarchy is updated." +"The :attr:`~class.__mro__` attribute of the class corresponding to " +"*object_or_type* lists the method resolution search order used by both :func:" +"`getattr` and :func:`super`. The attribute is dynamic and can change " +"whenever the inheritance hierarchy is updated." msgstr "" #: ../../library/functions.rst:1893 @@ -2981,6 +3179,14 @@ msgstr "" msgid "For both use cases, a typical superclass call looks like this::" msgstr "" +#: ../../library/functions.rst:1915 +msgid "" +"class C(B):\n" +" def method(self, arg):\n" +" super().method(arg) # This does the same thing as:\n" +" # super(C, self).method(arg)" +msgstr "" + #: ../../library/functions.rst:1920 msgid "" "In addition to method lookups, :func:`super` also works for attribute " @@ -3107,6 +3313,16 @@ msgstr "" msgid "Example::" msgstr "例如: ::" +#: ../../library/functions.rst:2020 +msgid "" +">>> for item in zip([1, 2, 3], ['sugar', 'spice', 'everything nice']):\n" +"... print(item)\n" +"...\n" +"(1, 'sugar')\n" +"(2, 'spice')\n" +"(3, 'everything nice')" +msgstr "" + #: ../../library/functions.rst:2027 msgid "" "More formally: :func:`zip` returns an iterator of tuples, where the *i*-th " @@ -3142,6 +3358,12 @@ msgid "" "result to the length of the shortest iterable::" msgstr "" +#: ../../library/functions.rst:2047 +msgid "" +">>> list(zip(range(3), ['fee', 'fi', 'fo', 'fum']))\n" +"[(0, 'fee'), (1, 'fi'), (2, 'fo')]" +msgstr "" + #: ../../library/functions.rst:2050 msgid "" ":func:`zip` is often used in cases where the iterables are assumed to be of " @@ -3149,6 +3371,12 @@ msgid "" "option. Its output is the same as regular :func:`zip`::" msgstr "" +#: ../../library/functions.rst:2054 +msgid "" +">>> list(zip(('a', 'b', 'c'), (1, 2, 3), strict=True))\n" +"[('a', 1), ('b', 2), ('c', 3)]" +msgstr "" + #: ../../library/functions.rst:2057 msgid "" "Unlike the default behavior, it raises a :exc:`ValueError` if one iterable " @@ -3194,6 +3422,17 @@ msgid "" "list::" msgstr "" +#: ../../library/functions.rst:2097 +msgid "" +">>> x = [1, 2, 3]\n" +">>> y = [4, 5, 6]\n" +">>> list(zip(x, y))\n" +"[(1, 4), (2, 5), (3, 6)]\n" +">>> x2, y2 = zip(*zip(x, y))\n" +">>> x == list(x2) and y == list(y2)\n" +"True" +msgstr "" + #: ../../library/functions.rst:2105 msgid "Added the ``strict`` argument." msgstr "增加了 ``strict`` 引數。" @@ -3249,10 +3488,18 @@ msgid "" "the following code::" msgstr "" +#: ../../library/functions.rst:2150 +msgid "spam = __import__('spam', globals(), locals(), [], 0)" +msgstr "" + #: ../../library/functions.rst:2152 msgid "The statement ``import spam.ham`` results in this call::" msgstr "" +#: ../../library/functions.rst:2154 +msgid "spam = __import__('spam.ham', globals(), locals(), [], 0)" +msgstr "" + #: ../../library/functions.rst:2156 msgid "" "Note how :func:`__import__` returns the toplevel module here because this is " @@ -3265,6 +3512,13 @@ msgid "" "saus`` results in ::" msgstr "" +#: ../../library/functions.rst:2162 +msgid "" +"_temp = __import__('spam.ham', globals(), locals(), ['eggs', 'sausage'], 0)\n" +"eggs = _temp.eggs\n" +"saus = _temp.sausage" +msgstr "" + #: ../../library/functions.rst:2166 msgid "" "Here, the ``spam.ham`` module is returned from :func:`__import__`. From " diff --git a/library/functools.po b/library/functools.po index c8c329e113..edc8e5f3f0 100644 --- a/library/functools.po +++ b/library/functools.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-05-14 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2024-05-11 16:02+0800\n" "Last-Translator: Matt Wang \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -65,6 +65,22 @@ msgstr "" msgid "For example::" msgstr "舉例來說: ::" +#: ../../library/functools.rst:41 +msgid "" +"@cache\n" +"def factorial(n):\n" +" return n * factorial(n-1) if n else 1\n" +"\n" +">>> factorial(10) # no previously cached result, makes 11 recursive " +"calls\n" +"3628800\n" +">>> factorial(5) # just looks up cached value result\n" +"120\n" +">>> factorial(12) # makes two new recursive calls, the other 10 are " +"cached\n" +"479001600" +msgstr "" + #: ../../library/functools.rst:52 ../../library/functools.rst:158 msgid "" "The cache is threadsafe so that the wrapped function can be used in multiple " @@ -99,6 +115,18 @@ msgstr "" msgid "Example::" msgstr "範例: ::" +#: ../../library/functools.rst:72 +msgid "" +"class DataSet:\n" +"\n" +" def __init__(self, sequence_of_numbers):\n" +" self._data = tuple(sequence_of_numbers)\n" +"\n" +" @cached_property\n" +" def stdev(self):\n" +" return statistics.stdev(self._data)" +msgstr "" + #: ../../library/functools.rst:81 msgid "" "The mechanics of :func:`cached_property` are somewhat different from :func:" @@ -218,6 +246,11 @@ msgstr "" "或正數(大於)的可呼叫物件。鍵函式是接受一個引數並回傳另一個用作排序鍵之值的" "可呼叫物件。" +#: ../../library/functools.rst:144 +msgid "" +"sorted(iterable, key=cmp_to_key(locale.strcoll)) # locale-aware sort order" +msgstr "" + #: ../../library/functools.rst:146 msgid "" "For sorting examples and a brief sorting tutorial, see :ref:`sortinghowto`." @@ -259,6 +292,13 @@ msgstr "" "如果指定了 *user_function*,則它必須是個可呼叫物件。這使得 *lru_cache* 裝飾器" "能夠直接應用於使用者函式,將 *maxsize* 保留為其預設值 128: ::" +#: ../../library/functools.rst:178 +msgid "" +"@lru_cache\n" +"def count_vowels(sentence):\n" +" return sum(sentence.count(vowel) for vowel in 'AEIOUaeiou')" +msgstr "" + #: ../../library/functools.rst:182 msgid "" "If *maxsize* is set to ``None``, the LRU feature is disabled and the cache " @@ -373,6 +413,26 @@ msgstr "" msgid "Example of an LRU cache for static web content::" msgstr "靜態網頁內容的 LRU 快取範例: ::" +#: ../../library/functools.rst:235 +msgid "" +"@lru_cache(maxsize=32)\n" +"def get_pep(num):\n" +" 'Retrieve text of a Python Enhancement Proposal'\n" +" resource = f'https://peps.python.org/pep-{num:04d}'\n" +" try:\n" +" with urllib.request.urlopen(resource) as s:\n" +" return s.read()\n" +" except urllib.error.HTTPError:\n" +" return 'Not Found'\n" +"\n" +">>> for n in 8, 290, 308, 320, 8, 218, 320, 279, 289, 320, 9991:\n" +"... pep = get_pep(n)\n" +"... print(n, len(pep))\n" +"\n" +">>> get_pep.cache_info()\n" +"CacheInfo(hits=3, misses=8, maxsize=32, currsize=8)" +msgstr "" + #: ../../library/functools.rst:252 msgid "" "Example of efficiently computing `Fibonacci numbers `_ 技法以有效率地計算\\ `費波那契數 (Fibonacci " "numbers) `_ 的範例: ::" +#: ../../library/functools.rst:258 +msgid "" +"@lru_cache(maxsize=None)\n" +"def fib(n):\n" +" if n < 2:\n" +" return n\n" +" return fib(n-1) + fib(n-2)\n" +"\n" +">>> [fib(n) for n in range(16)]\n" +"[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610]\n" +"\n" +">>> fib.cache_info()\n" +"CacheInfo(hits=28, misses=16, maxsize=None, currsize=16)" +msgstr "" + #: ../../library/functools.rst:272 msgid "Added the *typed* option." msgstr "新增 *typed* 選項。" @@ -413,6 +488,25 @@ msgstr "" "類別必須定義 :meth:`__lt__`、:meth:`__le__`、:meth:`__gt__` 或 :meth:" "`__ge__` 其中之一。此外,該類別應該提供 :meth:`__eq__` 方法。" +#: ../../library/functools.rst:293 +msgid "" +"@total_ordering\n" +"class Student:\n" +" def _is_valid_operand(self, other):\n" +" return (hasattr(other, \"lastname\") and\n" +" hasattr(other, \"firstname\"))\n" +" def __eq__(self, other):\n" +" if not self._is_valid_operand(other):\n" +" return NotImplemented\n" +" return ((self.lastname.lower(), self.firstname.lower()) ==\n" +" (other.lastname.lower(), other.firstname.lower()))\n" +" def __lt__(self, other):\n" +" if not self._is_valid_operand(other):\n" +" return NotImplemented\n" +" return ((self.lastname.lower(), self.firstname.lower()) <\n" +" (other.lastname.lower(), other.firstname.lower()))" +msgstr "" + #: ../../library/functools.rst:311 msgid "" "While this decorator makes it easy to create well behaved totally ordered " @@ -456,6 +550,18 @@ msgstr "" "引數,它們將被附加到 *args*。如果提供了額外的關鍵字引數,它們會擴充並覆寫 " "*keywords*。大致相當於: ::" +#: ../../library/functools.rst:340 +msgid "" +"def partial(func, /, *args, **keywords):\n" +" def newfunc(*fargs, **fkeywords):\n" +" newkeywords = {**keywords, **fkeywords}\n" +" return func(*args, *fargs, **newkeywords)\n" +" newfunc.func = func\n" +" newfunc.args = args\n" +" newfunc.keywords = keywords\n" +" return newfunc" +msgstr "" + #: ../../library/functools.rst:349 msgid "" "The :func:`partial` is used for partial function application which " @@ -511,6 +617,27 @@ msgstr "" "*self* 引數將作為第一個位置引數插入,甚至會在提供給 :class:`partialmethod` 建" "構函式的 *args* 和 *keywords* 的前面。" +#: ../../library/functools.rst:385 +msgid "" +">>> class Cell:\n" +"... def __init__(self):\n" +"... self._alive = False\n" +"... @property\n" +"... def alive(self):\n" +"... return self._alive\n" +"... def set_state(self, state):\n" +"... self._alive = bool(state)\n" +"... set_alive = partialmethod(set_state, True)\n" +"... set_dead = partialmethod(set_state, False)\n" +"...\n" +">>> c = Cell()\n" +">>> c.alive\n" +"False\n" +">>> c.set_alive()\n" +">>> c.alive\n" +"True" +msgstr "" + #: ../../library/functools.rst:408 msgid "" "Apply *function* of two arguments cumulatively to the items of *iterable*, " @@ -534,6 +661,19 @@ msgstr "" msgid "Roughly equivalent to::" msgstr "大致相當於: ::" +#: ../../library/functools.rst:419 +msgid "" +"def reduce(function, iterable, initializer=None):\n" +" it = iter(iterable)\n" +" if initializer is None:\n" +" value = next(it)\n" +" else:\n" +" value = initializer\n" +" for element in it:\n" +" value = function(value, element)\n" +" return value" +msgstr "" + #: ../../library/functools.rst:429 msgid "" "See :func:`itertools.accumulate` for an iterator that yields all " @@ -560,6 +700,16 @@ msgstr "" "``@singledispatch`` 定義函式時,分派調度 (dispatch) 是發生在第一個引數的型別" "上: ::" +#: ../../library/functools.rst:441 +msgid "" +">>> from functools import singledispatch\n" +">>> @singledispatch\n" +"... def fun(arg, verbose=False):\n" +"... if verbose:\n" +"... print(\"Let me just say,\", end=\" \")\n" +"... print(arg)" +msgstr "" + #: ../../library/functools.rst:448 msgid "" "To add overloaded implementations to the function, use the :func:`register` " @@ -570,10 +720,44 @@ msgstr "" "若要為函式新增過載實作,請使用泛型函式的 :func:`register` 屬性,該屬性可用作" "裝飾器。對於以型別來註釋的函式,裝飾器將自動推斷第一個引數的型別: ::" +#: ../../library/functools.rst:453 +msgid "" +">>> @fun.register\n" +"... def _(arg: int, verbose=False):\n" +"... if verbose:\n" +"... print(\"Strength in numbers, eh?\", end=\" \")\n" +"... print(arg)\n" +"...\n" +">>> @fun.register\n" +"... def _(arg: list, verbose=False):\n" +"... if verbose:\n" +"... print(\"Enumerate this:\")\n" +"... for i, elem in enumerate(arg):\n" +"... print(i, elem)" +msgstr "" + #: ../../library/functools.rst:466 msgid ":data:`types.UnionType` and :data:`typing.Union` can also be used::" msgstr "也可以使用 :data:`types.UnionType` 和 :data:`typing.Union`: ::" +#: ../../library/functools.rst:468 +msgid "" +">>> @fun.register\n" +"... def _(arg: int | float, verbose=False):\n" +"... if verbose:\n" +"... print(\"Strength in numbers, eh?\", end=\" \")\n" +"... print(arg)\n" +"...\n" +">>> from typing import Union\n" +">>> @fun.register\n" +"... def _(arg: Union[list, set], verbose=False):\n" +"... if verbose:\n" +"... print(\"Enumerate this:\")\n" +"... for i, elem in enumerate(arg):\n" +"... print(i, elem)\n" +"..." +msgstr "" + #: ../../library/functools.rst:483 msgid "" "For code which doesn't use type annotations, the appropriate type argument " @@ -581,6 +765,16 @@ msgid "" msgstr "" "對於不使用型別註釋的程式碼,可以將適當的型別引數明確傳遞給裝飾器本身: ::" +#: ../../library/functools.rst:486 +msgid "" +">>> @fun.register(complex)\n" +"... def _(arg, verbose=False):\n" +"... if verbose:\n" +"... print(\"Better than complicated.\", end=\" \")\n" +"... print(arg.real, arg.imag)\n" +"..." +msgstr "" + #: ../../library/functools.rst:494 msgid "" "To enable registering :term:`lambdas` and pre-existing functions, " @@ -589,6 +783,14 @@ msgstr "" "若要啟用註冊 :term:`lambdas` 和預先存在的函式,:func:`register` 屬性" "也能以函式形式使用: ::" +#: ../../library/functools.rst:497 +msgid "" +">>> def nothing(arg, verbose=False):\n" +"... print(\"Nothing.\")\n" +"...\n" +">>> fun.register(type(None), nothing)" +msgstr "" + #: ../../library/functools.rst:502 msgid "" "The :func:`register` attribute returns the undecorated function. This " @@ -598,12 +800,45 @@ msgstr "" ":func:`register` 屬性回傳未加裝飾器的函式。這讓使得裝飾器堆疊 (decorator " "stacking)、:mod:`pickling` 以及為每個變體獨立建立單元測試成為可能:" +#: ../../library/functools.rst:506 +msgid "" +">>> @fun.register(float)\n" +"... @fun.register(Decimal)\n" +"... def fun_num(arg, verbose=False):\n" +"... if verbose:\n" +"... print(\"Half of your number:\", end=\" \")\n" +"... print(arg / 2)\n" +"...\n" +">>> fun_num is fun\n" +"False" +msgstr "" + #: ../../library/functools.rst:516 msgid "" "When called, the generic function dispatches on the type of the first " "argument::" msgstr "呼叫時,泛型函式會分派第一個引數的型別: ::" +#: ../../library/functools.rst:519 +msgid "" +">>> fun(\"Hello, world.\")\n" +"Hello, world.\n" +">>> fun(\"test.\", verbose=True)\n" +"Let me just say, test.\n" +">>> fun(42, verbose=True)\n" +"Strength in numbers, eh? 42\n" +">>> fun(['spam', 'spam', 'eggs', 'spam'], verbose=True)\n" +"Enumerate this:\n" +"0 spam\n" +"1 spam\n" +"2 eggs\n" +"3 spam\n" +">>> fun(None)\n" +"Nothing.\n" +">>> fun(1.23)\n" +"0.615" +msgstr "" + #: ../../library/functools.rst:536 msgid "" "Where there is no registered implementation for a specific type, its method " @@ -625,6 +860,20 @@ msgstr "" "如果一個實作有被註冊到一個\\ :term:`抽象基底類別 `,則基" "底類別的虛擬子類別將被分派到該實作: ::" +#: ../../library/functools.rst:546 +msgid "" +">>> from collections.abc import Mapping\n" +">>> @fun.register\n" +"... def _(arg: Mapping, verbose=False):\n" +"... if verbose:\n" +"... print(\"Keys & Values\")\n" +"... for key, value in arg.items():\n" +"... print(key, \"=>\", value)\n" +"...\n" +">>> fun({\"a\": \"b\"})\n" +"a => b" +msgstr "" + #: ../../library/functools.rst:557 msgid "" "To check which implementation the generic function will choose for a given " @@ -632,12 +881,32 @@ msgid "" msgstr "" "若要檢查泛型函式將為給定型別選擇哪種實作,請使用 ``dispatch()`` 屬性: ::" +#: ../../library/functools.rst:560 +msgid "" +">>> fun.dispatch(float)\n" +"\n" +">>> fun.dispatch(dict) # note: default implementation\n" +"" +msgstr "" + #: ../../library/functools.rst:565 msgid "" "To access all registered implementations, use the read-only ``registry`` " "attribute::" msgstr "若要存取所有已註冊的實作,請使用唯讀 ``registry`` 屬性: ::" +#: ../../library/functools.rst:568 +msgid "" +">>> fun.registry.keys()\n" +"dict_keys([, , ,\n" +" , ,\n" +" ])\n" +">>> fun.registry[float]\n" +"\n" +">>> fun.registry[object]\n" +"" +msgstr "" + #: ../../library/functools.rst:579 msgid "The :func:`register` attribute now supports using type annotations." msgstr ":func:`register` 屬性現在支援使用型別註釋。" @@ -669,6 +938,22 @@ msgstr "" "用 ``@singledispatchmethod`` 定義函式時,分派調度是發生在第一個非 *self* 或" "非 *cls* 引數的型別上: ::" +#: ../../library/functools.rst:597 +msgid "" +"class Negator:\n" +" @singledispatchmethod\n" +" def neg(self, arg):\n" +" raise NotImplementedError(\"Cannot negate a\")\n" +"\n" +" @neg.register\n" +" def _(self, arg: int):\n" +" return -arg\n" +"\n" +" @neg.register\n" +" def _(self, arg: bool):\n" +" return not arg" +msgstr "" + #: ../../library/functools.rst:610 msgid "" "``@singledispatchmethod`` supports nesting with other decorators such as :" @@ -682,6 +967,25 @@ msgstr "" "``singledispatchmethod`` 必須是\\ *最外面的*\\ 裝飾器。以下範例是 " "``Negator`` 類別,其 ``neg`` 方法繫結到該類別,而不是該類別的實例: ::" +#: ../../library/functools.rst:616 +msgid "" +"class Negator:\n" +" @singledispatchmethod\n" +" @classmethod\n" +" def neg(cls, arg):\n" +" raise NotImplementedError(\"Cannot negate a\")\n" +"\n" +" @neg.register\n" +" @classmethod\n" +" def _(cls, arg: int):\n" +" return -arg\n" +"\n" +" @neg.register\n" +" @classmethod\n" +" def _(cls, arg: bool):\n" +" return not arg" +msgstr "" + #: ../../library/functools.rst:632 msgid "" "The same pattern can be used for other similar decorators: :func:" @@ -780,6 +1084,30 @@ msgstr "" "式裝飾器。它相當於 ``partial(update_wrapper, wrapped=wrapped, " "assigned=assigned, updated=updated)``。例如: ::" +#: ../../library/functools.rst:690 +msgid "" +">>> from functools import wraps\n" +">>> def my_decorator(f):\n" +"... @wraps(f)\n" +"... def wrapper(*args, **kwds):\n" +"... print('Calling decorated function')\n" +"... return f(*args, **kwds)\n" +"... return wrapper\n" +"...\n" +">>> @my_decorator\n" +"... def example():\n" +"... \"\"\"Docstring\"\"\"\n" +"... print('Called example function')\n" +"...\n" +">>> example()\n" +"Calling decorated function\n" +"Called example function\n" +">>> example.__name__\n" +"'example'\n" +">>> example.__doc__\n" +"'Docstring'" +msgstr "" + #: ../../library/functools.rst:711 msgid "" "Without the use of this decorator factory, the name of the example function " diff --git a/library/gettext.po b/library/gettext.po index 3f3673198f..37cf62718c 100644 --- a/library/gettext.po +++ b/library/gettext.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-05-09 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2018-05-23 16:02+0000\n" "Last-Translator: Adrian Liaw \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -132,6 +132,16 @@ msgstr "" msgid "Here's an example of typical usage for this API::" msgstr "" +#: ../../library/gettext.rst:106 +msgid "" +"import gettext\n" +"gettext.bindtextdomain('myapplication', '/path/to/my/language/directory')\n" +"gettext.textdomain('myapplication')\n" +"_ = gettext.gettext\n" +"# ...\n" +"print(_('This is a translatable string.'))" +msgstr "" + #: ../../library/gettext.rst:115 msgid "Class-based API" msgstr "" @@ -237,6 +247,10 @@ msgid "" "function, like this::" msgstr "" +#: ../../library/gettext.rst:187 +msgid "print(_('This string will be translated.'))" +msgstr "" + #: ../../library/gettext.rst:189 msgid "" "For convenience, you want the :func:`!_` function to be installed in " @@ -343,6 +357,13 @@ msgid "" "this code to make :func:`!_` available to their module::" msgstr "" +#: ../../library/gettext.rst:285 +msgid "" +"import gettext\n" +"t = gettext.translation('mymodule', ...)\n" +"_ = t.gettext" +msgstr "" + #: ../../library/gettext.rst:289 msgid "" "This puts :func:`!_` only in the module's global namespace and so only " @@ -430,6 +451,16 @@ msgstr "" msgid "Here is an example::" msgstr "以下是個範例: ::" +#: ../../library/gettext.rst:350 +msgid "" +"n = len(os.listdir('.'))\n" +"cat = GNUTranslations(somefile)\n" +"message = cat.ngettext(\n" +" 'There is %(num)d file in this directory',\n" +" 'There are %(num)d files in this directory',\n" +" n) % {'num': n}" +msgstr "" + #: ../../library/gettext.rst:360 msgid "" "Look up the *context* and *message* id in the catalog and return the " @@ -475,6 +506,14 @@ msgid "" "this version has a slightly different API. Its documented usage was::" msgstr "" +#: ../../library/gettext.rst:399 +msgid "" +"import gettext\n" +"cat = gettext.Catalog(domain, localedir)\n" +"_ = cat.gettext\n" +"print(_('hello world'))" +msgstr "" + #: ../../library/gettext.rst:404 msgid "" "For compatibility with this older module, the function :func:`!Catalog` is " @@ -528,6 +567,14 @@ msgid "" "`. For example::" msgstr "" +#: ../../library/gettext.rst:434 +msgid "" +"filename = 'mylog.txt'\n" +"message = _('writing a log message')\n" +"with open(filename, 'w') as fp:\n" +" fp.write(message)" +msgstr "" + #: ../../library/gettext.rst:439 msgid "" "In this example, the string ``'writing a log message'`` is marked as a " @@ -606,6 +653,13 @@ msgid "" "your module::" msgstr "" +#: ../../library/gettext.rst:496 +msgid "" +"import gettext\n" +"t = gettext.translation('spam', '/usr/share/locale')\n" +"_ = t.gettext" +msgstr "" + #: ../../library/gettext.rst:502 msgid "Localizing your application" msgstr "" @@ -624,12 +678,24 @@ msgid "" "main driver file of your application::" msgstr "" +#: ../../library/gettext.rst:512 +msgid "" +"import gettext\n" +"gettext.install('myapplication')" +msgstr "" + #: ../../library/gettext.rst:515 msgid "" "If you need to set the locale directory, you can pass it into the :func:" "`install` function::" msgstr "" +#: ../../library/gettext.rst:518 +msgid "" +"import gettext\n" +"gettext.install('myapplication', '/usr/share/locale')" +msgstr "" + #: ../../library/gettext.rst:523 msgid "Changing languages on the fly" msgstr "" @@ -641,6 +707,24 @@ msgid "" "explicitly, like so::" msgstr "" +#: ../../library/gettext.rst:529 +msgid "" +"import gettext\n" +"\n" +"lang1 = gettext.translation('myapplication', languages=['en'])\n" +"lang2 = gettext.translation('myapplication', languages=['fr'])\n" +"lang3 = gettext.translation('myapplication', languages=['de'])\n" +"\n" +"# start by using language1\n" +"lang1.install()\n" +"\n" +"# ... time goes by, user selects language 2\n" +"lang2.install()\n" +"\n" +"# ... more time goes by, user selects language 3\n" +"lang3.install()" +msgstr "" + #: ../../library/gettext.rst:546 msgid "Deferred translations" msgstr "" @@ -652,6 +736,18 @@ msgid "" "actual translation until later. A classic example is::" msgstr "" +#: ../../library/gettext.rst:552 +msgid "" +"animals = ['mollusk',\n" +" 'albatross',\n" +" 'rat',\n" +" 'penguin',\n" +" 'python', ]\n" +"# ...\n" +"for a in animals:\n" +" print(a)" +msgstr "" + #: ../../library/gettext.rst:561 msgid "" "Here, you want to mark the strings in the ``animals`` list as being " @@ -663,6 +759,23 @@ msgstr "" msgid "Here is one way you can handle this situation::" msgstr "" +#: ../../library/gettext.rst:567 +msgid "" +"def _(message): return message\n" +"\n" +"animals = [_('mollusk'),\n" +" _('albatross'),\n" +" _('rat'),\n" +" _('penguin'),\n" +" _('python'), ]\n" +"\n" +"del _\n" +"\n" +"# ...\n" +"for a in animals:\n" +" print(_(a))" +msgstr "" + #: ../../library/gettext.rst:581 msgid "" "This works because the dummy definition of :func:`!_` simply returns the " @@ -683,6 +796,21 @@ msgstr "" msgid "Another way to handle this is with the following example::" msgstr "" +#: ../../library/gettext.rst:593 +msgid "" +"def N_(message): return message\n" +"\n" +"animals = [N_('mollusk'),\n" +" N_('albatross'),\n" +" N_('rat'),\n" +" N_('penguin'),\n" +" N_('python'), ]\n" +"\n" +"# ...\n" +"for a in animals:\n" +" print(_(a))" +msgstr "" + #: ../../library/gettext.rst:605 msgid "" "In this case, you are marking translatable strings with the function :func:`!" diff --git a/library/glob.po b/library/glob.po index ad7eaed562..81018eaa85 100644 --- a/library/glob.po +++ b/library/glob.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-08-04 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2023-01-24 01:21+0800\n" "Last-Translator: Matt Wang \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -190,6 +190,21 @@ msgstr "" "gif`,和一個僅包含 :file:`3.txt` 檔案的子目錄 :file:`sub`,:func:`glob` 將產" "生以下結果。請注意路徑的任何前導部分是如何保留的。 ::" +#: ../../library/glob.rst:134 +msgid "" +">>> import glob\n" +">>> glob.glob('./[0-9].*')\n" +"['./1.gif', './2.txt']\n" +">>> glob.glob('*.gif')\n" +"['1.gif', 'card.gif']\n" +">>> glob.glob('?.gif')\n" +"['1.gif']\n" +">>> glob.glob('**/*.txt', recursive=True)\n" +"['2.txt', 'sub/3.txt']\n" +">>> glob.glob('./**/', recursive=True)\n" +"['./', './sub/']" +msgstr "" + #: ../../library/glob.rst:146 msgid "" "If the directory contains files starting with ``.`` they won't be matched by " @@ -199,6 +214,15 @@ msgstr "" "如果目錄包含以 ``.`` 開頭的檔案,則預設情況下不會去匹配到它們。例如,一個包" "含 :file:`card.gif` 和 :file:`.card.gif` 的目錄: ::" +#: ../../library/glob.rst:150 +msgid "" +">>> import glob\n" +">>> glob.glob('*.gif')\n" +"['card.gif']\n" +">>> glob.glob('.c*')\n" +"['.card.gif']" +msgstr "" + #: ../../library/glob.rst:158 msgid "Module :mod:`fnmatch`" msgstr ":mod:`fnmatch` 模組" diff --git a/library/gzip.po b/library/gzip.po index 3a665efc02..96e12dadd5 100644 --- a/library/gzip.po +++ b/library/gzip.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-06-18 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2018-05-23 16:03+0000\n" "Last-Translator: Adrian Liaw \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -313,18 +313,49 @@ msgstr "用法範例" msgid "Example of how to read a compressed file::" msgstr "如何讀取壓縮檔案的範例: ::" +#: ../../library/gzip.rst:221 +msgid "" +"import gzip\n" +"with gzip.open('/home/joe/file.txt.gz', 'rb') as f:\n" +" file_content = f.read()" +msgstr "" + #: ../../library/gzip.rst:225 msgid "Example of how to create a compressed GZIP file::" msgstr "如何建立一個壓縮的 GZIP 檔案的範例: ::" +#: ../../library/gzip.rst:227 +msgid "" +"import gzip\n" +"content = b\"Lots of content here\"\n" +"with gzip.open('/home/joe/file.txt.gz', 'wb') as f:\n" +" f.write(content)" +msgstr "" + #: ../../library/gzip.rst:232 msgid "Example of how to GZIP compress an existing file::" msgstr "如何壓縮一個已存在的檔案的範例: ::" +#: ../../library/gzip.rst:234 +msgid "" +"import gzip\n" +"import shutil\n" +"with open('/home/joe/file.txt', 'rb') as f_in:\n" +" with gzip.open('/home/joe/file.txt.gz', 'wb') as f_out:\n" +" shutil.copyfileobj(f_in, f_out)" +msgstr "" + #: ../../library/gzip.rst:240 msgid "Example of how to GZIP compress a binary string::" msgstr "如何壓縮一個二進位字串的範例: ::" +#: ../../library/gzip.rst:242 +msgid "" +"import gzip\n" +"s_in = b\"Lots of content here\"\n" +"s_out = gzip.compress(s_in)" +msgstr "" + #: ../../library/gzip.rst:248 msgid "Module :mod:`zlib`" msgstr ":mod:`zlib` 模組" diff --git a/library/hashlib.po b/library/hashlib.po index 7efc9db476..e5f1b6ad59 100644 --- a/library/hashlib.po +++ b/library/hashlib.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-08-31 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2024-05-11 16:03+0800\n" "Last-Translator: Matt Wang \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -169,6 +169,20 @@ msgid "" msgstr "" "獲取位元組字串 ``b\"Nobody inspects the spammish repetition\"`` 的摘要: ::" +#: ../../library/hashlib.rst:105 +msgid "" +">>> import hashlib\n" +">>> m = hashlib.sha256()\n" +">>> m.update(b\"Nobody inspects\")\n" +">>> m.update(b\" the spammish repetition\")\n" +">>> m.digest()\n" +"b'\\x03\\x1e\\xdd}Ae\\x15\\x93\\xc5\\xfe\\\\" +"\\x00o\\xa5u+7\\xfd\\xdf\\xf7\\xbcN\\x84:" +"\\xa6\\xaf\\x0c\\x95\\x0fK\\x94\\x06'\n" +">>> m.hexdigest()\n" +"'031edd7d41651593c5fe5c006fa5752b37fddff7bc4e843aa6af0c950f4b9406'" +msgstr "" + #: ../../library/hashlib.rst:114 msgid "More condensed:" msgstr "更濃縮:" @@ -809,6 +823,15 @@ msgstr "" "此範例示範了如何使用密鑰 ``b'pseudorandom key'`` 獲取訊息 ``b'message " "data'`` 的(十六進位編碼)128 位元驗證碼: ::" +#: ../../library/hashlib.rst:583 +msgid "" +">>> from hashlib import blake2b\n" +">>> h = blake2b(key=b'pseudorandom key', digest_size=16)\n" +">>> h.update(b'message data')\n" +">>> h.hexdigest()\n" +"'3d363ff7401e02026f4a4687d4863ced'" +msgstr "" + #: ../../library/hashlib.rst:590 msgid "" "As a practical example, a web application can symmetrically sign cookies " @@ -817,6 +840,35 @@ msgstr "" "舉一個實際的例子,網頁應用程式可以對發送給使用者的 cookie 進行對稱簽名 " "(symmetrically sign),然後驗證它們以確保它們沒有被篡改: ::" +#: ../../library/hashlib.rst:593 +msgid "" +">>> from hashlib import blake2b\n" +">>> from hmac import compare_digest\n" +">>>\n" +">>> SECRET_KEY = b'pseudorandomly generated server secret key'\n" +">>> AUTH_SIZE = 16\n" +">>>\n" +">>> def sign(cookie):\n" +"... h = blake2b(digest_size=AUTH_SIZE, key=SECRET_KEY)\n" +"... h.update(cookie)\n" +"... return h.hexdigest().encode('utf-8')\n" +">>>\n" +">>> def verify(cookie, sig):\n" +"... good_sig = sign(cookie)\n" +"... return compare_digest(good_sig, sig)\n" +">>>\n" +">>> cookie = b'user-alice'\n" +">>> sig = sign(cookie)\n" +">>> print(\"{0},{1}\".format(cookie.decode('utf-8'), sig))\n" +"user-alice,b'43b3c982cf697e0c5ab22172d1ca7421'\n" +">>> verify(cookie, sig)\n" +"True\n" +">>> verify(b'user-bob', sig)\n" +"False\n" +">>> verify(cookie, b'0102030405060708090a0b0c0d0e0f00')\n" +"False" +msgstr "" + #: ../../library/hashlib.rst:619 msgid "" "Even though there's a native keyed hashing mode, BLAKE2 can, of course, be " @@ -825,6 +877,15 @@ msgstr "" "儘管有原生密鑰雜湊模式,BLAKE2 還是可以透過 :mod:`hmac` 模組用於建構 " "HMAC: ::" +#: ../../library/hashlib.rst:622 +msgid "" +">>> import hmac, hashlib\n" +">>> m = hmac.new(b'secret key', digestmod=hashlib.blake2s)\n" +">>> m.update(b'message')\n" +">>> m.hexdigest()\n" +"'e3c8102868d28b5ff85fc35dda07329970d1a01e273c37481326fe0c861c8142'" +msgstr "" + #: ../../library/hashlib.rst:630 msgid "Randomized hashing" msgstr "隨機雜湊 (Randomized hashing)" @@ -936,6 +997,21 @@ msgstr "" msgid "BLAKE2 can be personalized by passing bytes to the *person* argument::" msgstr "BLAKE2 可以透過將位元組傳遞給 *person* 引數來做個人化: ::" +#: ../../library/hashlib.rst:705 +msgid "" +">>> from hashlib import blake2b\n" +">>> FILES_HASH_PERSON = b'MyApp Files Hash'\n" +">>> BLOCK_HASH_PERSON = b'MyApp Block Hash'\n" +">>> h = blake2b(digest_size=32, person=FILES_HASH_PERSON)\n" +">>> h.update(b'the same content')\n" +">>> h.hexdigest()\n" +"'20d9cd024d4fb086aae819a1432dd2466de12947831b75c5a30cf2676095d3b4'\n" +">>> h = blake2b(digest_size=32, person=BLOCK_HASH_PERSON)\n" +">>> h.update(b'the same content')\n" +">>> h.hexdigest()\n" +"'cf68fb5761b9c44e7878bfb2c4c9aea52264a80b75005e65619778de59f383a3'" +msgstr "" + #: ../../library/hashlib.rst:717 msgid "" "Personalization together with the keyed mode can also be used to derive " @@ -950,12 +1026,48 @@ msgstr "樹狀模式" msgid "Here's an example of hashing a minimal tree with two leaf nodes::" msgstr "下面是對具有兩個葉節點的最小樹進行雜湊處理的範例: ::" +#: ../../library/hashlib.rst:735 +msgid "" +" 10\n" +" / \\\n" +"00 01" +msgstr "" + #: ../../library/hashlib.rst:739 msgid "" "This example uses 64-byte internal digests, and returns the 32-byte final " "digest::" msgstr "此範例使用 64-byte 內部摘要,並回傳 32-byte 最終摘要: ::" +#: ../../library/hashlib.rst:742 +msgid "" +">>> from hashlib import blake2b\n" +">>>\n" +">>> FANOUT = 2\n" +">>> DEPTH = 2\n" +">>> LEAF_SIZE = 4096\n" +">>> INNER_SIZE = 64\n" +">>>\n" +">>> buf = bytearray(6000)\n" +">>>\n" +">>> # Left leaf\n" +"... h00 = blake2b(buf[0:LEAF_SIZE], fanout=FANOUT, depth=DEPTH,\n" +"... leaf_size=LEAF_SIZE, inner_size=INNER_SIZE,\n" +"... node_offset=0, node_depth=0, last_node=False)\n" +">>> # Right leaf\n" +"... h01 = blake2b(buf[LEAF_SIZE:], fanout=FANOUT, depth=DEPTH,\n" +"... leaf_size=LEAF_SIZE, inner_size=INNER_SIZE,\n" +"... node_offset=1, node_depth=0, last_node=True)\n" +">>> # Root node\n" +"... h10 = blake2b(digest_size=32, fanout=FANOUT, depth=DEPTH,\n" +"... leaf_size=LEAF_SIZE, inner_size=INNER_SIZE,\n" +"... node_offset=0, node_depth=1, last_node=True)\n" +">>> h10.update(h00.digest())\n" +">>> h10.update(h01.digest())\n" +">>> h10.hexdigest()\n" +"'3ad2a9b37c6070e374c7a8c508fe20ca86b6ed54e286e93a0318e95e881db5aa'" +msgstr "" + #: ../../library/hashlib.rst:769 msgid "Credits" msgstr "製作人員" diff --git a/library/heapq.po b/library/heapq.po index 074c79d9b8..ba394997bf 100644 --- a/library/heapq.po +++ b/library/heapq.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-05-09 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2023-07-01 18:20+0800\n" "Last-Translator: Liang-Bo Wang \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -254,6 +254,18 @@ msgstr "" "`堆積排序 (heapsort) `_ 可以透過將所" "有的值推入一個 heap,並且從 heap 中一個接一個彈出最小元素來實作: ::" +#: ../../library/heapq.rst:144 +msgid "" +">>> def heapsort(iterable):\n" +"... h = []\n" +"... for value in iterable:\n" +"... heappush(h, value)\n" +"... return [heappop(h) for i in range(len(h))]\n" +"...\n" +">>> heapsort([1, 3, 5, 7, 9, 2, 4, 6, 8, 0])\n" +"[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]" +msgstr "" + #: ../../library/heapq.rst:153 msgid "" "This is similar to ``sorted(iterable)``, but unlike :func:`sorted`, this " @@ -270,6 +282,17 @@ msgstr "" "Heap 中的元素可以是 tuple 。這有利於將要比較的值(例如一個 task 的優先度)和" "主要資料放在一起排序: ::" +#: ../../library/heapq.rst:159 +msgid "" +">>> h = []\n" +">>> heappush(h, (5, 'write code'))\n" +">>> heappush(h, (7, 'release product'))\n" +">>> heappush(h, (1, 'write spec'))\n" +">>> heappush(h, (3, 'create tests'))\n" +">>> heappop(h)\n" +"(1, 'write spec')" +msgstr "" + #: ../../library/heapq.rst:169 msgid "Priority Queue Implementation Notes" msgstr "優先佇列實作細節" @@ -334,6 +357,17 @@ msgstr "" "task 無法比較的另一個解決方案是建立一個包裝器類別,該類別忽略 task 項目,只比" "較優先等級: ::" +#: ../../library/heapq.rst:195 +msgid "" +"from dataclasses import dataclass, field\n" +"from typing import Any\n" +"\n" +"@dataclass(order=True)\n" +"class PrioritizedItem:\n" +" priority: int\n" +" item: Any=field(compare=False)" +msgstr "" + #: ../../library/heapq.rst:203 msgid "" "The remaining challenges revolve around finding a pending task and making " @@ -353,6 +387,37 @@ msgstr "" "行的方案是將原本的 entry 做一個標記表示它已經被刪除,並新增一個擁有新的 " "priority 的 entry: ::" +#: ../../library/heapq.rst:211 +msgid "" +"pq = [] # list of entries arranged in a heap\n" +"entry_finder = {} # mapping of tasks to entries\n" +"REMOVED = '' # placeholder for a removed task\n" +"counter = itertools.count() # unique sequence count\n" +"\n" +"def add_task(task, priority=0):\n" +" 'Add a new task or update the priority of an existing task'\n" +" if task in entry_finder:\n" +" remove_task(task)\n" +" count = next(counter)\n" +" entry = [priority, count, task]\n" +" entry_finder[task] = entry\n" +" heappush(pq, entry)\n" +"\n" +"def remove_task(task):\n" +" 'Mark an existing task as REMOVED. Raise KeyError if not found.'\n" +" entry = entry_finder.pop(task)\n" +" entry[-1] = REMOVED\n" +"\n" +"def pop_task():\n" +" 'Remove and return the lowest priority task. Raise KeyError if empty.'\n" +" while pq:\n" +" priority, count, task = heappop(pq)\n" +" if task is not REMOVED:\n" +" del entry_finder[task]\n" +" return task\n" +" raise KeyError('pop from an empty priority queue')" +msgstr "" + #: ../../library/heapq.rst:241 msgid "Theory" msgstr "原理" @@ -376,6 +441,19 @@ msgstr "" "上述乍看之下有些奇怪的不變式,是為了實作一個對記憶體來說有效率的方法,其表示" "方式如同錦標賽一般。下列的數字為 *k*,而不是 ``a[k]``: ::" +#: ../../library/heapq.rst:251 +msgid "" +" 0\n" +"\n" +" 1 2\n" +"\n" +" 3 4 5 6\n" +"\n" +" 7 8 9 10 11 12 13 14\n" +"\n" +"15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30" +msgstr "" + #: ../../library/heapq.rst:261 msgid "" "In the tree above, each cell *k* is topping ``2*k+1`` and ``2*k+2``. In a " diff --git a/library/html.parser.po b/library/html.parser.po index c3e3b966fe..bbd28d05f5 100644 --- a/library/html.parser.po +++ b/library/html.parser.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Python 3.12\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-05-09 00:03+0000\n" +"POT-Creation-Date: 2024-09-07 00:03+0000\n" "PO-Revision-Date: 2023-05-04 22:54+0800\n" "Last-Translator: Matt Wang \n" "Language-Team: Chinese - TAIWAN (https://github.com/python/python-docs-zh-" @@ -90,10 +90,45 @@ msgstr "" "以下的基礎範例是一個簡單的 HTML 剖析器,它使用 :class:`HTMLParser` 類別,當遇" "到開始標籤、結束標籤和資料時將它們印出: ::" +#: ../../library/html.parser.rst:48 +msgid "" +"from html.parser import HTMLParser\n" +"\n" +"class MyHTMLParser(HTMLParser):\n" +" def handle_starttag(self, tag, attrs):\n" +" print(\"Encountered a start tag:\", tag)\n" +"\n" +" def handle_endtag(self, tag):\n" +" print(\"Encountered an end tag :\", tag)\n" +"\n" +" def handle_data(self, data):\n" +" print(\"Encountered some data :\", data)\n" +"\n" +"parser = MyHTMLParser()\n" +"parser.feed('Test'\n" +" '

Parse me!

')" +msgstr "" + #: ../../library/html.parser.rst:64 msgid "The output will then be:" msgstr "輸出將是:" +#: ../../library/html.parser.rst:66 +msgid "" +"Encountered a start tag: html\n" +"Encountered a start tag: head\n" +"Encountered a start tag: title\n" +"Encountered some data : Test\n" +"Encountered an end tag : title\n" +"Encountered an end tag : head\n" +"Encountered a start tag: body\n" +"Encountered a start tag: h1\n" +"Encountered some data : Parse me!\n" +"Encountered an end tag : h1\n" +"Encountered an end tag : body\n" +"Encountered an end tag : html" +msgstr "" + #: ../../library/html.parser.rst:83 msgid ":class:`.HTMLParser` Methods" msgstr ":class:`.HTMLParser` 方法" @@ -326,24 +361,107 @@ msgid "" "examples::" msgstr "以下類別實作了一個剖析器,將用於解說更多範例: ::" +#: ../../library/html.parser.rst:235 +msgid "" +"from html.parser import HTMLParser\n" +"from html.entities import name2codepoint\n" +"\n" +"class MyHTMLParser(HTMLParser):\n" +" def handle_starttag(self, tag, attrs):\n" +" print(\"Start tag:\", tag)\n" +" for attr in attrs:\n" +" print(\" attr:\", attr)\n" +"\n" +" def handle_endtag(self, tag):\n" +" print(\"End tag :\", tag)\n" +"\n" +" def handle_data(self, data):\n" +" print(\"Data :\", data)\n" +"\n" +" def handle_comment(self, data):\n" +" print(\"Comment :\", data)\n" +"\n" +" def handle_entityref(self, name):\n" +" c = chr(name2codepoint[name])\n" +" print(\"Named ent:\", c)\n" +"\n" +" def handle_charref(self, name):\n" +" if name.startswith('x'):\n" +" c = chr(int(name[1:], 16))\n" +" else:\n" +" c = chr(int(name))\n" +" print(\"Num ent :\", c)\n" +"\n" +" def handle_decl(self, data):\n" +" print(\"Decl :\", data)\n" +"\n" +"parser = MyHTMLParser()" +msgstr "" + #: ../../library/html.parser.rst:269 msgid "Parsing a doctype::" msgstr "剖析文件類型: ::" +#: ../../library/html.parser.rst:271 +msgid "" +">>> parser.feed('')\n" +"Decl : DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3." +"org/TR/html4/strict.dtd\"" +msgstr "" + #: ../../library/html.parser.rst:275 msgid "Parsing an element with a few attributes and a title::" msgstr "剖析一個具有一些屬性和標題的元素: ::" +#: ../../library/html.parser.rst:277 +msgid "" +">>> parser.feed('\"The')\n" +"Start tag: img\n" +" attr: ('src', 'python-logo.png')\n" +" attr: ('alt', 'The Python logo')\n" +">>>\n" +">>> parser.feed('

Python

')\n" +"Start tag: h1\n" +"Data : Python\n" +"End tag : h1" +msgstr "" + #: ../../library/html.parser.rst:287 msgid "" "The content of ``script`` and ``style`` elements is returned as is, without " "further parsing::" msgstr "``script`` 和 ``style`` 元素的內容按原樣回傳,無需進一步剖析: ::" +#: ../../library/html.parser.rst:290 +msgid "" +">>> parser.feed('