记Python学习笔记
一、输入与输出
1. 输出
多种输出方式:
print('hello, python')
print('hello', 'python') # ,会被解释为空格
print(10)
print(1+2)
2. 输入
输入使用input,返回值就是输入的内容,参数就是提示语:
str1 = input('Please input:')
print('Your input is:' , str1)
# Please input:aaa
# Your input is: aaa
二、数据类型与变量
1. 数据类型
-
整数
对于大数字可以用_分割,而且十六进制数也支持,例如0xdead_beef,0x100_999_000
整数的大小没有限制
-
浮点数
对于很大或者很小的浮点数,必须使用科学计数法,把10用e替代,1.23x109就是
1.23e9,或者12.3e8,0.000012可以写成1.2e-5浮点数没有大小限制,但是超过一定范围就直接表示为inf(无穷大)
为什么python中的除法也是精确的?
python中有两种除法:
- / : 这种除法运算结果是浮点数,即使结果刚好整除,
- // : 地板除,两个整数的除法任然是整数,这会只保留整数部分,其余部分抛弃
-
字符串
字符串以 ’ 或者 “ 括起来,有以下转义字符表示特殊符号
\n 换行 \t 制表符 \ 右斜线\
r’ ’表示不转义,也就是想要输入\就不用输入\
多行内容用
print('''hello, world python ''') -
布尔值
布尔值与布尔代数完全一致,有True和False两种值
布尔值可以通过以下运算符运算
and 与运算 相当于 &&
or 或运算 相当于 ||
not 非运算 相当于 ~
-
空值
空值是python中的特殊值,用None表示,None与0不一样,0是有意义的,而None是一个特殊空值
在计算机内部,可以把任意数据类型看作对象,变量就是用来指向这些对象的,
2. 变量
python是动态语言,定义变量类型的时候不需要显式地指定变量类型
>>> a=1
>>> a="hello"
>>> print(a)
hello
3. 常量
常量就是不能改变的变量,通常python中用全部大写的变量名表示常量(只是约定俗成,但是实际并无限制)
三、字符串
总结字符串标志前缀:
r'' # 不转义内容
b'' # bytes类型数据 由于Python的字符串类型是str,在内存中以Unicode表示,
# 一个字符对应若干个字节。如果要在网络上传输,
# 或者保存到磁盘上,就需要把str变为以字节为单位的bytes。
f'' # f-string格式化字符串
大多数情况下,计算机在存储数据的时候使用UTF-8编码,显示的时候使用Unicode编码
使用记事本时,从文件读取的UTF-8字符被转换为Unicode字符到内存里,编辑完成后,保存的时候再把Unicode转换为UTF-8保存到文件:
浏览网页的时候,服务器会把动态生成的Unicode内容转换为UTF-8再传输到浏览器:
编码与解码
在python3中,字符串以Unicode编码,ord()可以将字符转为整数,chr()将编码转换为对于字符
>>> ord('A')
65
>>> ord('你')
20320
>>> chr(20320)
'你'
以Unicode表示的str通过encode()方法可以编码为指定的bytes
>>> 'aaa'.encode('ascii')
b'aaa'
>>> '你'.encode('ascii')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character '\u4f60' in position 0: ordinal not in range(128)
>>> '你'.encode('unicode')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
LookupError: unknown encoding: unicode
>>> '你'.encode('utf-8')
b'\xe4\xbd\xa0'
>>> b'\xe4\xbd\xa0'.decode()
'你'
如果bytes中存在小部分无效字节,可以使用error=’ignore’参数忽略
>>> b'\xe4\xbd\xa0\x87'.decode('utf-8', errors='ignore')
'你'
>>> b'\xe4\xbd\xa0\x87'.decode('utf-8')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x87 in position 3: invalid start byte
字符串长度
>>> len('aaa')
3
>>> len('你好')
2
>>> len(b'你好')
File "<stdin>", line 1
len(b'你好')
^
SyntaxError: bytes can only contain ASCII literal characters
>>> len('你好'.encode('UTF-8'))
6
一个中文字符在UTF-8编码之后通常占3字节,1个英文字母占一个字节
为了使Python解释器按UTF-8编码读取,可以在文件头加上:
#!/usr/bin/env python3 # 为了告诉Linux/OS X系统,这是一个Python可执行程序,Windows系统会忽略这个注释
# -*- coding: utf-8 -*- # 按照UTF-8编码读取源代码,否则,你在源代码中写的中文输出可能会有乱码
格式化字符串
-
方法一
类似于C语言的格式化方式,用%实现
>>> 'hello %s' % ('World')
'hello World'
>>> a = 1
>>> 'num is %d' % a
'num is 1'
如果不知道用什么,可以尝试使用%s,这回将任何类型转换为字符串,同时%%表示一个%字符
-
方法二 使用format()
>>> 'Hello, {0}! Num is {1}, it\'s {2}'.format('vstral', 19, True) "Hello, vstral! Num is 19, it's True" >>> 'Hello, {}! Num is {}, it\'s {}'.format('vstral', 19, True) "Hello, vstral! Num is 19, it's True" -
方法三 f-string
使用f开头的字符串
>>> print(f'Hello, {name}! Your age is {age}')
Hello, vstarl! Your age is 19
>>> r = 2.5
>>> s = 3.14 * r ** 2
>>> print(f'The area of a circle with radius {r} is {s:.2f}')
The area of a circle with radius 2.5 is 19.62
四、list与tuple类型
list
list是python内置的一种数据类型,是一种有序的集合,可以随时添加或删除其中的数据
>>> cls = ['aaa', 'bbb', 'ccc']
>>> cls
['aaa', 'bbb', 'ccc']
len()可以获得list元素的个数
>>> len(cls)
3
用索引访问对应位置元素,可以使用正负索引
>>> cls[1]
'bbb'
>>> cls[-1]
'ccc'
追加元素到末尾:
>>> cls.append('ddd')
>>> cls
['aaa', 'bbb', 'ccc', 'ddd']
插入到指定位置
>>> cls.insert(2, 'xxx')
>>> cls
['aaa', 'bbb', 'xxx', 'ccc', 'ddd']
删除末尾元素/删除指定位置
>>> cls.pop()
'ddd'
>>> cls
['aaa', 'bbb', 'xxx', 'ccc']
>>> cls.pop(1)
'bbb'
>>> cls
['aaa', 'xxx', 'ccc']
需要替换某个位置的元素可以直接赋值
>>> cls[1] = 'bbb'
>>> cls
['aaa', 'bbb', 'ccc']
list也可以是一个元素(二维)
>>> cls[2] = ['1', '2', '3']
>>> cls
['aaa', 'bbb', ['1', '2', '3']]
>>> cls[2][2]
'3'
tuple
tuple是另外一种有序列表,叫做元组,与list相似,但是tuple一旦初始化就不能修改,
>>> cla=(1, 2, 3)
>>> cla
(1, 2, 3)
>>> cla[1]=5
Traceback (most recent call last):
File "<python-input-21>", line 1, in <module>
cla[1]=5
~~~^^^
TypeError: 'tuple' object does not support item assignment
注意,当定义一个元素的tuple时,需要一点添加
>>> a=(2) # ()为运算符
>>> a
2
>>> b=(2,) # 添加一个, 以消除歧义
>>> b
(2,)
当一个tuple有一个list元素会怎么样?
内层的list元素的元素是可以改变的!
这就是指向不变的,tuple指向的是list这个对象,而不是内部的每一个元素
>>> a=(1,2, [3,4])
>>> a
(1, 2, [3, 4])
>>> a[2][1] = 1
>>> a
(1, 2, [3, 1])
五、条件判断与循环控制
条件判断
与C语言类型,使用if-else进行判断,对于多个判断使用elif
这一块不再学习
语法结构
if <条件判断1>:
<执行1>
elif <条件判断2>:
<执行2>
elif <条件判断3>:
<执行3>
else:
<执行4>
模式匹配
类似于swich case结构,python也有match-case结构
score = 'B'
match score:
case 'A':
print('score is A.')
case 'B':
print('score is B.')
case 'C':
print('score is C.')
case _: # _表示匹配到其他任何情况,类似于default
print('score is ???.')
复杂条件匹配
通过将一个值增加到一系列值的匹配
age = 15
match age:
case x if x < 10:
print(f'< 10 years old: {x}')
case 10:
print('10 years old.')
case 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18:
print('11~18 years old.')
case 19:
print('19 years old.')
case _:
print('not sure.')
循环
- for-in循环
a = ['aaa', 'bbb', 'ccc']
for i in a:
print(i)
##
aaa
bbb
ccc
range()函数可以生成一个0-10的整数序列,注意range函数为左闭右开
>>> for i in range(1,10):
... print(i)
...
1
2
3
4
5
6
7
8
9
- while循环
while可以一直循环运行,直到遇到退出的指令或者条件不满足
while True:
print(1)
- break
break可以使得循环提前退出
n = 1
while n <= 100:
if n > 10: # 当n = 11时,条件满足,执行break语句
break # break语句会结束当前循环
print(n)
n = n + 1
print('END')
- continue
循环中,可以使用continue语句跳过当前的循环,直接进入下一次循环
n = 1
while n <= 10:
n = n + 1
if n % 2 == 0:
continue
print(n)
print('END')
3
5
7
9
11
END
六、dict和set
dict
dict是python内置的字典,在其他语言中也被称为map,使用键值对(Key-Value)储存,有极快的查找速度
>>> d = {'aaa':111, 'bbb':222, 'ccc':333}
>>> d['ccc']
333
为什么dict查找速度这么快?
在list中,查找原理就是从前往后地依次遍历,list越大,查找越慢
而在dict中,给定一个名字 ’aaa’ ,dict就会在内部计算出这个 ‘aaa’ 对应数据的内存地址,直接取出来
dict查找原理:
基于哈希表,这是一种效率极高的数据结构,平均情况下时间复杂度为O(1)
-
当执行num[key]的时候,python会调用内置hash(key)计算key得hash值,hash值是一个整数
-
计算索引:hash通常是一个很大的整数,所以需要通过取模运算来进行映射
假设数组大小为n:(index = hash(key) % n)
-
检查槽位index位置
- 槽位为空:不存在这个健:抛出KeyError异常
- 槽位不为空:
- 键匹配:存在键值对,而且与查找的key相同(使用
==比较),返回值,查找完成 - 键不匹配:发生hash冲突。即两个不同的健经过hash函数计算后得到相同的数组索引。就需要处理hash冲突(二次探查)
- 键匹配:存在键值对,而且与查找的key相同(使用
判断一个值是否在dict中
-
使用 in 判断
>>> d = {'Michael': 95, 'Bob': 75, 'Tracy': 85} >>> 'Bob' in d True >>> 'aaa' in d False -
使用get方法,如果key不存在,返回None(交互环境不显示结果),或者自定义返回值
>>> d.get('Bob')
75
>>> d.get('Bob',-1)
75
>>> d.get('aaa',-1)
-1
删除一个Key
使用pop方法,对应的Value也会被删除
>>> d.pop('Bob')
75
>>> d
{'Michael': 95, 'Tracy': 85}
dict的特性
与list相比,有以下特点:
- 查找和插入速度极快,不会随Key增加而变慢
- 需要暂用大量内存,内存浪费多
所以dict是一种空间换时间的方法,切记dict的Key是不可变对象,因为dict是根据Key来计算对应Value的存储位置
七、函数
常用函数
| 函数名 | 功能 | |
|---|---|---|
| abs | 返回绝对值 | |
| help | 查看函数作用 | |
| int | 将其他数据类型转换为整数 |
函数的定义
def myFunction(a, b):
return a + b
空函数(用来做占位函数,待实现功能)
def nop_func():
pass
返回多个值(实际上是一个tuple元组)
import math
def move(x, y, step, angle=0):
nx = x + step * math.cos(angle)
ny = y - step * math.sin(angle)
return nx, ny
x, y = move(100, 100, 60, math.pi / 6)
print(x, y)
151.96152422706632 70.0
默认参数:当没有设置这个参数值的时候使用默认参数
def power(x, n=2):
s = 1
while n > 0:
n = n - 1
s = s * x
return s
def enroll(name, gender, age=6, city='Beijing'):
print('name:', name)
print('gender:', gender)
print('age:', age)
print('city:', city)
enroll('Adam', 'M', city='Tianjin') # 只更改需要更改的默认参数
注意点:默认参数必须指向不变对象!
可变参数
顾名思义,可变参数就是传入的参数是可变的,可以是1个,2个…还可以是0个
def calc(*num):
total = 0
for i in num:
total += i
return total
print(calc(1, 2))
print(calc(1, 2, 3)
这里传入函数内部的num是一个tuple类型
当想要将一个list或者一个tuple传入到函数的时候,可以使用*
num = {1, 2, 3, 4}
def calc(*nums):
total = 0
for n in nums:
total += n
return total
print(calc(*num))
关键字参数
可变参数允许你传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple。而关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。
def output(name, age, **say):
print(say)
print(f'Name: {name}, Age: {age}. say: {say}')
output('Alice', 30, hobby='reading', city='New York')
{'hobby': 'reading', 'city': 'New York'}
Name: Alice, Age: 30. say: {'hobby': 'reading', 'city': 'New York'}
注意:这里的say参数表示把函数外部的这个dict的所有传入到了函数内,并且是一份拷贝,所以函数内的改动并不会影响函数外部
八、高级特性
切片
如何只取出lsit或者tuple中的部分元素?
L = ['Michael', 'Sarah', 'Tracy']
print(L[0:2])
# ['Michael', 'Sarah']
str = "abcdefj"
print(str[1:4])
# bcd
# 倒数第一个元素的索引是-1
str = "abcdefj"
print(str[-4:-1])
# def
str = "abcdefj"
print(str[-4:])
# defj
# 每两个取一个
str = "abcdefj"
print(str[::2])
# acej
练习:利用切片和递归去除字符串首尾的空格
def trim(s):
if (s[:1] == ' '):
return trim(s[1:])
elif (s[-1:] == ' '):
return trim(s[:-1])
else:
return s
# 测试:
if trim('hello ') != 'hello':
print('测试失败!')
elif trim(' hello') != 'hello':
print('测试失败!')
elif trim(' hello ') != 'hello':
print('测试失败!')
elif trim(' hello world ') != 'hello world':
print('测试失败!')
elif trim('') != '':
print('测试失败!')
elif trim(' ') != '':
print('测试失败!')
else:
print('测试成功!')
迭代
如果给定一个list或者tuple,我们就可以通过for循环来遍历这个list或者tuple,这种遍历称为迭代(Iteration)
在python中,迭代通过for-in来完成,C语言的迭代通过遍历每一个下标值来完成,而python的for循环抽象程度高于C的for,因为python的for还可以用在其他可迭代对象上例如dict、字符串等
要想实现类似Java的下标循环,可以使用内置的enumerate将list转换为索引-元素对,这样就可以同时迭代索引和元素本身
a = ['aaa', 'bbb', 'ccc']
for i, v in enumerate(a):
print(i, v)
0 aaa
1 bbb
2 ccc
列表生成式
列表生成式即LIst Comperhensions,是python内置用来创建list的生成式
例如:
- 生成1-9的序列
l = list(range(10))
print(l)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
- 生成12,22,3^2 …
l = []
for i in range(10):
l.append(i * i)
print(l)
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
或者
l = [x * x for x in range(10)]
print(l)
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
进一步:
l = [x * x for x in range(10) if x % 2 != 0]
print(l)
[1, 9, 25, 49, 81]
还可以两层循环,生成全排列
l = [x+y for x in 'abc' for y in 'cde']
print(l)
['ac', 'ad', 'ae', 'bc', 'bd', 'be', 'cc', 'cd', 'ce']
将list中所有字符转小写
L = ['Hello', 'World', 'IBM', 'Apple']
print([s.lower() for s in L])
['hello', 'world', 'ibm', 'apple']
列表生成式中的if-else应用
L = [x if x % 2 == 0 else -x for x in range(10)]
print(L)
[0, -1, 2, -3, 4, -5, 6, -7, 8, -9]
生成器 generator
通过列表生成式可以直接创建一个列表,但是当我们想要创建一个很大的列表的时候,而且只需要前面几个元素,就会造成很大的内存浪费
所以可以使用生成器,生成器相当于是保存了列表规律的算法,他会循环推演出后续的元素,这样一边循环一边计算
创建一个generator,有很多方法:
- 只需要将一个列表生成式的{ }改为( )
L1 = [i for i in range(10)]
L2 = (i for i in range(10))
print(L1)
print(L2)
print(next(L2))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
<generator object <genexpr> at 0x0000025363676740>
0
L2 = (i for i in range(10))
print(L2)
for i in L2:
print(i)
当需要创建一些复杂一点的生成器的时候,单单for就很难实现,但是使用函数就会很容易,比如斐波拉契数列
def fb(max):
n, a, b = 0, 0, 1
while n < max:
print(b)
a, b = b, a + b
n = n + 1
return "done"
fb(6)
1
2
3
5
8
13
这就是定义generator的另一种方法,如果一个函数定义中包含yield关键词,那么这个函数就不再是一个普通函数而是一个generator函数,调用一个generator函数将会返回一个generator
yield函数的执行流程与普通函数不同普通函数是按顺序执行,直到遇到return或者全部执行完毕返回,而yield函数在每次调用next的时候执行,直到遇到yield返回,再次执行时从上一次yield的地方开始
def fb(max):
n, a, b = 0, 0, 1
while n < max:
a, b = b, a + b
n = n + 1
yield(b)
f = fb(6)
print(next(f))
print(next(f))
print(next(f))
print(next(f))
print(next(f))
1
2
3
5
8
注意:调用generator会创建一个generator对象,多次调用generator会创建多个相互独立的generator
在实际使用中一般不会用next来获得下一个返回值,而是使用for循环迭代
但是用for循环调用generator时,发现拿不到return的返回值因为return的返回值在StopIteration错误中
杨辉三角实现:
def triangles():
L = [1]
while True:
yield L[:]
temp = L[:]
for i in range(len(L) - 1):
L[i + 1] = temp[i] + temp[i + 1]
L.append(1)
# 期待输出:
# [1]
# [1, 1]
# [1, 2, 1]
# [1, 3, 3, 1]
# [1, 4, 6, 4, 1]
# [1, 5, 10, 10, 5, 1]
# [1, 6, 15, 20, 15, 6, 1]
# [1, 7, 21, 35, 35, 21, 7, 1]
# [1, 8, 28, 56, 70, 56, 28, 8, 1]
# [1, 9, 36, 84, 126, 126, 84, 36, 9, 1]
n = 0
results = []
for t in triangles():
results.append(t)
n = n + 1
if n == 10:
break
for t in results:
print(t)
注意一个易错点:返回yield的时候要返回L[:]这是为什么呢?
L[:}指的是对L做一次切片拷贝,拷贝和原来的占用不同的内存,为什么不能直接yield L,因为后面使用的是append,实际上是对同一个list对象的引用,下一次修改的时候会导致前面也被修改
本文来自博客园,作者:vstral,转载请注明原文链接:https://www.cnblogs.com/vstral/p/19059375

浙公网安备 33010602011771号