Python学习笔记(1)

数据类型

除,整除

与其他语言不通,/是除法,得到的 float 类型,要得到整型需要用//

1
2
3
4
type(2/2) # float
type(2//2) # int
1//2 # 0
1/2 # 0.5

二进制,八进制,十六进制

1
2
3
4
5
6
7
8
9
10
11
0b10 # 2进制
0o10 # 8进制
0x10 # 16进制
# 将一个数转为二进制
bin(12)
# 将一个数转为10进制
int(0x12)
# 将一个数转为16进制
hex(12131)
# 将一个数转为8进制
oct(0x1231)

布尔类型

布尔类型有两个值,TrueFalse

  • 对于整数来说,非 0 可以转为True,0 可以转为False
  • 对于字符串来说,空字符串可以转为False,其他字符串可以转为True
  • 对于列表和元组等序列来说,空序列可以转为False,序列中有元素可以转为True
  • 对集合和字典来说,空字典,空集合可以转为False,字典或序列中有元素可以转为True
  • None 也可以转为False
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
num1 = 1
if num1:
print('YES') # YES
else:
print('NO')

num2 = 0
if num2:
print('YES')
else:
print('NO') # NO

list1 = []
list2 = [1, 2, 3]
if list1:
print('YES')
else:
print('NO') # NO

if list2:
print('YES') # YES
else:
print('NO')

dict1 = {}
dict2 = {1: 'A', 2: 'B'}
if dict1:
print('YES')
else:
print('NO') # NO

if dict2:
print('YES') # YES
else:
print('NO')

单引号和双引号

  • 单引号:单引号可以包含双引号,例如:'My name is "ljl"'
  • 双引号:双引号也可以包含单引号,例如:"Let's go"

多行文本

多行文本可以用三个双引号表示,也可以用三个单引号表示,例如:

1
2
3
4
5
6
7
8
9
10
11
'''
Hello!
My name is Liuijinlong.
What is your name?
'''

"""
Hello!
My name is Liuijinlong.
What is your name?
"""
  • 要显示字符串的格式要使用print函数
  • idle 会把字符串中的格式变为转义字符,如下:

1

原始字符

在字符串前加一个 r,字符串中的转义字符不会被解析

1
print(r'aaa \n aaa') # aaa \n aaa

字符串的操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
s1 = "Hello"
s2 = "World"

# 拼接
s = s1 + s2
print(s) # HelloWorld

# 截取,切片操作
print(s[2]) # l
print(s[2: 5]) # llo
print(s[2: -3]) # lloWo

print(s1 * 2) # 重复字符串:HelloHello
print(len(s1)) # 字符串长度:5
print(s1.count('l')) # l在字符串中出现的次数
print(s1.find('ell')) # 查找字符串,返回第一次出现的位置,返回-1表示未找到
print(s1.index('ell')) # 返回首次出现的位置,与find方法类似,如果未找到会返回错误
print(s1.endswith('lo')) # 是否以lo结尾
print(s1.startswith('he')) # 是否以he开头
print(s1.isalnum()) # 返回是否至少有一个字符并且都是是字母或数字
print(s1.isalpha()) # 返回是否至少有一个字符并且都是字母
print(s1.isdigit()) # 返回是否至少有一个字符并且都是数字
print(s1.islower()) # 返回是否至少有一个字符并且都是小写字母
print(s1.isupper()) # 返回是否至少有一个字符并且都是大写字母
print(' '.join([s1, s2])) # 合并s1, s2,已空格分割
print((s1 + ' ' + s2).split(' ')) # 按指定分隔符分割字符串
print(s1.title()) # 返回首字母大写的字符串
print(s1.strip()) # 去掉s1前后的空格

模板字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
name = "Liujinlong"
print("My name is %s" % name)
pi = 3.14
print("Pi is %.2f" % pi)

str1 = "Hello"
str2 = "World"
print("%s %s" % (str1, str2))

msg = {"action": str1, "name": str2}
print("%(action)s %(name)s" % msg)
print("{0} {1}".format(str1, str2))
print("{action} {name}".format(**msg)) # 双星号相当于解包字典

Python 中的列表

列表的定义

  • 列表中元素的类型是任意的
1
2
3
a = [1, 2, 3]
b = [1, "ljl", [1, 2, 3], True]
c = list()

列表的操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
l1 = [1, 2, 3, 4]
l2 = ['a', 'b', 'c']

print(l1 + l2) # 合并
print(l1 * 2) # 重复
print(l1[2]) # 获取
print(l1[2: 4]) # 切片操作
l1.append(3) # 添加元素
print(l1.count(3)) # 列表中某个元素的个数
print(len(l1)) # 列表长度
print(l1.index(3)) # 某个元素在列表中的位置,未找到返回错误
l1.extend(l2) # 将l2的所有元素添加到l1中
print(l1)
l1.insert(11, 2) # 在指定位置添加元素
print(l1)
l1.pop() # 删除列表末尾元素
print(l1)
l1.remove('a') # 删除指定元素
print(l1)
l1.reverse() # 逆序列表
print(l1)
l1 = [3, 1, 4, 5, 8, 2]
l1.sort() # 列表排序
print(l1)

a = [1, 2, 3]
a.append(4)
print(a) # 1, 2, 3, 4
a.extend([5]) # 1, 2, 3, 4, 5
print(a)
a.append([6, 7]) # [1, 2, 3, 4, 5, [6, 7]]
print(a)
a.extend([8, 9]) # [1, 2, 3, 4, 5, [6, 7], 8, 9]
print(a)

# extend会自动把要添加的列表逐一添加到原列表模块,append是将元素直接添加到列表末尾

value = a.pop() # 删除列表中最后一个元素并返回这个元素
print(value)
print(a)
a.remove(3) # 删除列表中值为3的元素
print(a)
del(a[0:3]) # 删除a中第0到3位置上的元素
print(a)

元组

  • 列表与元组的区别
    • 列表时可变的,元组不可变
    • 元组可以作为字典的 key,但是列表不行
1
2
3
4
5
6
7
8
9
10
(1, 2, 3, True)
(1, 2, 3)[1]
(1, 2, 3, 4)[0:3] # 得到一个元素
(1, 2, 3) + (3, 3, 3) # (1, 2, 3, 3, 3, 3)
(1, 2, 3) * 3 # (1, 2, 3, 1, 2, 3, 1, 2, 3)
type((1)) # int,这是因为内层括被解析成了数学运算的括号
type((1,)) # tuple
min((1, 2, 3)) # 最小值
max((1, 2, 3)) # 最大值
(,) # 空元组

序列的总结

  • str list tuple 都属于序列
  • 每个元素都会分配一个序号
  • 都支持切片操作
  • 支持包含操作:
1
2
3
print('or' in 'Hello world')  # True
print(1 in [1, 2, 3]) # True
print('a' not in ('a', 'c', 12)) # False
  • 长度:len([1, 2, 3])
  • 最大最小:max([1, 2, 3]), min([1, 2, 3])

集合

  • 集合 Set 的特点
    • 元素是无序的
    • 元素是不重复的
1
2
3
4
5
6
7
8
{1, 2, 3, 4, 5}
len({1, 2, 3}) # 3
1 in {1, 2, 3} # True
1 not in {1, 2, 3} # True
{1, 2, 3, 4, 5} - {3, 4} # 求两个集合的差集
{1, 2, 3, 4, 5} & {3, 4} # 求两个集合的交集
{1, 2, 3, 4, 5} | {3, 4} # 求两个集合的并集
set() # 空集合

字典

  • Key 不能重复
  • Key 必须是不可变的类型
    • 列表是可变的,所以不能作为字典的 key
    • int,元组,bool 都是不可变的
1
2
3
4
5
6
7
8
9
10
11
12
empty = {}  # 空字典
user = {"name": "ljl", "age":12}
print(user["name"])
user["school"] = "tyut"
user.update({"address": "shenzhen"})
del(user["address"]) # 删除某个key
print(user)
user.clear() # 清空
print(user)
print(user.keys()) # 所有key
print(user.values()) # 所有value
print('address' in user) # 是否包含某个key

变量和运算符

变量的定义

  • Python 中的变量就是一个值的别名
  • 原则:变量名要有意义

变量命名规则

  • 变量名的首字符不能是数字
  • 只能包含字母,数字,下划线
  • 系统的关键字不能用作变量名,非系统保留关键字,但是标准库函数的,也不要使用,例如:type
  • 变量区分大小写

值类型和引用类型

  • 值类型:int, str, tuple
  • 引用类型:list, set, dict
  • id(): 显示变量内存地址

list 与 tuple

  • list 是可改变的
  • tuple 是不可改变的
  • 使用原则:能用元组尽量用元组,因为元组不可改变,更为安全
1
2
3
4
a = [1, 2, 3]
a[0] = 11 # OK
b = (1, 2, 3)
b[0] = 11 # error

运算符号

  • 数学运算符:+-*/
  • 整除://
  • 余数:%
  • 乘方:** 例如,2**2 = 4
  • 赋值运算符:=, +=, -=, *=, /=, %=, **=, //=
  • 比较运算符:==, !=, >=, >, <=, <
    • 字符串,bool 都可以比较,字符串转为 ascii 码进行比较,bool 则是 True 转为 1,False 转为 0
    • 比较返回一个 bool 值
    • 列表,元组都可以比较,比较的规则是一个一个元素进行比较,直到比较出结果
  • 逻辑运算符:and, or, not
    • 非 Bool 类型也可以进行逻辑运算,规则是将非 Bool 类型先转为 Bool 类型再进行计算
    • int, float 转为 bool,0 为 False,非 0 为 True
    • 字符串转为 bool,空字符串为 False,非空字符串为 True
    • 列表转为 bool,空列表为 False,非空列表为 True
    • 元组,set,dict 与列表一样
    • 举例:
      • 2 and 1 # 1
      • 1 and 2 # 2
      • 1 or 2 # 1
      • 0 or 1 # 1
      • 返回的值符合就近原则,例如2 and 1,更具左边的元素 2 无法判断出结果,读取 1 后,可以判断出结构,所有返回 1,1 or 2根据左边的元素 1 就直接可以判断出表达式的值,所以直接返回 1
  • 成员运算符:in, not in
    • 一个元素是否在另外的一组元素中
    • 返回 bool 类型
    • 可以作用于:列表,字符串,元组,set,dict
    • 字典判断的是 key
  • 身份运算符:is, not is
    • 比较的是两个变量的内存地址是否相等
    • 对象的三个特征:值,类型,身份
    • 判断类型 type(a): type(a) == int
    • 推荐使用 isinstance()方法进行类型判断,例如:isinstance(a, int), isinstance(a, (int, float, str))
  • 位运算符:&, |, ^, ~, <<, >>

特殊的地方:

  • Python 没有自增,自减操作

分支,循环,条件,枚举

什么是表达式

  • 表达式是运算符和操作数所构成的序列

表达式优先级

  • and 的优先级大于 or,not > and > or
  • 解析表达式的顺序:
    • 相同优先级从左向右,左结合
    • 使用括号改变优先级
    • 赋值运算符是右结合

流程控制语句

  • if, if-else
  • pass 空语句
  • while 语句, while-else(循环退出时,执行 else)
  • for: 遍历集合,序列,字典,for-else(遍历完成,执行 else)
  • break:跳出循环,从 break 退出循环,不会执行 else 语句
  • continue: 跳过本次循环
  • range 函数,第一个参数为起始位置,第二个参数为序列元素个数,第三个参数为步长
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
a = 1
while a < 10:
print(a)
a += 1
else:
print('Over')

for x in range(0, 10):
print(x)

for i in range(0, 10):
print(i)
if i == 8:
break
else:
print('Over') # Over不会打印,因为循环break了

num = 10
if 5 < num < 20: # 可以使用这种判断条件
print("hello")

Comprehension

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# List Comprehension
numbers = [i for i in range(0, 10)] # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print(numbers)
numbers = [i for i in range(0, 10) if i % 2 == 0] # [0, 2, 4, 6, 8]
print(numbers)
strings = [['1', '2', '3'], ['4', '5', '6'], ['7', '8', '9']]
faltten = [int(i) for item in strings for i in item]
print(faltten) # [1, 2, 3, 4, 5, 6, 7, 8, 9]
xSamples = [2, 5, 8]
ySamples = [2, 6, 8]
points = [(x, y) for x in xSamples for y in ySamples if x != y]
print(points) # [(2, 6), (2, 8), (5, 2), (5, 6), (5, 8), (8, 2), (8, 6)]

# Set Comprehension
numbers = {i for i in range(0, 10)}
print(numbers) # {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}

# Dictionary Comprehension
dicts = {i: str(i) for i in range(0, 10)}
print(dicts) # {0: '0', 1: '1', 2: '2', 3: '3', 4: '4', 5: '5', 6: '6', 7: '7', 8: '8', 9: '9'}

包,模块,类,函数与变量

  • 一个文件夹就是一个包,包名就是文件名
  • 子包:文件夹里还有一个文件夹
  • 文件夹里必须有一个__init__.py文件

模块

  • 一个文件就是一个模块,模块名就是文件名
  • 不同包的相同模块在引用是使用:包名.模块名
  • __init__.py文件也是一个模块

导入另外一个模块

导入一个模块有两种方法,import 和 from-import

import 导入

  • 语法:import package1
  • import 导入的是一个模块,使用模块里的变量名时需要带上模块名,例如package1.a
  • 可以使用 as 关键字给模块起一个别名
1
2
3
4
5
import test
print(test.a)

import package.modual as p1
print(p1.a)

from-import 导入

  • 语法:from module import a
  • from-input 可以直接导入变量,例如from package.module import a
  • from-input 可以导入模块from package import module
  • 使用引入所有变量:`from test import `
  • 指定使用*时模块可导出的变量:使用内置变量__all__
  • 引入多个变量:from test import a, b, c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
from test import a
print(a)

from test import *
print(a)
print(b)
print(c)

__all__ = ['a', 'c'] # 指定使用*导入是,只导入a和c两个变量
a = 2
b = 3
c = 4

from test import *
print(a)
print(c)
print(b) # ERROR

from test import b
print(b) # OK


# 导入多个变量换行
from test import a, b, c, d,\
e, f, g
from test import (a, b, c, d,
e, f, g)

__input__.py文件

  • 导入包或者包内的某个模块时,__init__.py会被自动执行,可以做一些初始化的工作
  • __init__.py 的应用场景:
    • 决定哪些模块可以被导出
    • 批量导入某些模块,在使用包是不需要再次导入
    • 做一些包的初始化工作
1
2
3
4
5
6
7
8
9
10
11
# __init__.py 包名:t
__all__ = ['module1', 'module3'] # 只有module1和module2两个模块可以被导出

# 批量导入
import sys
import datetime
import io

# other.py
import t
print(t.sys.path)

包和模块的几个常见问题

  • 包和模块是不会重复导入的
  • 避免循环导入,即 A 模块导入 B 模块,B 模块又导入 A 模块,这样编译器会报错
  • 导入模块时就会执行模块里的代码,但只会执行一次

模块里的变量

可以使用 dir()可以打印出模块里的所有变量,dic(module)打印模块中所有的变量

  • __name__: 模块的完整名称,包括包名package.module
  • __package__: 模块所属的包名
  • __file__: 模块文件的完整路径
  • __doc__: 模块的注释
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# module1
'''
This is doc
'''
print(__name__)
print(__file__)
print(__package__)
print(__doc__)

# 结果
#package.module
#/Users/liujinlong/Documents/Study/Python/package/module.py
#package
#
#This is doc
#

如果一个模块被当成应用程序执行的入口(直接通过pyton xxx.py执行),则上面的几个变量就会变。

  • __name__变为__main__
  • __package__为空
  • __file__为是执行路径与模块文件名的相对路径,与执行路径有关
1
2
3
4
5
6
7
8
9
10
11
12
print("__name__ :" + (__name__ or "None"))
print("__package__:" + (__package__ or "None"))
print('__doc__:' + __doc__)
print('__file__: ' + __file__)

# 结果:
#__name__ :__main__
#__package__:None
#__doc__:
#this is doc
#
#__file__: test2.py

__name__的应用

1
2
if __name__ == '__main__':
pass

上面的语句是标明的 Python 文件既可以作为模块,也可以作为 app 的入口文件

相对导入和绝对导入

  • 顶级包和入口文件有关,入口文件所在的文件夹并不是顶级包
  • 绝对导入:从顶级包开始导入 import package1.package2.modulefrom package1.package2 import module1
  • 相对导入:from .m3 import *,相对导入只能用于from-import
    • 入口文件不能用相对导入,因为__main__这个模块是不存在的,除非使用python -m
    • .当前文件夹
    • ..上一层文件夹
    • …上上层文件夹
  • 注意事项:与入口文件同级目录下不要再有其他模块

示例,如下图目录结构:

2

要在main.py中引入其他模块,不能使用相对导入,只能使用绝对导入:

1
2
3
4
5
6
# main.py
import package1.module1_1
import package1.package1_1.module1_1_1 as m1_1_1
from package2.package2_1 import module2_1_1

m1_1_1.test() # test是定义在module1_1_1中的一个方法

module1_1_2.py中导入其他模块可以使用相对导入

1
2
3
4
5
6
7
8
from . import module1_1_1
from ..module1_1 import test1_1
from ..package1_2 import module1_2_1
import package2.package2_1.module2_1_1 as m211 # 这里只能用绝对导入

test1_1() # test1_1是module1_1.py里的一个方法
module1_2_1.test1_2_1() # test1_2_1是module1_2_1.py里的一个方法
m211.test2_1_1() # test2_1_1是module2_1_1.py里的一个方法

上面要注意的一点是,package1中的模块引用package2中的模块时,只能用绝对导入,因为package1package2都是和入口文件main.py同级的

未完待续!