getpassの引数prompt

Python2.xだとgetpass()の引数promptに指定した文字列が化ける:

>>> import getpass
>>> from getpass import getpass
>>> pssword = getpass('パスワードを入力してください: ')
ƒpƒXƒ[ƒh‚ð“ü—Í‚µ‚Ä‚­‚¾‚³‚¢:

ソースを見てみると、

def win_getpass(prompt='Password: ', stream=None):
    """Prompt for password with echo off, using Windows getch()."""
    if sys.stdin is not sys.__stdin__:
        return fallback_getpass(prompt, stream)
    import msvcrt
    for c in prompt:
        msvcrt.putch(c)
    # 以下略

1バイトづつputch()してやがる。どうりで化けるはずだ。Pythonは、時々こういうデリカシーに欠けるコードが標準ライブラリにも混ざっているからウンザリする。

msvcrt.putch()の実装を見ると、

static PyObject *
msvcrt_putch(PyObject *self, PyObject *args)
{
    char ch;

    if (!PyArg_ParseTuple(args, "c:putch", &ch))
        return NULL;

    _putch(ch);
    Py_INCREF(Py_None);
    return Py_None;
}

最終的にはVCランタイムの_putch()が呼ばれるようだ。

ここで簡単な実験をしてみる。テーマは「_putch()とputchar()はどこが違うのだろうか」だ。

#include <stdio.h>
#include <conio.h>

int main() {
    char *str = "日本語の文字列\n";

    fputs("putchar: ", stdout);
    for (char *p = str; *p; p ++) {
        putchar(*p);
    }

    fputs("_putch: ", stdout);
    for (char *q = str; *q; q ++) {
        _putch(*q);
    }

    return 0;
}

// 結果
// putchar: 日本語の文字列
// _putch: &#147;&#250;&#150;{&#140;&#234;&#130;&#204;&#149;¶&#142;&#154;&#151;&#241;

1バイトづつ出力しているにもかかわらず、putchar()の方は化けていない! ランタイムのソースが見れないので原因はよくわからないが、おそらく_putch()の方は、

These functions write the character c directly,

http://msdn.microsoft.com/en-us/library/azb6c04e.aspx

なので化けてしまうんだと思う。

ちなみに、Python3.xではputwch()を使うようになっているので化けない。