effective python 第2版の翻訳改善点 1〜3章

オライリー・ジャパンから発売された「Effective Python 第2版 Pythonプログラムを改良する90項目」の日本語訳の改善提案である。気になった箇所について、原文と照らし合わせて問題点を述べ、日本語訳を自分で書き直している。

注意事項

いやー、もう、この記事を書くのが怖いといえばだいぶ怖い。 お前に訳文の誤りを指摘できるほどのPython力があるか、英語力があるか、と問われたら、両方とも完璧には程遠い。記事の内容には正確を期しているが、それでも正確性は保証できない。

「Effective Python 第2版」の日本語版をAmazonで、原著(電子書籍版)をInformIT(ピアソン社の電子書籍販売サイト)で購入した。
以下でそれぞれの本の文章の一部を書いているが、著作権法で定められた引用に該当する。 これは訳文の批評のために必要不可欠な引用である。

  • 選んだ箇所は私が問題だと思った部分である。文章の意味が間違っているところ(誤訳)と、文意が分かりづらいところとが混じっている。(両者をハッキリ判別するのは難しいので、どの部分がどちらかを示すことはしていない。)
  • ページ数は日本語版のページ数を示す。原著のページ数は省略した。
  • 「日本語訳:」のあとに続く部分は「Effective Python 第2版」の日本語版からの引用である。
  • 「原文:」のあとに続く部分は「Effective Python: 90 Specific Ways to Write Better Python (2nd Edition)」原著からの引用である。
  • また、「直訳」および「意訳」は原文から私がオリジナルで訳した文である。
  • 「直訳」は英語の単語を極力そのまま日本語に置き換えたもの。
    • 常に常体である。
    • 「I / you」も訳出している。
    • 高校の授業でやる英文和訳のような結果になるので、日本語として不自然な場合もある。
  • 「意訳」はそこから構文の変更などを加えて日本語として整えたものである。
    • 常体か敬体かは元の日本語訳と同じとした。
    • 「I / you」は日本語訳と同様、訳出しないことにした。
    • 仮に私が翻訳するとしたら「意訳」の文章を最終結果にするであろう。

無償の翻訳と出版された翻訳の違い

「プログラミング関係の誤訳の指摘」というジャンルで、私がパッと思い出すのは

腐った翻訳に対する態度について - アスペ日記
善意のひどい訳について - アスペ日記
「C言語でプログラミングする際の覚書」の誤訳箇所 - アスペ日記

である。でも上記で批判の対象となっているのは、趣味の、無償の翻訳である。
今回私が論じるのは、すでに出版された本である。

アマ翻訳とプロ翻訳の違いはなにか? こっちのほうが指摘する側のハードルは高いんじゃないか。だって金をもらって翻訳している、プロの翻訳者が相手なんだから。
マチュアの野球選手とプロの野球選手、どっちが投げる球が打てそうかと言われれば、どっちも無理だがプロの方がもっと無理だと思う(上手い喩えが思い付かない)。
一方で、プロのほうが高い成果を出すことを期待されているのも確かだ。
友人に髪を切ってもらって、変になったとしても、まぁ仕方ないか、と思えるけど、 美容室に行って変な髪型にされたら、おいおい、こっちは金払ってるのにこの結果は何やねん、と文句の一つも言いたくなるだろう(こっちも上手い喩えが思い付かない)。

マチュアの翻訳かプロの翻訳かという問題とは別に、公式の翻訳か、非公式の翻訳かという面も同時にあるのではないか。 日本語版の最初には、以下のように書いてある。

本書は、株式会社オライリー・ジャパンがPearson Education, Inc. の許諾に基づき翻訳したものです。日本語版についての権利は、株式会社オライリー・ジャパン保有します。

言うまでもなく、オライリーから出ているこの本が公式な翻訳である。私がしようとしている翻訳は非公式であり趣味であり、おまけであり添え物である。

第1版の日本語版を本屋で何度か見たときも、見るたびに生硬な翻訳が目に付き、結局買うのを見送った。 第2版の原著が出版されるという話を聞いたときも(Effective Python 第2版(原著)が出るみたいだよ - 子供の落書き帳 Renaissance)、どうか別の翻訳者が訳してくれますようにと願った。しかし願いは虚しく、同じ翻訳者によって翻訳された日本語版が出版された。(普通に考えれば、第1版と同じ人が翻訳するのが合理的だろう。) 公式に本が出版された以上、この本の内容が、日本語訳のせいで分かりにくくなっている箇所があれば、その改善案を非公式に挙げて、本の価値をより高いものにするのが、私ができる最善の行動ではなかろうか。 私も全ては読めてはいないが、大変ためになる素晴らしい本である。これが翻訳のせいで価値が減じられるのは不本意である。 したがって、Effecive Pythonの出版に関わった人に喧嘩を売るつもりはなく、 Pythonを使う人たちにも役立てれば良いと思う。 そういう意味だと「PRMLの副読本」の同人誌が、私のやろうしていることに近いかもしれない。(風が吹けばジュンク堂で「機械学習の学習」 - Cybozu Inside Out | サイボウズエンジニアのブログ

また、上掲の誤訳の指摘では、必要以上に強い言葉を使っていたのでそれに対する非難も多かった。
本記事は、翻訳の「批判・論評」であり、人の「誹謗中傷」とならないよう最大限留意したつもりだ。

第1章

p.20

原文:The combination of expressiveness, terseness, and clarity provided by f-strings makes them the best built-in option for Python programmers.
日本語版:f文字列で与えられる表現性、簡潔性、明晰性の組み合わせは、Pythonプログラマにとって組み込みの中の最良の選択です。

直訳:f文字列によってもたらされる表現力、簡潔性、明瞭性の組み合わせは、f文字列をPythonプログラマにとって組み込みの中の最良の選択肢にしている。
意訳:f文字列を使うと、コードを**に簡潔にそして明確に書けるので、f文字列はPythonプログラマにとって組み込みの中の一番良い選択肢なのです。

何気なく読み飛ばしそうになったが、「表現性」とは一体何なんだろうか。私自身は「表現性がある/表現性が高い」のような言い方をした覚えがない。試しに引用符をつけてググってみると、「身体表現性障害」という病気のことばかりが出てくる。そこまで一般的な用語でないことだけは確かだ。

英辞郎では「expressiveness」の訳語として「表現力」とだけ書いてある。 expressivenessのように派生語の場合は、その元の単語の意味を調べたほうが良い。 f-strings provide expressiveness, terseness, and clarityなのだから、f文字列を使うとコードがexpressive, terse, and clearになるということだ。
「expressive」を引くと「表情豊かな・表現力豊かな」という訳語が出てくるが、コードの形容としてはあまり似合わない。

Expressive suggests conveying, or being capable of conveying, a thought, intention, emotion, etc., in an effective or vivid manner: an expressive gesture.
https://www.dictionary.com/browse/expressive

という説明を見れば「expressive」の意味は「コードがその意図や処理内容を伝えられること」で、これclearと近い意味にならないか?
うまい日本語訳が思い付かなかったので最終的な訳は確定できませんでした、ごめんなさい。

p.25 項目6

日本語版:比較対照のため、アンパックを使わずにスナック食品リストのイテレーション例を次に示します。
原文:As an example for contrast, here I iterate over a list of snacks without using unpacking:

直訳:対比のための例として、以下で私はスナック食品のリストをアンパックを使わずにイテレートする。
意訳:対比のため、スナック食品のリストをアンパックを使わずにイテレートする例を以下に示します。

「アンパックを使わずに」の文節はどこを修飾してるんだろうか? 唯一考えられるのは「示します」だが、「アンパックを使わずに示します」は奇妙だろう。 「イテレートする例」を「イテレーション例」という名詞句にしてしまったため、「アンパックを使わずに」が修飾する先が消えてしまったのがここの問題である。

p.33 項目9

日本語版:elseブロックによる表現性は、(自分も含めた)人が将来そのコードを理解するのに必要な負荷に値しません。 s

原文:However, the expressivity you gain from the else block doesn’t outweigh the burden you put on people (including yourself) who want to understand your code in the future.

間違いなくworthかdeserveを直訳したなと予想したが、原文はどっちでも無かった。なるほどoutweighなのか。
「表現性」についてはすでに述べたので割愛。こっちはexpressivityかー。expressivityはそんなに大きくなく、burdenのほうが大きくなってしまうから、elseブロックを使うな、という話だから、以下のように意訳してみたが、どうでしょうか。
目的語のburden ...という名詞句を日本語版でも名詞句で訳すから読みづらいのだと思う。適切に品詞を変換してほしい。

直訳:しかしながら、あなたがelseブロックから得る表現力は、将来あなたのコードを理解しようとする人(あなた自身も含む)にあなたが課す負担を上回らない。
意訳:しかし、elseブロックを使ってしまうと、コードの意図が伝わりにくくなり、将来あなたのコードを理解しようとする人(あなた自身も含む)が苦労するというデメリットのほうが大きくなるのです。

p.36 項目10

日本語訳:この第2の方式は、peices変数が初めて定義されるif文の各ブロックの異なる位置にあるので奇妙に感じます。

「peices変数が」の主語に対応する述語は何か? 「定義される」だと、後段の「ある」に対応する主語が無いのでおかしい。したがって「ある」と解釈するしかない。「初めて定義されるif文の各ブロックの異なる位置にpeices変数があるので」と同じということだ。

しかしそうなると「初めて定義されるif文」とは何だ? 能動態に直すと「(誰かが)初めてif文を定義する」である。いつ誰がif文を定義したんだ?
疑問符が頭の中に浮かんできたところで原文を見ると、以下の通りである。

原文:This second approach can feel odd because it means that the pieces variable has two different locations—in each block of the if statement—where it can be initially defined.

だいぶ訳しにくい文章だね……because以下が長いので、ここで一旦文を切るのが良い。で、「different」は「分かれてしまう」でニュアンスを出した。日本語だとダッシュよりも括弧のほうが挿入句だと分かりやすいだろうと思ったので、そう変えてある。
「where it can be initially defined」のitは「the pieces variable」を指すので、定義されるのはif文ではなくてpeices変数だ。それなら話が通じる。

直訳:この2番めの方法は、奇妙な感じがする。なぜなら、このやり方は、pieces変数が、それが最初に定義される可能性のある2つの異なる場所―すなわちif文の各ブロック―にあることを意味するからだ。
意訳:この2番めの方法は、奇妙な感じがします。なぜなら、このやり方だと、pieces変数が最初に定義される可能性のある場所が2箇所(すなわちif文の各ブロック)に分かれてしまうことになるからです。

第2章

p.46 項目12

日本語訳:スライスでは、正の増分値をstartやendのどちらか一方のみと使う。
原文:Prefer using positive stride values in slices without start or end indexes.

without A or Bで「AもBも無しで」という意味になる。

直訳:正の増分値を、startやendのindexを使わずに使うこと。
意訳:正のストライド値をなるべく使うようにし、その場合はstartやendは使わないようにする。

「正のストライド値を使い、startやendは使わないようにする。」と書こうかと思ったが、これだとstartやendをどんな時も使ってはいけないように読めてしまう(実際は違う)。難しいね。

日本語訳に対応する文章は 「Use positive stride values in slices with either start or end index.」である。これは誤訳と断じても良いだろう。

抜き出した箇所は項目のまとめの部分だが、少し上を見ると本文の中で「ストライドを使わなければいけないときは、できる限り正の値にして、startとendのインデックスを省きます。」と書いてある。こちらが正しく、私の翻訳とも符合する。

p.47 項目13

日本語訳:このコードは短くて読みやすく、行間で同期しなければならない境界値エラーが生じる脆弱性がなくなりました。

「行間で同期しなければならない」のは何なのか?「境界値エラー」か「脆弱性」の二択だが、どっちも奇妙だ。「境界値エラーを行間で同期する」とは言わないだろう。通信処理ではないので「同期する」もパッと分かりづらく、この状況に合う語のほうが良い。

原文:This code is shorter, easier to read, and no longer has the error-prone brittleness of boundary indexes that must be kept in sync between lines.

直訳:このコードはより短く、より読みやすく、そしてもはやこのコードには、行間で一致させておかなければいけない境界のインデックスのエラーになりやすい脆弱性がない。
意訳:このコードのほうが短く読みやすくなりました。そしてこのコードには、複数の行の間で境界のインデックスを整合せねばならず、エラーを引き起こしやすいという脆弱性がありません。

p.56 項目15

日本語版:Python3.6、3.7以降はPythonの仕様として、辞書は挿入順を保持するようになりました。
原文:Starting with Python 3.6, and officially part of the Python specification in version 3.7, dictionaries will preserve insertion order.

何気なく原著を眺めていて、この部分が誤訳だと知った。 (だいたいは日本語版を見て引っかかって確かめることが多いのだが、この文は全く見ても引っかかることがなかった。原著を見てビックリ、違う意味じゃないか。)

直訳:Python3.6から始まり、バージョン3.7では公式にPython仕様の一部であるが、辞書は挿入の順序を保持する。
意訳:辞書は挿入の順序を保持するようになりました。これはPython3.6から始まり、バージョン3.7では公式にPython仕様の一部になりました。

(being) part of the ... とbeingが省略された構文と解釈した。

3.6では辞書は挿入の順序を保持するが、それは仕様に明記された動作ではない。(Python公式ドキュメントでは What's New In Python 3.6 — Python 3.10.6 ドキュメント にその旨の記載がある。)その後Python3.7で、 What's New In Python 3.7 — Python 3.10.6 ドキュメント「dict オブジェクトの挿入順序を保存するという性質が、公式に Python 言語仕様の一部であると 宣言されました。」と公式な仕様になった。

日本語版を読んだ人は「3.6、3.7以降」が並列だと思うから、「Python3.6では、Pythonの仕様として、辞書は挿入した順序を保持する。」を正しいと思うだろう。自分の日本語読解能力に自信が無くなってきたので、同時に日本語訳の本を読み進めている友人に聞いてみたが、「正しいと思う」という答えが返ってきた。上記の通り、実際はPythonの仕様でないから、正しくない。

p.57 項目15

日本語訳:Python 3.5以前では、イテレーション順序に依存するdictの全メソッドは、keys, values, items, popitemを含めて、同じようにランダムに見える振る舞いでした。

原著:With Python 3.5 and earlier, all methods provided by dict that relied on iteration order, including keys, values, items, and popitem, would similarly demonstrate this random-looking behavior:

「同じようにランダムに見える振る舞い」が引っかかる。「keysの振る舞いはvaluesの振る舞いと同じようにランダムに見えるなぁ」という話か? ピンと来ない。原文は「similarly demonstrate」なので、「同様に示す」という修飾関係である。

including ... は「……などの」と例示で訳したほうが通りが良いと思う(参考:詳解 技術英文大全 第3巻 高度な英文表現 p.74)。直訳だといきなり具体的なメソッド名が出てくるので、意訳の方ではカッコに入れて後回しにしてみたけど、どう処理するのがいいんだろうか。

thisは多分「直後の例で示す通りの」という意味だと思うが、くどいので訳出しなかった。

直訳:Python 3.5以前では、keys, values, items, popitemなど、dictによって提供される、イテレーション順序に依存する全てのメソッドは、ランダムに見える動作を同様に示していた。
意訳:Python 3.5以前では、イテレーション順序に依存するdictのメソッド(keys, values, items, popitemなど)は全て同じように、ランダムに見える挙動をしていた。

p.66 項目16

日本語版:もう1つ重要なことがあります。
原著:There’s also one important gotcha:

あららら。gotchaを訳し飛ばしてる。俺が前に記事に書いたところじゃん。詳細は以下の記事を参照してください。

linus-mk.hatenablog.com

検索すると原著の全体の中で「gotcha」は12回使われている。日本語版では「理解すべきところ・予想しない動作」などの訳が多いが、訳が飛んでいるところも少しある。

直訳/意訳:もう1つ重要な落とし穴があります。

第3章

p.88 項目23

日本語版:場合によっては、直近のセンサー測定値から、より長い時間尺度における時間あたりとか日あたりなどが役立つこともあるでしょう。
原文:Other times, it’d be helpful to use the last sensor measurements to approximate larger time scales, like hours or days.

日本語版は非文だろう。日本語版を読んだ時点で何かがおかしいことがわかり、一体どうしたんだろうと心配になる。

え、これは自信がない……「like hours or days」が「1時間あたりや1日あたり」だとしたら、per hourだから単数形になるのでは。なんで複数形になってるんだろう。
無冠詞複数形の「一般的なもの、不特定多数」の用法だろうか? 「数時間や数日」だとしたら「several hours or days」あたりになってないと不自然な気がする。分からん。分からないので、1時間・1日で訳します。

直訳:ある場合には、最近のセンサーの測定値を使うことでより大きな時間尺度、例えば1時間や1日を近似するほうが便利だろう。 意訳:ある場合には、最近のセンサーの測定値を使うことでより大きな時間尺度、例えば1時間や1日の値を近似するほうが便利だろう。

p.89 項目23

日本語訳:関数を書く側としては、すべての呼び出し元で、より明確なキーワードスタイルを用いることでエラーの可能性を極力減らす必要があります(カッコ内は略)。
原文:As a function author, you can also require that all callers use this more explicit keyword style to minimize potential errors (snip).

require S V(原型)で「SにVするよう命じる・要求する」です。 関数を書く人がキーワード専用引数を使えば、関数を呼び出す側に「引数を位置指定するな、絶対にキーワード方式で引数を指定しろ」と強制できるという話です。「要求する」だと要求に従わない場合もありそうなので、「強制」にしておこう。

直訳:関数を書く人として、あなたはすべての呼び出し元に、起こり得るエラーを最小化するためにこのより明確なキーワード方式を使うことを要求することもできる。
意訳:関数を書く人は、すべての呼び出し元に、このより明確なキーワード方式を使ってエラーの可能性を最小化することを強制することもできます。

p.95 項目25

日本語版:後で、拡張の必要性や好みが変わったために最初の2引数の名前を変える決定をしたとします。
原文:Later, I may decide to change the names of these first two arguments because of expanding needs or even just because my style preferences change:

直訳:後に、拡張の必要性のせい、またはただ単に私のスタイルの好みが変わるせいでさえ、私はこれらの最初の2個の変数の名前を変更することに決めるかもしれない。
意訳:将来、拡張の必要性が生じたせい、またはただ単にスタイルの好みが変わったせいで、これらの最初の2個の変数名を変更しようと決めるかもしれません。

この日本語訳だと「拡張の必要性が変わったために or 好みが変わったために」という解釈になると思うのだが。英語の名詞句を日本語の名詞句にそのまま翻訳するのは翻訳者の好みだけど、そのせいで文意が変わってくるのはよろしくないと思う……


気力があったら書く

p.23 提供する

p.30 が、デフォルトはNoneに
曖昧な接続助詞「が」。fillvalueとデフォルトが離れたのでどのデフォルトか分かりにくい。

p.52 重さでソートするラムダ関数も簡単に定義できて……(ラムダ関数はソートをしない)

p.52 ここで示したように(シーケンス、タプル、辞書では)……修飾関係がおかしい

p.57 一貫した挿入順序を提供

p.97 項目26 引数リストの1つの*の後として定義される。