15-1-第二章 python自定义函数与类(一)

1 介绍

第二章介绍了如何创建自定义函数并调用自定义函数,这些函数可以集成为模块,模块集成为程序包。Arcpy便是程序包。

同时还介绍了如何自定义类class,通过学习自定义函数与类,可以编写更加复杂的程序。

2 函数与模块

函数是执行特定任务的代码块。 Python 包含许多内置函数,例如 help()、int()、print() 和 str()。大多数函数需要一个或多个参数,作为函数的输入。

使用函数称为调用函数。当你调用一个函数时,你给它提供了参数。考虑 print() 函数:

name = "Paul"
print(name)

print的参数为变量name

函数的结构为:

<function>(<arguments>)

包括函数名与参数,python内置了一些函数,可以进行查看:https://docs.python.org/3/library/functions.html

也可以从其他模块导入函数,通常一个模块包含多个函数。使用后import导入模块,一般的语法结构为:

import <module>

例如下面的代码使用“random”这个模块中的函数randrange,生成一个1到99的随机数

import random
random_number = random.randrange(1, 100)
print(random_number)

生成随机数的代码等已经被发布于python社区中,所以我们很多时候不需要自己写代码,需要理解自己的逻辑,然后copy代码。

现在最经常使用的模块是os模块,该模块与操作系统相关的功能。例如:os.mkdir() 函数在当前工作目录中创建一个新文件夹

import os
os.mkdir("test")

非内置函数,需要从模块导入的函数的语法结构一般如下:

import <module>
<module>.<function>(<arguments>)

必须通过import导入模块后,才能调用模块中的函数,有的函数还需要参数。

在为arcgis pro编写脚本工具时,可以使用arcpy访问arcgis pro中已经有的功能,arcpy作为程序 包,包含了多个模块、函数与类,所以在进行地理处理时,需要import arcpy

例如可以使用arcpy中的Exists()函数确定要素类是否存在,并返回True或False。

import arcpy
print(arcpy.Exists("C:/Data/streams.shp"))

上面的代码也遵循了上面提到的语法结构,导入模块后,再调用函数并且添加了参数。

ArcPy 包括几个模块,包括数据访问模块 arcpy.da,用于描述数据、执行编辑任务和跟踪数据库的工作流。 da.Describe() 函数确定数据集的类型,以及数据集的几个属性。

例如,以下代码确定 shapefile 的几何形状类型:

import arcpy
desc = arcpy.da.Describe("C:/Data/streams.shp")
print(desc["shapeType"])

使用arcpy的一般语法结构如下:

arcpy.<module>.<function>(<arguments>)

在前面的示例代码中,Describe() 是 arcpy.da 模块的函数。
当引用一个函数时,引用它所属的模块很重要。例如,ArcPy 还包含一个 Describe() 函数。所以 arcpy.Describe() 和 arcpy.daDescribe() 都是有效的函数,但它们的工作方式不同。关于不同前一本书中也讲过了,具体可以看链接:
http://t.csdn.cn/7hmob中的第三节,描述数据的介绍

3 自定义函数

使用def关键字对函数进行定义,需要定义函数的名称或名称+参数。

def <functionname>(<arguments>):

在上面的定义语句最后,是有一个冒号,然后冒号回车后的代码要保持缩进,缩进的代码块是具体的定义。
例如下面的一个自定义函数:

def printmessage():
      print("Hello world")

这个函数printmessage没有定义参数,所以可以直接调用,有的函数需要使用参数来传递值并调用。

函数定义后并不会被立即执行,只有调用或传参调用后,才会被执行。

通产,自定义函数的功能会比上面复杂多,可以参考以下示例:创建一个表或要素类中所有field名称的列表。在arcpy中没有现成的函数,逻辑上是使用ListFields函数在表中创建field列表,然后使用for遍历列表获取字段名称,名称列表可以存储在列表对象中。

import arcpy
arcpy.env.workspace = "C:/Data"
fields = arcpy.ListFields("streams.shp")
namelist = []
for field in fields:
    namelist.append(field.name)

关于ListFields函数详细的介绍在本专栏 6、空间数据探索 章节中第四节有详细介绍。

假设经常在同一个脚本或其他脚本中使用这些代码行。可以简单地复制代码行,将它们粘贴到需要的地方,然后进行任何必要的更改,需要将参数“streams.shp”替换为感兴趣的要素类或表。

但更好的是创建一个自定义函数来执行相同的步骤,而不是复制和粘贴整个代码。首先,您必须为函数命名,例如 listfieldnames()。

def listfieldnames():

现在可以按名称从脚本中的其他位置调用该函数。在此示例中,调用函数时,希望将值传递给函数,即表或要素类的名称。因此函数必须包含一个参数来接收这些值。

def listfieldnames(table):

def 语句后面是一个缩进的代码块,其中包含函数的作用。 <is 代码块与前面的代码行相同,但现在将要素类的硬编码值替换为函数的参数,如下所示:

def listfieldnames(table):
    fields = arcpy.ListFields(table)
    namelist = []
    for field in fields:
        namelist.append(field.name)

这个函数中没有硬编码值。 缺乏硬编码是自定义函数的典型特征,因为您希望函数可在其他脚本中重用。

最后需要的是函数传回值的方法,也称为返回值。返回值可确保该函数不仅创建名称列表,而且还返回该列表,以便任何调用该函数的代码都可以使用它。这里是使用 return 语句完成的。 完整的功能描述如下:

def listfieldnames(table):
    fields = arcpy.ListFields(table)
    namelist = []
    for field in fields:
        namelist.append(field.name)
    return namelist

函数被定义后,可以在其他脚本中被调用。

fieldnames = listfieldnames("C:/Data/hospitals.shp")

运行代码会使用之前 定义的函数返回表或要素类中的 字段 名称列表。新函数 listfieldnames() 可以直接调用,因为它在同一脚本中被定义了。

一个重要方面是自定义函数 相对于调用该函数的代码的位置。 **自定义函数只有在 定义后才能调用。

先定义后调用的原则

import arcpy
arcpy.env.workspace = "C:/Data"
def listfieldnames(table):
    fields = arcpy.ListFields(table)
    namelist = []
    for field in fields:
        namelist.append(field.name)
    return namelist
fieldnames = listfieldnames("hospitals.shp")
print(fieldnames)

通常,还会在代码段落中添加空行,增强可读性
在这里插入图片描述
示例函数使用一个名为 table 的参数,它可以将值传递给函数。一个函数可以使用多个参数,并且参数可以是可选的。 参数应排序,以便列出所需的first,然后是可选的。通过指定默认值,参数是可选的。

自定义函数可用于许多其他任务,包括使用几何对象

接下来,解释一个示例脚本,然后将其转换为自定义函数。示例脚本计算代表河段的每个折线要素的曲折指数。在这种情况下,弯曲度被定义为表示河流段的折线的长度除以折线的 第一个和最后一个顶点之间的直线距离。相对笔直的线段具有接近 1 的弯曲度指数,而曲折线段具有更高的值,最高可达 1.5 或 2。计算可以通过使用折线对象的属性来完成,即长度、firstPoint 和 lastPoint。打印要素类中每个折线要素的弯曲度指数的脚本如下:

import arcpy
import math

arcpy.env.workspace = "C:/Data/Hydro.gdb"
fc = "streams"
with arcpy.da.SearchCursor(fc, ["OID@", "SHAPE@"]) as cursor:
    for row in cursor:
    oid = row[0]
    shape = row[1]
    channel = shape.length
    deltaX = shape.firstPoint.X - shape.lastPoint.X
    deltaY = shape.firstPoint.Y - shape.lastPoint.Y
    valley = math.sqrt(pow(deltaX, 2) + pow(deltaY, 2))
    si = round(channel / valley, 3)
    print(f"Stream ID {oid} has a sinuosity index of {si}")

对脚本如何工作的简要说明是有序的。搜索光标用于获取唯一 ID 和每条折线的几何形状。 几何的长度属性表示折线的长度。 折线的 第一个和最后一个顶点之间的直线距离是使用几何的 firstPoint 和 lastPoint 属性计算的,它们返回一个 Point 对象。 这些顶点的 x,y 坐标用于根据勾股定理计算距离。
将两个距离分开以获得弯曲度指数,为了显示目的,将值四舍五入到小数点后三位。
在这里插入图片描述
脚本的结果是每个段的弯曲指数的打印输出。
在这里插入图片描述
计算弯曲度指数需要几行代码,这些代码可能在其他地方有用,并且此代码适用于自定义函数。自定义函数接收几何对象并返回弯曲度指数。

使用自定义函数的脚本如下:

import arcpy
import math
arcpy.env.workspace = "C:/Data/Hydro.gdb"
fc = "streams"

def sinuosity(shape):
    channel = shape.length
    deltaX = shape.firstPoint.X - shape.lastPoint.X
    deltaY = shape.firstPoint.Y - shape.lastPoint.Y
    valley = math.sqrt(pow(deltaX, 2) + pow(deltaY, 2))
    return channel / valley
    with arcpy.da.SearchCursor(fc, ["OID@", "SHAPE@"]) as cursor:
    for row in cursor:
        oid = row[0]
        shape = row[1]
        si = round(sinuosity(shape), 3)
        print(f"Stream ID {oid} has a sinuosity index of {si}")

这个自定义函数称为 sinuosity(),唯一的参数是称为 shape 的几何对象。调用函数时,将几何对象传递给函数,并将索引作为值返回。
这个脚本使用 round() 函数返回四舍五入到指定小数位数的涂层点数。以这种方式舍入的唯一问题是任何尾随零都被丢弃 - 例如,1.300 打印为 1.3。另一种方法是使用格式代码来自定义打印格式。定义后的两行脚本使用的格式代码如下:

si = sinuosity(shape)
print(f"Stream ID {oid} has a sinuosity index of {si:.3f}")

这里的格式代码.3f 表示使用带有三位小数的涂层点编号格式化输出。 这个 格式的类型也适用于进行四舍五入 - 例如,数字 1.4567 被格式化为 1.457。

同样,通常在代码块周围添加空行,以提高可读性。
在这里插入图片描述
创建函数有多种好处: 如果要多次使用任务,创建函数可以减少您必须编写和管理的代码量。 执行任务的实际代码仅作为函数编写一次;从那时起,您可以根据需要调用此自定义函数。

创建函数可以减少多次迭代造成的混乱。例如,如果您想为工作空间列表中的所有地理数据库中的所有要素类创建 字段名称列表,它将快速创建一组相对复杂的嵌套 for 循环。使用创建字段 名称列表的函数会删除其中一个 for 循环并将其放置在单独的代码块中。

复杂的任务可以分解成更小的步骤。通过将每一步都分解为一个函数,复杂的任务不再显得那么复杂。精心设计的函数是组织较长脚本的好方法。

自定义函数不仅可以直接从同一个脚本调用,也可以从其他脚本调用,下一节将介绍。

20220702学习总结:

这一章前几节讲的内容都很简单,以前虽然没有使用过自定义函数,但是在arcgis中进行过很简单的自定义函数,写一个重分类的自定义函数,把不同范围i的值重新定义为一个值,当时就两三行代码,还是在arcgis的字段计算器中实现的,其实总体上大同小异。这一章很多的内容,需要前面的基础,与上一本书第六章的内容相关挺多的,还是需要不断回顾,打好基础,起码到时候知道去在哪抄,抄哪个函数。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
第一章Python基本 6 一Python 简介 6 (一) Python 定义 6 (二) Python程序的执行方式 7 (三)Linux常用命令 7 (四)执行过程 8 (五)解释器类型 8 (六)调试 9 二 数据基本运算 9 (一)pycharm常用快捷键(编译器) 9 (二) 函数 函数名(参数) 10 (三)变量 存储数据 11 (四)del 语句 14 (五)核心数据类型 14 (六)数据类型转换 16 (七)运算符 17 三 语句 23 (一)行 23 (二)pass 语句 23 (三)选择语句 24 (四)循环语句 25 (五)跳转语句 30 (六)print相关函数 30 四 容器类型 30 (一)通用操作 30 (二)字符串 str(不可变序列+字符编码值) 33 (二) 列表 list (预留空间+可变序列+储存变量) 35 (四) 元组 tuple(按需分配+不可变序列+存储变量) 44 (五) 字典 dict (按键取值+可变散列+存储键值对) 46 (六) 集合 set (去重复/数学运算+存储键+可变散列) 52 (七)固定集合 frozenset 54 五 函数 function(小而精) 55 (一)pycharm相关设置 55 (二)定义 55 (三)作用 56 (四)定义函数 56 (五)调用函数 56 (六)返回值 57 (七)可变/不可变类型在传参时的区别 58 (八)函数参数 59 六 作用域LEGB 66 (一)变量名的查找规则 66 (二)局部变量 66 (三)全局变量 66 (四)global 语句 67 (五)nonlocal 语句(外部嵌套) 67 第二章 面向对象 Object Oriented 68 一 概述 68 (一)面向过程 68 (二)面向对象 68 二 和对象 69 (一)语法 70 (二)实例成员 72 (三)成员 75 (四)静态方法 76 (总结)和对象 77 三 三大特征 78 (总结)三大特征 78 (一)封装(按需求分,按行为分) 78 (二)继承(抽象 -> 统一 -> 隔离) 86 (三) 多态 90 四 设计原则 95 (总结)设计原则 95 (一)开-闭原则(目标、总的指导思想,增加不改变原代码) 95 (二)的单一职责(一个的定义) 96 (三)依赖倒置(依赖抽象) 96 (四)组合复用原则(复用的最佳实践) 96 (五)里氏替换(扩展重写,继承后的重写,指导继承的设计) 96 (六)迪米特法则(用父减少传递数据量,交互的原则) 97 第三章 模块包+函数式编程 98 通用:快捷键 98 一 模块 Module 98 (一)定义: 包含一系列数据、函数的文件,通常以.py结尾。 99 (二)作用 99 (三)导入 99 (四) 模块变量 100 (五)加载过程 100 (六)分 101 (七)搜索顺序 102 二 包package 102 (一)定义:将模块以文件夹的形式进行分组管理。 102 (二)作用:让一些相关的模块组织在一起,使逻辑结构更加清晰。 102 (三)导入 102 (四) 搜索顺序 103 三 异常处理Error 104 (一)异常 104 (二)处理 105 (三)raise 语句 106 (四)自定义异常:为了快速传递错误信息 108 四 迭代 108 (一)可迭代对象iterable 109 (二) 迭代器对象iterator 110 五 生成器generator 113 (一)生成器函数 114 (二)内置生成器 116 (三)生成器表达式 116 六 函数式编程 118 (一)函数作为参数 119 (二)内置高阶函数 122 (三) 函数作为返回值 124

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值