字符串(格式化)
按照统一规则来输入字符串。
格式化方法format()
-
位置参数
通过位置参数把“I”,“python”和“world”传递给format方法,再有format方法对字符串进行格式化整理得到最终目标。 -
关键字参数
-
综合位置参数和关键字参数
位置参数必须在关键字参数之前,否则报错
-
打印花括号
与打印反斜杠\ 同理
这里引号内的字符串不打印,是因为这里的{0}已经不是位置了,而是被解释,变成了字符串。 -
化定点数
冒号表示格式化符号的开始,1f是四舍五入保留一位小数。
格式化符号含义
格式化独自享有一个操作符“%”。
- %c
格式化字符及其ASCII码
a 的ASCII码是97,这里就是用ASCII码显示97的字符
- %s
格式化字符串
- %d
格式化整数
- o%
格式化无符号八进制数 - x%
格式化无符号十六进制数 - X%
格式化无符号十六进制数(大写)
- %f
格式化定点数,可指定小数点后的精度
- %e
用科学计数法格式化定点数 - %E
作用同%e,用科学计数法格式化定点数
- %g
根据值的大小决定使用 %f 或 %e - %G
作用同 %g,根据值的大小决定使用 %f 或 %E
格式化操作符辅助指令
- m.n
m是显示的最小的总宽度,n是小数点后的位数
浮点数
科学计数法
- -
用于左对齐
- +
在正数前面显示加号(+)
- #
在八进制数前面显示零(‘ 0’),在十六进制数前面显示‘ 0x’ 或 ‘ 0X’
- 0
显示的数字前面填充‘ 0’取代空格
序列
列表、元组和字符串的共同点
(1)都可以通过索引得到每一个元素
(2)默认索引值都是从0开始
(3)可以通过分片的方法得到一个范围内的元素的集合
(4)有很多共同的操作符(重复操作符、拼接操作符、成员关系操作符)
常见内置方法
-
list()
把一个可迭代对象转换为列表
查看帮助文档
list 有两种参数形式
一个是没有参数,即建立一个空表
另一个是传入一个可迭代参数
(迭代:重复反馈过程的活动,其目的是为了接近并达到的目标或结果,每对过程重复一次,称之为一次迭代,每次得到的结果被用来作为下一次迭代的初始值。)
-
tuple([iterable])
把一个可迭代对象转换为元组
查看帮助文档
和list()操作类似 -
str(obj)
把obj对象转换为字符串 -
len(sub)
返回参数sub的长度
-
max()
返回序列或者参数集合中的最大值
-
min()
返回序列或者参数集合中的最小值
注意:使用max()和min()的时候要保证序列或参数的数据类型是统一的。
-
sum(iterable[, start=0])
返回序列iterable和可选参数start的总和
sum()只能用于数字类型
-
sorted()
返回一个排序的列表,默认从小到大排序,使用方法和list.sort()相同
-
reversed()
同list.reverse()
-
enumerate()
生成由每个元素的index值和intem值组成的元组
-
zip()
返回由各个参数的序列组成的元组
函数
一个Python函数
调用函数时只能调用之前定义过的,否则会报错
函数的参数
- 利用参数使函数可变
- 多个参数
注意:写程序时参数不宜过多,尽量不超过4个,并且写清函数的注释,便于后期代码的维护。
函数的返回值
- 定义带返回值的函数
通常情况下说一个函数是一个整型的函数,只是这个函数返回一个整型的返回值。
而Python是动态的确定类型,所以在Python中定义函数参数时并没有像C语言中的‘int a, char b, double c’,Python动态确定类型是指在赋值的时候,编译器自动确定你需要什么类型。
之前说过的,Python没有变量的,只有名字,即在Python里东西可以拿过来直接用,而不用管它是什么类型的,包括它的返回值,Python还可以返回多个值。
形参和实参
- 形式参数(parameter)
形参实参性质同c语言,形参是函数创建和定义过程中,小括号中的参数。 - 实际参数(argument)
实参是指在函数调用过程中,传递进去的参数。
>>> def Function2(name):
'此函数定义过程的中 name 称之为形参'
# 因为这里的 name 只是一个形式,表示占据一个参数位置
print('I love ' + name)
# 在这里调用函数,给name传入一个值,这个具体的值是实参
>>> Function2('Python')
>>> # 这里传入的‘Python’是实参,因为它是具体的参数值
函数文档
函数文档,便于他人更好的理解函数。
函数的文档区别于函数的注释。
‘.__doc__’ 是系统的特殊属性,一般系统的特殊属性都是用双下划线开始和结束的
关键字参数
用于避免参数传入时,顺序发生错误。
默认参数
是定义了默认值的参数。
收集参数
也可称为可变参数,是区别于传统编程语言的一个新有概念。
在这里要注意,如果在收集参数后面还要加上其他定制的参数,在定制参数传入的时候,就应该使用关键字参数来定制,否则就会将你之后传入的参数也列为收集参数收集的范畴。
其实我们常用的函数 pinrt()函数本身就存在一个收集参数
函数与过程
- 函数(function):有返回值
- 过程(procedure):简单、特殊并且没有返回值
Python只有函数,没有过程。
结合之前的 ‘函数的返回值’ 小节理解。
函数变量的作用域
即变量的可见性。
-
局部变量(Local Variable)
-
全局变量(Global Variable)
-
实例
新建窗口,写一个程序
函数discounts中有三个局部变量,price、rate和final_price
测试这个程序可以执行,修改程序打印局部变量final_price
执行,报错,显示final_price未定义
这里由于final_price是一个局部变量,作用范围只在discounts这个函数里面。python在调用函数时,利用栈进行数据的存储,执行完函数后,栈里的数据会被清空,所以函数外无法访问函数内部的局部变量。
在这个程序里,全局变量有old_price、rate和new_price,它们的作用域是整个程序。
尝试在函数中打印全局变量old_price的值:
成功打印。
注意:尽量不要在函数内修改全局变量,因为在函数内修改全局变量的值,Python会启用屏蔽(Shadowing)的方式来保护全局变量,使之并不会影响该全局变量本身的值,而是在函数内创建一个和该全局变量名称一样的局部变量,作用域仅在函数内。
发现函数外的old_price并没有改变。
然而,也并不是无法在函数内修改全局变量,如果在排除了在函数内修改全局变量所带来的,如程序的可读性变差、出现BUG、升高代码的维护成本、甚至程序报废等问题后。需要修改全局变量,那么就可以使用global关键字进行修改。
这时全局变量count的值也改变了。
内嵌函数
是指在函数内部创建另一个函数,也称为内部函数。
- 建立一个嵌套函数
调用执行函数fun1()时,在函数中调用fun2()。
注意:内部函数的整个作用域都在外部函数之内,如果试图在外部调用内部函数,机会报错。
闭包(closure)
是函数式编程的一个重要语法结构,函数式编程是一种编程范式,编程范式对代码进行提炼、抽象和概括,使得重用性和可用性变高。
编程范式(programming paradigm)
指的是计算机编程的基本风格或典范模式。
主要的编程范式有三种:命令式编程,声明式编程和函数式编程。
常见的编程范式有:函数式编程、程序编程、面向对象编程、指令式编程等。
1.命令式编程(Imperative programming)
计算机的硬件负责运行使用命令式的风格来写的机器码。计算机硬件的工作方式基本上都是命令式的。大部分的编程语言都是基于命令式的。
早期的命令式编程语言,例如汇编,都是机器指令。虽然硬件的运行更容易,却阻碍了复杂程序的设计。
2.面向对象编程(Object-oriented programming,OOP)
在面向对象程序编程里,计算机程序会被设计成彼此相关的对象。对象则指的是类的实例。它将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性、灵活性和扩展性,对象里的程序可以访问及经常修改对象相关连的数据。
面向对象程序设计可以看作一种在程序中包含各种独立而又互相调用的对象的思想,这与传统的思想刚好相反:传统的程序设计主张将程序看作一系列函数的集合,或者直接就是一系列对计算机下达的指令。面向对象程序设计中的每一个对象都应该能够接受数据、处理数据并将数据传达给其它对象,因此它们都可以被看作一个小型的“机器”,即对象。
3.声明式编程(Declarative programming)
一种编程范式,与命令式编程相对立。它描述目标的性质,让计算机明白目标,而非具体过程。
声明式编程不用告诉计算机问题领域,从而避免随之而来的副作用。而命令式编程则需要用算法来明确的指出每一步该怎么做。声明式编程通常被看做是形式逻辑的理论,把计算看做推导。声明式编程因大幅简化了并行计算的编写难度。
4、函数式编程:
函数式编程和声明式编程是有所关联的,因为他们思想是一致的:即只关注做什么而不是怎么做。但函数式编程不仅仅局限于声明式编程。
不同的编程语言实现闭包的方式不同,Python的闭包从表现形式定义为,如果在一个内部函数里,对外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包。
在闭包中,外部函数的局部变量,对内部函数就相当于全局变量对函数的关系,在内部函数中,只能对外部函数的局部变量进行访问,但不能进行修改。
这里在调用执行fun5()后,return调用执行fun6(),当执行到第四行时,由于x是外部函数fun5()的局部变量,不会在fun6()内被修改,所以执行第四行语句的时候,就在函数fun6()内重新定义了的同名为x的作用域在fun6()的局部变量,返回的也是这个同名变量x,但是这个x并未在fun5()中定义,所以出错。(参考前面内容“函数的作用域”来理解)
这个问题在Python3之前都是通过间接的通过容器类型来进行存放,因为容器类型不是存放在栈里面的,所以变量不会被屏蔽。
但是在Python3针对这个问题提出了专门的解决方案:关键字nonlocal
nonlocal关键字用来在函数或其他作用域中使用外层(非全局)变量
lambda表达式
Python允许使用lambda关键字来创建匿名函数。
- 语法
lambda [原函数的参数,…] : [原函数大返回值]
- 作用
(1)节省定义函数的过程,比如当只需要写个简单的脚本来管理服务器时间时,就不需要专门定义一个函数然后再调用,使用lambda就可以使得代码更加精简。
(2)对于一些比较抽象并且整个程序执行过程中只需调用一两次的函数,使用lambda就省去了给函数命名的问题。
(3)普通函数的阅读经常要跳到开头def定义不烦,使用lambda函数可以省去这个步骤。
常用BIF
- filter() 过滤器
filter有两个参数,第一个参数可以是一个函数或者None,第二个参数是一个可迭代数据;如果第一个参数是一个函数的话,就将第二个可迭代数据里的每一个元素作为函数的参数进行计算,把返回True的值给筛选出来,并成一个列表;如果第一参数为None,则将第二个参数里面的True的值给筛选出来。
- map() 映射
map有两个参数,一个是函数,一个是可迭代序列,功能是将序列的每一个元素作为函数的参数进行运算加工,直到可迭代序列的每一个元素都加工完毕,返回所有加工后的元素构成的新序列。
递归
在函数内部调用其他可见函数,甚至自身;
递归具有危险性,所以并不是在所有地方利用递归都是合适的。
-
应用
(1)汉诺塔
(2)定义树结构
(3)谢尔宾斯基三角形
(4)递归拍照 -
实例
建立一个递归函数
执行这个函数会发现,这个函数会一直执行,这时python报错,表示超出了最大递归深度(可以自己修改python的递归深度值);或者会出现一直执行不停下的情况(此时按ctrl+c停止)。
# 修改递归深度为1000000
import sys
sys.setrecursionlimit(100000)
# 递归深度最大1000000是python3的保护措施,python2.x的版本下更小
- 递归求阶乘
# 4的阶乘
# 用伪代码表示执行顺序
factorial(4):
result = 4
result = 4*1
result = 4*1*2
result = 4*1*2*3
return result
# 4的阶乘
# 用伪代码表示执行顺序
factorial(4):
return 4 * factorial(3):
return 3 * factorial(2):
return 2 * factorial(1):
return 1
- 递归实现斐波那契数列
若兔子幼崽需要成长两个月后才具有繁殖能力,从第三个月开始每个月诞下一对幼崽,且假设原来的兔子不会死亡,那么兔子的增长趋势:
所经过的月数 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
兔子的总对数 | 1 | 1 | 2 | 3 | 5 | 8 | 13 | 21 | 34 | 55 | 89 | 144 |
函数定义:
F
(
n
)
{
1
,
n
=
1
1
,
n
=
2
F
(
n
−
1
)
+
F
(
n
−
2
)
,
n
>
2
F(n)\left\{ \begin{matrix} 1,\text{ n}=1 \\ 1,\text{ n}=2 \\ F(n-1)+F(n-2),n>2 \\ \end{matrix} \right.
F(n)⎩⎨⎧1, n=11, n=2F(n−1)+F(n−2),n>2
代码实现:
# 非递归实现
def fab(n):
n1 = 1
n2 = 1
n3 = -1
if n < 1:
print('输入有误!')
return -1
while (n-2) > 0:
n3 = n2 + n1
n1 = n2
n2 = n3
n -= 1
return n3
mon =int(input('请输入月数:'))
result = fab(mon)
if result != -1:
print('%d个月后有%d对兔子' % (mon, result))
# 递归实现
def fab(n):
if n <1:
print('输入有误!')
return -1
if n == 1 or n == 2:
return 1
else:
return fab(n-1) + fab(n-2)
mon =int(input('请输入月数:'))
result = fab(mon)
if result != -1:
print('%d个月后有%d对兔子' % (mon, result))
递归算法在数据结构也被称为分治思想,递归如果用的不当就会效率很低,在这个例子里,将月数变大,就会发现递归要比迭代的效率低的多。
递归——汉诺塔
def hanoi(n, x, y, z):
if n == 1:
print(x, ' --> ', z)
else:
hanoi(n-1, x, z, y) # 将前n-1个盘子从x移动到y上
print(x, ' --> ', z) # 将最底下的最后一个盘子从x移动到z上
hanoi(n-1, y, x, z) # 将y上的n-1个盘子移动到z上
n = int(input('请输入汉诺塔的层数:'))
hanoi(n, 'L', 'M', 'R')