python - 在 Python 中使用递归时出现 UnboundLocalError?
问题描述
一个简单的递归搜索如下所示。关于嵌套函数是否是好的做法似乎存在矛盾的意见。一个 MOOC 正在使用下面的模板教授递归,但社区中的许多人反对这种方法。
无论如何,如果下面的递归片段是从这个工作版本更改的,
# subgroups exist, recurse into each one
for group in groups:
get_all_users(group)
到捕获返回参数的这个版本,
# subgroups exist, recurse into each one
for group in groups:
users = get_all_users(group)
然后出现以下错误:
Traceback (most recent call last):
File "problem_4.py", line 84, in <module>
print(is_user_in_group("sub_child_1_user", sub_child_1_group))
File "problem_4.py", line 53, in is_user_in_group
users = get_all_users(group)
File "problem_4.py", line 37, in get_all_users
users.extend(group.get_users())
UnboundLocalError: local variable 'users' referenced before assignment
这特别令人困惑,因为这不是进行更改的行,这意味着如果逻辑在这里失败,它应该在工作版本中失败。在调用递归函数之前,还清楚地定义了名为“用户”的列表。我对变量范围的理解是用户列表现在可以完全访问嵌套递归函数,那么为什么会在一个意想不到的地方抛出一个关于它“在赋值之前被引用”的错误呢?
class Group:
# group has a name, users, and children groups
def __init__(self, name):
self.name = name
self.groups = []
self.users = []
# simple getters and setters
def get_name(self):
return self.name
def get_groups(self):
return self.groups
def get_users(self):
return self.users
def add_group(self, group):
self.groups.append(group)
def add_user(self, user):
self.users.append(user)
def is_user_in_group(user, group):
"""
Return True if user is in the group, False otherwise.
Args:
user(str): user name/id
group(class:Group): group to check user membership against
"""
# initialize a blank list for output
users = []
# recursive function to collect all users in passed group
def get_all_users(group):
# add the users on this group level
users.extend(group.get_users())
# get the subgroup children of this group
groups = group.get_groups()
# base case, there are no subgroups and we are at the lowest level
if len(groups) == 0:
return users
# subgroups exist, recurse into each one
for group in groups:
get_all_users(group)
return users
# start recursion
users = get_all_users(group)
# search through the all collected users
for _user in users:
# current user matches passed user
if user == _user:
return True
return False
########## TESTING ##########
# create a few groups
parent_group = Group("parent_group")
child_1_group = Group("child_1_group")
child_2_group = Group("child_2_group")
sub_child_1_group = Group("sub_child_1_group")
# define the group heirarchy
parent_group.add_group(child_1_group)
parent_group.add_group(child_2_group)
child_1_group.add_group(sub_child_1_group)
# add a user to each group level
parent_group.add_user("parent_user")
child_1_group.add_user("child_1_user")
child_2_group.add_user("child_2_user")
sub_child_1_group.add_user("sub_child_1_user")
# check for the presence of the sub_child_1_user in its native sub_child_1_group
print(is_user_in_group("sub_child_1_user", sub_child_1_group))
# True
# the sub_child_1_user is also a member of the parent group
print(is_user_in_group("sub_child_1_user", parent_group))
# True
# check for the presence of a nonexistant user
print(is_user_in_group("sub_child_not_added", child_1_group))
# False
# verify the presence of the parent_user in the top level parent_group
print(is_user_in_group("parent_user", parent_group))
# True
解决方案
每当递归成为问题时,我的建议是保持简单并相信递归过程。以下是我可能会如何处理您的is_user_in_group()
功能:
def is_user_in_group(user, group):
"""
Return True if user is in the group, False otherwise.
Args:
user(str): user name/id
group(class:Group): group to check user membership against
"""
# recursive function to collect all users in passed group
def get_all_users(group):
# initialize a blank list for output
users = []
# add the users on this group level
users.extend(group.get_users())
# get the subgroup children of this group
groups = group.get_groups()
# if subgroups exist, recurse into each one
for group in groups:
users.extend(get_all_users(group))
return users
# start recursion
users = get_all_users(group)
# search through the all collected users
return user in users
解决此问题的更好方法是在递归时进行检查,user
以便在获得肯定结果时停止递归,并且仅在否定结果的情况下完全扩展树。
推荐阅读
- java - 由于多态性,声明与初始化对象不同的类型有什么好处?
- python - 如果名称存在,如何使用“01”创建文件?
- java - 如何在一个 maven 项目中定义 JUnit 测试并让它在另一个 maven 项目中运行?
- java - 为什么我不能将元素插入到我的链表实现中?
- java - heroku[web.1]:状态从开始变为崩溃
- sql - 格式化查询以在 Oracle SQL 中显示浮点小数
- javascript - 无法在 Testcafe 错误消息中运行 percy 快照测试:npm ERR!缺少脚本:test:percy
- angular-material - Angular 9 - sidenav 仅占用内容的高度
- c# - 您如何处理错误“读取令牌时意外结束。路径'状态机。<> t__builder'”
- javascript - React Native - 动态状态?或等效的解决方案