{ "cells": [ { "cell_type": "markdown", "metadata": { "toc": true }, "source": [ "

Table of Contents

\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Python3不完全入门指南\n", "**作者:**集美大学 郑如滨" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 1.第一个Python程序 \n", "\n", "**Hello, World入门**\n", "1. 启动Python Shell\n", "+ 使用cmd命令启动windows命令行\n", "+ 输入python启动Python Shell\n", "+ 在`>>>`后面输入`python`命令进行解释执行\n", "+ 在`>>>`后面输入`quit()`或者按住`ctrl+z`退出Python Shell\n", "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 基本概念1\n", "1. **缩进:**本教程统一以4个空格作为缩进。下列代码`def hello(name, age):`下一行的`print`左侧有4个空格,这就是缩进。\n", "2. **def关键字:**即define,函数定义关键字。下列代码定义了`hello`函数,有两个入参`name, age`。\n", "3. **入参:**只需给定入参名,Python中无需指定入参数据类型。\n", "4. **多个返回值:**Python中,函数可以有多个返回值。" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "你好!欢迎来到Python3的世界.\n", "小明你好,你的年龄是12岁!\n", "函数返回值: 张小明 13\n" ] } ], "source": [ "print(\"你好!欢迎来到Python3的世界.\")#直接输出信息到控制台\n", "\n", "def hello(name, age):#函数定义\n", " print(\"{}你好,你的年龄是{}岁!\".format(name, age)) #{}代表槽。将fromat后面的变量值依次放入槽中。\n", " return \"张\"+name,age+1\n", " \n", "x, y = hello(\"小明\",12) #函数调用\n", "print(\"函数返回值:\",x, y)" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " (1, -1)\n", "maxNum,minNum = 1 -1\n" ] } ], "source": [ "#Python的函数可以同时返回多个值,本质上多个返回值是以元组类型返回。\n", "def findMaxAndMin(a,b,c):\n", " '''\n", " 这里面的内容是注释,不参与运行\n", " 功能:求出a,b,c中最大与最小值\n", " 输入:a,b,c三个数值类型数据\n", " 返回:期中的最大值与最小值\n", " '''\n", " maxNum = minNum = a\n", " if b>maxNum:\n", " maxNum = b\n", " if c>maxNum:\n", " maxNum = c\n", " if b\n", "\n", "**注1:**Test.py文件应采用**UTF-8**编码。 \n", "**注2:**可在IDLE中选择`File-New File`,新建Python源文件,然后保存。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 2.Python数据类型与流程控制" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 2.1 数据类型" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 2.1.1 数值类型(Numberic Types)\n", "包含3种数值类型:**整数(int)、浮点(float)、复数(complex)**\n", "1. 整数:包括了所有的整数,无范围限制。\n", "2. 浮点:有小数的数值。\n", "3. 复数:如,2+3j" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "3.3333333333333335\n", "3\n", "1\n", "1024\n", "(2+3j)\n", "x+1 10000000000000000000000000000000000000\n" ] } ], "source": [ "x,y,z = 10, 3.14,2+3j\n", "print(x/3) #除法\n", "print(x//3) #求整\n", "print(x%3) #取余\n", "print(2**x) #乘方\n", "print(z)\n", "x = 9999999999999999999999999999999999999 #整型无范围限制\n", "print(\"x+1\",x+1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**math模块的导入与使用:**\n", "\n", "进行数学运算时,可使用**math库**。\n", "\n", "**导入方法1:** import 模块名 [as 别名]。如\n", "- import math\n", "- import random\n", "- import numpy as np" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "3.0\n", "512\n", "0.797131957122589\n", "23\n", "[1 2 3]\n" ] } ], "source": [ "import math\n", "print(math.sqrt(9)) #求开根号使用“模块名.函数名”形式调用\n", "\n", "import math as m\n", "print(m.gcd(1024, 512)) #求最大公约数。使用“别名.函数名”形式调用\n", "\n", "import random\n", "x=random.random() #在[0,1)范围上生成浮点型随机数\n", "print(x)\n", "print(random.randint(1,100))#在[1,100]范围上生成随机整数\n", "\n", "import numpy as np #导入numpy模块,然后为其取别名np。注意:首先要pip install numpy安装numpy模块后,才可使用。\n", "a = np.array((1,2,3)) #创建numpy中的array\n", "print(a)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**导入方法2:**from 模块名 import 对象名/函数名 [as 别名]\n", "\n", "`from 模块名 import 对象名/函数名`仅导入指定模块的某个对象或函数。其他未导入的对象/函数**无法使用**。 \n", "`from math import *`一次性导入模块中的所有对象或函数。" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "3.0\n", "0.1411200080598672\n", "0.1411200080598672\n", "2\n" ] } ], "source": [ "from math import *\n", "print(sqrt(9)) #直接使用math模块中的函数名sqrt调用\n", "\n", "from math import sin\n", "print(sin(3))\n", "from math import sin as f\n", "print(f(3))\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 2.1.2 布尔型\n", "值只有`True`和`False`。在Python中0或False代表false(假),1或True代表true(真)。" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "False\n", "True False True False\n", "11 比 10 大!\n", "True True\n" ] } ], "source": [ "x1 = False\n", "x2 = True\n", "b = 100>101\n", "print(b)\n", "print(1!=2,3!=3,5==5,5==6)\n", "x, y = 10, 11\n", "if x>y:\n", " print(x,\"比\",y,\"较大!\")\n", "else:\n", " print(y,\"比\",x,\"大!\")\n", "print(1 == True, 0 == False)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**其他:逻辑运算符**\n", "\n", "**and** 与,**or** 或,**not** 非" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "False False True\n" ] } ], "source": [ "x1 = True\n", "x2 = False\n", "print(not x1,x1 and x2, x1 or x2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 2.1.3 序列类型(Sequence Types)\n", "包含三种类型:字符串(str),列表(list),元组(tuple)。 \n", "**共同特点:**其中的元素均按顺序排列(符合线性表定义).\n", "\n", "- 字符串的形式:两个双引号`\"\"` 或两个单引号 `''`将字符串括起来。\n", "\n", "- 列表的形式 []\n", "\n", "- 元组的形式 ()\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.1.3.1 序列共同操作\n", "序列的大部分**共同**操作可适用于所有序列类型,如字符串、列表与元组。\n", "\n", "序列通用函数:索引、分片、连接(加)、重复(乘)、in操作(成员判断)\n", "\n", "序列相关函数:`len(),min(),max(),sum()`" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "索引操作: 3 b\n", "分片操作: [3, 5] bc\n", "链接操作: [1, 3, 5, 7, 9, 11, 12] abcdefgh\n", "重复操作: [11, 12, 11, 12] fghfgh\n", "in操作: True False\n", "5 1 9 25\n", "5 a e\n" ] } ], "source": [ "L=[] #定义一个空列表\n", "L1=[1,3,5,7,9]\n", "L2=[11,12]\n", "str1 = \"abcde\"\n", "str2 = \"fgh\"\n", "print('索引操作:', L1[1], str1[1]) \n", "print('分片操作:', L1[1:3], str1[1:3]) #L1[i:j]代表从L1列表中截取从位置i到位置j-1的所有元素,并作为列表返回。\n", "print('链接操作:', L1 + L2, str1 + str2)\n", "print('重复操作:', L2*2 , str2*2)\n", "print('in操作:', 3 in L1, 'x' in str1) #判断3有无在L1中,'x'有无在str1中\n", "print(len(L1), min(L1), max(L1), sum(L1)) \n", "print(len(str1),min(str1),max(str1))" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "#### 2.1.3.2 列表(list)与for循环" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1\n", "2\n", "3\n", "4\n", "5\n", "1 2 3 4 5 1 \n", "list1的长度为6,内容为[1, 2, 3, 4, 5, 1]\n", "list1中1的个数为2,第2个元素为2\n", "逆序: [1, 5, 4, 3, 2, 1]\n", "升序排序后的结果: [1, 1, 2, 3, 4, 5]\n", "降序排序后的结果 [5, 4, 3, 2, 1, 1]\n", "0 \n", "['a', 'b', 'c', 'd', 'e']\n" ] } ], "source": [ "list1 = [1,2,3,4,5]\n", "for e in list1: #打印出list1中的所有元素\n", " print(e)\n", "list1.append(1) #列表末尾添加1这个元素\n", "#输出每个元素都在其后加1空格\n", "for e in list1:\n", " print(e,end=' ') #打印e,e后面添加一个空格(不换行)。\n", "print() #换行\n", "print(\"list1的长度为{},内容为{}\".format(len(list1),list1))\n", "print(\"list1中1的个数为{},第2个元素为{}\".format(list1.count(1),list1[1]))\n", "list1.reverse()\n", "print(\"逆序:\",list1)\n", "list1.sort() #就地排序,改变list1中元素的排列\n", "print(\"升序排序后的结果:\",list1)\n", "list1.sort(reverse = True) #就地排序,改变list1中元素的排列\n", "print(\"降序排序后的结果\",list1)\n", "ls = list() #创建一个空列表。也可以使用ls = []创建空列表。\n", "print(len(ls),type(ls))\n", "charList = list(\"abcde\") #使用list函数创建一个字符列表。\n", "print(charList)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**二维或多维数组:** \n", "c或者java中有多维数组,Python中也有。" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[1, 1, 1], [2, 2, 2], [3, 3, 3]]\n", "[1, 1, 1]\n", "3\n", "1 1 1 \n", "2 2 2 \n", "3 3 3 \n", "[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]\n" ] } ], "source": [ "matrix = [[1,1,1],[2,2,2],[3,3,3]] #直接创建二位数组\n", "print(matrix)\n", "print(matrix[0])\n", "print(matrix[2][1])\n", "for line in matrix: #遍历多维数组\n", " for e in line:\n", " print(e, end=\" \")\n", " print() \n", "\n", "matrix = [[0 for j in range(5)] for i in range(3)] #使用列表生成式语法创建一个3*5的二位数组\n", "print(matrix)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.1.3.3 range\n", "顾名思义,range可用来产生**某个范围**的整数序列。\n", "\n", "**两种用法:**\n", "1. `range(stop) #产生从0开始直到stop-1个整数序列`\n", "2. `range(start,stop,[,step])#产生从start开始,直到stop-1的整数序列,步进为step`" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0 1 2 \n", "1 2 3 4 \n", "1 3 \n", "5 4 3 2 \n", "a b 3 5 6 \n", "使用list函数结合range创建一个有10个大小的list,其内容为 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n" ] } ], "source": [ "for i in range(3): #range(3)为从0开始,产生包含3个整数的序列。然后使用for在该序列上遍历\n", " print(i, end = \" \")\n", "print()\n", "for i in range(1,5):#从1开始,默认步进为1\n", " print(i,end=\" \")\n", "print()\n", "for i in range(1,5,2):#步进为2\n", " print(i,end=\" \")\n", "print()\n", "for i in range(5,1,-1):#从后往前\n", " print(i,end=\" \")\n", "print()\n", "#使用range遍历列表\n", "list1 = ['a','b',3,5,6]#python的list中的元素可以为不同类型\n", "for i in range(len(list1)):\n", " print(list1[i],end = \" \")\n", "print()\n", "list2 = list(range(10))\n", "print(\"使用list函数结合range创建一个有10个大小的list,其内容为\",list2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.1.3.4 while循环" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "5050\n", "输入x退出:1\n", "继续输入\n", "输入x退出:x\n", "flag = False\n" ] } ], "source": [ "i,temp = 1,0\n", "while i<=100:\n", " temp += i\n", " i += 1\n", "print(temp)\n", "\n", "flag = True\n", "while flag:\n", " str1 = input(\"输入x退出:\")\n", " if str1 == 'x':\n", " flag = False\n", " else:\n", " print(\"继续输入\")\n", "print(\"flag =\",flag)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.1.3.5 字符串\n", "使用单引号或双引号包含起来的是字符串,如`\"Hello World\"`或`'Hello World'`都代表字符串\n", "\n", "如果字符串中包含单引号',可以用\"将其包括起来,如**\"book's price\"**代表字符串**book's price**。\n", "\n", "反之也成立,如**'Zhang says \"How are you!\"'**代表字符串**Zhang says \"How are you!\"**" ] }, { "cell_type": "code", "execution_count": 37, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "字符串的拼接: 张三的身份证号是350204200110231013\n", "张 三 \n", "张三 的出生日期是 20011023\n", "350204200110231013 前6位为 350204\n", "350204200110231013 后4位为 1013\n", "A = 65\n", "65 = A\n", "打印5个str1: 张三张三张三张三张三\n", "350204200110231013是一个数\n", "请输入一个数字:13\n", "13 在 350204200110231013 中\n", "请输入一个数字:96\n", "96既不在350204200110231013也不在xyz中\n", "请输入一个数字:q\n", "您刚才输入了字符q,现在退出循环!\n" ] } ], "source": [ "str1,str2 = '张三',\"350204200110231013\"#使用''或者\"\"将字符串包含在其中\n", "\"\"\"\n", "可以使用三个引号\"\n", "将多行字符串一起注释\n", "\"\"\"\n", "print(\"字符串的拼接:\",str1+\"的身份证号是\"+str2)\n", "#可以将字符串看成一个字符列表\n", "for e in str1:\n", " print(e,end=\" \")\n", "print()\n", "#字符串既然可以看作列表,可以对其进行切片\n", "print(str1,'的出生日期是',str2[6:14])\n", "print(str2,'前6位为',str2[:6])\n", "print(str2,'后4位为',str2[-4:])\n", "\n", "#使用ord获得某个字符对应的整数值\n", "print('A =',ord('A'))\n", "#使用chr获取整数值对应的字符\n", "print('65 =',chr(65))\n", "print('打印5个str1:',str1*5)\n", "\n", "#演示字符串自带的函数\n", "if str2.isdigit():\n", " print(\"%s是一个数\"%str2)\n", "elif str2.isalpha():\n", " print(\"%s全是字母\"%str2)\n", "elif str2.isalnum:\n", " print(\"%s包含字母或者数字\"%str2)\n", "\n", "str3 = 'xyz'\n", "while True:\n", " x = input(\"请输入一个数字:\")\n", " if x in str2:\n", " print(x,\"在\",str2,'中')\n", " elif x in str3:\n", " print(x,\"在\",str3,'中')\n", " elif x in \"q\":\n", " print(\"您刚才输入了字符q,现在退出循环!\")\n", " break;\n", " else:\n", " print(\"%s既不在%s也不在%s中\"%(x,str2,str3))\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##### 字符串格式化\n", "字符串有两种格式化方法。使用%或使用字符串本身的format函数。\n", "\n", "**1.使用%**\n", "\n", "类似于c语言中printf中的%。\n", "\n", "常见格式字符:%d 十进制整数, %x 十六进制整数;%f 浮点数;%% 百分号;%s字符串。\n", "例子如下:" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "这款手机的价格是2699.67,销量为100(对应十六进制为64),销售占比为56.100000%.\n" ] } ], "source": [ "name = '手机'\n", "price = 2699.66789\n", "num = 100\n", "rate = 56.1\n", "print(\"这款%s的价格是%.2f,销量为%d(对应十六进制为%x),销售占比为%F%%.\"%(name, price, num, num, rate))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**2.使用字符串的format函数**\n", "\n", "不同于使用%,format函数在字符串中使用了占位符槽(**{}**)概念。参数可以代入占位符。格式字符与**%**方式基本相同。\n", "\n", "还可使用{}中带数字的方法来使用后面指定位置参数,如{0},代表使用后面第1个参数。\n", "\n", "例子如下:" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "这款手机的价格是2699.66789\n", "这款手机的价格是2699.67,销量为100,销售占比为56.1%。销量对应的十六进制为64。\n", "这款手机的价格是2699.67,销量为100,销售占比为56.1%。销量对应的十六进制为64。\n" ] } ], "source": [ "name = '手机'\n", "price = 2699.66789\n", "num = 100\n", "rate = 56.1\n", "print(\"这款{}的价格是{}\".format(name,price))\n", "print(\"这款{}的价格是{:.2f},销量为{},销售占比为{}%。销量对应的十六进制为{:x}。\".format(name, price, num,rate,num))\n", "print(\"这款{0}的价格是{1:.2f},销量为{2},销售占比为{3}%。销量对应的十六进制为{2:x}。\".format(name, price, num,rate)) #指定顺序" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##### 字符串相关常用函数\n", "\n", "字符串专有函数:split, join, strip\n", "\n", "**split()** 通过指定分隔符对字符串进行切片\n", "\n", "**join()** 方法用于将序列中的元素以指定的字符连接生成一个新的字符串\n", "\n", "**strip()** 移除字符串头尾指定的字符(默认为空格)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#split\n", "str3 = \"a b c def g\"\n", "str3List = str3.split() #以1个空格或者多个空格为分隔符切片字符串\n", "print(str3List)\n", "str3 = 'x,y,z,abc,def' \n", "str3List = str3.split(',') #以,为分隔符切片字符串\n", "print(str3List)\n", "\n", "#join\n", "str1 = '-'\n", "print(str1.join(str3List)) #使用-拼接字符\n", "\n", "str2 = \" abc def \"\n", "print(str2.strip()) #移除字符串前后所有空格\n", "str2 = \"**1 * asdfdf 3445**\"\n", "print(str2.strip('*')) #移除字符串前后所有*,直到碰到其他字符\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##### 字符串与数值类型相互转化" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "str1 = str(123.5)\n", "num1 = int(\"12\")\n", "num2 = float(\"12.45\")\n", "print(type(str1),type(num1),type(num2))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 2.1.4 元组(tuple)\n", "与列表类似,但元组的元素不能修改,访问速度快,使用小括号()标识。" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " \n", "张三 19 ['语文', '数学', '英语']\n", "\n", "英语\n", "张三 19 ['语文', '数学', '英语'] \n", "元素修改演示:\n", "('张三', 19, ['体育', '数学', '英语'])\n" ] }, { "ename": "TypeError", "evalue": "'tuple' object does not support item assignment", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[0;32m 12\u001b[0m \u001b[0mstudent1\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m2\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;34m\"体育\"\u001b[0m \u001b[1;31m#可以修改成功。注意:这里并没有修改元组中的列表,而是修改元组中列表中所包含的元素\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 13\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mstudent1\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 14\u001b[1;33m \u001b[0mstudent1\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;36m18\u001b[0m \u001b[1;31m#出错!元组不支持修改其中的元素\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[1;31mTypeError\u001b[0m: 'tuple' object does not support item assignment" ] } ], "source": [ "student1 = (\"张三\",19,['语文','数学','英语']) #元组、列表中的元素均可为不同类型。\n", "print(type(student1[0]),type(student1[1]),type(student1[2]))#输出元组中每个元素的类型\n", "print(student1[0],student1[1],student1[2])\n", "x,y,z = student1 #序列解包\n", "print(type(z))\n", "print(student1[2][2])\n", "for e in student1: #元组也是序列\n", " print(e,end=\" \")\n", "print(\"\")\n", "tup1 = (50,); #只有一个元素的元组,注意:不能使用tup1=(50),这个表达式指的是tup1存放一个整数50\n", "print(\"元素修改演示:\")\n", "student1[2][0] = \"体育\" #可以修改成功。注意:这里并没有修改元组中的列表,而是修改元组中列表中所包含的元素\n", "print(student1)\n", "student1[1] = 18 #出错!元组不支持修改其中的元素" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 2.1.5 集合与字典\n", "\n", "集合与元组内容较多,请参见[集合与字典专题](https://nbviewer.jupyter.org/github/zhrb/NoteBook/blob/master/SetAndDict/SetAndDict.ipynb)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.1.5.1 集合(Set)\n", "集合中的元素不能重复,使用{}包括起来。 \n", "集合常用于去重、成员判断、数学运算。" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "set0 {1, 2}\n", "charSet {'c', 'b', 'e', 'a', 'd'}\n", "set1 {1, 2, 3, 4, 5}\n" ] } ], "source": [ "set0 = {1,2,1}\n", "print(\"set0\",set0)\n", "charSet = set(\"abcdeabcde\")\n", "print(\"charSet\",charSet)\n", "ls = [1,2,3,4,5,1,3,5]\n", "set1 = set(ls) #使用set来去重\n", "print(\"set1\",set1)\n", "set2 = set() #创建一个空集合,不能使用{}来创建空集合。因为这是一个字典\n", "if 7 in set1: #使用in或not in进行成员判断,否则remove一个不存在的元素会异常。\n", " set1.remove(7)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.1.5.2 字典(dict)\n", "字典的创建,可使用{}将一些`key:value`括起来。 \n", "**字典用法:**通过某个值(key)**快速查找**对应的值(value)。比如,通过**学号**这个key来查找**学生姓名**这个value。\n", "\n", "字典中的每一个元素都是一个键值对(key:value),类似于y=f(x)\n", "\n", "字典的键不能重复,值可以重复。\n", "\n", "示例如下:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "95\n", "dict_items([('张三', 95), ('李四', 95), ('王武', 85)])\n", "dict_keys(['张三', '李四', '王武'])\n", "dict_values([95, 95, 85])\n", "95\n", "None\n", "在字典中没找到'张',返回 0\n", "{}\n" ] } ], "source": [ "dict1 = {\"张三\":95,\"李四\":95,\"王武\":85}\n", "print(dict1[\"张三\"]) #通过key取得对应的value,可能会产生KeyError\n", "print(dict1.items()) #items()获得一个键值对视图\n", "print(dict1.keys()) #keys()获得一个键值视图\n", "print(dict1.values()) #valuess()获得一个值视图\n", "print(dict1.get(\"张三\")) #找到,返回95\n", "print(dict1.get(\"张\")) #没找到,返回None\n", "print(\"在字典中没找到'张',返回\",dict1.get(\"张\",0)) #没找到,返回指定的0\n", "emptyDict = {} #创建一个空字典,也可使用dict()创建空字典\n", "print(emptyDict)\n", "if \"赵二\" in dict1: #通过in或not in查看key是否在dict1的键集中。如果key不在dict1中,直接del dict1[key]会引发异常\n", " del dict1[\"赵二\"]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**练习(字典):**编写一个函数,统计一个字符串中每个字母出现的频率。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 2.2 流程控制" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 2.2.1 分支结构(if..elif..else...)\n", "if elif else 及break、continue用法基本同C与Java" ] }, { "cell_type": "code", "execution_count": 44, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1\n", "1 是奇数\n" ] } ], "source": [ "x = int(input())\n", "if x % 2 == 0:\n", " print(\"{} b是偶数\".format(x))\n", "else:\n", " print(\"{} 是奇数\".format(x))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**多重if..elif..lf语句**\n", "\n", "```\n", "x = int(input())\n", "if x > 0:\n", " print(\"大于0\")\n", "elif x == 0:\n", " print(\"等于0\")\n", "else:\n", " print(\"小于0\")\n", "``` " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 2.2.2 循环结构(for与while)\n", "和Java中的foreach循环很相似。" ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "a b c x y z \n" ] } ], "source": [ "ls = list(\"abcxyz\")\n", "for e in ls:\n", " print(e, end = \" \")\n", "print()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "但是没有c和java中普遍存在的`for(int i = 0; i < 5;i++)`语法,即,不存在每个元素都有着对应的下标。如何对每个元素赋予下标?" ] }, { "cell_type": "code", "execution_count": 46, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0 a\n", "1 b\n", "2 c\n", "[97, 98, 99]\n" ] } ], "source": [ "ls = list(\"abc\")\n", "for i,e in enumerate(ls):\n", " print(i,e)\n", " ls[i] = ord(e)\n", "print(ls)" ] }, { "cell_type": "code", "execution_count": 47, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "hi\n", "You just input: hi\n", "quit\n", "end\n" ] } ], "source": [ "# 输入quit推出,输入其他值直接输出\n", "x = input()\n", "while (x!='quit'):\n", " print('You just input:',x)\n", " x = input()\n", "print('end')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 2.2.3 pass关键字\n", "仅用于占位,什么都不做" ] }, { "cell_type": "code", "execution_count": 48, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "n\n" ] } ], "source": [ "x = input()\n", "if x == \"n\": #如果x==n,则什么都不做\n", " pass\n", "else: \n", " print(x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**pass常见方法:**\n", "\n", "定义函数、类的时候还未想好定义,或者某个部分暂时不知道怎么写的使用pass关键字代替" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def foo():\n", " pass\n", "\n", "class StuClass:\n", " pass\n", "\n", "foo() #调用foo函数,碰到pass,什么也不做" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 2.3 其他" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 2.3.1 del 关键字\n", "\n", "del作用于变量名与列表名,将解除变量与值之间的指向关系。当再次使用时,将出现NameError。" ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [ { "ename": "NameError", "evalue": "name 'x' is not defined", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[0mx\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;36m3\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 2\u001b[0m \u001b[1;32mdel\u001b[0m \u001b[0mx\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 3\u001b[1;33m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mx\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[1;31mNameError\u001b[0m: name 'x' is not defined" ] } ], "source": [ "x = 3\n", "del x\n", "print(x) #会出错,因为x已经被释放" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "ename": "NameError", "evalue": "name 'list1' is not defined", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[0mlist1\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m[\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;36m2\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;36m3\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 2\u001b[0m \u001b[1;32mdel\u001b[0m \u001b[0mlist1\u001b[0m \u001b[1;31m#这里是删除列表,也可以删除某个元组\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 3\u001b[1;33m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mlist1\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;31m#会出错,因为list1已经被释放\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[1;31mNameError\u001b[0m: name 'list1' is not defined" ] } ], "source": [ "list1 = [1,2,3]\n", "del list1 #这里是删除列表,也可以删除某个元组\n", "print(list1) #会出错,因为list1已经被释放" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "将del用于列表中的某个元素,为删除该元素。\n", "\n", "**注1:**del不能用于元组,因为元组是不可变序列" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[0, 1, 2, 4, 5, 6, 7, 8, 9, 10]\n", "[0, 1, 2, 4, 5, 9, 10]\n" ] } ], "source": [ "list1 = [0,1,2,3,4,5,6,7,8,9,10]\n", "del list1[3]\n", "print(list1)\n", "del list1[5:8] #删除分片\n", "print(list1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 2.3.2 生成列表与列表生成式\n", "有多种方式生成列表。" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "ls1= [] ls2= [1, 2, 3] ls3= [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n", "['a', 'b', 'c']\n", "[1, 2, 3]\n", "[1, 3, 5]\n", "ls4= [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] id(ls3)==id(ls4) False\n", "[0, 2, 4, 6, 8]\n" ] } ], "source": [ "ls1 = [] #生成一个空的列表\n", "ls2 = [1,2,3] #定义的时候直接生成一个列表\n", "ls3 = list(range(10)) #利用range函数生成列表\n", "print('ls1=',ls1,'ls2=',ls2,'ls3=',ls3)\n", "print(list(\"abc\")) #利用可迭代对象(字符串)生成列表\n", "print(list(ls2)) #利用可迭代对象(列表)生成列表\n", "print(list((1,3,5))) #利用可迭代对象(元组)生成列表\n", "ls4 = ls3[::] #利用切片生成一个列表\n", "print('ls4=',ls4,'id(ls3)==id(ls4)',id(ls3)==id(ls4))\n", "for e in ls3: #将ls3中的所有偶数都加入ls1中\n", " if e % 2 == 0:\n", " ls1.append(e)\n", "print(ls1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**列表生成(推导)式(List Comprehension)**" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']\n", "[0, 2, 4, 6, 8]\n", "将nestedls变平 [1, 1, 1, 2, 2, 2, 3, 3, 3]\n" ] } ], "source": [ "ls = list(range(10))\n", "strls = [str(e) for e in ls] #将ls中的元素转化为字符串然后放入新生成的列表\n", "print(strls)\n", "evenls = [e for e in ls if e % 2 == 0] #将ls中的所有偶数抽出放到一个新的列表中\n", "print(evenls)\n", "\n", "nestedls = [[1,1,1],[2,2,2],[3,3,3]]\n", "ls1 = [e for line in nestedls for e in line ]\n", "print(\"将nestedls变平\",ls1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 2.3.3 yield关键字\n", "**简述:**yield常用于函数体内,用来返回值,有点类似return。但与return不同的是,return将值返回后跳出函数,yield则将值返回但不跳出函数而是挂起等待。当下一次再访问该函数时,则从上一次挂起等待的地方(即上一次执行yield的地方)继续往下执行。\n", "\n", "**原理**:yield关键字将函数变成一个**生成器(generator)**。当调用带有yield语句的函数时,获得一个生成器,然后往下执行直到碰到**yield**,然后挂起(suspend)并返回值。下一次再调用该函数时,从挂起的地方继续执行。" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "first in\n", "1\n", "4\n", "9\n", "16\n", "25\n" ] } ], "source": [ "def foo():\n", " print(\"first in\") #多次调用也只执行1次\n", " i = 1\n", " while True: #看起来要生成并返回无穷多个数,然而因为使用了yield关键字,只有当调用foo函数的时候,才返回1次值,而不是一下全部返回。\n", " yield i**2 #执行到这句通过yield返回值,然后停下来等待下一次的调用。下一次调用时,再接下去执行,然后再通过yield返回值。\n", " i += 1\n", " print(\"end.\") #这句永远不会被执行,思考一下为什么?\n", "\n", "\n", "x = 0\n", "for e in foo(): #使用for e in foo()这种方式调用,使得foo()看起来像是一个元素的集合,但实际上不是。而是调用1次,计算并返回1次。\n", " print(e)\n", " x += 1\n", " if x == 5:\n", " break" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 3. 函数\n", "## 3.1 函数的定义与基本使用\n", "### 3.1.1 函数的基本概念\n", "使用**def**关键字定义函数,使用缩进(一般采用4个空格)区分函数体。 \n", "定义函数一般考虑3大部分:函数名、入参(也可以无)、返回值。 \n", "编写函数时应按规范编写注释、且函数名、入参命名等要简单易懂。如下所示。" ] }, { "cell_type": "code", "execution_count": 76, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "5050\n", "*5050\n", "***5050***\n", "******5050*****\n", "********5050********\n" ] } ], "source": [ "def printX(x, n):\n", " print(str(x).center(n, \"*\" )) #x字符居中对齐,且占n个字符,不足部分用*填充\n", " \n", "def addFromBeginToEnd(begin, end): #函数定义\n", " '''累加从begin到end(包括end)之间的所有整数 \n", " Args:\n", " begin:累加的第一个值\n", " end: 累加的最后一个值\n", "\n", " Returns:\n", " 返回从begin到end(包括end)之间的所有整数之和\n", " '''\n", " n = 0\n", " for i in range(begin, end):\n", " n += i\n", " return n\n", "\n", "result = addFromBeginToEnd(1,101) #函数调用时直接使用:函数名(入参..) 的形式\n", "for i in range(5):\n", " printX(result, i*5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 3.1.2 函数的返回值\n", "\n", "`return`语句用于跳出函数,也可用来返回值。" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "12 23 34 " ] } ], "source": [ "def findX(numList, x):\n", " '''\n", " 如果找到x则跳出,否则输出\n", " '''\n", " for e in numList:\n", " if x == e:\n", " return\n", " print(e, end = \" \")\n", "\n", "xList = \"12 23 34 end 1 2\".split()\n", "findX(xList, \"end\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**1. Python中函数可以有多个返回值,函数值以元组形式返回**" ] }, { "cell_type": "code", "execution_count": 87, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " ('a', 'test!')\n", "a test!\n" ] } ], "source": [ "def findMinAndMaxWord(strList):\n", " minW = maxW = strList[0]\n", " for e in strList:\n", " maxW = e if len(e) > len(maxW) else maxW\n", " minW = e if len(e) < len(minW) else minW\n", " return minW, maxW\n", "\n", "strList = \"This is a test!\".split()\n", "result = findMinAndMaxWord(strList)\n", "print(type(strList), result)\n", "mx, mw = findMinAndMaxWord(strList) #自动解包\n", "print(mx, mw)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**2. Python中的函数如过无return语句,则返回None**" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "test\n", " None\n" ] } ], "source": [ "def foo():\n", " print(\"test\")\n", " \n", "x = foo()\n", "print(type(x), x)" ] }, { "attachments": { "%E5%9B%BE%E7%89%87.png": { "image/png": "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" } }, "cell_type": "markdown", "metadata": {}, "source": [ "### 3.1.3 Lambda表达式\n", "\n", "Lambda表达式可用于创建匿名函数。形式如下 : \n", "`lambda <参数列表>: <表达式>` \n", "参数列表为匿名函数的入参,\"return 表达式\"为匿名函数的函数体。如下图所示:\n", "![%E5%9B%BE%E7%89%87.png](attachment:%E5%9B%BE%E7%89%87.png)\n", "\n", "使用Lambda表达式创建的是函数对象。可将该函数对象赋值给一个变量,然后通过该变量就可以调用该函数对象。形式如下所示:\n", "\n", "```\n", "func1 = lambda <参数列表>: <表达式> #定义\n", "func1(<参数列表>) #通过func1变量调用该函数对象\n", "``` \n", "\n", "通过lambda表达式定义的函数与正常函数一样,是函数定义的简化写法。" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " 5\n" ] } ], "source": [ "func1 = lambda x, y: x +y\n", "print(type(func1), func1(2, 3)) #可以看到lambda表达式是一个function类对象" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**lambda表达式小练习:**" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "b\n", "B\n", "2\n", "100\n" ] } ], "source": [ "key = lambda x:x[1]\n", "print(key(\"abc\")) #返回b\n", "key = lambda x:x[1].upper()\n", "print(key(\"abc\")) #返回B\n", "key = lambda a, b: a if a>b else b #返回较大的值\n", "print(key(1,2))\n", "print(key(100,9))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**lambda表达式的应用:**\n", "\n", "Lambda表达式应用广泛。Python内置函数`sorted`就可通过接收不同的函数(可以用Lambda表达式),来实现对不同关键字进行排序。" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[(1, 'zhang', 65), (2, 'chen', 76), (3, 'Fang', 76), (4, 'bo', 56), (5, 'li', 100)]\n", "[(3, 'Fang', 76), (4, 'bo', 56), (2, 'chen', 76), (5, 'li', 100), (1, 'zhang', 65)]\n", "[(4, 'bo', 56), (2, 'chen', 76), (3, 'Fang', 76), (5, 'li', 100), (1, 'zhang', 65)]\n", "[(4, 'bo', 56), (1, 'zhang', 65), (3, 'Fang', 76), (2, 'chen', 76), (5, 'li', 100)]\n", "[(4, 'bo', 56), (1, 'zhang', 65), (3, 'Fang', 76), (2, 'chen', 76), (5, 'li', 100)]\n" ] } ], "source": [ "#学生数据以元组形式存储,分别是\"编号、姓名、分数\"\n", "xList = [(1,\"zhang\", 65), (3, \"Fang\", 76),(5, \"li\", 100), (4, \"bo\", 56), (2, \"chen\", 76)]\n", "\n", "print(sorted(xList, key = lambda x: x[0])) #按编号排序\n", "print(sorted(xList, key = lambda x: x[1])) #按姓名排序\n", "print(sorted(xList, key = lambda x: x[1].lower())) #忽略大小写按姓名排序\n", "print(sorted(xList, key = lambda x: x[2])) #按成绩排序\n", "print(sorted(xList, key = lambda x: x[2])) #按成绩排序" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "key参数为函数,可以使用Lambda表达式。排序过程中,两个元素比较前,要对元素调用key所指定的函数。 \n", "然后,对函数调用后的结果进行比较。比如`(1,\"zhang\", 65)`和`(3, \"fang\", 76)`这两个元素进行比较。如果 \n", "指定`key = lambda x: x[0]`,那么对这两个元素应用该Lambda表达式分别得到值`1`和`3`。也就是对这两个值 \n", "进行比较。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 3.2 函数的参数\n", "### 3.2.1 参数按值传递(passed by value)\n", "\n", "**实参:** 是函数调用时实际传递的值。如下述代码的第7行的n。n里面存储的实际的值。 \n", "\n", "**形参:** 函数定义时声明的变量。如下述代码第一行中的x。顾名思义,在定义的时候,形参只是一个标识符,不存储任何的值。\n", "\n", "**调用过程中的参数传递:**\n", "\n", "对如下代码。`n = 5`中n存放的不是5这个值本身,存放的是只想`5`这个对象的引用。 \n", "因此执行`test(n)`是,实际上是将实参n的值(即,指向`5`这个对象的引用值)赋值给形参x。这时候x存放的就是指向`5`的这个引用值。 \n", "在执行了`x = x + 10`之后。因为数值类型是不可变的。因此x指向了新生成的对象。" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "id(n) = 140724864512384\n", "Before Change id(x) = 140724864512384\n", "After Change id(x) = 140724864512704\n", "15\n" ] } ], "source": [ "def test(x):\n", " print(\"Before Change id(x) =\", id(x)) #形参x的id与实参n的id一样\n", " x = x + 10\n", " print(\"After Change id(x) =\", id(x))\n", " return x\n", " \n", "n = 5\n", "print(\"id(n) =\", id(n))\n", "print(test(n))\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**小思考:** \n", "如下代码中`changeX`函数能改变n的值吗?为什么" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1\n" ] } ], "source": [ "def changeX(x):\n", " x = 10\n", "\n", "n = 1\n", "changeX(n)\n", "print(n)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 3.2.2 默认值参数、关键参数、可变量参数\n", "\n", "**默认值参数:**函数定义的时候,指定参数的**默认值**。需放在函数所有形参的最右边。调用时如不指定默认值参数的值,则用**默认值**。\n", "\n", "**关键参数:**可以按参数名字传递值,实参顺序可以和形参顺序不一致。\n", "\n", "**可变数量参数:**如果为函数定义了可变数量参数。调用函数时,传递的变量个数可变。参数以元组或字典形式传入。" ] }, { "cell_type": "code", "execution_count": 35, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "演示:默认值参数\n", "(2, 1) (2, 2) (2, 3) (3, 4)\n", "演示:关键参数\n", "(1, 2, 3) (3, 2, 1)\n", "演示:可变数量参数,参数前1个*\n", " ()\n", "\n", " (1,)\n", "1 \n", " (1, 2, 3)\n", "1 2 3 \n", "演示:可变数量参数,参数前2个*\n", " {}\n", "\n", " {'x': 1, 'y': 2}\n", "('x', 1) ('y', 2) \n" ] } ], "source": [ "#演示:默认值参数\n", "print(\"演示:默认值参数\")\n", "def foo(x, y = 1):\n", " return x, y\n", "\n", "print(foo(2), foo(2, 2), foo(2, y = 3), foo(x = 3, y = 4))\n", "\n", "\n", "#演示:关键参数\n", "print(\"演示:关键参数\")\n", "def fooK(x, y, z):\n", " return x, y, z\n", "\n", "print(fooK(1, 2, 3), fooK(z = 1, x = 3, y =2))\n", "\n", "#演示:可变数量参数,参数前1个*\n", "print(\"演示:可变数量参数,参数前1个*\")\n", "def fooV(*x): # *x,代表的是将多个参数以元组的形式传入函数\n", " print(type(x),x)\n", " for e in x:\n", " print(e, end = \" \")\n", " print()\n", "\n", "fooV()\n", "fooV(1)\n", "fooV(1, 2, 3)\n", "\n", "#演示:可变数量参数,参数前2个*\n", "print(\"演示:可变数量参数,参数前2个*\")\n", "def fooVV(**x): # **x,代表的是将多个参数以字典的形式传入函数\n", " print(type(x), x)\n", " for e in x.items():\n", " print(e, end = \" \")\n", " print()\n", "\n", "fooVV() \n", "fooVV(x = 1, y = 2) #参数必须以 arg1 = value1, arg2 = value2 ...这样的方式给出" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 3.2.3 变量作用域\n", "\n", "**局部变量:**在函数内部定义的变量只在当前函数内部起作用。\n", "\n", "**全局变量:**在函数内使用`global`关键字声明的变量,能够同时作用于函数内外。" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# 演示:局部变量\n", "def test(n):\n", " i = 0 #i为局部变量\n", " for e in range(n):\n", " i += 1\n", " \n", "\n", "test(5)\n", "print(x) # 报错:name 'x' is not defined" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Before test(): x = 3, n = 2\n", "After test(): x = 3, n = 5\n" ] } ], "source": [ "# 演示:全局变量\n", "x = 3\n", "n = 2\n", "def test():\n", " x = 7 #这里给x赋值,使得x成为局部变量。不再是函数外定义的那个x。\n", " global n\n", " n = 5\n", " \n", "print(\"Before test(): x = {}, n = {}\".format(x, n))\n", "test()\n", "print(\"After test(): x = {}, n = {}\".format(x, n)) #可以看到x未被改变,而被声明为global的n被改变了" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "函数外创建的变量其作用域包括函数内部。即,函数内可以访问函数外定义的变量,但不能改变该变量的值。 \n", "换句话说:函数不能修改函数外创建的变量,但可以修改函数外创建的变量所指向的对象(如list)内部的值。 " ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Before: x = 3, xList = []\n", "3\n", "[]\n", "After: x = 3, xList = [0, 1, 2, 3, 4]\n" ] } ], "source": [ "# 演示:全局变量\n", "\n", "def test(n):\n", " print(x) #可以获得函数外的x所指向的值。此处未改变x存储的引用。\n", " print(xList) #可以获得函数心里的xList所指向的列表。此处未改变xList存储的引用。\n", " #x = 5 #会出错。因为 x = 5 代表x是局部变量。那么第4行的print(x)就使得x在第6行赋值前就被引用。所以报错\n", " for e in range(n):\n", " xList.append(e) #此处知识改变了xList指向的那个列表列表内部的值,所以不会出错。\n", "\n", "xList = []\n", "print(\"Before: x = {}, xList = {}\".format(x, xList))\n", "test(5)\n", "print(\"After: x = {}, xList = {}\".format(x, xList))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 3.3 函数对象\n", "在Python中函数也是对象。 \n", "在代码中只写函数名,而不写后面的括号与参数,就代表要使用的是函数对象。" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " \n", "True\n", "3 3\n", "__annotations__ __call__ __class__ __closure__ __code__ __defaults__ __delattr__ __dict__ __dir__ __doc__ __eq__ __format__ __ge__ __get__ __getattribute__ __globals__ __gt__ __hash__ __init__ __init_subclass__ __kwdefaults__ __le__ __lt__ __module__ __name__ __ne__ __new__ __qualname__ __reduce__ __reduce_ex__ __repr__ __setattr__ __sizeof__ __str__ __subclasshook__ " ] } ], "source": [ "def foo(x, y):\n", " return x + y\n", "\n", "fun1 = foo #这时候fun1与foo是同一个函数对象。相当于为foo函数起了一个别名\n", "print(type(fun1), type(foo))\n", "print(id(fun1) == id(foo))\n", "print(fun1(1, 2), foo(1,2))\n", "for e in dir(foo): #列出函数对象的所有方法\n", " print(e, end = \" \")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**函数对象作为函数参数:**\n", " \n", "函数对象可以作为函数的参数值传递进去(实际上是指向函数的引用传递到函数中去)。类似C语言中的函数指针。 \n", "这为Python编程带来极大的灵活性。\n", "\n", "下述代码中的`applyFxToNumbers`适用于所有接收两个入参的函数。从`addAB`到`complex`函数均可用于`applyFxToNumbers`。" ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "3\n", "-1\n", "2\n", "(1+2j)\n" ] } ], "source": [ "def applyFxToNumbers(fx, a, b):\n", " return fx(a, b)\n", "\n", "def addAB(a, b):\n", " return a + b\n", "\n", "fx = lambda a, b: a * b\n", "print(applyFxToNumbers(addAB, 1, 2))\n", "print(applyFxToNumbers(lambda a,b: a - b, 1, 2))\n", "print(applyFxToNumbers(fx, 1, 2))\n", "print(applyFxToNumbers(complex, 1, 2))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 3.4 递归函数\n", "\n", "函数可以被别人调用,也可在函数内部中被自己调用。 \n", "\n", "**递归函数**:在函数内部直接调用自己或通过一系列的调用语句间接地调用自己的函数。\n", "\n", "递归程序包含两大特征:\n", "1. 调用自身。\n", "2. 必须有递归出口。保证递归函数不会无限调用下去。" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "3\n", "2\n", "1\n", "0\n", "2\n", "4\n", "6\n", "递归函数最终返回值: 6\n" ] } ], "source": [ "def foo(n):\n", " print(n)\n", " if n == 0: # 2. 递归出口。只有n == 0,就跳出本次调用。\n", " return 0 \n", " x = 2 + foo(n-1) # 1.调用自身\n", " print(x)\n", " return x\n", " \n", "print(\"递归函数最终返回值:\",foo(3))# 输出什么?why?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**使用递归思想解决问题:**\n", "\n", "一般来说可以使用递归解决的问题,都可以化简为**与原问题相似**但**规模更小的问题**。\n", "\n", "比如求n!。求解n!这个问题可以化简为如下步骤:\n", "1. 求解(n-1)!这个规模更小,但于与问题相似的问题。\n", "2. 将n*r。该问题直接可解。\n", "\n", "其中第1步又可不断化简,直到`n=1`的时候,即求解1!这个问题。1!结果为1,问题解决。然后将结果不断返回进行上层进行步骤2。\n", "\n", "在这个问题的求解中,我们看到了可以使用递归函数解决该问题。代码如下:" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "求解5!问题\n", "求解4!问题\n", "求解3!问题\n", "求解2!问题\n", "求解1!问题\n", "1! = 1\n", "2! = 2\n", "3! = 6\n", "4! = 24\n", "5! = 120\n", "120\n" ] } ], "source": [ "def fac(n): #求解n!\n", " print(\"求解{}!问题\".format(n))\n", " if n == 1:\n", " print(\"{}! = {}\".format(n, 1))\n", " return 1\n", " result = n*fac(n-1)\n", " print(\"{}! = {}\".format(n, result))\n", " return result\n", "print(fac(5))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**小练习:尝试使用递归思想解决如下问题**\n", "\n", "1. 求解斐波那契数列\n", "2. 在一个列表中找到最大的数\n", "3. 拆分整数\n", "4. 结合tutle库使用递归法绘制二叉树\n", "\n", "**拆分整数:**\n", "这个问题考察的是如何将一个自然数拆成若干个小自然数的和,比如: \n", "```\n", "3 = 3\n", "3 = 2 + 1\n", "3 = 1 + 1 + 1\n", "```\n", "或者\n", "```\n", "5 = 5\n", "5 = 4 + 1\n", "5 = 3 + 2\n", "5 = 3 + 1 + 1\n", "5 = 2 + 2 + 1\n", "5 = 2 + 1 + 1 + 1\n", "5 = 1 + 1 + 1 + 1 + 1\n", "```\n", "很明显这里只考虑不同的小自然数的组合,顺序是无关的,所以5=2+3和5=3+2被认为是一样 \n", "的。写个小程序(语言不限),找出来12345这个数有多少种拆分方法" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 3.5 常用函数\n", "### 3.5.1 id、sorted与reversed函数\n", "\n", "**id(x)**: 获取变量x的id,可通过此函数判定两个变量是否指向同一个对象 \n", "\n", "**sorted(ls)**: 返回一个新的排序好的(升序)列表,并未改变ls。不同于list.sort()方法,list.sort()方法是就地排序,即对序列本身排序,不返回新的列表。\n", "\n", "**reversed(ls)**: 返回一个ls的逆序迭代器。**注意:**不是返回一个ls的逆序列表,而是返回一个**逆序迭代器**。list.reverse()就地逆序。\n", "\n", "**注意:**升序与降序对应,逆序与顺序对应。\n" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "------------------------------------------------id演示------------------------------------------------\n", "x与y的地址一样: 140734523601152 140734523601152\n", "两个列表的地址不一样,地址分别为: 2561276168264 2561276168328\n", "---------------------------------------sorted()与list.sort()演示---------------------------------------\n", "升序排序前ls: [3, 1, 2]\n", "升序排序后ls: [3, 1, 2]\n", "升序排序后新生成的ls3: [1, 2, 3]\n", "升序排序后生成了一个新的列表ls3,并未改变原来的列表ls: 2561276168264 2561276168648\n", "就地升序排序后,ls中的值: [1, 2, 3]\n", "-----------------------------------------------降序排序演示-----------------------------------------------\n", "降序排序前ls2: [4, 5, 3]\n", "降序排序后新生成的reversels: [5, 4, 3]\n", "就地降序排序后ls2: [5, 4, 3]\n", "-----------------------------------逆序演示:reversed()与list.reverse()-----------------------------------\n", "逆序输出前ls: [1, 2, 3]\n", "逆序输出后ls: [1, 2, 3]\n", "逆序输出后的结果:321\n", "对ls就地逆序: [3, 2, 1]\n" ] } ], "source": [ "print(\"{:-^100}\".format(\"id演示\"))\n", "x,y = 1,1\n", "print(\"x与y的地址一样:\",id(x),id(y))\n", "\n", "ls = [3,1,2]\n", "ls1 = [3,1,2]\n", "ls2 = [4,5,3]\n", "print(\"两个列表的地址不一样,地址分别为:\",id(ls),id(ls1))\n", "\n", "print(\"{:-^100}\".format(\"sorted()与list.sort()演示\"))\n", "\n", "print(\"升序排序前ls:\",ls)\n", "ls3 = sorted(ls)\n", "print(\"升序排序后ls:\",ls)\n", "print(\"升序排序后新生成的ls3:\",ls3)\n", "print(\"升序排序后生成了一个新的列表ls3,并未改变原来的列表ls:\",id(ls),id(ls3))\n", "ls.sort() #就地排序\n", "print(\"就地升序排序后,ls中的值:\",ls)\n", "print(\"{:-^100}\".format(\"降序排序演示\"))\n", "print(\"降序排序前ls2:\",ls2)\n", "reversels = sorted(ls2, reverse = True) #降序排列\n", "print(\"降序排序后新生成的reversels:\",reversels)\n", "ls2.sort(reverse = True)\n", "print(\"就地降序排序后ls2:\",ls2)\n", "\n", "print(\"{:-^100}\".format(\"逆序演示:reversed()与list.reverse()\"))\n", "print(\"逆序输出前ls:\",ls)\n", "ls4 = reversed(ls)\n", "print(\"逆序输出后ls:\", ls)\n", "print(\"逆序输出后的结果:\", end = \"\")\n", "for e in ls4:\n", " print(e, end = \"\")\n", "print()\n", "ls.reverse()\n", "print(\"对ls就地逆序:\",ls)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 3.5.2 sorted函数可用于所有序列(字符串、列表、元组)数据类型\n", "\n", "**sorted(x):**可以对序列x进行排序,并返回**新**的序列。 \n", "sorted函数接收`key`参数与`reversed`参数。 \n", "- `key`为一个函数,作用于每个元素。用于抽取所要比较的元素。\n", "- `reverse`为布尔值,决定是否逆序排序,默认为False\n", "\n", "列表本身也有sort方法,对列表本身进行排序(就地排序),不产生新队列。同时,也接收`key`于`reverse`参数。 \n", "\n", "**多关键字排序:**请见Operator模块。" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "sorted()函数可以应用于所有序列类型(字符串、列表、元组),reversed()也可以应用于所有序列类型\n", "对列表应用sorted()\n", "排序前ls: ['1d', '3A', '2b', '5C']\n", "排序后ls: ['1d', '3A', '2b', '5C']\n", "排序后ls2: ['1d', '2b', '3A', '5C']\n", "id(ls) = 2727408171272 id(ls2) = 2727446183112\n", "对ls进行就地排序: ['1d', '2b', '3A', '5C']\n", "对ls中的元素的第2个元素逆序排序: ['1d', '2b', '5C', '3A']\n", "对字符串应用sorted()\n", "排序前: DabCe\n", "排序后: DabCe\n", "忽略大小写后进行排序: ['a', 'b', 'C', 'D', 'e']\n", "对元组应用sorted()\n", "排序前t1: (3, 2, 1, 5, 4)\n", "排序后t2: [1, 2, 3, 4, 5]\n", "[1, 2, 3, 4, 5]\n" ] } ], "source": [ "print(\"sorted()函数可以应用于所有序列类型(字符串、列表、元组),reversed()也可以应用于所有序列类型\")\n", "ls = [\"1d\",\"3A\",\"2b\",\"5C\"]\n", "print(\"对列表应用sorted()\")\n", "print(\"排序前ls:\",ls)\n", "ls2 = sorted(ls)\n", "print(\"排序后ls:\",ls)\n", "print(\"排序后ls2:\",ls2)\n", "print(\"id(ls) = \",id(ls), \"id(ls2) = \",id(ls2)) #id不一致,说明ls2是新的列表\n", "ls.sort()\n", "print(\"对ls进行就地排序:\",ls)\n", "\n", "print(\"对ls中的元素的第2个元素逆序排序:\", sorted(ls, key = lambda x: x[1], reverse = True)) #对ls中的元素的第2个元素逆序排序,并生成新列表\n", "\n", "chars = \"DabCe\"\n", "print(\"对字符串应用sorted()\")\n", "print(\"排序前:\",chars)\n", "chars2 = sorted(chars)\n", "print(\"排序后:\",chars)\n", "print(\"忽略大小写后进行排序:\",sorted(chars, key = str.lower)) #注意:要传递进去的是str.lower函数对象\n", "\n", "t1 = (3,2,1,5,4)\n", "print(\"对元组应用sorted()\")\n", "print(\"排序前t1:\",t1)\n", "t2 = sorted(t1)\n", "print(\"排序后t2:\",t2)\n", "print(t2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 3.5.3 eval函数\n", "\n", "**eval(strx)**: 将字符串strx进行表达式来运算。" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eval演示\n", "6 3 5\n", "abc6\n", " [1, 2, 3]\n", " {'zhang': '张', 'chen': '陈'}\n" ] } ], "source": [ "print(\"eval演示\")\n", "str1,str2 = \"6\",\"1+2\"\n", "a = 3\n", "str3 = \"a+2\"\n", "print(eval(str1),eval(str2),eval(str3))\n", "str4 = \"'abc'+str1\"\n", "print(eval(str4))\n", "xlist = eval(\"[1, 2, 3]\") #用eval生成列表\n", "print(type(xlist), xlist)\n", "dict1 = eval('{\"zhang\":\"张\",\"chen\":\"陈\"}')#用eval生成字典\n", "print(type(dict1), dict1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 3.5.4 map函数\n", "\n", "将指定函数应用于某个可迭代对象(序列、集合、range等)中的每个元素。\n", "\n", "**例1. 将字符串中的每个元素转换成int型。**" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "1 \n", "2 \n", "3 \n", "4 \n", "5 \n" ] } ], "source": [ "strx = \"1 2 3 4 5\"\n", "strList = strx.split()\n", "xmap = map(int, strList) #将int函数应用于strList中的每个元素\n", "print(type(xmap))\n", "for e in xmap:\n", " print(e,type(e))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**例2. map函数常与list函数配合使用。使用list函数可将map对象转化为列表。**" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "字符串列表被转化为int列表xlist: [1, 2, 3, 4, 5]\n", "字符串(字符列表)转化为int列表: [1, 2, 3, 4, 5]\n" ] } ], "source": [ "xlist = list(map(int, strList))\n", "print(\"字符串列表被转化为int列表xlist:\", xlist)\n", "print(\"字符串(字符列表)转化为int列表:\",list(map(int, \"12345\"))) #将字符串序列中每个元素转化为int型" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**例3. map函数与lambda函数配合使用**" ] }, { "cell_type": "code", "execution_count": 57, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['Zhang', 'Wang', 'Li', 'Chen']\n", "[6, 7, 8, 9, 10]\n" ] } ], "source": [ "nameList = \"zhang wang li chen\".split() \n", "print(list(map(lambda x: x.capitalize(), nameList))) #首字母大写\n", "print(list(map(lambda x: x + 5, xlist))) #对序列中每个元素加5" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**4.将map函数包含两个及以上的入参**" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['Zhang飞', 'Wang宇', 'Chen官', 'Li逵']\n" ] } ], "source": [ "lastNameList = \"Zhang Wang Chen Li\".split()\n", "firstNameList = \"飞 宇 官 逵\".split()\n", "#将两个序列中的元素依次拼接\n", "print(list(map(lambda x, y: x+y, lastNameList, firstNameList)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 3.5.5 zip函数\n", "**zip**,英文中拉链的意思。就像拉链可以将拉链两侧的齿扣严丝合缝的一一扣起来。zip函数可将多个可迭代对象(如序列等)中的元素一一对应绑起来(这些元素以元组形式绑起来),然后以**元组**迭代器的形式返回。 \n", "\n", "**例1. 将多个列表中的元素zip起来。**" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "元组迭代器zipped中的内容(两个列表):\n", "(1, 4)\n", "(2, 5)\n", "(3, 6)\n", "元组迭代器zipped1中的内容(三个列表):\n", "(1, 4, 7)\n", "(2, 5, 8)\n", "(3, 6, 9)\n" ] } ], "source": [ "a = [1, 2, 3]\n", "b = [4, 5, 6]\n", "zipped = zip(a, b) #这时候得到了一个迭代器zipped,里面包含了来自a,b两个列表中一一对应的元素组成元组迭代器。\n", "print(\"元组迭代器zipped中的内容(两个列表):\")\n", "for e in zipped:\n", " print(e)\n", "\n", "c = [7, 8, 9]\n", "zipped1 = zip(a, b, c)\n", "print(\"元组迭代器zipped1中的内容(三个列表):\")\n", "for e in zipped1:\n", " print(e)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**例2. zip函数常与list函数配合使用。**\n", "使用list可将zip对象转化为列表。" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[(1, 4, 7), (2, 5, 8), (3, 6, 9)]\n" ] } ], "source": [ "ziplist = list(zip(a,b,c))\n", "print(ziplist)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**例3. zip函与*运算符结合可用来将一个zip迭代对象拆成列表。**" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " (1, 2, 3)\n", " (4, 5, 6)\n" ] } ], "source": [ "a = [1, 2, 3]\n", "b = [4, 5, 6]\n", "zipped = zip(a, b) #(1, 4), (2, 5), (3, 6)\n", "x, y = zip(*zipped) #*把上面由a与b绑起来的zip对象拆开,然后用zip组装成元组x与y\n", "print(type(x), x)\n", "print(type(y), y)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**例4. 使用zip函数快速生成字典。**" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{90: 'A', 80: 'B', 70: 'C', 60: 'D'}\n" ] } ], "source": [ "grade = [90,80,70,60]\n", "level = ['A','B','C','D']\n", "gradeDict = dict(zip(grade,level))\n", "print(gradeDict)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 3.5.6 filter函数\n", "筛选出某个可迭代对象(如列表等)中符合要求的元素。使用指定函数来判断该元素是否符合要求。" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " [91, 92, 93, 94, 95, 96, 97, 98, 99]\n", "[0, 25, 50, 75]\n", "['b', 'c', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'p']\n" ] } ], "source": [ "xlist = list(range(100))\n", "\n", "def greaterThan90(x):\n", " return x > 90\n", "result = filter(greaterThan90, xlist)\n", "print(type(result), list(result))\n", "\n", "result = filter(lambda x: x % 25 == 0, xlist) #返回了一个迭代器\n", "print(list(result))\n", "\n", "#输出所有不是aeiou的字符\n", "print(list(filter(lambda x: x not in \"aeiou\", \"abcdefghijklmnop\")))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 3.5.7 reduce函数\n", "reduce函数是**functools**模块中的一个函数。其形式为`reduce(function, iterable[, initializer])`。 \n", "该函数对可迭代对象(如列表、range对象等)中的元素,从左到右,对其中的元素依次应用有两个入参 \n", "的函数(function),从而实现累积运算,最后将值返回。 \n", "\n", "这个过程就相当于,把迭代对象中多个元素,通过逐步处理,逐渐reduce(缩减)为一个值。\n", "\n", "为了说明方便,以下例子使用列表进行说明:\n", "\n", "**1.如果列表中只有一个元素,且不设置初值(initializer)** \n", "\n", "使用reduce函数应用于这样的列表,直接返回列表中的元素。见如下代码3-4行。\n", "\n", "**2.如果列表中只有一个元素,但设置初值** \n", "\n", "如下代码6-8行,将初值100赋值给x,列表中的第1个值10赋值给y。然后计算`x+y`。" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1\n", " 110\n" ] } ], "source": [ "from functools import reduce\n", "\n", "xlist = [1]\n", "print(reduce(lambda x, y: x+y, xlist))\n", "\n", "xlist = [10]\n", "n = reduce(lambda x, y: x + y, xlist, 100)\n", "print(type(n), n)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**3.如果列表中超过1个元素,不设置初值** \n", "\n", "如下代码3-4行中。第一趟,将迭代过程的初值x设为第一个元素1,然后从xlist中取出下一个值(2)赋给y。 \n", "然后将`x+y`即`3`赋值为下一轮运算的x,然后再从列表中取出下一个值3赋值给y,在进行`x+y`运算。 \n", "直到取出`5`。整个迭代过程类似于6-9行代码。可以看出,通过reduce,可以大幅精简这种迭代过程的代码。 \n", "\n", "至于列表中超过1个元素,同时设置初值。大家可依次类推。" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "15\n", "15\n" ] } ], "source": [ "from functools import reduce\n", "\n", "xlist = [1, 2, 3, 4, 5]\n", "print(reduce(lambda x, y: x + y, xlist))\n", "\n", "n = 0\n", "for e in xlist:\n", " n += e\n", "print(n)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "上面的例子演示了对列表使用reduce函数。实际上reduce函数适用于所有可迭代对象。如下代码所示:" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "120\n", "120\n", "1+2+3+4+5\n", "班级总人数:77\n" ] } ], "source": [ "#使用reduce函数实现求6的阶乘\n", "from functools import reduce\n", "result = reduce(lambda x, y: x * y, range(1, 6)) #计算((((1*2)*3)*4)*5)\n", "print(result)\n", "\n", "print(reduce(lambda x, y: int(x)*int(y), \"12345\" ))\n", "print(reduce(lambda x, y: x + \"+\" + y, \"12345\" ))\n", "\n", "gradeDict = {\">=90\":10,\"80<=x<90\":30, \"60<=x<80\":22, \"0<=x<60\":15} \n", " \n", "print(\"班级总人数:\"+str(reduce(lambda x, y: x + y, gradeDict.values())))\n", " " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**map与reduce结合使用:**\n", "\n", "**求凯撒密码:**\n", "\n", "对每个英文字符(大小写)将其变化为后面第n个字符,且范围超出,则折返。 \n", "假设n为3,如果对如字符`z`变化,则得到`c`,对字符'A'变化,则得到'D'。对非英文字符保持 \n", "不变。\n", "\n", "在整个过程中包含两个步骤:\n", "1. 求出给定字母的经凯撒转化后的字母。使用getNextChar(x, n)转换。 \n", "2. 将这些转换后的字母拼接起来。 \n", "\n", "**思路:**\n", "\n", "1. plainText为待加密的明文。使用**map**函数对其每个字符应用getNextChar函数。\n", "2. 使用`reduce(lambda x, y: x + y .....)`函数将转换后的每个字符拼接起来\n", "\n", "**优化:**\n", "\n", "因为getNextChar需要两个入参,一个是字符,还有一个是n。并且对每个字符都是使用n进行变换。 \n", "所以第13行代码中的`[n]*len(plainText)`生成了一个列表,长度与plainText相同,值为n。比较占用空间。 \n", "我们可以定义一个产生length个n的生成器`nGenerator(length, n)`。比较节省空间。" ] }, { "cell_type": "code", "execution_count": 67, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "WklvL12vPbSdvvzrugC*\n", "WklvL12vPbSdvvzrugC*\n" ] } ], "source": [ "import random\n", "\n", "def getNextChar(x, n):\n", " if x.islower():\n", " return chr((ord(x) - ord('a') + n) % 26 + ord('a'))\n", " elif x.isupper():\n", " return chr((ord(x) - ord('A') + n) % 26 + ord('A'))\n", " else:\n", " return x\n", "\n", "plainText = \"ThisI12sMyPasswordZ*\"\n", "n = 3\n", "print(reduce(lambda x, y: x + y, map(getNextChar, plainText, [n]*len(plainText))))\n", "\n", "def nGenerator(length, n):\n", " for i in range(length):\n", " yield n\n", "#使用生成器进行优化\n", "print(reduce(lambda x, y: x + y, map(getNextChar, plainText, nGenerator(len(plainText), n)))) " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 3.6 random模块\n", "random模块实现了各种分布的伪随机数生成器。更多random库说明请见文档[random --- 生成伪随机数](https://docs.python.org/zh-cn/3/library/random.html)\n", "\n", "random.random()在[0.0,1.0)范围内生成随机数" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0.8649866132338427 0.5267219480941976 0.19735233180737644 0.6101665714392257 0.22115358552669073 " ] } ], "source": [ "import random\n", "for i in range(5):\n", " print(random.random(), end = ' ')" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "5 1 3 1 6 " ] } ], "source": [ "for i in range(5):\n", " print(random.randint(1,10) , end = ' ') #在[a,b]范围内生成随机整数" ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "k l t v u \n", "shuffule前: ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']\n", "shuffule后: ['e', 'g', 'b', 'j', 'c', 'l', 'i', 'z', 'q', 'r', 'x', 'v', 'm', 'y', 'o', 'h', 'u', 's', 'w', 'd', 'n', 'a', 'f', 't', 'p', 'k']\n", "从alphabetList列表中随机抽样5个元素组成新的列表 ['r', 'z', 'm', 'l', 'h']\n" ] } ], "source": [ "alphabet = \"abcdefghijklmnopqrstuvwxyz\"\n", "for i in range(5):\n", " print(random.choice(alphabet),end = ' ') #随机从字符串序列中抽取出5个元素\n", "print()\n", "alphabetList = [x for x in alphabet]\n", "print(\"shuffule前:\",alphabetList)\n", "random.shuffle(alphabetList) #将序列 x 随机打乱位置。\n", "print(\"shuffule后:\",alphabetList)\n", "\n", "print('从alphabetList列表中随机抽样5个元素组成新的列表',random.sample(alphabetList, 5))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 3.7 datetime模块\n", "未完成" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 4. 处理异常(try...except)\n", "程序运行时难免会碰到一些无法处理的错误(异常)。比如,要求输入若干数值类型求和,但输入过程中不小心输入了一个非数值类型的字符,如下列代码所示:" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1\n", "2\n", "x\n" ] }, { "ename": "ValueError", "evalue": "invalid literal for int() with base 10: 'x'", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mValueError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[0;32m 6\u001b[0m \u001b[1;32mreturn\u001b[0m \u001b[0mx\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 7\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 8\u001b[1;33m \u001b[0mSumAll\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m3\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[1;32m\u001b[0m in \u001b[0;36mSumAll\u001b[1;34m(n)\u001b[0m\n\u001b[0;32m 2\u001b[0m \u001b[0mx\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;36m0\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 3\u001b[0m \u001b[1;32mwhile\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mn\u001b[0m\u001b[1;33m!=\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 4\u001b[1;33m \u001b[0mx\u001b[0m \u001b[1;33m+=\u001b[0m \u001b[0mint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0minput\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 5\u001b[0m \u001b[0mn\u001b[0m \u001b[1;33m-=\u001b[0m \u001b[1;36m1\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 6\u001b[0m \u001b[1;32mreturn\u001b[0m \u001b[0mx\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[1;31mValueError\u001b[0m: invalid literal for int() with base 10: 'x'" ] } ], "source": [ "def SumAll(n):\n", " x = 0\n", " while(n!=0):\n", " x += int(input())\n", " n -= 1\n", " return x\n", "\n", "SumAll(3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "可以看到,程序运行中碰到了`ValueError`,程序无法处理该错误,于是直接崩溃。\n", "为了让我们编写的SumAll函数更健壮(碰到错误输入,不至于程序崩溃),我们可以使用try语句改进如上程序。当输入引发错误时,重新输入。" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1\n", "x\n", "输入错误,请重输!\n", "5\n", "0\n" ] }, { "data": { "text/plain": [ "6" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "def SumAll(n):\n", " x = 0\n", " while(n!=0):\n", " try:\n", " x += int(input()) #1\n", " n -= 1 #2\n", " except: #3\n", " print(\"输入错误,请重输!\")\n", " return x\n", "\n", "SumAll(3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "从程序的运行结果可以看到,该程序正确处理了输入错误(输入a)的情况。 \n", "具体原理为,当语句1发生错误的时产生异常,程序不会正常往下执行,即,未执行语句2,n也就不会-1。\n", "但是会跳到语句3处,随后提示错误信息,然后回到while语句处继续执行,并且因为n未-1,所以n的值永\n", "远无达到0,也就无法跳出循环。\n", "\n", "**总结:**\n", "使用try...except可以提高程序的健壮性,当程序运行产生异常时,程序中断正常运行流程,try..except机制可以让程序跳转到错误处理的地方(except块)来进行出错处理。\n", "\n", "关于try...except更多内容请参考文章:[异常处理try...except、raise](https://www.cnblogs.com/Lival/p/6203111.html)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 5. 自定义数据类型(面向对象入门)\n", "这里仅给出一个简介,更多面向对象的知识点请参考[Python官方文档-类](https://docs.python.org/zh-cn/3/tutorial/classes.html#)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "## 5.1 类的定义(class关键字)\n", "类可以将数据(属性)与功能(方法)综合起来。创建一个类相当于定义一个新的类型。使用这个新的类型可以创建很多该类的实例(对象)。 \n", "\n", "示例代码定义一个`Student`类,利用Student类可以创建出很多Student类型的对象,如下面的s1与s2两个对象。 \n", "该类中有两个关键点如下:\n", "\n", "1. **\\__init\\__方法:**Python类中的一种特殊方法,方法名的开始和结束都是**双下划线**,该方法称为构造函数主要用于初始化对象。当创建类的对象时,它被自动调用\n", "2. **self关键字:**对于一个类的所有方法,包括构造函数,其参数中都有一个self参数,用来代表对象本身。" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "析构函数执行。这里应该执行一些清理工作。\n", "Jordan 18\n", "sid = 1,name = Jordan, age = 18\n", "析构函数执行。这里应该执行一些清理工作。\n" ] } ], "source": [ "class Student:\n", " def __init__(self, sid, name, age):#构造函数,用于初始化。一定要有self参数且为第一个参数\n", " self.sid = sid #实例属性sid,每个实例(对象)都独有一个\n", " self.name = name \n", " self.age = age \n", " \n", " def printMe(self): #在类中定义的一个方法,self必不可少\n", " print(\"sid = {},name = {}, age = {}\".format(self.sid,self.name,self.age))\n", " \n", " def __del__(self): #析构函数。删除一个对象时执行该函数\n", " print(\"析构函数执行。这里应该执行一些清理工作。\")\n", "s1 = Student(1,\"Jordan\",18) #创建了一个Student实例(对象)\n", "print(s1.name,s1.age) #使用\"对象.属性名\"访问属性\n", "s1.printMe() #使用\"对象.方法名\"执行方法\n", "s2 = Student(2,\"Rose\",18)\n", "del s2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 5.2 继承与多态" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "子类(派生类)可以继承自父类(基类)。可以复用父类的属性与方法。 \n", "不同于Java,Python允许多重继承。详见官方文档。" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "sumShapesArea方法体现了多态:\n", "329.1593\n", "复用了Shape中printMe方法:\n", "name= 圆形 area= 314.1593\n", "name= 方形 area= 15\n", "调用Shape类型对象的__str__方法:\n", "name = 圆形 area= 314.1593\n", "name = 方形 area= 15\n", "True\n", "False\n", "True\n" ] } ], "source": [ "class Shape:\n", " PI = 3.141593 #类属性(类变量),属于该类所有对象。通过\"类名.属性名\"访问\n", " def __init__(self, name): #相当于Java中的构造函数,用于初始化对象\n", " self.name = name \n", " \n", " def printMe(self): #将在子类中被复用\n", " print(\"name=\",self.name,\" area=\", self.getArea())\n", " \n", " def __str__(self): #类似java的toString方法。返回对象的字符串表示\n", " return \"name = \"+self.name+\" area= \"+str(self.getArea())\n", " \n", " def getArea(self):\n", " raise AttributeError('子类必须实现这个方法') #抛出异常\n", " \n", "class Circle(Shape):\n", " def __init__(self, name, r):\n", " super().__init__(name) #复用父类的__init__函数\n", " self.r = r #对象属性\n", " \n", " def getArea(self): #覆盖父类的getArea方法,体现了自己的特点,多态的一种表现\n", " return Shape.PI*self.r*self.r #使用Shape的类属性PI\n", "\n", "class Rect(Shape):\n", " def __init__(self, name, width, length):\n", " super().__init__(name)\n", " self.width = width #对象属性\n", " self.length = length\n", " \n", " def getArea(self): #覆盖父类的getArea方法\n", " return self.width*self.length\n", "\n", "def sumShapesArea(shapes): #体现了多态,虽然都是执行了getArea方法,但是根据不同的实现类调用不同的代码\n", " area = 0\n", " for e in shapes:\n", " area += e.getArea() #这行代码适用于任何拥有getArea()方法的类\n", " return area\n", " \n", "shapes = []\n", "shapes.append(Circle('圆形',10))\n", "shapes.append(Rect('方形',3,5))\n", "print(\"sumShapesArea方法体现了多态:\")\n", "print(sumShapesArea(shapes))\n", "print(\"复用了Shape中printMe方法:\")\n", "for e in shapes:\n", " e.printMe()\n", "print(\"调用Shape类型对象的__str__方法:\")\n", "for e in shapes:\n", " print(e) #print时,会调用对象e的__str__方法\n", "print(isinstance(shapes[0], Shape)) #使用isinstance判断一个对象是否是某个类型shapes[0]是Circle,同时继承自Shape,所以为True\n", "print(isinstance(shapes[1], Circle))#shapes[1] 是Rect,不是Circle,所以返回False\n", "print(issubclass(Rect, Shape)) #使用issubclass判断一个类是否是某个类型的子类" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**常用函数:**\n", "\n", "**isinstance(obj, type)**: 用来判断obj是否为type类型对象或其type的子类型对象。\n", "\n", "**issubclass(type1, type2)**: 用来判断type1是否为type2类型或type2的子类型。" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "True False True\n", "张\n", "张 1\n", "王 7000.34\n", "True True True\n", "False False\n" ] } ], "source": [ "class Person:\n", " def __init__(self, name):\n", " self.name = name\n", " def __str__(self):\n", " return self.name;\n", " \n", "class Student(Person):\n", " def __init__(self, name, stuNo):\n", " self.name = name\n", " self.stuNo = stuNo\n", " def __str__(self):\n", " return super().__str__() + \" \" + str(self.stuNo)\n", "\n", "class Employee(Person):\n", " def __init__(self, name, salary):\n", " self.name = name\n", " self.salary = salary\n", " def __str__(self):\n", " return super().__str__() + \" \" + str(self.salary)\n", " \n", "p = Person(\"张\")\n", "s1 = Student(\"张\", 1)\n", "e1 = Employee(\"王\", 7000.34)\n", "print(isinstance(p, Person), isinstance(p, Student), isinstance(s1, Person))\n", "print(p, s1, e1, sep = \"\\n\")\n", "print(issubclass(Employee, Person), issubclass(Student, Person), issubclass(Person, Person))\n", "print(issubclass(Employee, Student), issubclass(Person, Student))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 5.3 私有属性与私有方法" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "图灵\n", "图灵\n", "我的类型为Foo\n" ] }, { "ename": "AttributeError", "evalue": "'Foo' object has no attribute '__name'", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mAttributeError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[0;32m 15\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 16\u001b[0m \u001b[1;31m#以下两句均无法执行\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 17\u001b[1;33m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mx\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m__name\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 18\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mx\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m__printMe\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;31m#这句也无法执行\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[1;31mAttributeError\u001b[0m: 'Foo' object has no attribute '__name'" ] } ], "source": [ "class Foo:\n", " def __init__(self, name):\n", " self.__name = name #双下划线__开头的属性为私有属性。无法被在类外部被直接访问,所以产生异常。\n", " def __printMe(self): #双下划线__开头的方法私有方法,类外部无法调用。但类内部可以调用。\n", " print(\"我的类型为Foo\")\n", " def getName(self):\n", " return self.__name\n", " def printMe(self):\n", " self.__printMe()\n", " \n", "x = Foo(\"图灵\") \n", "print(x.getName())\n", "print(x._Foo__name) #可以使用_类名__属性名的方式强行访问对象的私有属性,但不要这么做\n", "x.printMe()\n", "\n", "#以下两句均无法执行\n", "print(x.__name)\n", "print(x.__printMe()) #这句也无法执行\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 5.4 动态设置属性\n", "Python是动态语言,所以可以动态地为对象定义其原本不存在的属性。 \n", "可以将其当作c语言中的结构体使用。只让类与数据绑定而不与行为绑定。 \n", "除非你确实知道要这么用,否则不要用。" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "zhang\n", "id = 1, name = 张, age = 18\n", "id = 2, name = 王, age = 19\n", "id = 3, name = 赵, age = 18\n", "id = 4, name = 李, age = 20\n" ] } ], "source": [ "class Stu: #创建了一个空类\n", " pass\n", "\n", "x = Stu()\n", "x.name = \"zhang\"\n", "print(x.name)\n", "\n", "class Person:\n", " pass\n", "\n", "# 当结构体使用\n", "stuList = [(1,\"张\",18),(2,\"王\",19),(3,\"赵\",18),(4,\"李\",20)]\n", "persons = []\n", "for e in stuList:\n", " x = Person()\n", " x.id, x.name, x.age = e\n", " persons.append(x)\n", "\n", "for p in persons:\n", " print(\"id = {}, name = {}, age = {}\".format(p.id, p.name, p.age))\n", " " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 5.5 对象的`__hash__()`方法与`__eq__()`方法\n", "前面学习的集合(set),可以实现对相同元素的去重。 \n", "set如何判定两个加入的元素是否相同? \n", "set首先使用对象的`__hash__()`函数算出其哈希值。如果两个元素的哈希值相同,则使用了`__eq__()`函数来判断这两个元素是否相等。\n", "\n", "- `__hash__()`方法为计算对象的哈希值\n", "- `__eq__()`方法用来判断两个对象是否相同。eq为equal的缩写。" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{'b', 'a'}\n", "True\n", "True\n" ] } ], "source": [ "line = \"aba\"\n", "xset = set(line)\n", "print(xset)\n", "x, y = line[0], line[2]\n", "print(x.__eq__(y))\n", "print(x.__hash__() == y.__hash__())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "set也可以放入自定义类的对象。set也是通过上述两个方法来判断两个自定义类的对象是否相同。 \n", "从以下代码可以看到两个对象s1、s2的属性虽然都一样,但是他们不是同一个对象。所以两个对象都放入了stuSet。" ] }, { "cell_type": "code", "execution_count": 46, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "119495857230 -1649071504362339002\n", "NotImplemented\n", "2 {('zhang', 18, '数学'), <__main__.Student object at 0x000001BD282144E0>}\n" ] } ], "source": [ "class Student:\n", " def __init__(self, name, age, major):\n", " self.name = name\n", " self.age = age\n", " self.major = major\n", " \n", "s1, s2 = Student(\"zhang\", 18, \"数学\"), (\"zhang\", 18, \"数学\")\n", "print(hash(s1.__hash__()), hash(s2.__hash__()))\n", "print(s1.__eq__(s2)) ##Student未实现__eq__方法\n", "stuSet = set([s1, s2])\n", "print(len(stuSet), stuSet)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "如果我们希望两个Student对象只要name与age相同,就算作相同对象,要怎么实现呢? \n", "\n", "我们可以为自己的类覆盖`__hash__()`与`__eq__()`来实现上述功能。" ] }, { "cell_type": "code", "execution_count": 64, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "len(stuList)= 8\n", "len(stuSet)= 4\n", "id=1911934786136, name=王, age=17, major=计算机\n", "id=1911934786360, name=王, age=18, major=计算机\n", "None\n", "id=1911934785408, name=zhang, age=18, major=数学\n" ] } ], "source": [ "class Student:\n", " def __init__(self, name, age, major):\n", " self.name = name\n", " self.age = age\n", " self.major = major\n", " \n", " def __str__(self):\n", " #return self.name + \" \" + str(self.age) + \" \" + self.major\n", " return \"id={}, name={}, age={}, major={}\".format(id(self), self.name, self.age, self.major)\n", " \n", " def __hash__(self):\n", " return hash((self.name, self.age)) #Python官方文档推荐将要hash的属性作为一个元组进行hash\n", " \n", " def __eq__(self, other):\n", " if other == None: \n", " return False\n", " if id(self) == id(other):\n", " return True\n", " if self.name == other.name and self.age == other.age:\n", " return True;\n", " return False\n", " \n", "s1 = Student(\"zhang\", 18, \"数学\")\n", "s2 = Student(\"zhang\", 18, \"计算机\")\n", "s3 = Student(\"王\", 17, \"计算机\")\n", "s4 = Student(\"王\", 18, \"计算机\")\n", "s5 = s2\n", "s6 = None\n", "s7 = Student(\"zhang\", 18, \"物理\")\n", "stuList = [s1, s2, s3, s4, s5, s6, s7, None]\n", "print(\"len(stuList)=\",len(stuList))\n", "stuSet = set(stuList)\n", "print(\"len(stuSet)=\",len(stuSet))\n", "for e in stuSet:\n", " print(e)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "从以上代码可以看出,集合将s1、s2、s5、s7当作同一个元素。所以只存1份。 \n", "s3、s4虽然name与major相同,但是age不同,所以不是同一个元素,所以存两份。 \n", "一个集合中最多只能存放一个None。\n", "\n", "**覆盖`__hash__()`与`__eq__()`的原则:**\n", "\n", "一般来说如果需覆盖自定义类的`__hash__()`与`__eq__()`方法,那么这两个方法都要覆盖、且结果要一致。 \n", "即,如果对A、B两个对象`A.__eq__(B)`为True,那么这A、B的`__hash__()`方法返回的哈希值也要一样。 \n", "因为`__eq__()`方法在语义上是用来判定两个对象是否相等。`A.__eq__(B)`为True,那么A与B从语义上来 \n", "说是相等的对象。但是如果其哈希值不一样的话,A、B这两个被认定为相等的对象将都会被放入集合(set)中。 \n", "这在语义上来说是不对的。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 5.6 其他\n", "**未完成:**\n", "- 迭代器与__next__()\n", "- 生成器\n", "\n", "**一些参考资料:**\n", ">[为什么不需要为Python对象添加 getter 和 setter](https://www.cnblogs.com/astropeak/p/7229508.html)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 6. 使用第三方库完成复杂程序" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 6.1 使用Numpy库画图正弦曲线\n", "**依赖库:**\n", " \n", " numpy,matplotlib\n", "\n", "**步骤:**\n", " \n", " pip install numpy\n", "\n", " pip install matplotlib\n", " \n", "**注意:**\n", " 使用pip安装numpy时,可能会碰到需要C编译器,一个简单的解决方法,就是安装一个Visual Studio 2015,或者直接安装Anaconda集成安装包。\n", "\n", "**参考资料:**\n", "\n", " 使用Numpy处理数据: http://old.sebug.net/paper/books/scipydoc/numpy_intro.html#\n", "\n", " 用Python做科学计算: http://old.sebug.net/paper/books/scipydoc/index.html#\n", "\n", " Numpy官方文档: http://www.numpy.org/" ] }, { "cell_type": "code", "execution_count": 26, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[0. 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1. 1.1 1.2 1.3 1.4 1.5 1.6 1.7\n", " 1.8 1.9 2. 2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 2.9 3. 3.1 3.2 3.3 3.4 3.5\n", " 3.6 3.7 3.8 3.9 4. 4.1 4.2 4.3 4.4 4.5 4.6 4.7 4.8 4.9 5. 5.1 5.2 5.3\n", " 5.4 5.5 5.6 5.7 5.8 5.9 6. 6.1 6.2]\n" ] }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "import numpy as np\n", "import matplotlib.pyplot as plt\n", "%matplotlib inline\n", "\n", "x=np.arange(0, 2*np.pi, 0.1) #生成一个从0到2*PI之间以0.1作为间隔的序列\n", "print(x)\n", "y=np.sin(x)\n", "\n", "plt.plot(x,y)\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 6.2 二维码\n", "**简介**:Python 二维码生成器 GitHub - sylnsfar/qrcode: artistic QR Code in Python (Animated GIF qr code) 可生成普通二维码、带图片的艺术二维码(黑白与彩色)、动态二维码(黑白与彩色)。\n", "\n", "\n", "\n", "**安装:**\n", "pip install myqr\n", "\n", "**依赖库:**pillow, numpy, imageio\n", "\n", "**说明:**\n", "安装myqr的时候可能会自动安装相关的依赖库,如果没有自动安装,请自行安装,如pip install pillow\n", "\n", "**拓展:**\n", "生成自己的名片二维码。\n", "\n", "**参考资料:**\n", "\t二维码名片的格式 - vcard\n", "http://blog.csdn.net/johnsuna/article/details/8482454" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from MyQR import myqr\n", "words = 'http://cec.jmu.edu.cn'\n", "pic='jmu.png'\n", "saveName = 'jmuQRCode.png'\n", "saveDir = '.'\n", "version, level, qr_name = myqr.run(\n", " words,\n", " version=1,\n", " level='H',\n", " picture=pic,\n", " colorized=True,\n", " contrast=1.0,\n", " brightness=1.0,\n", " save_name=saveName,\n", " save_dir=saveDir\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "jmu.png如下图:\n", "\n", "生成的二维码jmuQRCode.png如下图,可以扫一扫:\n", "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 6.3 使用小海龟作图\n", "**安装:** Python默认自带turtle库。如没有,请使用**pip install turtle**安装turtle库\n", "\n", "实例如下:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from turtle import *\n", "fillcolor(\"red\")\n", "begin_fill()\n", "while True:\n", " forward(200)\n", " right(144)\n", " if abs(pos()) < 1:\n", " break\n", "end_fill()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "效果如下图:\n", "\n", "**参考资料:**\n", "\n", "官方文档 https://docs.python.org/2/library/turtle.html\n", "\n", "海龟绘图中文教程参考资料 http://www.jb51.net/article/52659.htm\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 6.4 验证码识别\n", "**安装:**\n", "1. 需安装Pillow与pytesseract库\n", "2. 安装软件tesseract-ocr,下载地址https://sourceforge.net/projects/tesseract-ocr-alt/files/ 选择里面的tesseract-ocr-setup-3.02.02.exe \n", "\n", "注:Tesseract是一个开源的OCR(Optical Character Recognition,光学字符识别)引擎,可以识别多种格式的图像文件并将其转换成文本。\n", "\n", "\n", "**库安装步骤:**\n", " \n", " pip install pillow\n", " \n", " pip install pytesseract\n", " \n", "**例子:**\n", " 现在需要识别如下验证码" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "图片中的字符是: 3948\n" ] } ], "source": [ "import pytesseract\n", "from PIL import Image\n", "\n", "image = Image.open('vcode3.png')#可将此处替换为vcode2.png实验\n", "vcode = pytesseract.image_to_string(image)\n", "print('图片中的字符是:',vcode)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "参考资料:\n", "\n", "使用Python识别验证码 http://www.tuicool.com/articles/E3MNziM\n", "\n", "利用Tesseract来识别验证码 http://blog.csdn.net/zhangxb35/article/details/49592071 \n", "\n", "说明:识别能力还较弱。如下图,就无法识别。\n", "\n", "如需增强识别能力,还需学习线性代数、图像、模式识别等知识。\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 7. 附录:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 7.1 Python的下载与安装\n", "**官网:** https://www.python.org/ Python官网。尽量在官网下载文件。\n", "\n", "**版本说明:** 2.7.x 或 3.5.x。注意:如果操作系统是xp,请安装3.4.x版本。操作系统是32位请安装32位,是64位请安装64位安装文件。\n", "\n", "**安装过程中**:要选择\"Add python.exe to Path\"\n", "\n", "**控制台启动python:**在CMD命令行提示符下输入python,将显示Python控制台。控制台上将显示所安装的Python版本号。\n", "\n", "\n", "**IDLE(Python GUI):**在开始菜单中Python项目下点击IDLE,可启动Python图形界面,如下图所示。可在其中编写简单的Python文件。常用快捷键:Alt+P,查看上一条命令。Alt+/,自动补全曾经出现过的单词。\n", "\n", "\n", "\n", "## 7.2 使用pip管理Python扩展库\n", "**三种常见的pip命令:**\n", "\n", "`pip install SomePackage` #安装SomePackage模块,如**pip install numpy**\n", "\n", "`pip install -upgrade SomePackage` #升级SomePackage模块\n", "\n", "`pip uninstall SomePackage` #卸载SomePackage模块\n", "\n", "**注1:**在CMD命令行提示符下输入上述命令,如 `C:\\temp>pip install numpy`\n", "\n", "**注2:**pip安装慢时,可指定国内源,如下命令指定使用豆瓣的源\n", "`pip install numpy -i https://pypi.douban.com/simple`\n", "\n", "**注3:**如果提示“拒绝访问”或者碰到其他的安装错误时,尝试以**管理员身份运行**命令提示符,然后安装。\n", "\n", "**注4:** Python3下也可使用pip3或者pip3.5命令代替pip命令,Python3下执行pip相当于执行pip3。均在Python安装目录下的Scripts目录中可以找到相应的文件。\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 7.3 Python常见参考资料" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "1. [Google的Python 风格指南(语言规范、风格规范)](https://zh-google-styleguide.readthedocs.io/en/latest/google-python-styleguide/contents/)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 7.4 [IPython](http://ipython.org/)与[Jupyter项目](https://jupyter.org/)\n", "\n", "**IPython:** \n", "一个功能强大的Python命令行交互程序。可以尝试一下。一般来说安装了Jupyter,就会安装IPython。\n", "\n", "**Jupyter:** \n", "Jupyter项目包含经典的Jupyter Notebook与更新的Jupyter Lab,他们的内核基于IPython。 \n", "这两个项目提供一个基于Web的交互开发环境,还支持Markdown语法。因此,不仅可用其运行Python \n", "代码,还可以使用其做笔记,笔记内部可以内嵌代码及代码运行结果。通过结合使用GitHub与 \n", "[Jupyter Notebook Viewer](https://nbviewer.jupyter.org/)还可分享自己的Juyter笔记。 \n", "\n", "\n", "**相关参考资料:**\n", ">[Python-Jupyter Notebook使用技巧](https://www.cnblogs.com/zhrb/p/6892011.html)\n", "[在VS Code中使用Jupyter Notebook](https://code.visualstudio.com/docs/python/jupyter-support)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 7.6 [Anaconda集成安装包](https://www.anaconda.com/)\n", "一个Python的发行版本。集成了如numpy等科学计算、IPython、Jupyter Notebook、Spyder(一个小型的Python IDE)常用第三方模块的集成安装包。无需考虑各种依赖,使用方便。推荐科学计算的研究人员直接使用。\n", "\n", "**注意:**安装了Anaconda也会自动安装IPython与Jupyter。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 7.7 本笔记相关链接\n", "- 笔记项目的github地址:[https://github.com/zhrb/NoteBook](https://github.com/zhrb/NoteBook)\n", "- 笔记内容留言反馈地址:[http://www.cnblogs.com/zhrb/p/6223192.html](http://www.cnblogs.com/zhrb/p/6223192.html)\n", "- 本笔记的NBViewer地址:[https://nbviewer.jupyter.org/github/zhrb/NoteBook/blob/master/LearnPython3In90Min.ipynb](https://nbviewer.jupyter.org/github/zhrb/NoteBook/blob/master/LearnPython3In90Min.ipynb)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 7.8 Python练习题\n", "\n", "[Python安装与使用的常见问题](http://www.cnblogs.com/zhrb/p/6891948.html)\n", "\n", "[PTA中提交Python3程序的一些套路](http://www.cnblogs.com/zhrb/p/7837981.html)\n", "\n", "**Python基本语法练习 邀请码:**da3ce820092697b8\n", "\n", "**使用邀请码做题步骤:**登录[pintia.cn](http://pintia.cn)后,在右上角**个人中心**-**应邀做题**中输入邀请码。" ] } ], "metadata": { "anaconda-cloud": {}, "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.4" }, "toc": { "base_numbering": 1, "nav_menu": {}, "number_sections": false, "sideBar": true, "skip_h1_title": false, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": true, "toc_position": { "height": "836px", "left": "0px", "right": "1708px", "top": "111px", "width": "212px" }, "toc_section_display": "block", "toc_window_display": true } }, "nbformat": 4, "nbformat_minor": 1 }