2017-03-11 95 views
1

我嘗試爲類創建表示函數,我希望它是python-2.x和python-3.x兼容的。但我注意到,正常字符串傳遞到PyUnicode_FromFormat%U將segfault。唯一可行的解​​決辦法,我發現是我自己用PyUnicode_FromObject轉換爲Unicode的對象,然後結果傳遞到PyUnicode_FromFormatPyUnicode_FromFormat with(not-unicode)strings

/* key and value are arguments for the function. */ 
PyObject *repr; 
if (PyUnicode_CheckExact(key)) { 
    repr = PyUnicode_FromFormat("%U=%R", key, value); 
} 
else { 
    PyObject *tmp = PyUnicode_FromObject(key); 
    if (tmp == NULL) { 
     return NULL; 
    } 
    repr = PyUnicode_FromFormat("%U=%R", tmp, value); 
    Py_DECREF(tmp); 
} 

的一點是,我要表示是沒有""(或'' ),如果我使用%R%S,將會被添加。

我只是最近才發現問題,我在全國各地都使用PyUnicode_FromFormat("%U", something);,所以我的問題是:這可以簡化,同時保持Python 2.x和3.x兼容?

+1

我對此沒有一個很好的答案(我不認爲存在),但我會試圖簡化它以刪除if語句,並且每次都按照「else」路徑。在已經是一個unicode對象的東西上調用'PyUnicode_FromObject'只是做一個'incref'並且返回對象,所以總是這樣做並不會花費太多。 – DavidW

+0

@DavidW並不完全像我想的那麼簡單,但它確實使它更短,更簡單。你介意加入它作爲答案嗎?我不會馬上接受它(仍然希望採用更簡單的方式),但它確實有幫助。 – MSeifert

+0

這段代碼有問題嗎?如果沒有(即它按預期工作),這個問題可能屬於代碼審查,而不是Stack Overflow。 –

回答

1

我不認爲一個簡單的方式來做你想要的東西存在。我能看到的最好的是隻要使用你的else情況下,因此總是調用PyUnicode_FromObject消除if聲明:

PyObject *tmp = PyUnicode_FromObject(key); 
if (tmp == NULL) { 
    return NULL; 
} 
repr = PyUnicode_FromFormat("%U=%R", tmp, value); 
Py_DECREF(tmp); 

如果你看看the implementation of PyUnicode_FromObject你會看到它做的第一件事是PyUnicode_CheckExact在這種情況下,它會返回原始對象的版本號incref。因此,所做的額外工作是非常小的(對於key已經是unicode的情況),並且在key不是unicode的情況下它應該稍微更有效,因爲您避免了分支。