如何使for循环在python中更易于理解?

时间:2019-05-08 12:27:47

标签: python loops

我目前正在向一些相当年轻的学生教授一些python编程。我希望他们学习的一件事是如何编写for循环。

到目前为止,我向学生展示的方式是这样的:

for i in range(1,11):
    print(i)

给出一个循环,其中i从1到10。

我的问题是,对于学生来说,当他们想将循环增加到10时需要写11作为range(1,11)的第二个参数,这对学生来说似乎很奇怪。学生会感到困惑。

在C / C ++和相关语言中,这样的循环可以这样写:

for(int i = 1; i <= 10; i++)
    { /* do something */ }

在我看来,表达循环的C ++方法更直观,因为在那种情况下,我可以显式地编写1和10,这是我希望循环变量采用的第一个和最后一个值。

在python中使用for循环时,我最终告诉学生之类的东西“”我们只需要接受我们需要在循环数达到10时编写11,这有点烦人但是您只需了解range函数就可以通过这种方式工作”。我对此不满意;我希望他们了解编程很有趣,而且恐怕这种事情会使它变得不那么有趣。

由于python通常被描述为强调可读性的语言,我怀疑有一种更好的方式来表达for循环,这种方式对我的学生不会造成什么混乱。

是否有更好和/或更少混淆的方法来用python语言表达这种for循环?

14 个答案:

答案 0 :(得分:17)

提醒他们,范围函数以这种方式工作是有原因的。它的一个有用特性是循环将运行的次数等于范围的第二个参数减去第一个参数。

我认为人们确实对此抱有戒心,但事实是Python中的for循环与C截然不同。在C中,for循环基本上是while循环的包装。

这两个示例应该有助于说明C和python中循环的工作方式之间的区别。

# for(int x=1; x <= 10; x++)
x = 1
while x <= 10:
    print(x)
    x += 1


i = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]  # range(1, 11)
for x in i:
    print(i)

但是,老实说,这里的真正问题是,所有循环和数组如果从零而不是零开始,则更易于理解和使用。请考虑将示例从零开始调整。

这样,如果要循环10次,请使用数字10。

   # for(int x=0; x < 10; x++)
x = 0
while x < 10:
    print(x)
    x += 1


i = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]  # range(10)
for x in i:
    print(i)

答案 1 :(得分:13)

您可以向他们展示此代码以更好地理解:

start = 1
length = 10
for i in range(start,start+length):
    print(i)

还有另一个类似的功能,称为slice

答案 2 :(得分:6)

我相信有两种简单的方法可以回答这个问题。 1)一种解释此答案的方法是使用数学符号半封闭间隔[a,b]。在此间隔中,包括一个端点(在此示例中为'a'),但不包括另一个端点('b')。 因此,对于您的示例,

for i in range(1,11):
     print(i)

(1,11)是一个半封闭间隔,其中a和b分别是1和11。

2)您还可以使用以下示例进行解释

    for i in range(1,11)  //in python 
        {do something}

    for(int i=1;i<11;i++)  //in C++
        {do something}

在这两种情况下,我都从1迭代到10。这对我来说似乎更直观。

答案 3 :(得分:5)

向他们展示两个C ++变体:

<pdf-viewer [src]="pdfSrc"
             [show-all]="false"
             [page]="page"
           (after-load-complete)="afterLoadComplete($event)"
                        ></pdf-viewer>

告诉他们python的# using <= operator for(int i = 1; i <= 10; i++) { /* do something */ } # using < operator for(int i = 1; i < 11; i++) { /* do something */ } 函数的作用类似于第二个函数。

答案 4 :(得分:4)

您将受益于早期学习,因为大多数编程语言都使用基于零的索引。理解Python的range()函数的最简单方法是仅使用一个参数。

for i in range(10):
    # will iterate exactly 10 times with i going from 0 to 9

在从零开始的世界中,这是很合理的。

以区间符号表示的Python范围具有一个上限:[0 .. [10,与非计算机工程师默认使用的包括区间[1 ... 10]

鉴于此,赋予范围功能的参数应理解为排他的“停止”值。

当使用额外的参数提供起点时,突然以不同的方式对待停止值将是不一致的。这将使range(0,10)的行为与range(10)有所不同,这将非常令人困惑。

与C的主要区别在于range()意味着“小于”比较,而不是“小于或等于”:

 for i in range(A,B):   # for (i=A;i<B;i++)
     ...

您可以为学生提供一个“ inclusiveRange”功能,让他们开始学习而无需掌握从零开始的概念。

 def inclusiveRange(start=0,end,step=1):
     return range(start,end+1,step)

他们可以用它代替range()

 for i in inclusiveRange(1,10):
     ... # will iterate from 1 to 10 inclusively

缺点是,当学生开始使用列表索引或计算坐标系中的位置时,他们将不得不“取消学习”循环。您可以通过今天使用基于零的索引将它们添加到列表中,从而在将来节省大量- 1off by one

答案 5 :(得分:4)

  

我的问题是,让学生感到奇怪的是,当他们希望循环上升到10时,他们需要将11作为range(1,11)的第二个参数编写。学生对此感到困惑。

混乱不是来自for语句,而是来自range。您需要做的是将解释分为两部分:首先是for迭代它的参数,而不关心参数的内容。所以

for i in [1,2,3]:
    {*do something*}

在列表中包含3个元素。

现在,range被定义为整数a <= x < b的半开间隔,因为它具有许多不错的数学属性,例如

len(range(a, b)) == b - a
len(range(a)) == a
range(a, a) == []
range(a, b) + range(b, c) == range(a, c)

,如果range的定义是一个封闭的间隔,则程序员将不得不在此处和此处使用-1进行调整。

This是关于主题的一篇不错的博客文章。

答案 6 :(得分:3)

这不是“多”或“少”可理解的,而是关于您如何描述的:

  • for x in something:将来自可迭代something的值迭代为变量x。因此,您需要解释“ range(...)返回了什么”。
  • range(start, end,...)返回一个对象,该对象生成从开始(含)到停止(不含)的整数序列。只需向他们显示help(range)

您问的是“如何使for循环更像C语言?”

有一些方法可以做到这一点:


def nrange(start, num_elements, step=1):
    """Similar to `range`, but second argument is number of elements."""
    return range(start, start + step*num_elements, step)


def inclusive_range(start_or_stop, stop=None, step=1):
    if stop is None:
        start = 0
        stop = start_or_stop+1
    else:
        start = start_or_stop
        stop = stop + step
    return range(start, stop, step)


_default_update_func = lambda item: item+1
def c_like_iterator(start, test_func, update_func=_default_update_func):
    cur_value = start
    while test_func(cur_value):
        yield cur_value
        cur_value = update_func(cur_value)

for i in nrange(1, 10):
    print(i)

for i in inclusive_range(1, 10):
    print(i)

for i in inclusive_range(10):  # this will give 11 elements because both 0 and 10 values are included
    print(i)

for i in c_like_iterator(1, lambda x: x<=10, lambda x: x+1):
    print(i)

for i in c_like_iterator(1, lambda x: x<11, lambda x: x+1):
    print(i)

for i in inclusive_range(1, -10, -1):
    print(i)

答案 7 :(得分:2)

尝试一下:

for i in range(10):
    print(i+1)

list_of_numbers = range(1,11)

for number in list_of_numbers:
    print(number)

答案 8 :(得分:2)

让他们理解列表和数组始终以0开头的标准方式很重要。为了易于理解,请向他们显示以下代码,这很容易理解为什么数组从索引上开始0.不要避免复杂性,而应该简化它。

for i in range(10):
    i+=1
    print(i)

for i in range(10):
    print(i+1)

答案 9 :(得分:2)

问题不是了解for循环,而是了解除端点之外的范围。一种查看方式是将范围的一部分视为围栏和围栏。用range(10)建立一个“栅栏”会为您提供10条栅栏 posts == |

|-|-|-|-|-|-|-|

但是,您看到的数字计算了围栏 ==-您必须在围栏柱(|)的左侧,该数字应为0-1-2-3-4-5 -6-7-8-9

如果添加起点range(1,10),它仍然会构建具有10个栅栏柱的栅栏,但是您的索引只会查看至少具有1个栅栏段的所有东西,因此第一个栅栏柱不属于您的一部分范围。但是当您看到的第一个栅栏柱的索引从0开始时,您将得到1-2-3-4-5-6-7-8-9;仍然没有10,因为我们最初的围栏只有10个帖子长。因此,要么构建一个包含11个桩的围栏,然后忽略少于1个段(range(1,11))的所有对象,要么构建包含10个桩的围栏,并假装它的左边还有另一个段(range(0,10 )+1)。

将步长更改为大于1只是意味着您仅从第一个开始就计算每个第2个/第3个/ etc围栏帖子,因此,如果还有更多的围栏帖子但没有其他要数的话,最后剩下的是切断并忽略。

答案 10 :(得分:2)

我认为计算机科学学习中最重要的概念之一就是了解数组索引的工作原理。您应该花一些时间以简单的例子,以清晰的方式向学生们解释这个概念。从LISP开始,几乎所有 编程语言都以Zero-based numbering开头。 Python和C ++没什么不同。在Python中,简单的lists可以用作示例来说明这一概念。

#a simple list
In [15]: list1 = [1,2,3,4,5,6,7,8,9,10,11]
In [23]: len(list1) #number of items in the list
Out[23]: 11
In [26]: list1[0] #the first item in the list
Out[26]: 1
In [25]: print("list1 starts at index {}. The number at this index is {}.".format(list1.index(1), list1[0]))
list1 starts at index 0. The number at this index is 1.
In [37]: list1[10] #the last item in the list
Out[37]: 11
In [19]: print("list1 ends at index {}. The number at this index is {}.".format(len(list1)-1, list1[-1]))
list1 ends at index 10. The number at this index is 11.

如您所见,“数字”值比“索引”值高1。如果列表list1以0开头并以11结尾,那么索引值和'number'值将相同,但是列表中的项目数将增加1怎么办,这是因为我们添加了0。请稍等一下,因为我们需要这个:

In [29]: list2 = [0,1,2,3,4,5,6,7,8,9,10,11]
In [31]: len(list2) #total number of items in list
Out[31]: 12
In [32]: list2[0]
Out[32]: 0
In [35]: list2[11]
Out[35]: 11

请记住,根据文档,range()的语法为:range(start, end, step)。在此讨论中,我们将忽略 step

因此,现在,如果我想使用list2生成与range()类似的列表,则可以使用以上信息形成range()的通用语法:

Syntax: range(start, len(list2)+start), where start is the first item in the range, 
        list2 is a list and len(list2) is its size and the end is len(list2) + start

要将其放入列表中,我只是将以上内容作为参数传递给list()函数。深入了解此功能并不重要,仅用于说明。因此,我们得到:

In [39]: list3 = list(range(0,len(list2)+0))    
In [40]: list3
Out[40]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]    
In [41]: list2 == list3 #both lists are equivalent
Out[41]: True
In [42]: len(list3)
Out[42]: 12          #same number of items as list2
In [46]: for i in range(0,len(list3)+0): #can replace list3 with list2 to get same results
    ...:     print(i, end=' ')
        ...:

0 1 2 3 4 5 6 7 8 9 10 11   #Output         

for循环按索引位置进行迭代。因此,i从项目0的索引位置0(范围的开始)开始,一直到项目11的索引位置11(范围的结束= 11 + 0)。

我们还可以验证上述list1的语法,其中 start 为1,长度为11。

In [6]: list(range(1,len(list1)+1))
Out[6]: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] #same as list1 above
In [15]: for i in range(1,len(list1)+1):
    ...:     print(i, end=' ')
    ...:
1 2 3 4 5 6 7 8 9 10 11

再次,for循环通常从索引位置0开始,索引项1(范围的开始),到索引位置10结束,索引项10的项11(范围的结束= 11 +1)。

现在,让我们看看这个概念如何也适用于C ++。我们使用具有12个项目的同一list2,即len(list2) = 12。同样,如果学生不太熟悉数组,则在下面的示例中深入了解所有内容并不重要。这只是出于说明目的:

#include <iostream>

using namespace std;

int main()
{
    int list2[12] = {0,1,2,3,4,5,6,7,8,9,10,11};
    std::cout << "Length of array list2 = " << (sizeof(list2)/sizeof(*list2)) << std::endl;
    for(int i=0;i<(sizeof(list2)/sizeof(*list2));i++)
    {
        cout<<i<<' ';
    }
    return 0;
}

//Output:
Length of array list2 = 12                                                                                            
0 1 2 3 4 5 6 7 8 9 10 11  #Output

通知i<(sizeof(list2)/sizeof(*list2))确保从数组的上限检索最终项,即从索引= 12-1 = 11的项11。这正是range()函数的作用。如果我做i<=(sizeof(list2)/sizeof(*list2)),那还将在输出中打印12,这不是list2中的项,并且将超出数组的上限。在Python中,range()函数对数组边界更为明确。因此,如果我重写上面的range()语法,并通过将 end 加1,允许for循环从0迭代到list2之后的项目,则可以显式打印该项目:

In [13]: for i in range(0,len(list2)+1):
    ...:     if i>=len(list2):
    ...:         print("\nI am outside of list2: {}".format(i))
    ...:     else:
    ...:         print(i, end=' ')
    ...:
0 1 2 3 4 5 6 7 8 9 10 11
I am outside of list2: 12

从这次讨论中我们了解到,将for循环迭代理解为基于索引的操作非常重要,range(start,end)是Python内置函数,仅在开始和结束之间组成值< em> range ,包含起始值,但不包含结束值。将遍历的值总数(包括开始len(total) + start)的项视为范围的结束。 for循环的实现与此无关,并且仅考虑Python和C ++中的索引位置。

答案 11 :(得分:1)

Python for循环与传统的C风格的循环操作不同,如here所述。它们的功能更像其他语言或迭代器方法中的“对于每个”循环。在您的示例中使用了range函数,这只是一种方便的方法来创建要迭代的整数对象的集合。 here很好地总结了包括“开始”和不包括“停止”的原因。

在向新程序员说明这一点时,我将对此进行分解,并说明for循环的运行方式,然后说明如何使用range函数为for循环提供一组迭代。

示例: for循环用于为集合中的每个项目执行以下代码块:

collection = [1, 2, 3]
for collectionMember in collection:
    print(collectionMember)

接下来说明如何使用范围函数创建整数集合。

创建整数集合的一种简单方法是使用range()函数:

collection = range(1,4)
print(collection)
for collectionMember in collection:
   print(collectionMember)

我知道这不是for循环在其他语言中的工作方式,但是在我看来,如果您正在教他们使用python进行编程,那么先教他们python版本的工作方式,然后对它们进行牢固的掌握会比较容易上的内容解释了循环在其他语言中的工作方式以及两者之间的不同。

答案 12 :(得分:1)

我猜孩子们是上小学的年龄,而教学要记住的是保持简单。一次给他们少量的信息。
您想教他们循环吗?仅针对for循环教他们。

假设他们了解字符串和列表,也许可以使用以下示例:

somelist = ['a', 'b', 'c', 'd', 'e']
for letter in somelist:
    print(letter)

答案 13 :(得分:0)

通过阅读您的帖子。我认为一切都不能一概而论。分开的东西各有千秋。 编程概念相同,但是用不同的语言表示或语法是不同的。 因此,如果我是您,那么我将分享这个概念,然后我将用语言语法来代表那些概念。

for循环的概念是相同的。 (Initialize, condition, increment/decrement) 现在,如果要用python编写,则可以编写。例如。

start, stop, step = 1, 11, 1
for i in range(start, stop, step):
    print(i, end=', ')
# Output: 1 2 3 4 5 6 7 8 9 10 
  • 开始:序列的起始编号default=0. (initialize)
  • 停止::生成最多但不包括该号码的号码。 (condition)
  • 步骤:序列中每个数字之间的差,default=1. (increment/decrement)

在其他人的答案中已经提供了python for循环示例。谢谢。