[toc]

导入模块

Python 下 py 后缀的文件就是模块

编写 m.py 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
g_num1 = 100
g_num2 = 100
def main():
#若当前模块不是被导入的,那么这就是主模块
print("这是主函数,需要在当前为主模块的时候被执行")
#main()

#模仿主函数的行为,若当前模块为主模块,则__name__这个全局变量就会保存
#__main__字符串
if __name__ == "__main__":
main()

#写在全局范围的代码无论如何都会被执行,若是被导入的模块,那么__name__就是
#模块名,即去除后缀的文件名称
print(__name__)

#模块的私有属性(不会被直接访问到)
#所有以单下划线开头的全局变量不能被其他模块以
# from xxx import * 的方式访问
_pnumber = 10

编写 my.py 文件

使用 import 可以直接导入模块,导入模块的同时会执行其中的代码,但同一模块的代码不论 import 多少次都只执行一次,类似于 C++ 中的 include 没有使用命名空间

1
2
3
4
import m
print(m.g_num1)
# 访问模块私有的属性
print(m._pnumber)

推荐使用的方法,但较为繁琐,类似于 C++ 中的 include + using std::xxx 指令

1
2
from m import g_num2
print(g_num2)

直接使用指定模块内的所有对象不需要加模块名,类似于 C++ 中的 include + using std::xxx 指令

1
2
from m import *
print(g_num1, g_num2)

Python 中的类

Python 中类的格式:class 类名(基类名):

python3 中所有的类都默认继承自 object

1
2
3
4
5
6
7
class Student(object):
#所有的构造函数都叫__init__
def __init__(self):
pass
#所有的析构函数都叫__del__
def __del__(self):
pass

类属性的添加和使用,可以使用类名在类内或类外动态地添加新属性,虽然类名和实例都可以访问到类属性,但推荐使用类名,不能使用实例修改类属性

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
class CObj(object):
#在类的作用域中直接编写的属性就是类属性
#类属性类似C++中的静态数据成员
class_number = 10
#调用这个方法来生成一个新的类属性
def add_number(self):
CObj.class_number2 = 20
cobj = CObj()
#可以使用类名和实例访问到类属性,推荐使用类名
print(CObj.class_number, cobj.class_number) #10 10

#使用类名可以直接修改类属性,若尝试使用实例修改,
#本质上是给实例添加一个自己的属性
cobj.class_number = 100;
print(cobj.class_number, CObj.class_number) #100 10
CObj.class_number = 100
print(cobj.class_number, CObj.class_number) #100 100

#__dict__是一个字典,保存了当前的实例或对象中的所有属性
#包括函数,内置属性和自定义属性
print(cobj.__dict__, "\n", CObj.__dict__)

#可以在成员方法中或类外使用类名动态添加属性
CObj.class_number1 = 10
print(CObj.class_number1, "\n", CObj.__dict__) #10
cobj.add_number()
print(CObj.class_number2, "\n", CObj.__dict__) #20

实例属性就是使用 self 或实例名定义出来的属性,每个实例都会拥有自己的实例属性,同样可以使用类名或 self 动态添加属性

实例数据属性中包含类数据属性,而类数据属性不一定包含实例属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class CObj(object):                                                                                                                                                                                                                              
#构造函数添加的实例属性是每一个实例都拥有的
def __init__(self):
self.num = 10
#调用这个函数会动态地添加属性
def add_number(self):
self.num1 = 20
#创建两个实例分别测试
cobj1 = CObj()
cobj2 = CObj()
print(cobj1.__dict__, "\n", cobj2.__dict__)
print()
#动态地使用self添加属性
cobj1.add_number()
print(cobj1.__dict__, "\n", cobj2.__dict__)
print()
#动态地使用实例名添加属性
cobj2.num2 = 30
print(cobj1.__dict__, "\n", cobj2.__dict__)
print()
#删除一个属性
del cobj1.num1
print(cobj1.__dict__, "\n", cobj2.__dict__)

image-20191203160752046

遍历基类:

1
2
3
4
5
6
class CObj(object):
def __init__(self):
#所有的基类组成的一个元组
print(CObj.__bases__)
#并非所有的属性都能被遍历到
cobj = CObj()

类方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class CObj(object):
#一个类属性
class_num = 10
#实例方法必须使用实例调用,第一个参数是一个指向
#当前对象的“指针”,名字通常是self,自己可以改为其他名字,参数可以自己添加内容
def function1(self):
#print("实例方法", CObj.class_num)
print("实例方法", self.class_num)

#使用@classmethod修饰的方法就是类方法,类方法的第一个参数就是类本身
#通常叫做cls,可以使用cls访问到当前类的类属性
@classmethod
def function2(cls):
print("类方法",cls.class_num)

#静态方法使用和类方法没有太大区别,对参数没有要求,若想访问类属性
#可以直接通过类名
@staticmethod
def function3():
print("静态方法", CObj.class_num)
cobj = CObj()
cobj.function1()
cobj.function2()
cobj.function3()

类的私有属性,所有以双下划线开头的属性会被认为是私有的,不能直接被外界访问到。实际上私有只是解释器给属性进行更名,改为 _类名+属性名,但不推荐使用这种方式进行访问,所有以单下划线开头的命名约定是不可访问的

1
2
3
4
class CObj(object):
__num = 10
print(CObj.__dict__)
print(CObj._CObj__num)

类的继承:

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
class CBase1(object):
def __init__(self):
print("CBase1")

class CBase2(object):
def __init__(self):
print("CBase2")
#继承的形式:class 类名(父类名, ...)
class CObj(CBase1, CBase2):
def __init__(self):
print("CObj") #CObj
#可以使用父类的类名直接访问父类的属性(方法)
CBase1.__init__(self) #CBase1
#默认调用的是原型链中当前类的下一个
super().__init__() #CBase1
#super实际找到的类就是第一个参数在原型链中的下一个
super(CBase1, self).__init__() #CBase2
cobj = CObj()

#判断一个类是不是另一个类的子类
print(issubclass(CObj, CBase1))
#输出当前的所有父类组成的元组
print(CObj.__bases__)
#显示当前类的继承原型链
print(CObj.mro())

python 存在继承关系时不会出现二义性问题,当访问一个属性时解释器会遍历原型链首先找到谁就用谁

异常

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#若认为一部分代码可能会触发异常,就应该使用try进行包含
#产生异常的时候,异常的类型可以在输出窗口看到,不需要记忆
try:
print(a)
#接受任意一个异常对象并且取名字,输出
except Exception as e:
print(e)

#try finally 无论是否产生异常,都保证执行代码
try:
print("没有异常")
finally:
print("永远会执行")

#主动的抛出异常
name = input("please input name:")
if name == "hello":
raise NameError("input name error!")

特殊函数

filter

接收一个序列,将序列中的每个元素传入到提供的函数中进行判断,若函数的返回值为真,则将此元素添加到新的序列

1
2
3
4
5
6
7
8
#筛选出所有字符
def filter_alpha(param):
#传入所有的元素,但只留下返回值为True的元素
print(param)
#isalpha 是 str 的一个成员方法,用于判断是否是字母
#islower 是 str 的一个成员方法,用于判断是否是小写
return param.isalpha() and param.islower()
print(list(filter(filter_alpha, "Adj!df#@1ASdh&*")))

reduce

接收一个序列和函数,函数必须拥有2个参数,首先将序列的第一个元素和第二个元素作为参数传入到函数中,之后每次都将前一次的计算结果和下一个元素传入到函数中,最终返回计算结果

1
2
3
4
5
6
7
8
9
10
def add(num1, num2):
return num1 + num2
def mul(num1, num2):
return num1 * num2
#在 Python3 中 reduce 函数不再是内置函数,需要使用 fucntools
#模块才能够调用到 reducue 函数
from functools import reduce

print(reduce(add, range(101))) #可用来求和
print(reduce(mul, range(1, 6))) #可用来求阶乘

map

要求传入一个函数及一个或多个可迭代序列,函数的参数个数必须和序列的数量相同,map 会在内部分别将每个序列的元素传入到提供的函数中,并把函数返回值组合成一个新的可迭代序列

1
2
3
def rep_string(s, time):
return s * time
print(list(map(rep_string, "abcd", [1, 2, 3, 4])))

lambda

语法:lambda 参数:实现

实现部分只能有一条语句,且不能有 return,整个实现部分的结果就是函数的返回值

1
2
3
4
from functools import reduce
print(list(map(lambda a, b: a*b, "abcd", [1, 2, 3, 4])))
print(reduce(lambda x, y: x*y, range(1, 11)))
print(list(filter(lambda n: True if n.isalpha() else False, "A1!b2#C3%d4^E5&f6")))

高阶函数

闭包

一个函数在另一个函数内,外层函数返回的是内层函数,即函数本身被返回了,返回的函数还可以访问它的定义所在的作用域,即它带着它的环境信息,这个称之为闭包

闭包指内部函数和外部函数作用域的变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def outer(factor):
def inner(number):
return number * factor
#返回一个函数
return inner
fun = outer(10)
"""
在执行以上代码时,会返回一个内部函数
def inner(number):
return number * 10
"""
print(outer(10))
print(fun(20))
"""
fun 接受了上一个函数的返回值,已经是一个函数了
def inner(20):
return 20 * 10
"""

装饰器

在闭包的基础上,内部函数调用了外部作用域提供的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def outer(func):
def inner():
print("执行前的时间")
func()
print("执行后的时间")
return inner
# @outer # 在 Python 中 @ 的是语法糖
def f1():
print("f1:原有功能")

f1 = outer(f1)
"""
def inner():
print("这里是在原有函数上新添加的功能")
return 以前的f1()
"""
f1()
""" 这里是返回的新的函数
def f1():
print("这里是在原有函数上新添加的功能")
return 以前的f1()
"""

有时候需要给一些特定的函数添加功能,但不能修改函数的名称,函数的参数个数和函数的调用形式,可以使用装饰器实现功能

语法糖是为了让代码可读性更高,使用更简单,如

1
array[10][10] == *(*(array + 10) + 10)

模块的使用

时间模块 time

1
2
3
4
5
6
7
import time
#获取元组显示的当前时间,若传入一个时间戳就会将时间戳进行转换
print(time.localtime())
#指定休眠的秒数
time.sleep(2)
#将时间元组转换成字符串
print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))

随机模块 random

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import random
for i in range(1000):
# 可以接受一个参数,生成的是 0~n(不包括)
print(random.randrange(10))
# 要求两个参数,生成 n~m(包含)
print(random.randint(10, 20))

tmp = ""
for i in range(6):
# 有一半的概率是数字或者字母
rad1 = random.randrange(4)
if rad1 == 1 or rad1 == 3:
rad2 = random.randrange(10)
tmp += str(rad2)
else:
# 生成字母对应的 ASCII 码
rad3 = random.randrange(65, 91)
tmp += chr(rad3)
print(tmp)

目录文件 os

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import os
#目录操作
dir_path = "D:\\"
file = [os.path.splitext(dir_path + f) for f in os.listdir(dir_path)
if os.path.isfile(dir_path + f)] #判断D盘下的文件
print(file)

# 文件的操作,默认的打开方式是只读的 "r"
f = open("file.txt", "w+")
# 写入数据到文件中
f.writelines("dfkjhsif")
f.close()

# 读取文件中的数据
f = open("file.txt")
print(f.readlines())
f.close()

结构体

1
2
3
4
5
6
7
8
import struct
# 打包: pack int + int + char[1024]
b = struct.pack("ii1024s", 1, 2, b"nihao")
print(b)

# 解包: 提供二进制数据和 fmt,返回一个元组,需要元组解包
i1, i2, s = struct.unpack("ii1024s", b)
print(i1, i2, s)