3

我正在尝试构建一些代码,并且我已经定义了一个函数来测试计数器在函数内部的工作方式:

def errorPrinting(x):
    x += 1
    return x

然后我在一些条件逻辑中使用该函数,如果满足条件,我希望计数器增加。

x = 1

for row in arcpy.SearchCursor(fc):              

    if not row.INCLUSION_TYPE or len(row.TYPE.strip()) == 0:
        errorPrinting(x)
        print x

    elif len(row.TYPE) not in range(2,5):
        errorPrinting(x)
        print x

    elif row.INCLUSION_TYPE.upper() not in [y.upper() for y in TableList]:
        errorPrinting(x)
        print x

我对使用函数还是很陌生,所以也许我不明白如何将值返回到函数之外,以便在 for 循环的下一次迭代中使用。它一直在我身上返回 1。任何人都可以告诉我如何在 x+= 1 增加一个 x+= 1 后返回函数外部的 x 吗?

谢谢,迈克

4

4 回答 4

3

你被范围所吸引。您可能想查看此链接以获得快速入门。

您可以做一些简单的事情,并x = errorPrinting(x)在所有情况下说您调用 errorPrinting 并得到您想要的。但我认为有更好的解决方案,你会学到更多。

考虑实现一个为您维护计数的错误记录器对象。然后您可以执行 logger.errorPrinting() 并且您的 logger 实例将管理计数器。您可能还想查看 python 的内置日志记录工具

于 2013-08-29T21:51:52.437 回答
3

您不是在增加全局 x,而是在增加也恰好名为 x 的本地参数!(您的 errorPrinting 参数可以命名为任何名称。我称它为 xLocal。)

正如您在此处看到的,x不会由函数递增。

>>> def inc(xLocal):
...     xLocal += 1
...     return xLocal
... 
>>> x = 4
>>> inc(x)
5
>>> x
4

每次都需要将 x 的值重新赋值给函数的返回值。像这样

x = 1
for row in arcpy.SearchCursor(fc):              

    if not row.INCLUSION_TYPE or len(row.TYPE.strip()) == 0:
        x = errorPrinting(x) # <=== here
        print x

    elif len(row.TYPE) not in range(2,5):
        x = errorPrinting(x) # <=== here
        print x

    elif row.INCLUSION_TYPE.upper() not in [y.upper() for y in TableList]:
        x = errorPrinting(x) # <=== here
        print x

在 Python 中,整型参数和其他原语通常不通过引用传递。(列表、字典等都是。无意中修改列表实际上是 Python 中非常常见的错误。)

编辑:通过“引用”和“值”传递在 Python 中讨论并不正确。有关更多详细信息,请参阅这个不错的问题。

因此,使用我之前的示例:

>>> x = 4
>>> x = inc(x)
>>> x
5

请注意,如果这是通过引用传递的参数,例如列表,则此策略会起作用。

>>> def incList(xList):
...     for i in range(len(xList)):
...         xList[i] += 1
... 
>>> xList
[1]
>>> incList(xList)
>>> xList
[2]

请注意,正常的 Pythonic 语法:

for i in xList:
    i += 1

不会增加全局值。

注意:如果您希望密切关注很多事情,我还推荐 @SB 的日志记录模块。提及。它非常有用,使调试大型程序变得容易得多。您可以获取时间、消息类型等。

于 2013-08-29T21:54:09.213 回答
2

为 OP 的利益而编辑,因为如果函数是一个新概念,我之前的评论可能有点难以理解。

我个人认为解决这个问题的最好方法是将相关代码包装在一个对象中。

Python 很大程度上基于对象的概念,您可以将其视为将数据与对数据进行操作的函数进行分组。一个对象可能代表一个事物,或者在某些情况下可能只是让一些相关函数共享一些数据的一种方便方式。

对象被定义为“类”,它定义了对象的类型,然后您创建“实例”,每个实例都是类中定义的数据分组的单独副本。

class MyPrint(object):

    def __init__(self):
        self.x = 1

    def errorPrinting(self):
        self.x += 1
        return self.x

    def myPrint(self):
        for row in arcpy.SearchCursor(fc):              

            if not row.INCLUSION_TYPE or len(row.TYPE.strip()) == 0:
                self.errorPrinting()
                print self.x

            elif len(row.TYPE) not in range(2,5):
                self.errorPrinting()
                print self.x

            elif row.INCLUSION_TYPE.upper() not in [y.upper() for y in TableList]:
                self.errorPrinting()
                print self.x

p = MyPrint()
p.myPrint()

函数__init__(self),errorPrinting(self)myPrint(self), 都称为“方法”,它们是为类中的任何对象定义的操作。为类的实例对象之一调用这些函数会自动self在任何包含对调用该函数的特定实例的引用的参数前面添加一个参数。 self.x指的是由该实例对象存储的变量,因此函数可以共享该变量。

看起来像对类名的函数调用:

p = MyPrint()

实际上创建了一个 MyPrint 类的新实例对象,调用MyPrint.__init__(<instance>)<instance>新对象在哪里,然后将该实例分配给 p。然后,调用

p.myprint()

来电MyPrint.myprint(p)

这有一些好处,因为您以这种方式使用的变量只会在需要对象时持续存在,您可以为执行相同操作的不同任务设置多个计数器,并且范围都得到了照顾,而且您不会弄乱全局命名空间或不必在函数之间传递值。

于 2013-08-29T22:23:25.177 回答
0

最简单的修复,虽然可能不是最好的风格:

def errorPrinting():
    global x
    x += 1

然后将 x=errorPrinting(x) 转换为 errorPrinting()

"global x" 使函数使用全局定义的 x,而不是在函数范围内创建一个。

其他的例子都很好。研究所有这些。

于 2013-08-29T23:32:08.183 回答