2011-12-31 129 views
3

我使用了Python編程語言,因爲它的設計哲學,它的偉大社區,對我來說最重要的是它的美麗語法。不過,最近我還是有點沮喪。在我試圖自定義Django的過程中,我遇到了一些代碼,我認爲語法可能更清晰。我絕不是一個經驗豐富的Python程序員,事實上,我在過去的幾個月裏一直只使用它。我會很感激你的見解和你的觀點。爲什麼Django讓Python看起來很醜?

這裏是我所遇到的一些代碼示例:

爲什麼有需要的斜線?

from django.contrib.admin.util import get_model_from_relation, \ 
    reverse_field_path, get_limit_choices_to_from_path 

這可以寫得更優雅嗎?

rel_name = other_model._meta.pk.name 
    self.lookup_kwarg = '%s__%s__exact' % (self.field_path, rel_name) 
    self.lookup_kwarg_isnull = '%s__isnull' % (self.field_path) 
    self.lookup_val = request.GET.get(self.lookup_kwarg, None) 
    self.lookup_val_isnull = request.GET.get(
            self.lookup_kwarg_isnull, None) 
    self.lookup_choices = f.get_choices(include_blank=False) 

我不明白的一件事是爲什麼後面的if語句的代碼是在單獨的行上?

def has_output(self): 
    if isinstance(self.field, models.related.RelatedObject) \ 
     and self.field.field.null or hasattr(self.field, 'rel') \ 
     and self.field.null: 
     extra = 1 
    else: 
     extra = 0 
    return len(self.lookup_choices) + extra > 1 

這看起來很凌亂!

def choices(self, cl): 
    from django.contrib.admin.views.main import EMPTY_CHANGELIST_VALUE 
    yield {'selected': self.lookup_val is None 
         and not self.lookup_val_isnull, 
      'query_string': cl.get_query_string(
          {}, 
          [self.lookup_kwarg, self.lookup_kwarg_isnull]), 
      'display': _('All')} 
    for pk_val, val in self.lookup_choices: 
     yield {'selected': self.lookup_val == smart_unicode(pk_val), 
       'query_string': cl.get_query_string(
           {self.lookup_kwarg: pk_val}, 
           [self.lookup_kwarg_isnull]), 
       'display': val} 
    if isinstance(self.field, models.related.RelatedObject) \ 
     and self.field.field.null or hasattr(self.field, 'rel') \ 
     and self.field.null: 
     yield {'selected': bool(self.lookup_val_isnull), 
       'query_string': cl.get_query_string(
           {self.lookup_kwarg_isnull: 'True'}, 
           [self.lookup_kwarg]), 
       'display': EMPTY_CHANGELIST_VALUE} 

請不要誤會我的意思,我不是對得住的Django的許多貢獻者,相反我真的很佩服他們,我很感激。我明白,也許這是我對Python本身缺乏經驗,或者使得語法看起來不清晰的代碼實際上是Python編程語言的核心功能。

只要說清楚這個問題是真誠的,我真誠地問這個問題本着學習和討論的精神。如果您沒有任何有助於貢獻的內容,請不要回復。

謝謝

+2

所有的「 \「是否能夠繼續下一行的代碼。這是一種保持行較短的方法(例如,少於80個字符)。保持這種方式很常見,因爲您可以在同一區域看到所有代碼。現在,對於「如果」條件,我會將所有內容都包含在圓括號中,這樣就不需要在行末加「\」...... – 2011-12-31 13:42:14

+2

@RicardoCárdenes:反斜槓不是必需的,它們實際上是不鼓勵的Python風格指南。 – 2011-12-31 13:44:47

+0

我同意Bastien,這個代碼本來可以用很多其他語言寫得非常相似。沒有使用優雅的Python功能。 – 2011-12-31 13:46:48

回答

2

1)你需要斜線,因爲通常,但並非總是如此,Django遵循pep8,其中行最多應有80個字符。更好的方式,雖然寫這篇文章,就是:

from django.contrib.admin.util import (get_model_from_relation, 
    reverse_field_path, get_limit_choices_to_from_path) 

\一般應避免。

2)這段代碼沒有什麼不雅之處。創建查詢所需的簡單屬性。你爲什麼覺得它不夠優雅?你希望如何寫這個?

3)再次滿足需要行少於80個字符。這可以通過使用()被改寫,並縮短:

def has_output(self): 
    extra = (isinstance(self.field, models.related.RelatedObject) and 
      self.field.field.null or hasattr(self.field, 'rel') and self.field.null) 
    extra = 1 if extra else 0 
    return len(self.lookup_choices) + extra > 1 

但是由於Django使用Python的2.4(我想他們很快就會撞到版本或者已經做到了),他們不能內嵌if-else使用。

在另一方面,它可以同時寫在更短的方式:

def has_output(self): 
    if isinstance(self.field, models.related.RelatedObject) \ 
     and self.field.field.null or hasattr(self.field, 'rel') \ 
     and self.field.null: 
     return len(self.lookup_choices) > 0 
    else: 
     return len(self.lookup_choices) > 1 

但我覺得原來的方式是通過具有extra可變稍微清晰。在這裏你需要一個評論,爲什麼它是0或1.有了額外的你不需要評論,這很清楚。我不喜歡評論,所以我更喜歡第一種方式:-)

4)這確實看起來很凌亂。我相信將它分成三個更小的方法會更好,每個方法都有可能產生某種效果。但後來我不確定python2.4(或python2.5)是否允許從子例程中產生(我有一些模糊的內存,這是後來引入的,甚至在py3中)。無論如何,我會把這些字典的創建成一個單獨的方法,因爲它看起來非常平凡。我寧願是這樣的:

def choices(self, cl): 
    from django.contrib.admin.views.main import EMPTY_CHANGELIST_VALUE 
    yield self._some_default_choice() 
    for pk_val, val in self.lookup_choices: 
     yield self._choice_from_lookup_choices(pk_val, val) 
    if isinstance(self.field, models.related.RelatedObject) \ 
     and self.field.field.null or hasattr(self.field, 'rel') \ 
     and self.field.null: 
     yield self._some_conditional_choice() 

當然,我會用一些更有意義的名稱爲子方法,但我沒有看到完整的情況下,我真的不知道這些選擇是。

最後:

你在這裏看到的是什麼Python2推到了極限。 Django是一個大框架。有一些功能,這些功能只是Django是大型項目的結果,現在已經開發好幾年了,人們正在學習新的東西。幸運的是,Django開發人員正在慢慢地移除他們認爲是錯誤的東西,例如改變Django 1.4中的默認項目結構,棄用東西並碰撞python版本。您實際上可以通過閱讀django代碼並提問來學習很多東西。通過嘗試重構一些代碼然後學習,你可能會學到更多東西,爲什麼它不那麼容易,爲什麼它必須保持原樣;-)試試吧,它會很有趣:-)

+0

非常感謝啓發。 – 2011-12-31 15:51:56

1

對於\至少:這是常見的要行的最大數量爲80個字符(有很多方面的原因,使得它更容易閱讀,或有多個文件被邊開邊,永遠不必滾動,大會/傳統等)。 \可以將(邏輯)行分成幾行實際行,而不會導致縮進錯誤。

第一個例子,如果沒有反斜槓,可以寫成

from django.contrib.admin.util import get_model_from_relation, reverse_field_path, get_limit_choices_to_from_path 

注意到你怎麼也得向右滾動才能看到整個事情,這是很尷尬。保持80個字符的替代方案將是

from django.contrib.admin.util import get_model_from_relation 
from django.contrib.admin.util import reverse_field_path 
from django.contrib.admin.util import get_limit_choices_to_from_path 

但現在您必須重複導入的模塊,這是醜陋的。最終歸結爲風格/個人喜好的問題。

更一般地說,圖書館代碼看起來很混亂或不常見 - 有時爲了揭示一個更好的界面,有時候爲了實現清潔,有時候會犧牲清潔程度。特別是Django經常犯這個錯誤。例如聲明模型或用於自定義管理站點或使用關鍵字參數來完成數據庫查詢的整個業務的語法 - 使用起來都非常好,但使所有工作都成功的代碼很難包裝一個人的頭。

+0

謝謝,這真的很有幫助。 – 2011-12-31 13:54:06

+1

導入可以包裝在看起來更清潔的圓括號 – 2015-07-07 16:39:55

3

我明白,也許這是我對Python本身缺乏經驗,或者使得語法看起來不清楚的代碼片段實際上是Python編程語言的核心功能。

就是這樣。隨着你繼續編碼,你會意識到你正在經歷的是一切都是新的結果。這種類型的代碼幾乎可以在任何語言中發生,因爲語言只會描述響應消息的對象和函數之間的通信。

一個很好的練習就是瀏覽代碼庫並獲得它的感覺。過了一段時間,你會習慣於表達的代碼和關係。因此,總而言之,'醜'不是Python專有的,但是當你開始熟悉這門語言並且變得無意識且能夠流利地使用該語言時,你很快就會認爲它只是代碼。

+0

謝謝,我認爲是這樣。感謝您的洞察力,真的很感激它。 – 2011-12-31 13:55:53

+0

不認爲一句話結束了(第1段的結尾) – 2011-12-31 14:01:33

相關問題