2013-03-28 46 views
2

我最近決定開始使用.format()而不是%(請參閱this question)。相反,{0}{1}語法的,我想知道如果下面是一個可接受的使用:這是一個可接受的方式來使用str.format()?

import os 
def get_filename(player_name): 
    for ext in ('jpg', 'jpeg', 'png'): 
     filename = "data/avatars/{player_name}.{ext}".format(**locals()) 
     if os.path.exists(filename): 
      return filename 
    return None 

我喜歡它的粗獷 - 局部變量進入串 - 但我想知道是否有任何理由我不該做到以上。

+0

如果字符串來自不受信任的來源,您可能不希望公開您的變量。但是,就這樣,沒有問題。 – JBernardo

+0

如果你曾經,甚至可能會格式化不受信任的源提交的字符串,你絕對不想這樣做。除此之外,一些pythonistas不喜歡這種「隱含的而非明確的」 - 每當有人建議語言應該使這個更容易/更明顯時,郵件列表上有爭論 - 但其他人不同意,所以我會說這是一種風格尚未解決的問題。 – abarnert

+0

我同意將本地人暴露給可能不可信任的來源。這就是說,我個人沒有在這種風格中使用'**'的問題。 –

回答

4

與傳遞locals()(或globals())到format(或%)的主要問題是經常,格式字符串可以來自不受信任的來源,你的風險你不想暴露變量。如果你只是格式化一個文字字符串,那不是問題,但如果你可能有不可信的格式字符串,你必須仔細考慮你正在做什麼 - 而且更容易做到這一點。

更小的問題是,您的某些代碼讀者不會理解locals**語法,並且很難弄清楚它的功能或原因。這不是一個爭論。事實上,你甚至可以說,很多Python的設計決策都是爲了確保這幾乎不是一個好的論點 - 語言的大小足以讓你的讀者理解/學習任何你寫的pythonic。但它仍值得思考。

然後是樣式問題。每隔幾個月,就會有人提出這個語言應該會讓這個操作更容易,並且它會在郵件列表上啓動一個參數。有些人肯定認爲這是「隱含的而不是明確的」。其他人不同意。我認爲這裏的神奇本地人不會是pythonic的,但是如果你必須明確地通過locals(),也許這很好,也許不是。就像大多數尚未達成共識的風格論點一樣,這真的取決於你。 (順便說一下,在format API最終出來一個這樣的說法,這裏原來的建議是爲更類似Perl的字符串插補隱式locals的。)

但最終,你必須要考慮你」重新保存。比較:

filename = "data/avatars/{player_name}.{ext}".format(**locals()) 

到:

filename = "data/avatars/{0}.{1}".format(player_name, ext) 

你的版本是不是更清晰,更明確,更容易輸入,甚至更短。所以,我認爲讓新手閱讀起來有點困難,並且對社區的某些部分感到煩惱(即使是因爲不好的原因),如果沒有任何好處,這是不值得的。

+1

有人可能會爭辯說,對於具有很多佔位符的長格式字符串,很難跟蹤哪個佔位符是哪個參數(必須要計數)以及明確的關鍵字參數(如「{player_name}」)。format(player_name = player_name) 「有一些臭三胞胎。 –

+0

@PavelAnossov:這是我的主要問題。我喜歡將格式字符串顯式化,但是對於'.format'的參數不是很好,除非我做''locals()'這可以說是hack-y。然而,我認爲不合適的是,在這種特殊情況下,它們都具有相同的可讀性,如果不是後者更清晰,並且說實話,我還沒有遇到過難以跟蹤格式字符的情況。 – Claudiu

+0

@PavelAnossov:對。然後,你可以爭辯說,一個有很多佔位符的長格式字符串應該使用比format更復雜的模板。 – abarnert

1

正如我上面所說,這不應該用於不可信的來源。另外它可能不夠我是Pythonic。

你也可以定義一個函數來做到這一點,但要訪問正確的當地人,就需要做一些幀處理

def format_locals(string): 
    return string.format(**sys._getframe().f_back.f_locals) 

這種模式是不是很好之類的東西Pypy不能租期,提高這種代碼。

我會使用這段代碼(除非你需要Python 2。6支持,因此您必須添加索引):

filename = 'data/avatars/{}.{}'.format(player_name, ext) 
+0

如果你正在做太常見的「現在爲US_en構建它,弄清楚以後如何國際化」,你可能想要爲2.7/3.x添加索引。 – abarnert

相關問題