目录
4.1 函数
4.1.1 内置函数
内置函数是安装完Python后无须调用任何库就可直接使用的函数,这些函数提供了编程所需的最基础的功能。Python中的内置函数多并且全面,按属性和功能差异可以分为几个类别,大致有:与数据对象相关的函数、数学计算函数、str相关函数、序列对象相关函数、I/O功能函数、查询与判断函数等。
1.与数据对象相关的函数
这类函数往往用于创建数据对象、转换数据对象的变量类型或者获取数据对象的属性
创建或转换数据对象:
(此处代码较多,不贴出,请见代码附录)
2.数学计算函数
(此处代码较多,不贴出,请见代码附录)
3.与str相关的函数
(此处代码较多,不贴出,请见代码附录)
4.与序列对象相关的函数
使用序列对象相关函数操作序列对象:
(此处代码较多,不贴出,请见代码附录)
5.I/O功能函数
6.用于查询与判断的函数
(此处代码较多,不贴出,请见代码附录)
7.其他内置函数
(此处代码较多,不贴出,请见代码附录)
4.1.2 自定义函数
好了,到了最喜欢的环节
1.def语句
在Python中,一般使用def语句自定义函数。def语句的首行包括标识符def、函数名和圆括号,任何传入的参数都放在圆括号中;之后为函数的执行体,以冒号起始,换行缩进;如果函数有返回值,则以return表达式结束函数,不带return表达式的情况相当于返回None值。执行体的内容不能为空,至少要用pass来表示空语句,否则函数将无法执行。
def语句的基本语法格式如下:
def function(par1, pa2, …):
suite
return expression
使用def语句创建一个自定义函数,语句执行的逻辑及过程为:def可以视作创建函数的一个声明,该声明将创建名为function的函数;函数可以传入par1、par2等参数,并代入执行语句suite中;expression是一段可执行代码,程序最终返回其执行结果。在函数功能十分简单时,def语句中往往不包含suite,要对传入参数进行的操作可以放在expression中。
使用def语句创建幂运算函数:
(此处代码较多,不贴出,请见代码附录)
创建不同设定的输入与输出的自定义函数:
(此处代码较多,不贴出,请见代码附录)
2.参数
输入与输出是函数的两个重要方面。输入,即参数的传入;输出,即返回值的输出。前面介绍def语句时,已对自定义函数的返回值做过阐述。而自定义函数的参数则是更加重要的一个方面,只有对参数有深刻的理解,才能理解自定义函数。
参数的名称和位置一旦确定,函数的接口定义就完成了。除正常定义的必选参数外,还可以使用默认参数、可变参数和关键字参数,这使得函数定义的接口不但可以处理复杂的参数,还能简化调用者的代码。在Python中,函数的参数主要有3大类,分别是:位置和关键字参数;任意数量的位置参数;任意数量的关键字参数。第1类参数又称为定长参数、不可变参数,第2、第3类参数又称为不定长参数、可变参数。
(1)位置和关键字参数
位置参数和关键字参数是Python默认的参数类型。位置参数的形式往往是简单的数字,数字的排序是有意义的,代表了参数的位置;关键字参数则类似于dict中的元素,关键字与值成对出现,值有对应的关键字,没有位置的概念。
在自定义函数中使用位置参数和关键字参数:
(此处代码较多,不贴出,请见代码附录)
默认参数:
(此处代码较多,不贴出,请见代码附录)
(2)不定数量的位置参数
任意数量的位置参数:
(此处代码较多,不贴出,请见代码附录)
(3)不定数量的关键字参数
定义含有不定数量的关键字参数的自定义函数:
(此处代码较多,不贴出,请见代码附录)
3.作用域
每当在Python程序中使用名字时,就会在所谓的名字空间中生成和改变名字。创建一个函数前,所有代码都在模块的顶层,模块中的名字要么在模块本身中,要么在预定义的内置名字空间中(如内置函数)。
在模块中创建或调用函数,会生成一个嵌套的名字空间,称为函数的作用域。作用域使得函数中的名字不会与模块中或其他函数中的名字冲突。因此可以说:函数定义了局部的作用域,而模块定义了全局的作用域。
def语句里的所有赋值名字默认情况下都是局部的,函数可以使用全局作用域的名字,但必须声明为全局才可以改变。Python的名字解析被称为LGB规则,该规则包含3点内容。
1)当在函数中使用一个无限制型的名字时,Python依次查找3个作用域:局部的(Local)、全局的(Global)、内置的(Built-in)(合情合理),在第1个发现名字的位置停止。
2)在函数中赋值一个名字时,Python总在局部作用域中生成或改变它,除非在函数中对它进行了全局声明。
3)在函数外部时,局部作用域与全局作用域等效,都是一个模块的名字空间。
(此处代码较多,不贴出,请见代码附录)
Python中有一个global语句,可以起到声明的作用,声明的内容是:一个函数计划改变其内部某个变量的作用域。在某个局部变量前使用global标识符时,该变量在函数体内部被赋值或索引时会被映射到包含它的模块的作用域上。(何必呢?这个语言我真是服了)
在自定义函数中应用global语句:
(此处代码较多,不贴出,请见代码附录)
通过上述代码可以看出,当自定义函数func()内部的变量x未做global声明时,执行func函数并不能影响该程序模块顶部x的值。只有在声明func()内部的x为全局变量时,该函数的执行才能影响整个模块中x的引用值。只定义不执行还是没用。
Python内函数中参数传递的都是对象的引用,且具有3个主要特征:
参数通过局部名字传递;
一个函数中对参数名赋值不影响调用者;
在一个函数中改变一个可变的对象参数可能影响调用。在自定义函数中应用参数传递,
联系一下java里面的,其实也算合情合理
(此处代码较多,不贴出,请见代码附录)
4.1.3 匿名函数
def语句是一种典型的自定义函数方法,但方式并非仅有这一种。有时,不需要显式地定义函数,创建匿名函数就会更加方便。所谓匿名函数,即没有具体名称的函数。在Python中,可以使用lambda语句来创建匿名函数,lambda的主体是一个表达式,而不是一个代码块,用其创建函数比使用def语句创建要简单很多。
f = lambda par1, …, parn : exp
在lambda语句中,冒号前是函数参数,多个函数则使用逗号分隔,冒号右边是返回值。创建匿名函数时不需要写return表达式,返回值是exp表达式代入参数后的结果。
使用lambda语句创建一个求平方的匿名函数:
(此处代码较多,不贴出,请见代码附录)
创建可传入多个参数的匿名求和函数:
(此处代码较多,不贴出,请见代码附录)
将匿名函数赋值给对象:
(此处代码较多,不贴出,请见代码附录)
使用lambda语句创建函数有一些优势:编写脚本时可以省去定义函数的过程,使代码变得精简;对于一些抽象的、不会在其他地方复用的函数,给一个函数命名也是难题(需要避免重名),创建匿名函数则不需要考虑函数命名的问题。
以map函数为例,计算f(x)=x^{2}时,除了使用def语句定义一个f(x)函数外,还可以直接使用匿名函数实现。
在map函数中应用lambda语句
(此处代码较多,不贴出,请见代码附录)
4.2 对象
在计算机科学领域里,对象指的是一个拥有值的存储器地址,通常有一个标识符指向该地址。变量、数据结构或者函数都可以称为一个对象。
4.2.1 面向对象简介
面向对象编程(Object-oriented programming,OOP),是一种具有对象概念的编程思想,也是一种程序开发的抽象方针。在面向对象编程的思想中,对象指的是类的实例。对象作为程序的基本单元,将程序和数据封装其中,用以提高软件的重用性、灵活性和扩展性,对象里封装的程序可以访问及修改对象相关连的数据。在面向对象程序编程里,计算机程序会被设计成彼此相关的对象。
面向对象中最重要的概念是类和实例,对象是类的实例,每个对象可认为是一个特定类的实例。例如每位学生都有自己对应的学号,每个学号都是独一无二的,只会指代特定的一位学生。程序在面向对象编程当中被视为方法,变量被视为成员或属性。如学号为“310800123”的学生就是一个具体的学生,他的姓名、性别、学习成绩的值就是具体的属性。具体对象的属性的值被称为状态,如学号为“310800123”的学生的性别的状态为男性。系统只会给对象分配内存空间,而不会给类分配内存空间。因为类是一个抽象的存在,系统无法给抽象的存在赋值,所以无法分配内存空间。而对象是一个具体的存在,具有属性和状态,可以为对象赋值。
在Python中,类通过关键字class定义,语法格式如下。
class ClassName:
<statement-1>
…
<statement-N>
其中,“ClassName”为类名,通常按驼峰命名法进行命名,类名的每个单词首字母均大写,不包含下划线。类定义语句的内容通常是函数定义,类中的函数定义通常包括了一个特殊形式的参数列表,用于方法调用。调用类需要实例化,采用“ClassName()”的形式。
创建一个内部封装有函数的类,将其实例化并调用内部函数,
(此处代码较多,不贴出,请见代码附录)
4.2.2 属性与方法
类中包含属性与方法,类属性可从外部进行引用和操作,类方法也可从外部调用。
1.类属性与实例属性
类中封装的变量被称为类属性。类属性是类对象所拥有的属性,它被所有类对象的实例对象所共有,在内存中只存在一个副本,这与C++、Java中类的静态成员变量有些类似。对于公有的类属性,在类外可以通过类对象和实例对象访问。
(此处代码较多,不贴出,请见代码附录)
操作实例属性不会影响类属性
(此处代码较多,不贴出,请见代码附录)
在Python中,可在类中定义一个特殊的方法:__init__()方法。通过该方法在创建实例的时候将需要绑定的属性填写进类中,会使得类显得更加模板化。学生类中的学号、姓名、性别、成绩等属性可先在__init__()方法中定义,之后实例化的时候再进行绑定,传入参数的时候不需要传入self
(此处代码较多,不贴出,请见代码附录)
2.访问限制
由于外部代码可通过实例属性直接操作数据,为避免被外部错误引用,可创建私有的类属性,私有类属性为对类中数据的封装。私有类属性分为两种,一种为“_attributename”,这种私有属性名称前仅有一个下划线,仅声明该属性为私有属性,外部仍可调用;另一种为“__attributename”,这种私有属性名称前有两个下划线,无法从类外部调用。
将“Student”类中的“name”和“score”属性分别私有化,并查看实例化后的外部调用结果:
(此处代码较多,不贴出,请见代码附录)
私有属性虽然无法通过实例属性对数据进行操作,但仍然可通过在类中定义方法进行修改。通过方法操作私有属性的一个好处是,可以在方法内部增加限制,在方法中对参数进行检查,避免传入无效参数。
定义方法修改和获取私有属性:
(此处代码较多,不贴出,请见代码附录)
3.方法
创建函数和方法
下代码中:“self”参数指代的就是“stu”实例本身,代码运行时,Python解释器会自行将“self”参数传入方法中,而无须像外部函数那样传实例对象的参数进去。
(此处代码较多,不贴出,请见代码附录)
4.特殊属性和方法
使用dir函数可以查看一个对象的所有属性和方法,返回的内容包含在一个list中。
查看一个int对象的所有属性和方法:
(此处代码较多,不贴出,请见代码附录)
使用__len__方法与len函数获取字符串长度:
(此处代码较多,不贴出,请见代码附录)
常用的特殊方法
4.2.3 装饰器
装饰器本质上是一个Python函数或类,可以在其他函数或类不需要做任何代码修改的前提下增加额外功能,装饰器的返回值也是一个函数/类对象。
可以抽离出大量与函数功能本身无关的雷同代码到装饰器中并继续重用。装饰器的作用是为已经存在的对象添加额外的功能。
在面向对象的思想中,函数也能作为一个对象,函数对象拥有名称属性,可通过“__name__”获取
获取name属性:
(此处代码较多,不贴出,请见代码附录)
通过装饰器增加输出函数执行的日志功能,如下:
函数car作为参数传入装饰器中,获取函数car的name属性后输出该函数的运行日志,整个过程并没有改变函数car本身的功能。
(此处代码较多,不贴出,请见代码附录)
在Python中,类也同样可通过装饰器增加功能。类中的装饰器常用的有3种:@staticmethod、@classmethod和@property。
1.@staticmethod
装饰器@staticmethod用于创建静态方法,在类中,@staticmethod表示下面的方法为静态方法,静态方法与一般方法的不同之处在于没有self参数。静态方法通常为一些功能与类相关但是不与类中属性绑定的方法,为封装进类中使用了静态方法的形式。
定义检查变量值的静态方法:
(此处代码较多,不贴出,请见代码附录)
2.@classmethod
装饰器@classmethod用于定义类方法,在类中,@classmethod表示下面的方法为类方法,类方法的函数参数对象为类对象而不是实例对象,第1个参数为“cls”。
创建一个类方法,用于计算实例个数
(此处代码较多,不贴出,请见代码附录)
3.@property
装饰器@property用于在类中将方法转换为属性进行调用。
使用装饰器@property实现将“Stundet”类中的name方法转换为私有属性:
(此处代码较多,不贴出,请见代码附录)
4.2.4 继承和多态
面向对象编程的一个重要特性是继承,在类中将体现为,新建一个类时可以从现有的类进行继承,此时新建的类称为子类,被继承的类称为父类、基类或超类。
1.继承
继承可以使得子类具有父类的各种属性和方法,而不需要再次编写相同的代码。在令子类继承父类的同时,还可重新定义某些属性,并重写某些方法,即覆盖父类的原有属性和方法,使其获得与父类不同的功能。为子类追加新的属性和方法也是常见的做法。
定义一个交通工具类,其中含有run方法,创建子类并调用父类的方法:
(此处代码较多,不贴出,请见代码附录)
2.多重继承
子类不仅可以继承一个父类的属性和方法,还可以同时继承多个父类的属性与方法,这便是多重继承。在设计类的继承关系时,通常主线都是单一继承下来,多重继承为给子类实现继承额外功能的方法。定义子类时,在“()”中按顺序写明想要继承的父类的名称,用“,”隔开即可。定义一个Run类和Fly类,使用多重继承使Car类和Airplane类继承其中的方法,注意java 是单继承,C++是多继承。
在继承多个父类的属性和方法时,子类按照广度优先原则继承,即优先搜索同一级的父类中是否存在需要调用的属性或方法。
搜索的顺序按照MRO表中类的顺序:
(此处代码较多,不贴出,请见代码附录)
在继承多个父类的属性和方法时,子类按照广度优先原则继承,即优先搜索同一级的父类中是否存在需要调用的属性或方法。搜索的顺序按照MRO表中类的顺序,可使用特殊属性“__mro__”查看类的MRO表。
定义3层继承顺序的类组合,并查看其中方法的搜索顺序:
(此处代码较多,不贴出,请见代码附录)
3.super函数
子类继承父类的__init__()方法时,会因为重写导致父类的__init__()方法被覆盖,为了调用父类的__init__()方法,可使用super函数实现。
使用super函数调用父类的属性和方法:
(此处代码较多,不贴出,请见代码附录)
4.多态
多态指面向对象程序执行时,相同的信息可能会发送给多个不同的类别对象,由系统依据对象所属的类别,引发对应类别的方法而产生不同的行为。
拥有多态特性的程序并不严格限制变量所引用的对象类型,对于未知的对象类型也能进行一样的操作。
如count()方法就没有限制传入的对象类型,count()方法对于字符串对象和数组对象都能进行相同的操作,是多态的一个典型代表。
(此处代码较多,不贴出,请见代码附录)
使用isinstance函数检查对象的数据类型:
(此处代码较多,不贴出,请见代码附录)
多态的一个好处为,任何依赖父类作为参数的函数或者方法,在新增子类时都可以不加修改地正常运行。定义一个函数依赖Transpotation类运行,查看该函数对子类的运行结果,并查看新增的子类的运行结果
(此处代码较多,不贴出,请见代码附录)
4.3 Python常用库安装
Python主要提供了两种类型的库,分别为标准库和第三方库。标准库在安装了官方的Python后就能够直接调用。第三方库则需要额外安装后才能调用。本节主要介绍机器学习的常用第三方库及其作用、安装第三方库的方法、导入第三方库的方法,以及自主创建一个第三方库的方法。
安装Python第三方库有4种主流方法,分别是使用pip安装、使用easy_install安装、使用源文件安装和通过安装包安装。
4.3.1 第三方库安装
1.pip
pip是一个通用的Python包管理工具,提供第三方库的管理功能。安装pip后,在系统命令行窗口(cmd)输入“pip-h”,即可查询pip可执行的操作及指令,
使用pip安装第三方库
其他方式略
4.3.2 第三方库导入
第三方库的默认所在目录是site-packages文件夹,将其中的库引入程序中调用,就是导入第三方库。导入一个第三方库,就可以引用其中的任何公共函数、类或属性,一个程序通过这种方法可以使用其他程序(库)的功能。
Python提供了4种导入第三方库的方法,分别为:使用import语句导入、使用别名导入、使用from…import…语句导入、通过内建函数_import_()导入。
最基本的导入第三方库的方法是使用import语句,在import标识符后添加模块名就能实现导入操作
import mod_name
如果库中包含的属性和方法与某个已有库同名,就必须使用这种方式导入第三方库,以避免名字冲突。
在其他的名字空间中同样可以导入一个库,实现这种导入方式的语句是import as,使用如下所示的格式,就可以在另一名字空间中导入模块。
import full_name as part_name
执行上述代码,系统将所有对full_name模块的调用在part_name名字空间中进行标识。使用别名导入模块这种方式,可以在测试模块新版本时不影响原版本。
要从给定模块中导入特定的函数或对象,可以使用from import语句。该语句在当前的名称空间建立一个到该模块的引用,引用时必须使用全称,使用在被导入模块中定义的函数时必须包含模块的名字。该语句支持从一个模块中导入多个函数或类,如下所示。
from mod_name import func_name1, func_name2, …, func_nameN
如果经常要访问模块的属性和方法,又不想重复地输入模块名,或要有选择地导入指定的属性和方法,from…import…语句是最佳的工具。
Python提供了__import__()函数,同样可以导入模块,其基础使用方法如下所示。
my_module=__import__('module_name')
4.3.3 第三方库创建
创建一个库,就是将写好的模块以库的形式组合起来,这种组合遵照一定的规则。创建第三方库的基本内容是以一定方式导入自定义模块,包括函数模块与类模块,创建过程中最关键的是安排好文件路径。
导入自定义模块的方式有3种:直接import;通过sys模块导入自定义模块的路径;通过pth文件找到自定义模块。
直接import适用于py执行文件和模块同属于同个目录(父级目录)的情况,
在图4-1中,main.py和pwcong同在Python目录,main.py为执行文件,pwcong文件夹为一个模块,pwcong模块所提供的函数被写在_init_.py文件中。_init_.py里面只提供一个hi函数,
def hi(): print("hi")
执行文件main.py,就可以直接导入pwcong模块并调用该模块中的hi函数,该执行文件中的代码如下所示。
import pwcong pwcong.hi()
运行main.py文件,可以看见Python命令行输出一句“hi”。完整的过程是:自定义模块pwcong在一个程序文件main.py中被导入,执行了其中的hi函数。这一过程即创建第三方库pwcong并调用。
小结
Python中为提高编程效率而使用的代码组织方式,包括函数、类与库这3部分内容,各部分主要知识点如下。
1)Python内置函数的类别与使用方法、自定义函数的创建方法与作用域、lambda匿名函数的使用方法。
2)面向对象编程过程中类的创建方法、类的属性与方法,以及继承与多态。
3)pip命令的使用方法,包括在线安装、换源安装和离线安装,还介绍了几种第三方库的导入方法。