2011-07-26 37 views
1

我正在Django工作。在Django中,當你渲染一個模板時,你會發送一個上下文字典來替換它。由於我是懶/幹,我經常使用locals()作爲快捷方式,而不是發送類似於{'my_var':my_var,'var2':var2}的字典。Python:酸洗當地人(),還是當地人有輕量級的堂兄弟?

這通常工作很好,並節省了很多令人頭腦麻木的重複。

我在使用django-notifications在某些事件發生時發送電子郵件 - 比如說您收到私人消息。 Django通知帶有一個現在正在集成的內置排隊功能。

但問題是,django-notifications會在隊列時間醃製上下文字典。這就是locals()技巧失敗的地方 - 來自本地人的字典在局部變量之外有很多廢話(例如它有導入和int())。由當地人創建的字典不醃。

我看到三個選擇:1)重寫django-notifications的排隊方法,在模板存儲之前呈現模板(直截了當,但有點乏味並且可以升級)2)停止使用當地人的技巧並開始重複自己3)試着找到一個輕量級的本地人(或者一種醃製當地人的方法)。

我在這裏希望有人帶領#3的方向。

在情況下,它可能是相關的,這裏是我的錯誤,當我嘗試用當地人鹹菜()快捷:

TypeError: can't pickle ellipsis objects 

另外,當地人的字典輸出():

{ 
    '__builtins__': 
    { 
     'bytearray': <type 'bytearray'>, 
     'IndexError': <type 'exceptions.IndexError'>, 
     'all': <built-in function all>, 
     'help': Type help() for interactive help, 
     or help(object) for help about object., 
     'vars': <built-in function vars>, 
     'SyntaxError': <type 'exceptions.SyntaxError'>, 
     'unicode': <type 'unicode'>, 
     'UnicodeDecodeError': <type 'exceptions.UnicodeDecodeError'>, 
     'isinstance': <built-in function isinstance>, 
     'copyright': Copyright (c) 2001-2010 Python Software Foundation. 
All Rights Reserved. 

Copyright (c) 2000 BeOpen.com. 
All Rights Reserved. 

Copyright (c) 1995-2001 Corporation for National Research Initiatives. 
All Rights Reserved. 

Copyright (c) 1991-1995 Stichting Mathematisch Centrum, 
     Amsterdam. 
All Rights Reserved., 
     'NameError': <type 'exceptions.NameError'>, 
     'BytesWarning': <type 'exceptions.BytesWarning'>, 
     'dict': <type 'dict'>, 
     'input': <built-in function input>, 
     'oct': <built-in function oct>, 
     'bin': <built-in function bin>, 
     'SystemExit': <type 'exceptions.SystemExit'>, 
     'StandardError': <type 'exceptions.StandardError'>, 
     'format': <built-in function format>, 
     'repr': <built-in function repr>, 
     'sorted': <built-in function sorted>, 
     'False': False, 
     'RuntimeWarning': <type 'exceptions.RuntimeWarning'>, 
     'list': <type 'list'>, 
     'iter': <built-in function iter>, 
     'reload': <built-in function reload>, 
     'Warning': <type 'exceptions.Warning'>, 
     '__package__': None, 
     'round': <built-in function round>, 
     'dir': <built-in function dir>, 
     'cmp': <built-in function cmp>, 
     'set': <type 'set'>, 
     'bytes': <type 'str'>, 
     'reduce': <built-in function reduce>, 
     'intern': <built-in function intern>, 
     'issubclass': <built-in function issubclass>, 
     'Ellipsis': Ellipsis, 
     'EOFError': <type 'exceptions.EOFError'>, 
     'locals': <built-in function locals>, 
     'BufferError': <type 'exceptions.BufferError'>, 
     'slice': <type 'slice'>, 
     'FloatingPointError': <type 'exceptions.FloatingPointError'>, 
     'sum': <built-in function sum>, 
     'getattr': <built-in function getattr>, 
     'abs': <built-in function abs>, 
     'exit': Use exit() or Ctrl-D (i.e. EOF) to exit, 
     'print': <built-in function print>, 
     'True': True, 
     'FutureWarning': <type 'exceptions.FutureWarning'>, 
     'ImportWarning': <type 'exceptions.ImportWarning'>, 
     'None': None, 
     'hash': <built-in function hash>, 
     'ReferenceError': <type 'exceptions.ReferenceError'>, 
     'len': <built-in function len>, 
     'credits':  Thanks to CWI, 
     CNRI, 
     BeOpen.com, 
     Zope Corporation and a cast of thousands 
    for supporting Python development. See www.python.org for more information., 
     'frozenset': <type 'frozenset'>, 
     '__name__': '__builtin__', 
     'ord': <built-in function ord>, 
     'super': <type 'super'>, 
     '_': None, 
     'TypeError': <type 'exceptions.TypeError'>, 
     'license': Type license() to see the full license text, 
     'KeyboardInterrupt': <type 'exceptions.KeyboardInterrupt'>, 
     'UserWarning': <type 'exceptions.UserWarning'>, 
     'filter': <built-in function filter>, 
     'range': <built-in function range>, 
     'staticmethod': <type 'staticmethod'>, 
     'SystemError': <type 'exceptions.SystemError'>, 
     'BaseException': <type 'exceptions.BaseException'>, 
     'pow': <built-in function pow>, 
     'RuntimeError': <type 'exceptions.RuntimeError'>, 
     'float': <type 'float'>, 
     'MemoryError': <type 'exceptions.MemoryError'>, 
     'StopIteration': <type 'exceptions.StopIteration'>, 
     'globals': <built-in function globals>, 
     'divmod': <built-in function divmod>, 
     'enumerate': <type 'enumerate'>, 
     'apply': <built-in function apply>, 
     'LookupError': <type 'exceptions.LookupError'>, 
     'open': <built-in function open>, 
     'quit': Use quit() or Ctrl-D (i.e. EOF) to exit, 
     'basestring': <type 'basestring'>, 
     'UnicodeError': <type 'exceptions.UnicodeError'>, 
     'zip': <built-in function zip>, 
     'hex': <built-in function hex>, 
     'long': <type 'long'>, 
     'next': <built-in function next>, 
     'ImportError': <type 'exceptions.ImportError'>, 
     'chr': <built-in function chr>, 
     'xrange': <type 'xrange'>, 
     'type': <type 'type'>, 
     '__doc__': "Built-in functions, 
     exceptions, 
     and other objects.\n\nNoteworthy: None is the `nil' object; Ellipsis represents `...' in slices.", 
     'Exception': <type 'exceptions.Exception'>, 
     'tuple': <type 'tuple'>, 
     'UnicodeTranslateError': <type 'exceptions.UnicodeTranslateError'>, 
     'reversed': <type 'reversed'>, 
     'UnicodeEncodeError': <type 'exceptions.UnicodeEncodeError'>, 
     'IOError': <type 'exceptions.IOError'>, 
     'hasattr': <built-in function hasattr>, 
     'delattr': <built-in function delattr>, 
     'setattr': <built-in function setattr>, 
     'raw_input': <built-in function raw_input>, 
     'SyntaxWarning': <type 'exceptions.SyntaxWarning'>, 
     'compile': <built-in function compile>, 
     'ArithmeticError': <type 'exceptions.ArithmeticError'>, 
     'str': <type 'str'>, 
     'property': <type 'property'>, 
     'GeneratorExit': <type 'exceptions.GeneratorExit'>, 
     'int': <type 'int'>, 
     '__import__': <built-in function __import__>, 
     'KeyError': <type 'exceptions.KeyError'>, 
     'coerce': <built-in function coerce>, 
     'PendingDeprecationWarning': <type 'exceptions.PendingDeprecationWarning'>, 
     'file': <type 'file'>, 
     'EnvironmentError': <type 'exceptions.EnvironmentError'>, 
     'unichr': <built-in function unichr>, 
     'id': <built-in function id>, 
     'OSError': <type 'exceptions.OSError'>, 
     'DeprecationWarning': <type 'exceptions.DeprecationWarning'>, 
     'min': <built-in function min>, 
     'UnicodeWarning': <type 'exceptions.UnicodeWarning'>, 
     'execfile': <built-in function execfile>, 
     'any': <built-in function any>, 
     'complex': <type 'complex'>, 
     'bool': <type 'bool'>, 
     'ValueError': <type 'exceptions.ValueError'>, 
     'NotImplemented': NotImplemented, 
     'map': <built-in function map>, 
     'buffer': <type 'buffer'>, 
     'max': <built-in function max>, 
     'object': <type 'object'>, 
     'TabError': <type 'exceptions.TabError'>, 
     'callable': <built-in function callable>, 
     'ZeroDivisionError': <type 'exceptions.ZeroDivisionError'>, 
     'eval': <built-in function eval>, 
     '__debug__': True, 
     'IndentationError': <type 'exceptions.IndentationError'>, 
     'AssertionError': <type 'exceptions.AssertionError'>, 
     'classmethod': <type 'classmethod'>, 
     'UnboundLocalError': <type 'exceptions.UnboundLocalError'>, 
     'NotImplementedError': <type 'exceptions.NotImplementedError'>, 
     'AttributeError': <type 'exceptions.AttributeError'>, 
     'OverflowError': <type 'exceptions.OverflowError'> 
    }, 
    'notification': <module 'notification.models' from '/home/b/webapps/myapp/notification/models.pyc'>, 
    'u': <User: abcd>, 
    'User': <class 'django.contrib.auth.models.User'> 
} 
+5

我認爲你的問題始於有點太聰明。只是因爲你*可以*做些事情(例如,使用'locals()'作爲Context的詞典)並不意味着這是一個好主意。直接構建字典,用你想要的值明確表示,並不需要太多時間,它完全避免了其他「創建」的問題。研究[Zen of Python](http://www.python.org/dev/peps/pep-0020/)並注意項目2. –

+1

當你有15個對象時,locals()的時間節省是可觀的。這個重複的上帝更加吸引了加權儲蓄。 – Ted

+0

是的,但看看你有多少時間浪費在SO上。在我所做的所有Django站點中,我很少有具有超過6個值的視圖特定上下文。另一方面,我確實有一個通用的[上下文處理器](https://docs.djangoproject.com/en/dev/ref/templates/api/#writing-your-own-context-processors),可以提供各種一般對我們的模板有用的信息。 –

回答

0

不,如果你要泡菜,它值得重複。許多物體,其中一些不直觀,不能被醃製(即形式輸入)。

僅當您確定模板將立即呈現時,才應使用locals()快捷方式。

0

你可以將所有東西都存儲在非全局變量中。

2

請允許我建議使用locals()

class Object(object): 
    pass 

def foo(): 
    result = Object() 
    result.my_var = 'bar' 
    your_var = 'not to be returned' 
    result.var2 = 'baz' + result.my_var + len(your_var) 
    return result.__dict__ 

另一種選擇是隻添加對象的上下文創建它們的替代品。

def foo(): 
    result = {} 
    result['my_var'] = my_var = 'bar' 
    your_var = 'not to be returned' 
    result['var2'] = var2 = 'baz' + my_var + len(your_var) 
    return result 

儘管在每次修改變量(或者至少是最後一次)時都要確保發生多重賦值。

編輯:您應該使用第二個版本。我敢肯定,使用上下文字典(resultctx或其他)的額外擊鍵感覺不太乾,但讓我告訴你,這實際上是一件好事。 「Python的禪」狀態「顯式比隱式更好」。當您返回值locals()時,您正在返回誰知道什麼。全局名稱空間中的所有內容,嵌套命名空間中的所有內容,每次可能進行的中間計算,所有這些都隱式返回給調用者。

如果你創建你想返回,你這是明確你的意圖,繪製

this_is_for_me = 'foo' 

result['this_is_for_you'] = 'bar' 

的差異之間的尖銳線值的容器是明文的編碼什麼是公開的,供他人使用;和私人的,如有變更,具體實施。調用者也很清楚,因爲那些私人價值根本不可用。

如果你正在整合一個永遠不會使用的外部庫,你應該對使用它的方式和方式猶豫不決。我可能會更喜歡補丁代碼,這可以通過任何其他可用選項執行此操作。

+0

或者甚至更簡單,直接寫入上下文字典(即無論您使用本地'a',使用'ctx ['a']'代替)。 –

+0

我原本計劃使用普通字典,但我認爲海報可能會反對輸入三個額外的字符,即result ['my_var']'而不是'result.my_var'。是的,我真的更喜歡使用正規字典。 – SingleNegationElimination

+0

這是一個很好的解決方案,但在django的上下文中的對象。變量不是一個社區標準,它並不真正起作用。這意味着如果我拉入社區應用程序,則必須通過並重做其所有函數以將局部變量存儲在本地對象中 - 這對我來說是非首發。 – Ted

0

我在locals()的代碼片段中看不到任何內容,它是dill的「不可剔除」。 Dill可以序列化幾乎所有python中的東西,並且還有some good tools可幫助您理解當代碼失敗時導致酸洗失敗的原因。只要django使用pickle而不是cPickle,所有你需要做的延長泡菜序列化的東西,如EllipsisType是:

>>> import dill 
>>> # this will enable python's pickle to pickle almost everything dill can pickle 
>>> 
>>> # on the full set of dill's types, this usually works unless there's a generator 
>>> # or an interator-type or something odd like a traceback object in locals 
>>> dill.loads(dill.dumps(locals())) 
>>> ... 
>>> # if you get a pickling error, use dill's tools to figure out a workaround 
>>> dill.detect.badobjects(your_bad_object, depth=0) 
>>> dill.detect.badobjects(your_bad_object, depth=1) 
>>> ... 

如果你絕對想,你可以使用蒔蘿的badobjects(或其他的一個檢測功能)以遞歸方式潛入locals()引用鏈中的所有內容,並彈出不可打開的對象,而不是在每個深度調用它,如上所述。