首先,是的,我是个初学者。代码的功能确实正确,但是它看起来很难看,我不确定它是否容易读。
我认为我的问题是,我在一个函数中使用了5次‘返回假’。这能写得更好吗?如果是这样的话,是很糟糕还是只是轻微的调整(S)?
def is_valid(s):
length = len(s)
# Length between 2 and 6
if length < 2 or length > 6:
return False
# False for punctuation
if not s.isalnum():
return False
# First 2 char must be letters
if not s[0:2].isalpha():
return False
# Numbers cannot start with 0
# Numbers cannot be in the middle of letters
for i in range(length):
if s[i].isdigit():
if s[i] == '0':
return False
elif not s[i:].isdigit():
return False
else:
break
return True发布于 2023-03-25 20:34:23
def is_valid(s):你没有给我们多少提示,在那里。s是什么?什么样的有效性标准?作为一名工程师,我为什么要调用这个函数?
这个函数迫切需要一个有用的“”docstring“。
考虑使用一个更长的名称:is_valid_foo (我还不知道什么是"foo“)。
考虑添加一个可选类型注释:s: str。虽然有用的...(s: str) -> bool:前缀已经告诉我们返回类型,但您在它的时候最好还是以is_结束。
就像i和j通常是索引局部变量的好选择一样,s对于字符串来说也是一个很好的选择。但是在这里,s是公共API的一部分,因此文档负担要高得多。函数名没有拼写出来,所以参数名称应该至少提供一个单词的提示。
# Length between 2 and 6
if length < 2 or length > 6:删除#注释,因为它不会告诉我们除了代码已经说了什么。我们使用注释来描述“为什么”,用代码来描述“如何”。
考虑将比较链接起来:
if not(2 <= length <= 6):我用过5次‘返回假’
这还不算太糟。您有一些稍微复杂的规则,代码是清楚的。
这里有一个方法可以帮助我们更清晰地理解。用正的而不是否定的表示规则,为每一个规则释放一个辅助函数,并将它们串在一起作为连接:
def starts_with_alpha(s: str) -> bool:
return s[:2].isalpha()
def is_valid(s: str) -> bool:
return (is_valid_length(s)
and s.isalnum()
and starts_with_alpha(s)
and is_alpha_then_number(s))这样做的目的是让它读起来像一个英语句子,所以很少或根本不需要评论。
您没有提供任何英语要求,但从代码中可以看出它们。
满足这些要求的另一种方法是将其表述为正则表达式:
import re
valid_re = re.compile(r'^[a-z]{2,}(?P<num>([1-9]\d*)?)所编写的代码是明确的,并实现了其设计目标。我很乐意委托或接受它的维护任务。在将其合并到main之前,应该对签名/ docstring进行改进,这样维护工程师就可以立即看到该函数的好处,而无需阅读其所有代码。)
...
return (is_valid_length(s)
and valid_re.search(s.lower()))所编写的代码是明确的,并实现了其设计目标。
我很乐意委托或接受它的维护任务。
在将其合并到main之前,应该对签名/ docstring进行改进,这样维护工程师就可以立即看到该函数的好处,而无需阅读其所有代码。
发布于 2023-03-26 01:56:57
具有多个返回的函数不一定是一个问题。早期返回通常被称为短路,它们可以有效地保持代码的可读性:直觉是先处理简单的检查,然后再处理更困难的事情。
在可行的情况下,给函数更明确的名称。当前的名称告诉我们您正在验证某些内容,但仅此而已。在可能的情况下,更具体地使用名称,特别是在接口点(函数名称本身就是一个:它是调用方和函数工作之间的接口)。
在Python中,通过索引迭代很少有用。Python序列(包括字符串)是可直接迭代的。如果需要序列中的离散值(在本例中为字符),则直接在字符串上迭代。如果还需要索引,请使用enumerate()。
最难的部分是:第一个字母然后是数字。当前方法的大部分复杂性涉及到确定车牌是否由字母组成,然后由数字组成。您当前的代码不太难遵循。您可以通过两种方式简化代码并帮助代码的可读性:(1)稍微修改注释以澄清数字是可选的;(2)立即返回以强调我们在看到第一个数字后才做出决定。
def is_valid_vanity_plate(s):
# Basic checks:
# - length
# - ASCII letters and digits
# - start with 2 letters
ok = (
2 <= len(s) <= 6 and
s.isalnum() and
s[0:2].isalpha()
)
if not ok:
return False
# Digits, if any, must come at the end and cannot start with zero.
for i, c in enumerate(s):
if c.isdigit():
return c != '0' and s[i:].isdigit()
return True最难的部分是:另一种选择。您可以使用正则表达式来执行大多数验证:两个或多个字母,可选地后面跟着一个非零数字,然后是一些其他数字。我怀疑许多Python程序员会这样处理它。
import re
PLATE_RGX = re.compile(r'^[a-z]{2,}([1-9]\d*)?最难的部分是另一种选择。另一种方法是将字符串划分为非数字和数字的子序列。这可以直接用itertools.groupby来完成,它需要任何可迭代性和一个函数来执行分类。一旦有了这些部分,验证逻辑就会非常简单。def is_valid_vanity_plate(s):
# Basic checks (same as above).
...
# Break string apart into sub-sequences of non-digits and digits.
parts = [
''.join(g)
for _, g in groupby(s, str.isdigit)
]
# Digits, if any, must be in the second part and cannot start with zero.
n = len(parts)
return (
n == 1 or
(n == 2 and parts[1][0] != '0')
), re.IGNORECASE)
def is_valid_vanity_plate(s):
return bool(
2 <= len(s) <= 6 and
PLATE_RGX.search(s)
)最难的部分是另一种选择。另一种方法是将字符串划分为非数字和数字的子序列。这可以直接用itertools.groupby来完成,它需要任何可迭代性和一个函数来执行分类。一旦有了这些部分,验证逻辑就会非常简单。
A4
https://codereview.stackexchange.com/questions/284160
复制相似问题