gpt4 book ai didi

Python "null coalescing"/级联属性访问

转载 作者:太空宇宙 更新时间:2023-11-03 18:32:19 25 4
gpt4 key购买 nike

免责声明:我对 Python 和 Django 比较陌生。

虽然我的问题不是 Django 特有的,但我经常在这种情况下遇到它。有时,我会向网站添加新功能,这些功能假定经过身份验证的用户并访问只有经过身份验证的用户才具有的属性。然后,当我在另一个未登录的浏览器中访问该页面时,我收到“AttributeNotFound”错误,因为该用户实际上是 AnonymousUser。

那又怎样,没什么大不了的。只需检查是否已通过身份验证:

def my_view(request):
if request.user.is_authenticated():
posts = user.post_set.filter(flag=True).all()
else:
posts = None

return render(request, 'template.html', {posts: posts})

然后在模板中:

<h1>Your Posts</h1>
<ul>
{% for post in posts %}
<li>{{ post.name }}</li>
{%else%}
<p>No posts found.</p>
{%endfor%}
</ul>

但是我在我的代码中经常注意到这种模式,我想做一些事情,前提是满足调用链中的某个条件(即属性不是 None),或者只是返回 None、空集或类似的东西。

所以我立即想到了选项(如 Scala 中所示),但由于 python 中 lambda 表达式的繁琐语法,我不太喜欢结果:

# create a user option somewhere in a RequestContext
request.user_option = Some(user) if user.is_authenticated() else Empty()

# access it like this in view
posts = request.user_option.map(lambda u: u.post_set.filter(flag=True).all()).get_or_else(None)

代码被选项语法遮蔽,几乎隐藏了实际意图。此外,我们还必须知道用户必须经过身份验证才能拥有 post_set 属性。

相反,我想要的是一个类似“空合并”的运算符,它允许我编写这样的代码:

def my_view(request):
user_ = Coalesce(user)
posts = user_.post_set.filter(flag=True).all() # -> QuerySet | None-like
return render(request, 'template.html', {posts: posts})

然后我继续编写一个包装类,它实际上允许我执行此操作:

class Coalesce:
def __init__(self, inst):
self.inst = inst

def __call__(self, *args, **kwargs):
return Coalesce(None)

def __iter__(self):
while False:
yield None

def __str__(self):
return ''

def __getattr__(self, name):
if hasattr(self.inst, name):
return getattr(self.inst, name)
else:
return Coalesce(None)

def __len__(self):
return 0

使用 Coalesce 包装用户对象使我能够按照自己的意愿编写代码。如果用户没有定义属性 post_set ,它将表现得像一个空集/列表(关于可迭代)并且计算结果为 False。所以它可以在 Django 模板中工作。

因此,假设合并对象是通过命名约定或显式转换来标记的,这样做可以吗?或者您认为应该避免这样做?如果避免的话,在没有大量 if-else block 的情况下处理可选属性的最佳方法是什么?

最佳答案

您的解决方案是 Null object pattern 的变体。只要明确使用它,我认为使用它就完全没问题。特别是当它提高代码的可读性时。

您还可以使用以下方法扩展您的 Coalesce 类,以允许像这样的索引访问 first_post = user_.post_set.filter(flag=True)[0]

def __getitem__(self, i):
try:
return self.inst[i]
except (TypeError, IndexError, KeyError):
return Coalesce(None)

对于membership tests 不在:

def __contains__(self, i):
try:
return i in self.inst
except (TypeError, IndexError, KeyError):
return False

关于Python "null coalescing"/级联属性访问,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22197783/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com