为什么Django让Python看起来很难看?

时间:2011-12-31 13:36:20

标签: 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编程语言的实际核心功能。

为了表明这个问题是真诚的,我本着学习和讨论的精神提出这个问题。如果您没有任何有助于贡献的内容,请不要回复。

谢谢

3 个答案:

答案 0 :(得分:3)

  

我很欣赏可能是因为我缺乏Python本身的经验,或者使语法看起来不干净的代码是Python编程语言的实际核心功能。

就是这样。当你继续编码时,你会意识到你所经历的是一切都是新事物的结果。这种类型的代码几乎可以在任何语言中发生,因为语言只会描述对象和响应消息的函数之间的通信。

一个好的练习就是浏览代码库并感受它。过了一会儿,你将习惯于表达的代码和关系。

总而言之,“丑陋”并不是Python所独有的,但是当你开始熟悉语言并且无意识地使用该语言并且能够流利地使用该语言时,你很快就会将其视为代码。

答案 1 :(得分: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代码和提问来学到很多东西。你可能可以通过尝试重构一些代码然后学习来学习更多东西,为什么它不那么容易以及为什么它必须保持原样;-)尝试它,它会很有趣: - )

答案 2 :(得分: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经常对此感到内疚。例如,声明模型或自定义管理站点或使用关键字参数进行数据库查询的整个业务的语法 - 这一切都非常好用,但是使它全部工作的代码很难包装一个人的头。