程序运行主要有两种机制:编译型和解释型。编译型是将代码(源文件)通过编译器,编译成机器码文件,当运行的时候直接执行机器码文件,例如 C 语言;解释型是将源文件通过解释器,逐行进行翻译并运行。
Python 则属于解释型的语言。
编译型和解释型语言各有优缺点:
缺点:执行慢
优点:可以跨平台(操作系统)
缺点:不能跨平台
优点:执行快
先说两个最基本的函数:输入和输出。
输出函数 print (),语法就是:
print(要输出的内容)
输入函数是 input (),功能是接收用户输入的内容,语法是:
input(输出的内容)
在 Python 里,“#” 表示注释,“#” 后面的东西不会被执行。
变量就是一个名字,需要先赋值在使用,变量要符合标识符 (名字) 的命名规范,这是硬性要求,标识符相当于名字,包括变量名、函数名、类名等等
数据类型可分为以下 6 类:
(1) 整型:整数,英文名 int ,例如 5 的数据类型就是整型。
(2) 浮点型:小数,英文名 float ,例如 0.5 就是1个浮点型数据。科学计数法,e表示乘以10几次方,例如
b=1e10 表示1*10的10次方。
(3) 字符串:英文str,表现形式有4种:‘xs’ 、 “xs” 、 “”“xsxs”"" 、 ‘’’‘xxx’’’
三引号有个特殊功能,表示注释,跟 # 一样的功能,例如:
"""
xsx
xs
这里面的都是注释内容
"""
(4)布尔类型:英文bool,True为真,False为假;1表示真,0表示假。
(5)None 是一个单独的数据类型。
(6)列表、元组、字典、集合也是常见的数据类型。
常用的获取数据类型信息的函数有 type ( ) 和 isinstance ( ) 两个。
(1)type( )
语法是 type (对象) ,返回的是对象的类型,前面我们也有用过,但是它是在内部返回的,如果你不输出它你是看
不到的,所以经常会和输出函数 print ( ) 嵌套使用。
(2)isinstance( )
isinstance ( ) 常用来判断数据类型,它返回的是布尔值(True 或 False),语法是 isinstance (对象,class) 。
for 循环和 while 循环都是循环语句,但不一样的点在于 for 循环是技术循环。
语法:
l=[3,2,1]
for 变量 in 可迭代对象:
代码块
例子:
l=[3,2,1]
for n in l:
print("1")
执行:
1
1
1
l 是个列表,后面我们会讲,列表里面有 3 个元素,每执行一次 for 循环,列表里面的元素就会被赋值给 n,直到列表里面没有了元素可赋值,则 n 就跳出了列表,此时的 for 循环就不成立了,不执行 for 里面的代码块。
for 循环经常会搭配 range 来使用,range 是一个可迭代对象,range 的语法如下:
range(start=0,stop,step=1)
start 值的是开始下标。range 序列里面的所有元素都有下标,第一个元素的下标是 0,所以,默认是从 0 开始。
stop 是结束位置。结束的位置下标为(元素个数 - 1),例如 range 里面有 4 个元素,那么结束下标最大为 3, 大于
3 则跳出 range。
step 是步长,如果 step 是 2,那么每次会隔开 1 个元素,默认步长为 1,即每个元素都会取到。
举例:
for i in range(8): #可以不写star和step,但结束位置一定要写的
print(i)
print("---------")
for i in range(10, 2, -2):
print(i)
执行结果:
0
1
2
3
4
5
6
7
-------------
10
8
6
4
通过第一个 for 循环可以看出,range () 的第一个元素的下标是从 0 开始,而不是从 1 开始;range () 可以不写开始下标和步长,但一定得有结束位置;第二个 for 循环可以看出步长可以为负数,用于递减。
列表是可以存放任何数据,包括整型,浮点型,字符串,布尔型等等,是常用的数据类型之一。
列表也是一个可迭代对象
l = [1,2,3,4,5] ---整型列表
l = ["a","b","c"] ---字符串列表
l = [True,False,1>2,5<6] ---布尔列表
l = [1,2.5,"a",True] ---混合列表
l = [] ---空列表
列表是有下标的,并且下标从 0 开始,元素是指列表中每个数据,例如 l = [5,4,3,2,1] 里面有 5 个元素,但 5 的下标为 0,1 的下标为 4。
列表交换数据,对指定下标的元素进行数据交换。
例如把 [1, 2, 3, 4, 5] 里面的下标为第 2 和第 3 的元素进行数据交换:
l = [1, 2, 3, 4, 5] # 下标/索引:0开始
l[2], l[3] = l[3], l[2]
print(l)
执行结果:
[1, 2, 4, 3, 5]
修改列表中的元素方法其实很简单,直接用这个方式就可以了:
变量[下标]=新值
例如:
l = [1, 2, 3, 4, 5]
l[2]=6
print(l)
执行结果:
[1, 2, 6, 4, 5]
切片操作
切片,顾名思义就是把 1 个列表切分为多个列表,语法如下:
变量[起始下标:结束下标] #结束下标取不到
l = [1, 2, 3, 4, 5]
print(l[0:4])
执行结果:
[1, 2, 3, 4]
做切片操作时要注意以下几个点:
①如果下标从0开始可以省略不写,例如 n = l[:4]
②如果结束下标取的是最后一个元素,可以省略不写,例如 n = l[3:]
③如果列表中的元素都要,开始和结束下标都可以省略,例如 n = l[:]
④n = l[:-1] 表示从0开始 - 到数二个元素
n = l [开始:结束:步长] ,这个方法既可以正向去操作列表,也可以反向去操作列表,例如:
l = [1, 2, 3, 4, 5]
n = l[-1:-3:-1]
print(n)
执行结果:
[5, 4]
元祖也是 Python 中常见的数据类型之一,它可以用来存放任何数据类型,但它也有它的特点:
t = (1, 2, 3, 4, 5)
print(t[2]) #输出下标为2的元组元素
n = t[2:4] #切片,范围是下标2~4
print(n)
执行结果为:
3
(3, 4)
元组是不可变类型,不能修改,但是可以通过将元组转换成列表的形式进行修改和删除等操作,最后再将列表转换成元组,完成元组的修改和删除。
例如:修改元组中的元素
t = (1, 2, 3, 4, 5)
l = list(t) #将元组转换成列表
print(l) #输出列表
l[2] = 6 #列表指定元素的修改
print(l) #输出新列表
t = tuple(l) #列表转换成元组
print(t)
[1, 2, 3, 4, 5]
[1, 2, 6, 4, 5]
(1, 2, 6, 4, 5)
删除元组中的元素可用 del t [下标] 方法,前提还是一样的先将元组转换成列表,例如:
t = (1, 2, 3, 4, 5)
l = list(t) #将元组转换成列表
print(l) #输出列表
del l[2] #列表指定元素的删除
print(l) #输出新列表
t = tuple(l) #列表转换成元组
print(t)
[1, 2, 3, 4, 5]
[1, 2, 4, 5]
(1, 2, 4, 5)
字典是用来存储数据的,字典中的数据以映射关系存储。
字典的特点
1. 字典是Python中唯一的映射类型
2. 字典是无序的
3. 字典是可迭代对象
4. 字典的构成
键:key
值:value
映射:键映射值
键-值:键值对,又叫项
创建字典
d = {} #空字典. d = {“name”:“不良人”,“apple”:“苹果”}
dict() 例如:d = dict() #空字典
dict(可迭代对象)
d3 = dict([("one",1),("two",2)])
print(d3)
执行结果:{'one': 1, 'two': 2}
这就是一个元组,one 是键,1 是值, ‘one’ : 1 是键值对。
dict(**kwargs)
d4 = dict(a=3, b=4)
print(d4)
执行结果:
{'a': 3, 'b': 4}
字典访问
变量名[键名] #键所对应的值
d = {"name": "小黑"}
print(d["name"])
执行结果:
小黑
函数是由一组代码组成,完成某个特定的功能。
def 函数名(参数):
代码块(函数的实现/函数体)
参数相当于变量,参数可以为 1 个或者多个,用逗号隔开,还可以没有参数,等于无参;代码块是函数的实现,又叫函数体。
函数的运行机制
函数的运行遵循以下机制:
从函数调用开始执行
通过函数名字找到函数定义的位置(创建函数的位置)
执行函数体
执行完毕之后,返回到函数的调用处
函数的特点
通过上面的例子可以发现,函数具有以下特点:
避免了代码的冗余
提高了代码的可维护性
提高了代码的可重用性
提高了代码的灵活性
函数的参数
形式参数:形参
在定义函数的时候传递的参数
实际参数:实参
在调用函数时传递的参数
无参
没有任何参数
默认参数: 给了默认值的参数--形参 如果传递了新的值,那么默认值就被覆盖了
位置参数和关键字参数混用: 当位置参数和关键字参数混用时,位置参数在前
关键字参数: 用形参的名字作为关键字来指定具体传递的值,则在函数调用时,前后顺序将不受影响。
位置参数:实参的位置和形参一一对应,不能多也不能少。
可变成参数: def 函数名(*a) 本质上封装成了元组
可变成参数:def 函数名(**kwargs) 将参数封装成了字典
可变成参数和位置参数混用的时候:可变参数优先
函数的文档
写代码的时候我们经常需要写文档,前面有提过 #和三引号可以进行代码的注释,但在这里要介绍一种新的方法,也是写代码时常用的函数文档书写格式:在函数体的第一行用 “”"“”" 进行文档说明,这是标准化的函数文档书写。
拥有函数说明文档之后,就可以获取函数的文档内容,方法是:
函数名.__doc__
函数的返回值
关键字:return
返回值谁调用就返回给谁任何函数都有返回值
如果不写return ,也会默认加一个return None
如果写return ,不写返回值 也会默认加一个None
可以返回任何数据类型
return后面的代码不在执行,代表着函数的结束
函数的变量的作用域
局部变量
定义在函数内部的变量
先赋值在使用
从定义开始到包含他的代码结束
在外部无法访问全局变量
定义在源文件的开头
作用范围:整个文件
局部变量和全局变量发生命名冲突时,以局部变量优先
global
声明全局变量
nonlocal
声明的是局部变量
内嵌函数
定义在函数内部的函数叫做内嵌函数(或者叫内部函数),内部函数的作用范围:从定义开始到包含给他的代码块结束在内部函数中不能进行 a+=1,a=a+1 这样的操作,解决方案是 nonlocal 和 global。
闭包
闭包是函数式编程的重要语法结构。
编程范式:一种编程范式,对代码进行提炼和抽象概括,使得重用性更高
如果内部函数调用了外部函数的局部变量,并外部函数返回内部函数的函数对象(函数名)
闭包是有条件的:
1. 必须是一个内嵌函数
2. 外部函数必须返回内部函数的函数对象
3. 内部函数必须使用外部函数的局部变量
lambda 表达式
匿名函数
没有名字的函数使用时机:
只使用一次的时候语法:
关键字: lambda
lambda 参数1,参数2:返回值lambda的书写形式更加的简洁,优雅
l = lambda x:x
print(l(100))lambda的优先级最低
类是产生对象的模板,类就是对象的抽象化,对象是类的具象化。
创建类:
#创建Student类
class Student:
name = "小明" #学生类的name属性
age = 18 #学生类的age属性
def learn(self): #学生类的learn方法
print("学生的学习方法被调用了")
#创建Student类的对象
s1 = Student() #Student()就是创建的1个类对象,只是便于简写,我把它传给了s1
s1.learn() #对象的方法
print(s1.age) #执行对象的属性
#上面这两行代码其实可以直接写成Student().learn() ,也同样是利用类创建了对象并调用对象的方法
执行结果:
学生的学习方法被调用了
18
对象的属性和类的属性
1. 类属性定义在类的内部,任何方法之外
1. 创建类的时候直接创建
2. 类名.新的属性名=属性值
2. 使用类属性:
1. 对象.类属性
2. 类.类属性
3. 类属性的特点:
1. 类属性是属于类对象的
2. 对象共用类属性。如果类属性变化,所有的对象也会改变
4. 类属性有且只有一份,牵一发而动全局
对象属性定义在方法内部
1. 创建
1. 对象.实例属性名=属性值
2. 方法内部创建:self.属性名 = 属性值
2. 使用对象属性
对象.实例属性名
3. 对象属性各自拥有互相独立
4. 对象属性和类属性发生命名冲突
1. 以对象属性名优先
2. 对象属性名会遮蔽同名的类属性
类方法的声明
def 函数名(self,参数1,参数2,....)
self
1.self默认传递,不需要传值
2.self指代的是当前的实例(对象)
3.一定会有self传递,但名字不一定必须叫self,可以叫aa
4.self后面可以跟多个参数,用“,”隔开
方法的调用
1.对象.方法名(自动传递对象),例如 s2.fun1()
2.类名.方法名(类名()) #“类名()”相当于创建对象
注:方法的调用与函数类似,谁调用就返回给谁
初始化的方法(特殊的类的方法)
def __ init __( ):
1.这个方法不需要被调用,只要创建对象就会自动执行
2.这个方法只能返回None值,无法返回其他类型的值
3.如果要给init传递多个参数,只能通过 类名(多个参数) 的方式去传递
4.如果类里面没有定义init,默认去调用父类
5.如果类里面重复定义了多个init方法,会被最后一个init方法覆盖
举例:创建对象,查看默认执行的 init 并传递多个值;调用 1 个类的方法,确认该方法被调用并执行传递的值。
#创建类
class Student:
name = "小莫"
age = "18"
def __init__(self,aa,bb):
print("init被调用了")
print(aa)
print(bb)
def fun1(self):
print("函数1")
print(self)
def fun2(self):
print("函数2")
Student.fun1(Student(100,200)) #创建对象并传递多个值给init
执行结果为:
init被调用了
100
200
函数1
<__main__.Student object at 0x000001DAD8168400>#self值的存储地址
三大特性:封装、继承、多态
封装
对象都有明确的边界,把属性和方法保护在边界之内。(安全性)
封装的力度适中。
封装的原则
(1)将不需要对外提供的内容进行隐藏。
(2)隐藏属性,提供公共的方法对其访问
私有属性:__name="xxx"
继承
继承是父类与子类的关系
1)定义形式(类的完整形式)
class 子类的类名(父类的类名):
属性
方法
2)父类:基类,超类
object————顶层类
如果对象没有书写继承关系,默认继承object
3)继承的特点
# 定义父类
class A:
name1 = "父类的属性1"
def aa(self):
print("父类的方法1")
# 定义子类
class B(A):
name2 = "子类的属性1"
def bb(self):
print("子类的方法1")
n = B()
print(n.name2) #调用子类的属性
n.bb() #调用子类的方法
print(n.name1) #调用父类的属性
n.aa() #调用父类的方法
执行结果为:
子类的属性1
子类的方法1
父类的属性1
父类的方法1
可扩展性。父类扩展了,子类也得到扩展。
如果子类没有构造方法,对象会去调用父类的。
如果子类有自己的构造方法,则不会去调用父类的。
子类的构造方法可以调用父类的构造方法,调用可以有以下两种方式:
父类的类名.__init__(self) #手动传递self
super().__init__() #不需要加self
多继承
一个子类可以继承多个父类
# 定义父类A
class A:
name_a = "父类A的属性1"
def aa(self):
print("父类A的方法1")
# 定义父类B
class B:
name_b = "父类B的属性1"
def bb(self):
print("父类B的方法1")
#定义子类C
class C(A,B): #继承两个父类
pass #跳过
n = C()
print(n.name_a)
print(n.name_b)
n.aa()
n.bb()
执行结果为:
父类A的属性1
父类B的属性1
父类A的方法1
父类B的方法1
注:多继承有好有坏,优点是增强了可拓展性,缺点则是继承关系复杂之后容易混乱逻辑,难看懂,同时也会占用大量资源,比如著名的钻石继承问题。
4)方法覆盖
子类中的方法与父类中的方法同名,则覆盖父类。
#定义父类
class Animal:
def eat(self):
print("动物会吃东西")
#定义子类狗
class dog(Animal):
def eat(self):
print("狗会吃东西")
d = dog()
d.eat()
执行结果为:
狗会吃东西
子类覆盖了覆盖的方法之后,本质上并没有替换父类的方法,父类的方法依然存在并可以给其他子类调用。
5)方法重载
出现多个方法名一样的方法(函数),Python 中通过默认值进行方法重载。
多态
多态:一类事物有多种形态,是一种使用对象的方式,子类重写父类的方法,调用不同的子类对象的相同父类的方法,可以产生不同的效果。
举例:以王者荣耀选英雄为例,英雄类(Hero)为父类,该父类中有一个方法叫 stroke (技能);程咬金和后裔分别为两个子类,两个子类中也有 stroke 这个方法;调用者为另一个父类,有一个选择英雄的方法,该方法需要调用 stroke 这个类方法,最后调用不同的子类(程咬金或后裔)对象,得到不同的技能描述。
#定义父类Hero
class Hero :
def stroke(self): #技能函数
print("英雄技能")
#定义子类程咬金
class ChengYaoJin(Hero):
def stroke(self): #技能函数
print("一技能跳跃,二技能旋转,大招回血")
#定义子类后裔
class HouYi(Hero):
def stroke(self): #技能函数
print("一技能多发,二技能射圈,大招大鸟眩晕")
#定义调用者
class Person:
def chose_hero(self,hero): #玩家选择英雄
hero.stroke()
c = ChengYaoJin() #程咬金
x = HouYi() #后裔
p = Person() #玩家
p.chose_hero(c) #玩家选择程咬金,"c"换成"x"就会产生不同的结果
执行结果为:
一技能跳跃,二技能旋转,大招回血
多态性:向不同的对象发送不同的信息,不同的对象接收到信息后,会做出不同的反应。
#定义鸟类
class Bird:
def fly(self):
print("鸟会飞")
#定义飞机类
class Plane:
def fly(self):
print("飞机会飞")
#定义火箭类
class Rocket:
def fly(self):
print("火箭会飞")
#函数调用父类的fly方法
def fun1(obj):
obj.fly()
fun1(Bird()) #调用鸟类的fly方法
fun1(Plane()) #调用飞机类的fly方法
fun1(Rocket()) #调用火箭类的fly方法
执行结果为:
鸟会飞
飞机会飞
火箭会飞