python基础(一):函数、递归、字典、集合、文件系统、else语句和with语句、图形界面入门EasyGui、类和对象、魔法方法:构造和析构、算数运算(运算符重载)、类的属性访问、描述符、定制容器、迭代器和生成器、模块

以下内容参考:

https://www.bilibili.com/video/BV1Fs411A7HZ?p=20&spm_id_from=pageDriver

十三、函数

python中用关键字 def 来创建函数。

 

函数的参数:

 

 

函数的返回值:

在函数中用关键字 return 返回值。

 

 

函数的形参和实参:

 

 

函数文档:

 

函数文档主要来对函数进行一些说明作用。

 

关键字参数:

 

 

默认参数:

定义了默认值的参数:

 

 

收集参数:

在形参前加上 * 号,这个函数可以有任意多个参数

 

如果使用收集参数后还要使用自定义的参数,此时自定义参数一定要使用关键字参数来调用:

 

 

▲:函数与过程(procedure)

一般来说,函数是有返回值的,而过程是简单的,没有返回值的

而python中只有函数,没有过程,因为python中的任何函数都有返回值,如下图所示:

 

可以看出,及时 hello()没有返回值,也会自动给变量 temp 返回一个None。

 

python中可以用列表来返回多个值:

 

如果上图中在return 后不是以列表的形式返回多个值,默认是会以元组的形式返回多个值,如下图所示:

 

 

▲函数变量的作用域问题

 

 

上面程序中,final_price 是局部变量,old_price 以及 rate 、new_price 都是全局变量。

如果在一个函数外访问定义函数时定义的局部变量,则会发生错误:

 

 

在上述程序中,old_price 以及 rate 、new_price 都是全局变量,如果在一个函数定义时访问全局变量是可以的:

 

 

如果尝试在函数中修改全局变量的值:

 

 

如上图所示,虽然在函数中修改了old_price的值为50,并且在函数中打印的old_price的值也为50,但是在函数外打印的old_price的值却为100。这是因为如果尝试在定义函数时函数内部修改一个全局变量的值,python会自动在此时(在栈内)创建一个与全局变量名相同的局部变量。因此可知在函数内修改的old_price的值只是python刚刚自动创建的函数内的局部变量old_price,并不是修改的全局变量old_price的值。

 

因此,在定义函数时函数中不建议修改程序中的全局变量的值,但是可以访问程序中全局变量的值。

那么,有没有一种方法能够在函数内修改全局变量呢?

答案是有的,就是使用 global 关键字。如下图:

 

 

由上述结果看出,在函数内使用 global关键字后,就可以在函数中修改全局变量的值了。

 

▲内嵌函数和闭包

python支持函数的嵌套:

 

 注意上面的程序中,内部函数fun2()的整个作用域都在外部函数fun1()之内。在fun1()外是不能够调用fun2()的,如下图。

 

 

闭包:

如果在一个内部函数里对外部作用域(但不是全局作用域)的变量进行引用,内部函数就被认为是闭包。

 

如上图中, FunX 中的内部函数 FunY 就是一个闭包。

注意,上图程序中不能这样写:

 

因为 执行 return FunY(y)语句时,y 是属于在外部函数 FunX 中执行的,而FunX中并没有定义变量 y,变量 y 只是内部函数 FunY 中的一个局部变量。

同样的,在内部函数FunY中只能对外部函数FunX的变量进行访问,但是不能修改。

如果要在内部函数中访问外部函数的变量(非全局变量),要使用 nonlocal 关键字,如下图:

 

▲lambda,匿名函数

python允许通过lanbda表达式来创建匿名函数。

 

如上图所示,在语句 g = lambda x : 2 * x + 1

中,: 左边是形式参数,:右边是原函数的返回值,实际上 lambda 关键字是构建了一个函数对象。

 

 

十四、递归

求阶乘:

 

 

十五、字典

即键、值对,python的字典也称为 hash、关系数组。字典是python中的唯一一个映射类型。

 

还可以使用工厂函数(类型) dict() 函数来创建字典:( str(),int(),list(),tuple() 等都是工厂函数)

 

字典推导式和集合推导式:

 

 如上图所示,第一个是字典推导式,因为 { } 中有 :,

第二个是集合推导式,因为 { } 中没有 :,所以 c 中的元素都不重复,是集合。

 

字典中的BIF方法:

 

 该方法用来创建并 返回 一个新的字典。

有两个参数,第一个参数 S 是键,第二个参数 v(可选)是键对应的值,如果第二个参数不提供,默认为NULL

 

如上图,第二个参数不提供,所以 值 为 NULL。

 

注意,第二个参数只能写一个,并将其设置为每一个键的值,如下图所示:

 

并且该函数不能修改字典的值,只会创建新的字典,如下图所示,如果想要使用 fromkeys() 函数修改 dict1 的键:1 和 3 对应的值,会发现该函数会创建一个新的字典:

 

 

访问字典的几个BIF方法:

 

 

 keys() 函数用来返回字典中 键 的引用。

 

values() 函数用来返回字典中 键 对应的值。

 

items() 函数用来打印字典中的每一项:

 

 

用 get() 方法来访问字典中的项:

 

如果该项存在,就会返回,不存在就会返回None。

 

清空字典用 dict1.clear() 或者直接 dict1 = { },推荐用 clear() 方法。

 

拷贝:(浅拷贝)copy():

注意上图中浅拷贝和赋值的不同,浅拷贝 是使用了其他的内存来存储copy的内容,而赋值仅仅是将不同的变量名贴到了同一个内存中的内容。

 

pop() 和 popitem():

pop():给定键弹出对应的值

popitem():弹出末尾一项

 

 

 

 

 

十六、集合

 

上图是字典和集合之间的关系,一般来说,使用大括号 {} 括起来的内容是字典变量。

注意,集合之间的元素是唯一的:

 

且集合不支持使用索引下标来访问。

 

 

十七、文件系统

我们使用 open 关键字来打开一个文件。

 

 

 open 的前两个参数最重要,file 参数为文件名,mode 参数为打开模式

如果E盘中有一个“record.txt”:

那么这样来获取该文件对象:

 

这样就将该文件对象赋值给了f。

 

☆注意,如果txt中有汉字,应该这样将文件对象赋值给f:

 

 

如何对文件对象进行操作呢?如下图所示:

 

 

 

 

需要注意的是,在文件对象 f 中是存在一个指针的,如下图所示:

 

我们可以看到,在第一次 f.read() 之后,文件中的指针已经移到文件末尾,因此再用 f.readline() 已经不能读出东西了。只有用 f.seek(0,0) 来讲文件中的指针移到起始位置,在用 f.readline() 函数,才能再读出东西

同时,我们还可以将一个文件对象中的内容赋值给列表:

 

假如一个文件有多行内容,可以这样来显示其内容:

 

也可以:

 

 

▲关于os模块:

首先需要使用 import os ,语句,然后可以使用下面的方法

https://www.cnblogs.com/alan-babyblog/p/5172781.html

 

 

 

 

 

 

▲将列表、元组、字典(即使用{}括起来的内容)等转换为二进制字节流存放:

使用 pickle 模块。

如果要将一个列表保存为二进制文件:

 

一般来说经常讲 字典 用该方法存储,如果一个字典 (例如:city = {…(很多内容)…} )太大,就可以先将字典 city 放入文件 city_data.pkl 中(即将上图代码中的 my_list 换为 city ,将my_list.pkl 换为 city_data.pkl) ,再进行操作。

 

十八、else 语句 和 with 语句

else语句除了可以和 if 语句搭配,还可以和 while语句搭配:

 

上图中,如果while语句全部执行完毕,紧接着会执行else语句

    如果while语句没有全部执行完毕(即执行过程中执行了break语句,跳出了循环),则接下来不会执行else语句

 

with:

 

会在用不到文件的时候自动调用 f.close() 函数。

 

十九、图形界面入门:EasyGui

 教学文档:

http://easygui.sourceforge.net/

先安装easygui:

桌面上有:

 

 

其中这个文件夹里包含:

 

 

这两个程序。

 

 

 

 

 

实际上安装到了这里:

 

 

 

接着就可以使用了:

 

 

 

二十、类和对象

python中的对象 = 属性 + 方法

 

对象的创建和使用:

 

 

▲python中类的继承:

如上图所示,创建了一个 MyList 类继承了 list 类(其中下面一行 pass 表示什么也不做)

这样用 Mylist 类也可以创建对象 list2,并可以使用list类的方法 append(),sort(),等。

 

更多的例子:

 

 

注意:如果子类中定义与父类同名的方法或者属性,则会自动覆盖父类对应的方法或属性。

如果想让子类中的同名函数不覆盖父类的同名函数,有两种方法:

 

1)调用为绑定的父类方法

 

注意,上图中红框里的 self 是子类Child的对象p的self,并不是父类的实例对象。所以实际上还可以这样写:

 

2)使用 super 函数

 

 

 

此外,python还支持多重继承:

 

例子如下:

 

 

▲python中类的多态性:

 

self:python中的self相当于C++中的this指针,在定义类的函数的时候,将self写入第一个参数

 

 

▲python中的构造函数:被双下划线包围的方法:

 

即构造函数,是python自动调用的,其可以被重写:

 

 

 

▲公有和私有:

默认来说,python的属性和方法都是公开的:

 

那么如何在类中定义私有变量呢?

 

如下图所示,私有变量就不可以被访问了:

 

 

私有变量可以通过使用类中的公有方法来调用:

 

事实上,python的私有机制是伪私有机制,只是将私有变量的名字改变了,可以这样来访问:

 

 

▲类的组合:将一个类的实例化放在一个新类的定义中,就称为将旧的类组合进了新的类:

 

 

python中,如果属性的名字与方法的名字相同,属性会覆盖方法:

 

因此:

 

上图中的组合机制即将旧类组合进新类中。

 

▲python中的 绑定 概念

 

 

一般我们创建属性时不使用类属性而使用实例属性。

类属性,一般我们定义属性时不这样:

 

实例属性,一般如果我们想要定义属性,这样定义:

 

 

 

与类和对象相关的BIF:

查询某个对象是否有某个属性名,其中name要用双引号。

 

 

 

 

 

 

 

 

 返回一个对象的属性值,如果属性不存在,如果设置了default,会将default返回,否则报错。

 

 

 

设置对象中指定属性的值,如果指定属性不存在,那么会自动创建该属性并给其赋值。

 

 

删除对象中指定属性,如果属性不存在,则会抛出异常。

 

 

魔法方法篇:

二十一、构造和析构

 

 

构造函数:

 

 

 

 

一个对象实例化的时候第一个调用的方法,它的第一个参数是 一个类 cls。该方法需要一个实例对象作为返回值,它会返回一个对象。

一般情况下我们不会重写它,但当一个类继承一个不可变类型的时候,有需要进行修改时,就要重写:

如果不重写new函数,就实现不了大写的功能:

 

因为str是不可变的类,不能用init()函数对其自身进行修改,如果不重写new函数,创建对象时就会调用 基类 str 的new函数,就实现不了大写功能。

 

 

将对象被销毁时,该函数会自动被调用。并不是说使用 del 关键字删除一个变量时候就会自动调用该函数,而是一个对象被垃圾回收机制回收时才会调用该对象。

 

二十二、算数运算

运算符的重载:

 

 

 如果想自定义加法,注意下面这个方法是错误的:

 

如上图所示,发生了无限递归。在 Try_int中重写了 int 类型的内置函数 __add__(self,other),利用Try_int类创建了两个实例并且将他们相加,执行加法运算时,会执行 Try_int 中的 __add__(self,other)函数,其中 self为a,other 为b;但是执行该函数时又遇到了 + 运算,再次调用该函数……出现了死循环。

改正:

 

这样在执行 a+b 时调用 Try_int类中的 __add__(self,other) 函数时,再执行 return int(self)+int(other) 时,此时调用的 + 就是int类型中的 __add__(self,other) 函数而不是Try_int 类中的函数了。

 

反运算:

 

当执行 a + b 时,如果a的__add__(self,other) 方法不可用,就会调用 b 的 __radd__(self,other) 方法。此时注意,调用 b 的 __radd__(self,other)方法时,self 是 b,other 是b前面的数。

 

如上图所示,执行 a + b 时,调用的是 a 的 __add__(self,other) 方法。

而执行 1 + b 时,调用的是 b 的 __radd__(self,other) 方法。且self 为 b = 3,other 是1,所以 3 - 1 = 2。

 

二十三、属性访问

 

 

 

二十四、描述符

 

特殊类型就是实现了上图中三个方法中的至少一个。

 

 

 

二十五、定制容器

 

python中,序列类型(列表、字符串等)和映射类型(字典等)都是容器类型

 

 

如:编写一个不可改变的自定义列表,要求记录列表中每个元素被访问的次数。

根据第一张图,应该使用  __len__(self)  以及 __getitem__(self,key)  方法

 

 

在上图中,创建了一个自定义容器CountList,由于该容器只定义了 len() 和 getitem() 方法,因此该列表只能返回列表长度和获取列表元素,即是一个不可改变的自定义列表。

我么使用 count 字典对象来计算列表中每一个元素被访问的次数,初始值全部为0,即刚开始每一个元素都未被访问。

 

二十六、迭代器

 

 对于一个容器对象,调用 iter() 就得到一个迭代器,调用next(),迭代器就会返回下一个值。

在另一篇python基础中 十二、列表 这一知识点也有有关迭代器的内容。

 

 

关于迭代器的魔法方法有两个:

 

iter() 用来返回迭代器本身。

 

 

二十七、生成器

生成器使用 yield 关键字,生成器是一个特殊的迭代器。

生成器是一个特殊的函数,调用时会中断暂停,暂停后将控制权交出来。在需要时还可以重新拿回控制权。

 

如上图,一旦一个函数中出现 yield 关键字,这个函数就被定义为生成器。yield 与函数中的 return 类似,但是普通函数中的 return 一旦被执行,这个函数就结束了。但对于生成器来说,出现 yield 就会把 yield后的参数返回,并暂停在 yield 的位置。

生成器相当于一个特殊的迭代器,所以用 next() 来访问接下里的内容。

生成器还可以使用循环来访问:

 

之前讲过推导式的内容。

 

如图,上图是一个列表推导式。

但是注意,由 ( ) 中构成的推导式并不是 元组(tuple)推导式,而是 生成器推导式。

 

 

生成器推导式如果作为函数的参数,则可以直接写推导式,而不用再加括号:

 

如上图中,第一行代码就没有加 sum() 函数的括号,但仍是正确的。

 

二十八、模块

 

 

在python路径下创建 moudletest.py:

此时 moudletest.py 就是一个模块。注意,应确保模块 moudletest.py 与 python.exe 在同一目录下。

紧接着:

 

 

导入模块的方法:

 

 注意,第二种:

 

但是一般不推荐使用。推荐使用第三种:

 

搜索路径:

写好的模块应该放在:

除了放在和 python.exe 同一目录下

python模块的导入会有一个路径搜索的过程,如果在搜索路径中找到该模块,则导入成功,否则导入失败。搜索路径是一个列表,可以通过 sys 模块的 path 变量将其显示出来:

 

即python会从上述路径中一个个查找需要导入的模块,可以使用下面方法来在搜索路径中加入内容:

 

在没有添加搜索路径时,导入模块失败,使用 sys.path.append() 方法添加该路径后,导入成功:

 

 

包 package:

 

然后使用 import 包名.模块名 即可

 

 

posted @ 2021-08-24 18:09  SanFranciscoo  阅读(36)  评论(0编辑  收藏  举报