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



我选择了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编程语言的核心特性。

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

Thank You

我很欣赏这一点,也许是我缺乏Python本身的经验,或者是那些使语法看起来不干净的代码实际上是Python编程语言的核心特性。

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

一个很好的练习就是浏览一下代码库,感受一下。过一段时间后,您将习惯所表示的代码和关系。

所以总结一下,"丑陋"并不是Python独有的,但是当你开始熟悉这门语言,并在不知不觉中熟练地使用这门语言时,你很快就会把它看作是代码。

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。有了extra,你不需要评论,这是非常清楚的。我不喜欢注释,所以我更喜欢第一种方式:-)

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

至少对于:通常希望每行最多包含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经常犯这个错误。例如,用于声明模型的语法,或用于定制管理站点的语法,或使用关键字参数进行数据库查询的整个业务—这些都非常好用,但是使所有这些工作的代码可能很难让人理解。

相关内容

  • 没有找到相关文章

最新更新