2009-12-14 35 views
49

Django的書給當地的伎倆,以避免輸入的參數方面dictionnary http://www.djangobook.com/en/2.0/chapter04/Django的模板和當地人招

它建議這對懶惰的程序員很長的名單,但指出了一些開銷,這可能有一個對性能的影響。

我想知道你們中的一些人是否在真實應用程序中使用本地人的技巧。你推薦它還是這是一個不好的做法?

回答

75

我不喜歡重複 - 我認爲「幹」,「不要重複自己」,是一個關鍵的編程原則。因此,我確實在類似情況下使用了locals()。 Django模板渲染遠不是這種唯一的情況:一般情況是「接受字典的函數或運算符,但不介意字典是否包含額外的條目」。 (例如,Python中的普通字符串格式是另一種這樣的情況)。

但是,有一個反補貼原則:程序應該可以通過本地化的方式來理解 - 這有助於維護和重構(因爲它避免了研究其他文件以檢查重構是否可接受的需要)。這表明,對於locals()的情況,如果模板(或字符串格式等)是本地文字(少數情況下只有少數變量可能被使用,因此locals()不是一個巨大的勝利!) - 但在模板存在於不同文件中的正常情況下存在問題。

因此,在大多數情況下,使用locals()會嚴重妨礙重構。幾乎在Python的每種情況下,局部變量及其名稱都可以作爲本地重構的一部分自由更改,因爲它們沒有「外部可見」效果...但使用locals()會突然中斷 - 突然間,您無法安全地重命名變量以不同的名字提供更好的清晰度,以不需要變量等的方式重構代碼流,而不需要每次都研究單獨的模板文件來檢查是否可能不需要舊名稱(並且可能編輯模板文件,例如,如果爲了i18n/L10n的目的而使用幾種不同的自然語言來維護模板文件,那麼該模板文件可能並不重要)。

因此,除了性能的次要問題,存在「嚴重」,「生產」代碼中使用locals()強大壓力 - 代碼確實需要長期維護,因此易於重構性和局部性。所以,當我「編程最好,我知道如何」,而不是「偷工減料」時,我意識到我最好避免使用locals()

想要在呈現模板的上下文中使用的值不一定「本質上」可用作本地裸機名稱;畢竟,也許其中的一些或許多是計算結果,來自列表或詞典的項目等等。在這種情況下,如果只是將這些值累加到合適的字典中,而不是將它們分配給本地裸機名稱,則更容易避免使用locals()「偷工減料」的誘惑。

這不是最簡單的折衷,因爲兩個很好的原則(避免重複,並具有良好的局部性)不可避免地會發生衝突 - 因此,這是一個很好的問題!而不是完全容易受到尖銳的黑色或白色答案,這就是爲什麼我試圖擴大雙方。最後,我認爲這是那些「風格」方面之一,編程團隊可能會被建議採用團隊統一的風格指導方針並堅持下去 - 至少它不需要每次都做出決定問題出現的時間,併產生一個更均勻(因此可維護)的代碼庫。 [[我必須承認,這個具體的觀點從來沒有在我參加過的球隊的風格指南中得到明確解決,但是,儘管很多人都有! - ]]]

+3

+1由於幾個原因。如果你有一組默認的context_processors爲你的所有視圖提供一些標準值,那麼我會立即發生這種情況。如果你不小心覆蓋了一個顯式傳遞給模板的值,但是如果它是一個隨機覆蓋,你會把你的頭髮拉出來,這是非常糟糕的,因爲有一個本地()值與理智的名字作爲'全局名稱'來自上下文處理器。 – 2009-12-14 19:36:33

12

我個人不喜歡它。對於我的偏好,可能沒有任何理由,除了舊的Python格式「顯式優於隱式」之外。我喜歡確切地知道我的模板中會發生什麼。

+0

我也是,我不喜歡它,它太乾燥,如果發生了一些錯誤,你不能調試那麼好 – doniyor 2015-11-18 16:00:44

3

我已經使用它沒有任何問題(到目前爲止!)。

我不特別喜歡打字,這就是爲什麼我喜歡它。代碼如

'customer' : customer, 
'invoice' : invoice, 
'date' : date 

只是看起來很可笑,如果我能避免它,我會的。我喜歡Python的原因之一是缺乏樣板(儘管這不是真正的樣板,但它很相似)。

2

我想這取決於你在函數中定義了多少個局部變量。

如果它完全匹配你想要返回給你的模板的數字,或者'額外'變量是簡單的結構(比如整數或布爾值),那麼我想沒有必要明確地返回它們,因爲這需要更多的工作。但是另一方面,如果你的視圖有很多複雜的'helper'變量,比如你在視圖中使用你的模型的實例來生成你想發送給模板的數據,那麼你可能想要考慮使用顯式變量返回到模板。

27

我經常想到做以下事情,但我不確定它是否真的有用。

class MyStruct(object): 
    pass 

def my_view(request, id): 
    c = MyStruct() 
    c.customer = .. 
    c.invoice = .. 
    c.date = .. 
    return render_to_response('xxx,html',c.__dict__) 
+8

天啊! - 這太棒了! – 2011-07-27 07:46:52

+1

只需將此註釋添加到類定義中:#屬性將在__init__ pylint之外定義:disable = W0201 – 2011-07-27 08:17:36

+3

爲什麼不使用簡單字典? – 2013-04-09 16:41:43

0

我同意亞歷克斯。不要看到創建一個類實例的點(如尼爾斯建議)時,你可以這樣做:

def my_view(request, id): 
    customer = .. 
    invoice = .. 
    date = .. 
    return render_to_response('xxx,html', locals()) 

如果你想表現的原因,查找點綴速度較慢。

如果您想要維護的原因,這是更少的代碼行,即使更多可讀,少一個不必要的結構。

0

我知道這是一箇舊的線程......目前render_to_response已被棄用。使用渲染而不使用locals()。繞過所有當地人是一種不好的做法。 下面是一個views.py例如:

from django.shortcuts import render 
from django.contrib.auth.decorators import login_required 

@login_required 
def mybooks(request): 
    entries = Book.objects.all() 
    return render(request, 'mybooks.html', {'entries': entries}) 
+0

render_to_response尚未棄用。它將在2.0中被棄用,但現在不會。 – Dracontis 2015-07-21 21:39:22

1

爲了減少雜波views.py卻如此明確的:在controllers.py

import sys 

def auto_context(the_locals=None): 
    # Take any variable in the locals() whose name ends with an underscore, and 
    # put it in a dictionary with the underscore removed. 

    if the_locals is None: 
     # We can access the locals of the caller function even if they 
     # aren't passed in. 
     caller = sys._getframe(1) 
     the_locals = caller.f_locals 

    return dict([ 
     (key[:-1], value) 
     for (key, value) in the_locals.items() 
     if key[-1] == "_"]) 

views.py

from app.controllers import auto_context 

def a_view(request): 
    hello_ = "World" # This will go into the context. 
    goodnight = "Moon" # This won't. 
    return render(request, "template.html", auto_context()) 

template.html,使用{{ hello }}

你不太可能給一個變量命名以下劃線結尾。所以你會知道到底是什麼進入模板。使用auto_context(locals())auto_context()也可以。