Notes for python Chapter1
一、python的基本元素
输出语句
1 .print(< expr >, < expr >, …, end = ‘< expr >’)
注意: 缺省情况下, print函数将在各个输出值之间自动加入一个空格,并在末尾自动进行换行,end 默认为’\n’.
示例:
# 输出1,2,3并指定末尾表达式
>>> print(1, 2, 3, end = 'print over')
1 2 3print over
2 .格式化输出:
i.用%表示占位符:
>>> print('hello, %s' % ('world'))
hello, world
ii. format()方法
格式:print("{…}, {…}".format(…, …))
{}的内容为:
{<序号>: <填充> <对齐> <宽度> <,数字的千位分隔符> <. 精度> <类型>},
注意:只有填充无对齐会出错,<>^只存在一个时 默认为对齐。
示例:
# 以*为填充符号,左对齐,宽度20,加入数字千位分隔符,精度为保留小数点后两位,类型为浮点数的方式输出30000
print("{0:*<20,.2f}".format(30000))
30,000.00***********
# 根据关键词输出
print("{word1}, {word2}".format(word1 = 'hello', word2 = 'world'))
hello, world
赋值语句
1.input()赋值语句
< variable > = input(< prompt >)
>>> name = input("enter your name:")
enter your name:jack
>>> name
'jack'
input()函数将用户输入的数据作为字符串存储, 若为数值,需用eval()函数进行转换.
>>> num = eval(input("enter your number:"))
enter your number:10
>>> num
10
2.同时赋值
< var1 >, < var2 >, … = < expr1 >, < expr2 >,…
>>> x, y = eval(input("enter x, y:"))
enter x, y:1, 2
>>> x, y
(1, 2)
>>> x
1
>>> y
2
>>> x, y = y, x
>>> x
2
循环语句
- range()函数: 动态生成一个列表
>>> a = range(10)
>>> a
range(0, 10)
>>> list(a)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
- for循环: 作用于一个可迭代对象, 遍历其每一个元素,循环次数已知
>>> for i in range(0, 10):
print(i)
0
1
2
3
4
5
6
7
8
9
>>>
>>> for i in [0, 1, 2, 3, 4]:
print(i)
0
1
2
3
4
>>>
- while循环: 和C/C++,Java类似, 不满足循环条件时才退出循环,循环次数未知.
>>> i = 5
>>>> while i > 0:
i = i-1
>>> i
0
二、python的数值数据
数值数据类型
- int 和 float
利用type()函数验证:
>>> type(1)
<class 'int'>
>>> type(1.0)
<class 'float'>
- 两种除法 / 和 //
/ 为浮点除法,结果为浮点型.
// 为整除,结果只取整数部分,小数部分丢弃,结果的数据类型与参与计算的操作数的最高数据类型相同(float>int)
>>> 10/3
3.3333333333333335
>>> 10//3
3
>>> 10.0//3
3.0
四舍五入
需要使用round(<数据>, <保留小数位数>)函数
>>> round(3.1415926, 3)
3.142
*.5的情况:结果为和其最靠近的偶数,例如,round(1.5) = 2, round(2.5) = 2
>>> round(1.5)
2
>>> round(2.5)
2
>>> round(3.5)
4
>>> round(4.5)
4
三、图形
阅读graphics.py源代码,该代码基于Tkinter库实现了python的GUI编程和基本图形绘制.
练习题:绘制射箭的标靶,每个圆环有相同的宽度,并且该宽度等于黄色圆的半径.
from graphics import *
def main():
width = 960
height = 720
win = GraphWin("标靶", width, height)
win.setCoords(0, 0, 1000, 800)
# 开始绘制
centerPoint = Point(width / 2, height / 2)
radius = 15
circleWidth = radius
colorList = ['yellow', 'yellow', 'red', 'red', 'blue', 'blue', 'black', 'black', 'white', 'white'] # 将颜色存放到列表
i = 10
while i > 0: # 循环画圆
tempCircle = Circle(centerPoint, i * radius) # 设置圆的圆心和半径
tempCircle.setFill(colorList[i-1]) # 设置填充颜色
tempCircle.setOutline("gray") # 设置边框颜色
tempCircle.draw(win) # 将圆画入窗体
tempText = Text(Point(centerPoint.getX() + (i-1)*radius, centerPoint.getY()), 11 - i) # 设置Text的位置和内容
tempText.move(6, 0) # 将Text向右移动6个像素
tempText.setTextColor('pink') # 设置Text颜色
tempText.setSize(10) # 设置Text字体大小
tempText.draw(win) # 将Text写入窗体
i = i-1
win.getKey() # 键盘输入任意键结束
if __name__ == "__main__":
main()
运行结果:
四、字符串,列表与文件
字符串
字符串对象不可通过下标进行修改,但可通过replace()方法进行修改
-
下标:
从左往右,从0开始依次递增;
从右往左,从-1开始依次递减. -
索引:
直接通过下标进行访问 -
切片:
i.str[< start > : < end >],返回从 start 到 end-1 的字符串;
ii.str[ : < end >}, 返回从 0 到 end-1 的字符串;
iii.str[< start > : ],返回从 start 到 结束 的字符串. -
简单连接:
用运算符"+"将两个字符串连接在一起 -
重复连接:
用运算符"*",重复连接字符串多次 -
len():
返回字符串的长度
列表
列表对象可通过下表进行修改
- 列表解析式:
[< expr >]
例如:
>>> [x * 2 for x in range(10)]
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
>>> [x * 2 for x in range(10) if x%2 == 0]
[0, 4, 8, 12, 16]
- 列表生成器:
(< expr >)
与列表解析式最大的不同就是将中括号改成了圆括号,其好处是减少了内存占用,提高了空间效率.ps:具体还没弄太明白…
字符编码
Unicode编码标准
为解决乱码问题,国际标准化组织ISO提出了Unicode编码标准, 它把所有的语言都统一到这套编码里了.
最常用的是2个字节表示一个字符(如果要用到非常偏僻的字符,就需要4个字节)
但其缺点也很明显, 固定长度对英文字符不友好, 很多英文字符只需要1个字节便可编码, 两个字节只能补零, 存在浪费, 存储和传输过程中消耗较大.
UTF-8编码规则
UTF-8把一个Unicode字符根据不同的数字大小编码成1-6个字节, 常用的英文字母被编码成1个字节, 汉字通常是3个字节, 只有很生僻的字符才会被编码成4-6个字节, 传输大量包含英文字符的文本可节省空间.
ASCII编码实际上可以看成是UTF-8编码的一部分, 大量只支持ASCII编码的历史遗留软件可以在UTF-8编码下继续工作.
字符和编码的转换
1.对于单个字符, python提供了内建函数 ord(ordinal) 和 chr(character), 允许在字符及其Unicode编码之间进行转换:
>>> ord('a')
97
>>> chr(97)
'a'
2.python3中字符串类型数据为 str 类型, 而保存在磁盘或在网络上传输的数据为bytes类型, 他们之间常常需要相互转换.
# 字符串类型数据加上前缀 b 转变为bytes类型数据
>>> type('1')
<class 'str'>
>>> type(b'1')
<class 'bytes'>
str 转换为bytes:
使用encode()方法,需指定编码规则
>>> '中文'.encode('utf-8')
b'\xe4\xb8\xad\xe6\x96\x87'
bytes 转换为 str:
使用decode()方法,需指定编码规则
>>> b'\xe4\xb8\xad\xe6\x96\x87'.decode('utf-8')
'中文'
文件
- 生成文件对象
< variable > = open(< name >, < mode >)
其中< name >是文件名称, < mode >是打开模式, 可以是 “r”,或"w", 表示read和write.
例如:
infile = open("numbers.dat", "r")
- 读取文件内容
< file >.read(): 读取整个文件内容,将内容放到一个字符串对象中;
< file >.readine(): 读取文件的一行, 将内容放到一个字符串对象中;
< file >.readlines(): 读取整个文件内容,将内容以列表的形式放到一个列表对象中, 列表的每一个元素是文件的每一行;
五、函数和对象
函数:
-
定义:
def < name >(< formal-parameters >):
< body >
<return < value >>
函数名称 < name > 必须是一个合法的标识符, < formal-parameters >是形式参数序列, return 语句是可选的. -
设计原则:
i.代码尽量要复用——清晰(clarity)、简介(simplicity);
ii.避免语句反复出现——效率(efficiency),当然还包括运行于空间效率;
iii.多使用优雅的循环结构——优雅(elegance);
iiii.通用性(generality)与可扩展性(scalability);
iiiii.如果涉及到字符串的打印输出,最好使用 return 返回字符串,而不是在函数中使用 print 函数直接输出字符串,这样调用者可以自己决定字符串的处理方式(是输出到屏幕,还是输出到文件等)。 -
函数参数:
包括位置参数、默认参数、可变参数和关键字参数位置参数:
形式参数与实际参数要严格一一对应。默认参数:
放在必选参数之后,赋给其默认值。可变参数:
在可变参数情况下,传入参数的个数是可变的,定义和调用时,为可变参数加上前缀 * 。
使用方法:如果要传入列表或元组,可在对象前面添加 “ * ”;如果是一组数据,直接当作一般参数传入即可。
实际上,在函数调用时,可变参数自动组装成一个元组,可与其他类型参数一起混用
>>> def sum(*numbers): # numbers为可变参数
result = 0
for num in numbers:
result = result + num
return result
>>> l = [1,2,3,4,5]
>>> print(sum(*l)) # l为列表,作为可变参数传入时要加上前缀*
15
>>> print(sum(1,2,3,4,5)) # 一组数据直接传入
15
关键字参数:
与可变参数一样,关键字参数可用于其他类型参数一起混用——可变参数转换成元组,而关键字参数转换成字典。
不指定参数名称调用:
>>> def PrintInfo(name, **kp): # **kp为关键字参数,字典类型
print('name', name, end = ' ')
for key, value in kp.items():
print(key, value, end = ' ')
# 调用格式
>>> PrintInfo('zhangSan', sex = '男', age = 10)
name zhangSan sex 男 age 10
>>> d = {'sex' : '男', 'age' : 20}
>>> PrintInfo('lisi', **d) # 将字典类型参数传入
name lisi sex 男 age 20
指定参数名称调用:
>>> def PrintInfo(name, *, sex, age): # 用 * 将位置参数和关键字参数隔开
print('name', name, end = ' ')
print('sex', sex, 'age', age, end = ' ')
>>> PrintInfo('wangwu', sex = '女', age = 30)
name wangwu sex 女 age 30
# 调用函数时没有传入指定名称的关键字参数,执行时会报错
小结: 在定义函数时,这五种参数可以组合使用。但是,参数必须按如下顺序定义:必选参数§、默认参数(p = ?)、可变参数(*p)、命名关键字参数(…, *, kp1, kp2)和关键字参数(…, **kp)
对象
1. 对象的属性
- id号:可简单地认为它就是该对象的地址,可用内建函数 id() 来得到。
- 类型:类型决定了对象的值的类型、属性以及方法。可使用内建函数 type() 来查看对象的类型
- 值:及对象所表示的数据
2. 可变性与不可变性
- 可变的对象,意味着可对其进行修改;如 list,dict,set,bytearray;
- 而不可变的对象,是不能被修改的,当时图改变它们时,python将会返回一个新对象。如 int,float,decimal,complex,bool,string,tuple,range,frozenset,bytes。
- 在只读应用中,不可变对象的访问速度要快于可变对象;
- 在读写数据的情况下,使用可变对象;在只读的情况下,使用不可变对象;
- “更新”不可变对象会导致新对象的创建,代价大;更新可变对象不会创建新对象(成为 in-place 或原地修改方式),代价小;
- 在处理函数的缺省值时,不要使用可变对象,而要使用不可变对象;
- 将可变对象与不可变对象当作实际参数进行传递时,产生的效果是不一样的。
2. 参数传递
python采用传值方式——传递对象的ID号进行参数传递;
不可变对象作为参数进行传递时,修改其值会生成新对象,要达到类似C++中引用传递的效果,有两种解决办法:1.利用 return语句直接返回结果;2.要修改的值设为可变对象,将可变对象”嵌入“不可变对象中。
六、类
类的定义
-
格式:class < class-name >(< base >):
< method-definitions >
其中,< base >是基类名称.< method-definitions >是位于类的内部的方法, 每个方法的第一个参数是特定的——表示类的实例化对象,其名称是任意的,一般命名为 self (与C++中 this 指针起同样作用) -
构造函数: _ _ init _ _(self, < parameters >)
访问限制
- 在缺省情况下, 属性与方法都是 public 访问类型
- 在属性名称前加上两个下划线_ _,使该属性变成私有(private)变量.名称类似于 _ _ xxx _ _ 的变量是特殊变量, 它是可以直接访问的, 不是private变量.在类的内部,_xxx是protected类型,也可以直接访问.
- 两种定义 get 和 set 的方法:1.使用内建函数property(__get, __set) 关联__get 和 __set方法; 2.使用@property装饰器
七、其他结构化数据类型
1. 元组tuple:
简单地说,元组就是不可变的列表,如果不涉及到元素的修改, 优先使用元组——数更安全, 效率要优于列表.
2. 字典dictionary
python中具有映射关系的数据结构, < variable > = {key1 : value1, key2 : value2, …}
注意: 键可以是任意的不可变数据类型, 值可以是任意类型
在赋值的时候, 如果没有找到指定的键, python将自动新增该项
在应用中, 可以使用 "for key in dict"结构便利字典 dict 中的元素. 默认情况下, 该结构遍历字典中的 key .如果要遍历 value, 可以使用 " for value in dict.values() ".如果要同时遍历 key 和 value ,可以使用 " for k, v in
dict.items() "结构.
3. 集合set
集合和字典类似, 也是一组 key 的集合, 但他不存储 value ,并且不允许 key 重复.
集合中不允许key是可变对象, 因为无法判断两个可变对象是否相同, 也就无法保证集合内部是否存在相同的元素.
4. 堆heap
堆是一种树形数据结构, 它的父节点与子节点之间具有某种顺序关系.堆有最大堆和最小堆两种.python的 heapq 实现了最小堆.
5. 迭代器
可迭代对象:
- 结构化数据类型, 例如,字符串, 列表, 元组, 字典, 集合等;
- 生成器, 例如, 列表生成器及带 yield 的生成器函数.
可使用内建函数 isinstance 判断一个对象是否可迭代.
>>> from collections.abc import Iterable
>>> isinstance([1,2,3], Iterable)
True
迭代器:
- 可置于 for 循环中, 也可被内建函数 next 不断地调用而产生新元素,
- 字符串,列表,字典等结构化对象是可迭代对象但不是迭代器,生成器是迭代器
- 可使用内建函数 iter 将可迭代对象转换成迭代器
>>> from collections.abc import Iterator
>>> isinstance((x for x in range(10)), Iterator) # 生成器是迭代器
True
>>> isinstance([1,2,3], Iterator)
False
>>> isinstance({'1' : 1, '2' : 2, '3' : 3}, Iterator)
False
>>> isinstance('abc', Iterator)
False
>>> isinstance(iter('abc'), Iterator) # 将可迭代对象转换为迭代器
True
八、函数式编程
1. lambda算子
用于创建微型的、一次性使用的匿名函数,基本语法如下:
lambda arguments : expression
>>>> t = lambda x, y : x + y
>>> t(1,2)
3
>>> type(t)
<class 'function'>
lambda算子返回的是函数对象, 可用作高阶函数的参数.
2. 高阶函数
- map: map(function, iterable,…)
map接受两种类型的参数: 函数和可迭代对象, 其作用是, 将function作用于可迭代对象的每一项;
如果传入多个可迭代对象, 则function将并行作用于他们中的每一个元素;
如果可迭代对象的长度不一, map函数简单地忽略掉多余的元素;
map的执行结果作为迭代器(Iterator)返回.
>>> list(map(max, [1,2,3], [2,3,4])) # 并行作用于每一个元素
[2, 3, 4]
>>> list(map(max, [1,2,3], [2,3,4,5])) # 多余的元素被忽略
[2, 3, 4]
>>> isinstance(map(max, [1,2,3], [2,3,4]), Iterable) # map返回迭代器
True
- reduce: reduce(function, iterable, [initializer])
在可迭代对象中嵌套使用function
参数 initializer 充当一个缺省元素放在所有序列元素的前面并参与计算
>>> reduce(lambda x,y : x*10+y, [1,2,3,4,5], 6)
612345
- filter: filter(function, iterable)
从可迭代对象中过滤出满足条件的元素(函数 function 返回 True 的哪些元素)序列, 并作为迭代器对象返回.
如果 function不是 None 参数:
[item for otem in iterable if function(item)]
否则:
[item for item in iterable if item]
>>> list(filter(lambda x : x%2 == 1, [1,2,4,5,6,9,10,15]))
[1, 5, 9, 15]
>>> list(filter(None, [0,1,2]))
[1, 2]
- sorted: sorted(iterable, [key], [reverse])
key 指定用于数据预处理的函数, 它作用于可迭代对象的每一个元素上, 并根据返回结果进行排序.
reverse = False, 表示按从小到大顺序排序(缺省情况), 否则,reverse = True, 表示反向排序(从大到小).