1 简介
1.1 python解释器
语言分为编译型语言和解释型语言, C语言是一种编译型语言, 代码写完后会由编译器编译生成可执行的二进制文件交由机器执行. python是一种解释型语言, 代码写完后, 解释器会从上向下每读取一行代码, 翻译成机器语言, 交由机器执行, 再翻译下一行. 编译型语言执行速度较高, 但是其编译好的二进制文件只能在其编译的操作系统上运行. 但是python代码写好之后, 可以由不同平台的python解释器来进行解释执行, 达到了跨平台的目的.
1.2 python语言设计思想
- 工整
- 简单
- 明确
1.3 python语言特点
- 完全面向对象
- 拥有强大的标准库
- python社区提供了大量的第三方模块
1.3.1 python优点
可扩展性很高
1.3.2 python缺点
执行速度慢
1.4 执行python文件方式
- python/python3 + python文件名
- 交互式运行, 直接在终端中输入python/python3, 然后输入想要执行的python代码
- ide执行
2 语法
- 每一行只能执行一个动作
- 注释: 单行注释需要使用在需要注释内容的行首加 #, 也可以在代码行后面加#再加上注释内容, 多行注释, 可以使用连续的三个引号.
2.1 运算
2.1.1 除法
当想要取除法运算的整数部分时, 可以连续使用两个/(即" // "), 取余则是使用%.
2.1.2 幂运算
如果想要进行幂运算, 比如想要计算, 就是使用2 ** 3.
2.1.3 乘法
字符串 * 整数a得到的结果是字符串拼接a次. 列表和元组也是支持的.
- 需要注意的是, python中也支持variable = variable + a ---> variable += a
2.2 变量
2.2.1 定义变量方式
直接用变量名称 = 要赋予的值就可以, 且变量名只有在第一次出现的时候才是定义变量, 以下就是使用变量了
2.2.2 变量的类型
变量类型是有运行的时候解释器自动根据赋值的类型来自动进行转换.
需要注意的是, 只能定义float类型的小数, 不能定义double类型的小数.
python还可以定义复数类型
以及可以定义列表, 元组, 字典.
2.2.3 不同变量之间的运算
bool型进行运算的时候, 其值如果是true, 就会用1参与运算, 否则以0进行运算.
字符串与整数只能进行相乘运算, 也就是字符串拼接多少次.
2.2.4 输入和打印变量
varible = input("这里的内容会打印到控制台上") #从键盘接收varible这个变量的值
注意, 输入的数据都是string类型的.
print(varible) #把varible变量的值输出到控制台
2.2.5 字符串类型转换
用int(字符串)或者float(字符串)可以把字符串转换为int或者float类型
2.2.6 输出变量
如以下例子:
name1 = "Marshall"
print("name is %s" % name1)
name2 = "Wu"
print("name1 is %s, name2 is %s" % (name1, name2))
num1 = 100
num2 = 10.5
print("num1 is %d, num2 is %f" % (num1, num2))
运行结果:
注意, 如果想要输出百分号(%), 那就要连续打两个百分号.
print默认在输入完成后换行, 如果不希望换行, 就要在末尾加上 end="", 如下代码:
print("* ", end="")
print("* ", end="")
print("* ", end="")
print("* ", end="")
结果为:
2.2.7 变量命名
同C语言一样, python变量命名也只能用字母, 数字和下划线命名, 且不能用数字开头.
建议变量命名, 如果变量名含有多个单词, 单词最好都使用小写字母, 单词之间用下划线分隔.
2.2.8 列表
类似于C中的数组. 定义方法如下:
int_list = [1, 2, 3, 4]
int_list1 = []
定义完列表后可以直接用列表名加 . 然后就会显示出列表中的所有接口, 增删改查等(类似于vector).
想要获取列表元素个数, 使用len(list), 如下:
len(int_list) #为4
列表的遍历, 可以使用for关键字, 语法如下:
for iteration in str_list:
print("%s" % iteration)
注意, python是允许列表中存储不同类型数据的.
如果想要取列表(也包括字符串)的子列表(子串), 直接用list[start: end](左开右闭)的方式取就可以.
2.2.9 元组
定义元组变量只能用小括号定义, 且定义完成后不允许修改元组的元素.
如果想要定义一个只包含一个元素的元组, 如下:
single_tuple = (5,)
2.2.10 字典
定义字典使用打括号定义, 如下定义方法:
dic = {
"name": "Michael",
"age": 18
}
需要注意的是, 键必须是唯一的.
遍历字典的时候, for后面接的是key值, 如果想要拿到value, 需要用字典[key]的方法取到value.
在创建字典的时候, 字典的key必须是不可变类型
2.3 判断语句
2.3.1 if语句
首先是行首写if+空格+条件+:
如下:
if number > 10:
print("number > 10")
注意:
- 冒号之前不能有空格.
- if语句满足的话, 其后所有缩进的代码都会执行, 相当于大括号.
如果要加else, 后面也要加冒号, 还需要注意的是else if需要写成elif, 如下代码:
number = int(input("输入number: "))
if number > 10:
print("number > 10")
elif number == 10:
print("number = 10")
else:
print("number < 10")
2.3.2 关系判断
同C语言相同 > < == <= >=等
2.3.3 逻辑运算符
- 与运算符, 对应 &&, 用and
- 或运算符, 对应||, 用or
- 非运算符, 对应!, 用not
语法如下代码:
variable = int(input("请输入variable: "))
if variable >= 5 and variable <= 15:
print("variable在[5, 15]")
if variable > 15 or variable < 5:
print("variable不在[5, 15]")
if not (variable >= 5 and variable <= 15):
print("variable不在[5, 15]")
2.3.4 随机数使用
首先需要添加如下代码:
import random
random.randint(10, 20) #返回10 ~ 20(包括10和20)之间任意一个整数
2.4 循环语句
2.4.1 while循环
与if类似语法, 如下代码:
variable = 5
while variable > 0:
print("hello")
variable = variable - 1
2.4.2 for循环
语法如下:
int_list = [1, 2, 3, 4]
for int_iter in int_list:
print(int_iter)
如果在for下面存在else, 在break退出后, else的代码就不会执行.
如下代码:
int_list = [1, 2, 3, 4]
for int_iter in int_list:
if int_iter > 3:
break
print(int_iter)
else:
print("finish traverse")
结果是:
而如果把break那句去掉, 即:
int_list = [1, 2, 3, 4]
for int_iter in int_list:
print(int_iter)
else:
print("finish traverse")
结果是:
for还有一种使用方法, 如下:
int_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
for index in range (4, len(int_list)):
print(int_list[index])
else:
print("finish traverse")
需要注意的是 range里面的两个数代表范围为[ ), 即左闭右开.
结果为:
如果想要从0开始, 那么左边的数, 也就是0可以省略.
2.5 import
python程序中会把import导入的模块先编译成二进制文件, 生成pyc后缀的二进制文件.
2.6 del
使用del关键字把变量从内存中删除.
2.7 python中的引用
3 函数
3.1 定义函数的语法:
如下代码:
def 函数名():
函数体
函数体
函数体
3.2 调用方法
调用方式同C一样.
3.3 函数注释
在函数定义下方缩进加注释
3.4 函数参数
python中参数同样不需要声明类型
python函数中支持多值参数, 就是不确定参数个数的情况, 如果想要声明一个参数是元组, 就在参数前加 *, 如果想要声明一个参数是字典, 就在参数前面加 **, 如果多值参数中同时有元组和字典, 需要使用拆包语法, 需要在元组参数前加一个*, 字典前加两个星号.如下测试代码:
def fun(*param_tuple, **param_dic):
print(param_tuple)
print(param_dic)
g_tuple = (1, 2, 3)
g_dic = {
"name": "Michael",
"age": 18
}
fun(g_tuple, g_dic)
结果为:
说明实参的元组和字典都被传给了形参的元组, 而如果使用了拆包语法:
def fun(*param_tuple, **param_dic):
print(param_tuple)
print(param_dic)
g_tuple = (1, 2, 3)
g_dic = {
"name": "Michael",
"age": 18
}
fun(*g_tuple, **g_dic)
结果为:
附和预期
3.5 字符串, 列表, 元组, 字典的公共接口
del
max
min
3.6 字符串, 列表, 元组的切片
用如下测试代码:
string = "abcdefg"
print(string[1:4]) #取出1 ~ 3, 右边是开区间, 左边是闭区间
结果是:
3.7 局部变量和全局变量
在函数内部不能直接修改全局变量的值, 如下测试代码:
g_a = 10
def fun1():
g_a = 20
print("fun1: g_a: %d" % g_a)
def fun2():
print("fun2: g_a: %d" % g_a)
fun1()
fun2()
运行结果为:
这是由于在函数fun1内部运行到g_a = 20这一步时, 会在函数内部定义一个同名的g_a变量并赋值为20.
如果按照如下测试函数:
g_a = 10
def fun1():
g_a += 20
print("fun1: g_a: %d" % g_a)
def fun2():
print("fun2: g_a: %d" % g_a)
fun1()
fun2()
运行会报错:
说明函数正常是不能直接修改全局变量的值的.
如果在函数内部想要修改全局变量的值, 需要在使用全局变量之前需要用global关键字声明一下变量, 如下测试代码:
g_a = 10
def fun1():
global g_a
g_a += 20
print("fun1: g_a: %d" % g_a)
def fun2():
print("fun2: g_a: %d" % g_a)
fun1()
fun2()
运行结果为:
3.8 列表作为函数参数
假如有如下代码:
g_list = [1, 2, 3]
def fun(param_list):
param_list = [4, 5, 6]
print(param_list)
fun(g_list)
print(g_list)
结果为:
说明在函数内部直接用赋值语句操作列表参数的时候, 实参列表本身不会改变
如果用如下方法操作:
g_list = [1, 2, 3]
def fun(param_list):
param_list.append(9)
print(param_list)
fun(g_list)
print(g_list)
结果为:
说明如果函数内部通过参数的方法来修改参数时, 实参也会发生修改.
需要注意的一点是, 如果有如下测试代码:
g_list = [1, 2, 3]
def fun(param_list):
param_list += [6, 9]
print(param_list)
fun(g_list)
print(g_list)
发现结果为:
这是因为在python中, list重载了 += 符号, 本质是调用了append.
4 类和对象
4.1 私有属性和方法
在属性和方法前增加两个下划线.
4.2 继承
4.2.1 语法
语法, 只需要在类名后面加上需要继承的类的类名, 如下:
class FatherClass:
def __init__(self, name=None, param1=None):
self.name = name
self.param1 = param1
class SonClass(FatherClass):
def __init__(self, son_param1=None, son_param2=None):
self.son_param1 = son_param1
self.son_param2 = son_param2
4.2.2 父类方法的重写
在子类中重写父类的同名方法就可以. 或者可以对父类的同名方法的拓展, 也就是说既调用父类方法也调用子类方法.
如果想要在子类方法中调用父类同名方法, 可以用super()来代表此类的父类, 如下代码:
class FatherClass:
def show_method(self):
print("this is father's method")
class SonClass(FatherClass):
def show_method(self):
super().show_method()
print("this is son's method")
当如下测试代码时:
son_instance = SonClass()
son_instance.show_method()
结果为:
也可以使用如下代码来在子类中调用父类的同名方法:
class FatherClass:
def show_method(self):
print("this is father's method")
class SonClass(FatherClass):
def show_method(self):
FatherClass.show_method(self)
print("this is son's method")
也就是用父类名调用父类同名方法, 还要把self传进去.
4.2.3 私有属性和私有方法的权限
子类中是不能访问父类的私有属性和私有方法的.
4.2.4 多继承
多继承可以在括号中把父类用逗号分割. 如果父类之间存在同名方法, 会按照mro展示的顺序执行父类中的方法.
4.2.5 继承后的__init__
如果子类重写了__init__函数, 那么就不会调用父类的__init__函数, 除非在子类的__init__函数中通过super().__init__调用父类的__init__函数.
4.3 多态
4.4 类属性和类方法
4.4.1 类属性
类似于C++类中的静态成员, 用类名点属性名直接访问.如果使用对象名访问类属性, 如果是用赋值语句直接赋值, 就会在对象的属性中增加同名属性, 而如果是通过对象名访问类属性不会有这种问题.
4.4.2 类方法
类方法可以访问类的类属性, 定义语法如下:
@classmethod #标注为类方法
def 类方法名(cls): #类方法的第一个参数是class, 调用哪个类的类方法, 这个cls就是哪个类
pass
4.4.3 静态方法
既不需要访问类的类属性, 也不需要访问对象的实例属性, 可以如下定义:
@staticmethod
def static_method():
pass
调用静态方法的方式为直接用类名+静态方法名的方式就可以直接调用, 不需要创建对象.
4.4.4 new
new方法是一个静态方法这个方法是object这个基类提供的方法, 给对象分配空间, 把内存地址把地址传给__init__的self, 使用方法如下:
class TestClass(object):
def __new__(cls, *args, **kwargs):
# 创建对象时new方法会被自动调用
print("this is TestClass __new__")
pass
def __init__(self):
print("this is TestClass __init__")
instance1 = TestClass()
print(instance1)
发现结果是:
发现创建的对象是个空对象, 这是因为__new__方法必须返回一个创建的对象的引用给__init__的self参数, 需要如下修改:
class TestClass(object):
def __new__(cls, *args, **kwargs):
# 创建对象时new方法会被自动调用
print("this is TestClass __new__")
# 为对象分配空间
instance = super().__new__(cls)
# 返回该对象的引用
return instance
def __init__(self):
print("this is TestClass __init__")
instance1 = TestClass()
print(instance1)
此时的结果为:
如果想要让每次创建对象都只有一个实例, 也就是单例, 可以如下操作:
class TestClass(object):
__instance = None
def __new__(cls, *args, **kwargs):
# 创建对象时new方法会被自动调用
print("this is TestClass __new__")
# 如果此时对象为空, 就创建一个新对象
if cls.__instance is None:
cls.__instance = super().__new__(cls)
# 返回该对象的引用
return cls.__instance
def __init__(self):
print("this is TestClass __init__")
# 创建多个对象对比内存地址是否相同
instance1 = TestClass()
print(instance1)
instance2 = TestClass()
print(instance2)
这样的结果为:
这样就实现了单例设计. 但是此时发现__init__调用了两次, 可以使用如下方法只要用一次__init__:
class TestClass(object):
__instance = None
__have_init = False
def __new__(cls, *args, **kwargs):
# 创建对象时new方法会被自动调用
print("this is TestClass __new__")
# 如果此时对象为空, 就创建一个新对象
if cls.__instance is None:
cls.__instance = super().__new__(cls)
# 返回该对象的引用
return cls.__instance
def __init__(self):
if self.__have_init:
return
self.__have_init = True
print("this is TestClass __init__")
# 创建多个对象对比内存地址是否相同
instance1 = TestClass()
print(instance1)
instance2 = TestClass()
print(instance2)
结果为(发现只init了一次):
5 异常
5.1 异常语法
python程序执行错误时, 会把异常抛给代码, 这是就需要进行异常处理, 捕获异常的语法如下:
try:
执行的代码
except:
try中的代码执行异常出现时执行的代码
假如有如下例子:
try:
number = input("请输入一个整数: ")
result = 8 / number
except:
print("输入有误")
这样我们输入0的话, 结果如下:
但是有时候需要对不同的异常做不同的处理, 比如在不进行异常处理的时候我们输入0会有如下错误:
在输入A的时候会有如下错误:
我们可以根据不同情况做不同处理, 代码如下:
while True:
try:
number = int(input("请输入除数: "))
result = 8 / number
print(result)
except ValueError:
print("除数有误")
except ZeroDivisionError:
print("不能除0")
except KeyboardInterrupt:
print("886")
break
5.2 捕获未知错误
捕获位置错误的语法如下:
try:
number = int(input("请输入除数: "))
result = 8 / number
print(result)
except Exception as ret:
print("未知错误: %s" % ret)
5.3 抛出异常
可以使用raise关键字在函数执行过程抛出想要抛出的异常.