我想获取带有指定“日志”标签的主题:
在嵌套函数中get_topics_with_log_tag,我设置了变量topics_with_log_tagnonlocal:
def log(request):
"""Show all topics and entries with log tags"""
topics = Topic.objects.all()
#select entries with log tag
def get_topics_with_log_tag(topics):
nonlocal topics_with_log_tag
topics_with_log_tag = []
for topic in topics:
for entry in topic.entry_set.all():
if "#log" in entry.tags:
topics_with_log_tag.append(topic)
get_topics_with_log_tag(topics)
Run Code Online (Sandbox Code Playgroud)
它抛出语法错误:
SyntaxError: no binding for nonlocal 'topics_with_log_tag' found
Run Code Online (Sandbox Code Playgroud)
实际上,我确实绑定了它 topics_with_log_tag = []
上面的代码可以用冗余的方式重写为
topics = Topic.objects.all()
#select entries with log tag
def get_topics_with_log_tag(topics):
# nonlocal topics_with_log_tag
topics_with_log_tag = []
for topic in topics:
for entry in topic.entry_set.all():
if "#log" in entry.tags:
topics_with_log_tag.append(topic)
return topics_with_log_tag
topics_with_log_tag = get_topics_with_log_tag(topics)
Run Code Online (Sandbox Code Playgroud)
我的使用有nonlocal什么问题?
我发现了错误。
Willem Van Onsem 引入了数据库级过滤器而不是嵌套的 for 循环。
模型.py
class Topic(models.Model):
"""A topic the user is learning about."""
text = models.CharField(max_length=200)
date_added = models.DateTimeField(auto_now_add=True)
owner = models.ForeignKey(User)
def __str__(self):
"""Return a string representation of the model."""
return self.text
class Entry(models.Model):
"""Something specific learned about a topic"""
topic = models.ForeignKey(Topic)
title = models.CharField(max_length=200)
text = models.TextField()
tags = models.CharField(max_length=200)
date_added = models.DateTimeField(auto_now_add=True)
Run Code Online (Sandbox Code Playgroud)
nonlocal工作如果您使用nonlocal,这意味着 Python 将在函数的开始处从上面(以及超出)一个范围内查找具有相同名称的变量。但是在这里你没有定义这样的一个。我们可以通过定义一个更高的级别来修复它:
def log(request):
"""Show all topics and entries with log tags"""
topics = Topic.objects.all()
#select entries with log tag
topics_with_log_tag = []
def get_topics_with_log_tag(topics):
nonlocal topics_with_log_tag
topics_with_log_tag = []
for topic in topics:
for entry in topic.entry_set.all():
if "#log" in entry.tags:
topics_with_log_tag.append(topic)
get_topics_with_log_tag(topics)Run Code Online (Sandbox Code Playgroud)
您可以使用global在这种情况下不需要声明这样的变量(在这种情况下它是在上层声明的),但这实际上也是一种反模式。
然而,您在此处执行过滤的方式通常效率很低:您首先在这里迭代所有Topics,然后对每个主题执行额外的查询以获取所有Entrys,然后为每个Entry获取所有Tags,然后查看是否其中一个标签是#log。现在假设您有 10 个主题,每个主题有 10 个条目,每个条目有 5 个标签。这会导致您在数据库级别执行 500 多个查询。我们可以构造一个过滤器,如:
topics_with_log_tag = Topics.objects.filter(entry__tags__contains='#log').distinct()
Run Code Online (Sandbox Code Playgroud)
或更易读(括号用于允许多行表达式):
topics_with_log_tag = (Topics.objects
.filter(entry__tags__contains='#log')
.distinct())
Run Code Online (Sandbox Code Playgroud)
请注意,上面将(就像您的代码所做的那样)还包含主题,tags例如'#logarithm'. 它只检查它是否包含某个子字符串。为了防止这种情况发生,您将需要更高级的过滤或更好的标签表示(带有结束标记)。
例如,如果每个主题都以逗号(如'#foo,#bar,')结尾,那么我们可以查询'#log,'.
我们还可以使用正则表达式并检查新的哈希字符或字符串的结尾。
小智 5
def log(request):
"""Show all topics and entries with log tags"""
topics_with_log_tag=[]
topics = Topic.objects.all()
#select entries with log tag
def get_topics_with_log_tag(topics):
nonlocal topics_with_log_tag
topics_with_log_tag = []
for topic in topics:
for entry in topic.entry_set.all():
if "#log" in entry.tags:
topics_with_log_tag.append(topic)
get_topics_with_log_tag(topics)
Run Code Online (Sandbox Code Playgroud)
您只能使用非局部局部变量而不是全局变量
| 归档时间: |
|
| 查看次数: |
16639 次 |
| 最近记录: |