Python简介
起源
Python的创始人为 吉多·范罗苏姆(Guido van Rossum)。1989年圣诞节期间,他为了打发时间,决心开发一个新的脚本解释程序,在1991年,第一个python解释器诞生,他是用c语言实现的。
设计哲学
明确、优雅、简单
主要应用领域
云计算:云计算最火的语言,典型应用OpenStack
Web开发:众多优秀的Web框架,Django、flask Youtube、豆瓣
科学运算、人工智能:NumPy, SciPy, Matplotlib, Enthought
系统运维:运维人员必备语言
图形GUI:PyQt、WxPython、Tkinter
分类
-
编译型: 把源程序的每一条语句都编译成机器语言,并保存成二进制文件 c c++ go ...
-
解释型: 只有,在执行程序时才一条一条的解释成机器语言给计算机去执行 python ruby php javascript
-
混合型: java c#
编译和解释的区别
编译器:是把源程序的每一条语句都编译成机器语言,并保存二进制文件,这样运行时,计算器可以直接以机器语言来运行此程序,速度很快。因为编译只做一次,运行时不需要编译,所以编译型语言的程序执行效率高。缺点,如果需要修改,就需要整个模块重新编译。
解释器:只是在执行程序时,才一条一条的解释成机器语言来计算机来执行,所有运行速度是不如编译后的程序运行的快。优点,有良好的平台兼容性,在任何安装了解释器的平台都可以使用。缺点,每次运行的时候都要解释一遍,性能上不如编译性语言。
优点
-
优雅、明确、简单,快速入门
-
开发效率非常高,有非常强大的第三方库,避免重复造轮子
-
高级语言,开发的时候无需关心,内存一类的底层细节
-
可移植性强,如果的代码不依赖系统特性,那么你的python程序无需修改就可以在市场上所有的系统平台上运行 ifconfig ipconfig
-
可拓展性,如果你的一段关键代码需要运行的很快,那么你可以你这段代码用C或者C++来写,然后用Python调用他们就可以
缺点
-
速度慢,运行度相对于C和C++ 甚至java都要慢很多
-
假多线程,线程不能利用多核CPU,GIL全局解释锁,由于这个锁的存在,使得任何时刻仅有一个线程在执行
环境安装
重大版本
Python2 和 Python3,主要差异在 print、编码、整数相除等,为了对Python3进行推广,预计 Python 2 到 2020 年 4 月 12 日就不再维护了,Python 2 将停止所有的更新,包括安全性更新。所以后续我们直接使用Python3就可以了。其实语法上差别并不大,稍微注意一下就可以了。
下载
一路确定即可
第一个Python程序
交互模式
输入python进入交互模式,这时候我们可以直接编写Python程序
文件模式
创建一个文件,文件后缀为.py ,在文件中编写代码,通过python命令来执行解释这个文件,运行代码
PyCharm
后续我们会在 集成开发环境Pycharm中来进行学习,在官网中下载这个软件,安装后打开即可,默认情况下Pycharm会自动关联python解释器,不需要进行额外的配置,直接创建一个项目,就可以开始编写代码了。
基础语法
引入变量和数据类型
a = 1
b = 2
c = a + b
print (c)
abc为变量 1、2是整数
变量
变量的定义:
将运算的中间结果暂存到内存,以便后续程序调用
变量的命名规则:
-
变量一般由 字母、数字、下划线搭配组成
-
可以用数字开头,更不能是全数字
-
不能是python的关键字,关键字就是被python占用的单词,不可以使用
['False', 'None', 'True', 'and', 'as', 'assert', 'async', 'await', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield']
-
可以是中文,但不要用中文
-
名字要有意义
-
不要太长
-
区分大小写,大写的A 和小写的 a是两个不一样的变量
变量命名方法:
下划线: student_first_name
小驼峰: studentFirstName
大驼峰: StudentFirstName
常量
在python中不存在绝对的常量,我们约定,所有字母大写的变量,就是常量
PI = 3.141592635
注释
有时候我们写的东西不一定都是给用户看的,或者不希望解释器执行,那么我们就注释掉代码,被注释的内容是不会被执行的。
单行注释: # 注释内容
多行注释:
'''
这里面的内容都是被注释掉的
'''
数字类型
定义
我们人类可以很容易的分清楚数字和字符的区别,但计算机并不能,我们要明确的告诉他,1是数字,a是字符,所以在每个编程语言里面,都会有一个叫数据类型的东西,其实就是对常用的各种数据类型进行了明确的划分。
分类
-
数字型 int float bool complex
-
字符串 str
-
列表 list
-
元组 tuple
-
字典 dict
-
集合 set
数字类型 (int float bool complex)
整数 int
就是 -1 -2 -3 ,1 2 3 …
在32位机器上,int的范围是 -231~231-1,即-2147483648~2147483647
在64位机器上,int的范围是 -263~263-1,即-9223372036854775808~9223372036854775807
浮点 float
其实就是我们说的小数 1.2 -2.3 …
a = 1
b = 1.1
c = a + b
整数 + 浮点数 = 浮点数
布尔 bool
真 或 假
True False
复数 complex
a = 4+3j
基本运算符
- 算数运算:
+ 加
- 减
* 乘
/ 除
% 取模 返回除法的余数
** 幂
// 取整除,返回商的整数部分
- 比较运算:
== 比较对象是否相等 相等 返回true
!= 判断对象是否不相等
> 判断大于
< 判断小于
>= 判断大于等于
<= 判断小于等于
- 赋值运算:
= 赋值
+= 加法赋值运算符 c+=a c=c+a
类似的还有 -= *= /= %= //=
-
逻辑运算:
and 与 如果x为False, x and y返回False,否则返回y的计算值
(3 and (2+2)) // 如果是0 ,直接返回 0
or 或 如果x是True,他返回x,否则它返回y的计算值
(4 or (3))
not 非
-
逻辑常用:
and True and False 只要有一个是假,那么结果就是假
or True and False 只要有一个是真,那么结果就是真
字符串
字符串定义
在Python中,凡是用引号引起来的,全部都是字符串
引号可以是 单引号、双引号和三引号
a = 'Hello'
b = 'World'
字符运算符
+ 字符串连接 a+b 'HelloWorld'
* 重复输出字符串 a * 2 'HelloHello'
[] 通过索引获取字符串中的字符 a[2] l a[-1] o
[:] 截取字符串中的一部分内容,遵循左闭右开原则
a[1:3] el
a[:3] Hell
a[3:] lo
a[1:-2] el
in 成员运算符 如果字符串中包含给定的字符,返回True
not in 如果字符串中不包含给定的字符串,就返回True
字符串常用的方法
lower() #全部转为小写
upper() #全部转为大写
swapcase() #大小写互相转换
strip() #去掉两端的空格
lstrip() #去掉左边空格
rstrip() #去掉右边空格
len('hello') #计算字符串的长度
replace('a','b') #字符串替换
split(' ') #字符串切割 转为列表
格式化输出
int %d
float %f
string %s
a = 1
b = 2
c = 1.2
d = 2.3
e = 'JONE'
f = 'TACA'
print ('a= %d,b= %d'%(a,b))
print ('c= %f,c= %f'%(c,d))
print ('e= %s,d= %s'%(e,f))
print ('a= %d,d= %s'%(a,f))
流程控制
条件控制引入
我们在生活中经常会遇到各种各样的选择,比如玩骰子,石头剪刀布时,你就需要做出你的选择,在写代码的时候,我们也会遇到这种情况,这就需要用到if条件控制语句。
条件控制语法
-
语法1
if 条件1: #冒号后换行,将条件与结果分开 结果1 #用一个tab或者四个空格的代码缩进来控制代码作用域 结果2 scores = 60 if scores >= 60: print ('及格了') print ('6666')
-
语法2
if 条件1: 结果1 else: 结果2 scores = 59 if scores >= 60: print ('及格了,6666') else: print ('不及格,gg')
-
语法3
if 条件1: 结果1 elif 条件2: 结果2 ... else: 结果3 scores = 80 if scores >= 90: print ('牛逼') elif scores >= 80: print ('优秀') elif scores >= 60: print ('及格') else: print ('不及格')
-
语法4
if 条件1: 结果2 if 条件2: 结果2 else 条件3: 结果3 else: 结果4 #可以无限的嵌套,但是在实际开发中,尽量不要超过三层 scores = 99 if scores >= 80: print ('优秀') if scores >= 90: print ('牛逼') else: print ('不够牛逼') else: print ('不够优秀')
循环语句引入
在代码,我们有时需要重复的去做一些事情,比如打印100次hello,此时写 100遍print显然不太合适,这是我们会用到循环。
循环语句语法
#当判断条件为真的时候,执行语句
while 判断条件:
语句
a = 1
while a < 10:
print (a)
a = a + 1
else:
print a
while True:
print (100)
#for循环
for 变量 in 范围:
语句
a = 'helloworld'
for var in a:
print (var)
#在0-10的范围内,遵循左闭右开原则
for var in range(10):
print (var)
跳出循环
break 语句可以跳出for和while的循环体,从循环中终止
for var in range(10):
print (var)
if var == 5:
break
#当变量==5时,跳出循环
continue语句用来告诉Python跳过当次循环中的剩余语句,直接执行下一次循环
for var in range(10):
if var == 5:
continue
print (var)
Pass语句是空语句,是为了保持程序结果的完整性,不做任何的事情,一般用作占位语句
for var in range(10):
if var == 5:
pass
else:
print (var)
列表
列表的引入
列表是最常用的Python数据类型之一。
创建一个列表,只需要把逗号分隔的不同的数据项,使用方括号括起来即可。
list1 = ['Hello','World',1997,6.6]
list2 = [1,2,3,4,5]
访问列表中的值
可以使用下表索引来访问列表中的值,同样也可以使用方括号的形式切片截图列表的值,这样会生成一个新的列表,和字符串的索引、切片用法一致。切片时,同样遵循左闭右开的原则。
list1 = ['Hello','World',1997,6.6]
print (list1[1])
print (list1[1:-1])
增加列表的项
注意,list和str是不一样的,list是可以发生改变的,直接操作原来的对象,那么对象就会直接改变
var = 'hello'
var + 'world'
print (var)
list1 = ['hello','test','good']
list1.append('yes')
print (list1)
#在最后增加 append
list1.append('no')
print (list1)
#在中间插入
list1.insert(2,'get')
print (list1)
#列表拓展,在最后插入一个列表
extend_list = ['make','gppp']
list1.extend(extend_list)
print (list1)
删除列表的项
list1 = ['hello','test','good','make','yes']
#pop(),如果不写参数默认删除最后一项,写参数可以指定删除的项
list1.pop()
print (list1)
list1.pop(3)
print (list1)
#remove,删除指定元素
list1.remove('test')
print (list1)
#del,按下表或者索引删除
list1 = ['hello','test','good','make','yes']
del list1[1]
print (list1)
del list1[1:3]
print (list1)
#clear 清空整个列表
list1.clear()
修改列表的值
通过索引和切片的方式直接修改
list1 = ['hello','test','good','make','yes']
list1[2] = 'no'
print (list1)
#如果长度不够,直接往后增加
list1[1:2] = ['thanks','you']
print (list1)
#如果长度太长,直接删除
list1[1:4] = ['thanks','you']
print (list1)
#几乎不这么用,知道就行
其他操作
list1 = [1,2,3,4,1,2,3,3,4]
# 计算1在列表中出现的次数
num = list1.count(1)
print (num)
# 排序
list1.sort()
print (list1)
# 倒序
list1.sort(reverse=True)
print (list1)
list1 = [1,2,3,4,1,2,3,3,4]
# 列表反转
list1.reverse()
print (list1)
print (len(list1))
#如果是字符串,会按照字母顺序来排序
list1 = ['speed','test','as','country']
list1.sort()
print (list1)
#遍历列表
for var in list1:
print (var)
列表的嵌套
list1 = [1,2,3,4]
list2 = [1,2,3,4,list1]
#一层一层看即可,并不复杂
print (list2[4][1])
字典
字典的简单介绍
字典是python中唯一的一个映射类型,他是以大括号括起来的键值对组成。
dict1 = {'a':11 , 'b': 222,'123':'22'}
在字典中,键是唯一的,值可以重复。在保存的时候,根据key来计算出一个内存地址,然后将key-value保存在这个地址中,这种算法被称为hash算法,所以,在dict中,这个key必须是可哈希的,如果你现在还搞不懂什么是可哈希的,暂时可以这样记,可以改变的都是不可哈希的,可以哈希的都不可以变。
可哈希(不可变): num str tuple bool
不可哈希的 (可变的): list dict set
字典保存的时候,并不是按照我们添加进入的顺序保存的,是按照hash表的顺序保存的,而hash表不是连续的,所以它是不支持下表索引和切片的,它只能通过key来获取dict中的数据。
访问字典的值
dict1 = {'name':'xiaoming','sex':'man'}
print (dict1['name'])
# print (dict1['test']) 没有这个值的时候会报错
print (dict1.get('sex'))
# 没有找到时打出 None
print (dict1.get('test'))
增加和修改
dict1 = {}
# 如果字典中没有出现这个key,就会新增一个这个键值对
dict1['name'] = 'xiaoming'
#如果字典中已经有这个key,就会修改这个值
dict1['name'] = 'xiaohua'
dict2 = {'name':'xiaowang','sex':'man'}
dict1.update(dict2)
#把dict2中的内容更新到dict1中,如果key存在,就替换,如果key不存在,就新增
print (dict1)
删除
dict1 = {'name':'xiaoming','sex':'man','scores':88}
#索引删除
del dict1['name']
print (dict)
#随机删除
dict.popitem()
print (dict)
#清空字典
dict.clear()
print (dict)
其他操作
#获取字典的键列表
dict1 = {'name':'xiaoming','sex':'man','scores':88}
print (dict1.keys())
#获取字典的值列表
print (dict1.values())
#遍历字典
for temp in dict1.keys():
print (temp)
print (dict1[temp])
#字典嵌套
dict2 = {'name':'xiaohua','sex':'girl','dict1':dict1}
print (dict2['dict1']['name'])
元组
元组的简单介绍
元组和列表类似,不同之处在于元组的元素不能修改,元组使用小括号
tup1 = (50)
#不加逗号,类型为整数
print type(tup1)
#加上逗号,才是元组
tup2 = (50,)
print type(tup2)
访问元组的值
元组可以通过索引和切片的方式来访问值,和列表一致,不作拓展
删除
#元组不允许修改和删除单个值,只能整个删除
tup1 = (50,20)
del tup1
print (tup1)
集合
集合的基本介绍
set集合是python的一个基本数据类型,一般不是很常用,简单了解一下即可
用大括号括起来,set中的元素是不重复、无序的,其实就是类似dict类型的key,但是不保存 value,所以里面的类型必须是可hash的
set1 = {1,2,3,4,'xiaoming'}
set2 = {1,1,2,3,'xiaoming','xiaoming'}
print (set1)
print (set2)
集合的常用操作
add 增加
pop 随机删除一个
remove 根据元素删除
clear 清空set集合
# 利用set的特性来进行列表去重
list1 = [1,1,1,12,4,23,42,4,4]
list2 = list(set(list1))
print (list2)
函数
函数的引入
为什么要有函数,比如看下面的例子:
scores = 88
if scores >= 60 :
print ('及格了')
else :
print ('不及格')
scores = 56
if scores >= 60 :
print ('及格了')
else :
print ('不及格')
如果只有几个同学,可能复制几遍就可以了,但是如果全班同学大几十个人,要怎么去做统计呢。引入函数的概念,我们定义一个事情或者功能,等到需要的时候直接去用就可以了,那里这里定义的东西就是一个函数。
函数是组织好的,可重复使用的,用来实现单一、或者相关联功能的代码块。
函数能提高应用的模块性和代码的重复利用率。print()这就是python的一个内建函数,我们也可以自己创建函数,这被叫做用户自定义函数。
语法
def 函数名(参数列表):
函数体
#函数名的命名和变量的命名规则一致,复习下
#简单的函数实例
def hello():
print ('hello world')
#执行函数
hello()
参数
形参:写在函数生命位置的变量叫形参,形式上的一个完整,表示这个函数调用时需要一个参数。
实参:在函数调用的时候给函数传递的值,叫实参。
传参:将实际参数交给形式参数的过程被称为传参
#带参数的函数实例
def helloSomeone(name):
print ('hello %s' %name)
helloSomeone('xiaoming')
形参的分类:
#按位置顺序排序的参数
def helloSomeone(name1,name2):
print ('hello %s' %name1)
print ('hello %s' %name2)
helloSomeone('xiaoming','xiaohua')
#name2就是一个默认值参数,在调用函数的时候,如果不给它传参,就会使用默认值
def helloSomeone(name1,name2='xiaohua'):
print ('hello %s' %name1)
print ('hello %s' %name2)
helloSomeone('xiaoming','xiaoqiang')
helloSomeone('xiaoming')
实参的分类:
#位置参数,按位置来传参
def helloSomeone(name1,name2):
print ('hello %s' %name1)
print ('hello %s' %name2)
helloSomeone('xiaoming','xiaohua')
#关键字参数,按关键字来传参
def helloSomeone(name1,name2):
print ('hello %s' %name1)
print ('hello %s' %name2)
helloSomeone(name1='xiaoming',name2='xiaohua')
#混合参数,位置参数必须在关键字参数前面
def helloSomeone(name1,name2,name3):
print ('hello %s' %name1)
print ('hello %s' %name2)
print ('hello %s' %name3)
helloSomeone('xiaoming','xiaohua','xiaoqiang')
helloSomeone('xiaoming',name2='xiaohua',name3='xiaoqiang')
#保存
helloSomeone(name1='xiaoming',name2='xiaohua','xiaoqiang')
返回值
return语句用于退出函数,并且在退出的时候选择性的向调用方返回一个表达式,不带参数值的return语句返回None
def sum(a,b):
sum = a + b
return sum
print (sum(1,2))
def sum(a,b):
sum = a + b
return
#返回none
print (sum(1,2))
全局变量和局部变量
定义在函数内部的变量只在局部作用域中使用,称为局部变量。
定义在函数外的拥有全局作用域,称为全局变量。
# 外面的total就是一个全局变量
total = 0
def sum(a,b):
# 这个total就是一个局部变量
total = a + b
print (total)
print (total)
# 外面的total就是一个全局变量
total = 0
def sum(a,b):
# 这个total就是一个局部变量
global total
total = a + b
print (total)
sum(1,2)
print (total)
函数名的应用
函数名是一个变量,但它是一个特殊的变量。
def hello():
print ('helloworld')
#赋值给其他变量,这个变量也拥有了和这个函数一样的功能
hello2 = hello
hello()
#也可以和其他变量一样,用来作为函数的参数和函数的返回值
def func1(var):
var()
return var
hello3 = func1(hello)
hello3()
内置函数
内置函数的定义
什么是内置函数,就是python给尼提供库,拿来直接用的函数,比如前面一直用的print,到python3.6.2,python一共提供了68个内置函数,我们来讲讲一些常用的内置函数。
常用内置函数
#输出和输入
print ('hello')
str1 = input('请输入')
print (str1)
#获取对象的内存地址
a = 1
b = 1
print (id(a))
print (id(b))
#获取帮助
print (help(print))
#数字相关
#bool() 将给定的数据转成bool值,不传参返回False
print (bool(5))
#int() 将给定的数据转成int值,不穿参返回0
print (int('555'))
#float() 将给定的数据转成float值,不传参返回0.0
print (float('55.66'))
#sum 求和 min最小值 max最大值
list = [1,2,3,4]
print (sum(list))
print (min(list))
print (max(list))
#文件操作 open(file,mode='r') 常用模式 r 读 w从头覆盖写 a追加
r = open('1.txt')
print (r.read()) #全部读成一个字符串,同时把光标移动到最后
r.close()
#所以这里重头在读
r = open('1.txt')
print (r.readlines()) #按行分割成列表
r.close()
w = open('1.txt','w')
w.write('11111')
w.close()
w = open('1.txt','a')
w.write('11111')
w.close()
面向对象1
面向对象的基本概念
- 我们之前学习的编程方式就是 面向过程的
- 面向过程、面向对象是两种不同的编程方式
面向过程怎么做:
-
收到一个需求,我们把完成需求的所有步骤,从头到尾逐步实现
- 把某些功能独立的代码封装成一个又一个的函数
- 最后完成的代码就是顺序的调用不同的函数
面向对象:
相比较函数,面向对象是更大的封装,根据职责或者说功能,在一个对象中去封装多个方法,你也可以理解为将函数进行分类
我们需要在面向过程的基础上,再学习一些面向对象的语法。
类和对象
类: 是对一群 具有 相同特征或者行为的事物的一个统称,是抽象的,不能直接使用,类的特征 被称为 属性,类的行为被称为方法。
比如 类就相当于制造飞机的图纸,是一个模板,是负责用来创建对象的。比如飞机,飞机的长、宽、高就是飞机的特征也就是属性,比如飞机会飞就是飞机的行为,被称为方法。
对象: 是由类创建出来的一个具体存在,可以直接使用,比如我们用飞机的图纸制造出一台真正的飞机,那么这个飞机就有了我们图纸中设想的长、宽、高,然后有飞的方法。
所以,在程序开发中,应该
- 先有类,再有对象
- 一个类可以创建多个对象
- 类中定义了的属性、方法,在对象创建后就会有对应的属性和方法
类的设计
- 确定类名,分析整个业务流程,确定类名。
- 对对象的特征描述,通常可以定义成为属性
- 对象具有的行为,通常可以定义成方法
练习1:
-
小明今天18岁,身高1.75,每天早上跑步,会去吃东西
-
小美今年17岁,身高1.65,小美不跑步,喜欢吃东西
类名: Person
属性: name age height
行为: run() eat()
定义简单的类
面向对象是更大的封装,在一个类中封装多个方法,就可以通过这个类创建出来的对象,直接调用这些方法。
class 类名:
def 方法1(self,参数列表):
pass
def 方法2(self,参数列表):
pass
方法的定义格式和之前学习过的函数的定义方式几乎一样,但是区别在于第一个参数必须是self,稍后介绍self
创建对象
对象变量 = 类名()
第一个面向对象程序
需求: 小狗爱吃骨头,小狗旺旺叫
类名: dog
方法: eat() wang()
class Dog:
"""这是一个狗"""
def eat(self):
print("小狗吃骨头")
def wang(self):
print("旺旺")
tom = Dog()
tom.eat()
tom.wang()
Self
由哪一个对象调用的方法,方法内的self就是哪一个对象的引用
class Dog:
def eat(self):
print ('%s 吃骨头' % self.name)
tom = Dog()
tom.name = 'Tom'
tom.eat()
kat = Dog()
kat.name = 'kat'
kat.eat()
在类的外部,通过 对象.,来访问对象的属性和方法
在类的内部,通过self. ,来访问对象的属性和方法
初始化方法
如果先调用方法,再设置属性,会如何呢
tom = Dog()
tom.eat()
tom.name = 'Tom'
# 会报错,对象没有 name的属性
所以,在开发过程中,不推荐在类的外部给对象增加属性,可能会存在这样的问题,对象包含属性,应该封装在类的内部
__init__
专门用来定义一个类具有哪些属性的方法,当使用类名来创建对象时,这个方法里面的内容就会自动运行
class Dog:
def __init__(self):
print("初始化方法")
tom = Dog()
在开发中,如果希望在创建对象的同时,就设置对象属性,可以给init设置参数
class Dog:
def __init__(self,name):
print ('这是初始化方法')
self.name = name
def eat(self):
print ('%s 吃骨头' % self.name)
tom = Dog('tom')
tom.eat()
内置方法
__del__
对象从内存中销毁前,会被自动调动
__str__
返回对象的描述信息,print函数输出使用,默认情况下, 会输出这个变量引用的对象是由哪一个类对象创建的,以及内存中的地址
class Dog:
def __init__(self, name):
self.name = name
print("%s 创建了" % self.name)
def __del__(self):
print("%s 销毁了" % self.name)
def __str__(self):
return "我是小狗:%s" % self.name
# tom 是一个全局变量
tom = Dog("Tom")
print (tom)
# del 关键字可以删除一个对象
del tom
私有属性和私有方法
私有属性: 只在对象内部使用,不能在外部使用的属性
私有方法: 只在对象内部使用,不能在外部使用的方法
在创建属性和方法时,在前面加上两个下划线即可
class Dog:
def __init__(self,name):
print ('这是初始化方法')
self.__name = name
def __eat(self):
print ('%s 吃骨头' % self.name)
tom = Dog('tom')
print (tom.name)
tom.eat()
面向对象2
面向对象的三大特征
- 封装,根据职责将属性和方法封装到一个抽象的类中
- 继承,实现代码的重用,相同的代码不需要重复的编写
- 多态,不同的对象调用相同的方法,产生不同的执行结果
封装
封装是面向对象编程的 一大特点,将属性和方法封装到一个抽象的类中,外界使用它时就创建对象,然后让对象调用方法
实例:
- 小华体重100公斤
- 小华每次跑步减肥 1 公斤
- 小华每次吃东西体重就会 增加2公斤
class Person:
def __init__(self, name, weight):
self.name = name
self.weight = weight
def __str__(self):
return "我是 %s,我的体重是 %d" % (self.name,self.weight)
def run(self):
self.weight = self.weight - 1
def eat(self):
self.weight = self.weight + 2
hua = Person('小华',100)
hua.eat()
hua.run()
hua.run()
print (hua)
继承的基础语法
继承后,子类拥有父类的所有方法和属性
class 类名(父类名):
pass
class Person:
def __init__(self, name, weight):
self.name = name
self.weight = weight
def __str__(self):
return "我是 %s,我的体重是 %d" % (self.name,self.weight)
def run(self):
self.weight = self.weight - 1
def eat(self):
self.weight = self.weight + 2
class Student(Person):
pass
hua = Student('小华',100)
hua.eat()
hua.run()
hua.run()
print (hua)
方法的重写
当父类的方法实现不能满足子类需求的时候,可以对方法进行 重写
class Person:
def __init__(self, name, weight):
self.name = name
self.weight = weight
def __str__(self):
return "我是 %s,我的体重是 %d" % (self.name,self.weight)
def run(self):
print ('run -1')
self.weight = self.weight - 1
print (self.weight)
def eat(self):
print ('eat +2')
self.weight = self.weight + 2
print (self.weight)
class Student(Person):
def eat(self):
print ('eat + 3')
self.weight = self.weight + 3
print (self.weight)
# super(Student, self).eat()
hua = Student('小华',100)
hua.eat()
hua.run()
print (hua)
多继承
子类可以拥有多个父类,可以同多个父类中继承属性和方法
class 子类名(子类A,子类B):
pass
class Student:
def __init__(self, name, weight):
self.name = name
self.weight = weight
def __str__(self):
return "我是 %s,我的体重是 %d" % (self.name, self.weight)
def run(self):
print('run')
self.weight = self.weight - 1
print(self.weight)
def eat(self):
self.weight = self.weight + 2
class Man:
def __init__(self):
print ('我是一个男人')
class ManStudent(Man,Student):
pass
xiaohua = ManStudent()
如果 不同的父类中存在同名的方法,那么子类对象在调用方法时,会按照继承顺序来查找,先查找自己的,然后查找第一个父类,然后查找第二个父类,但是,不要这么去做,在开发过程要尽量避免这种情况的发生。
object类
在python3里,如果没有指定父类,会默认使用object类来作为该类的父类,object类已经提供了一些内置的属性和方法供我们使用,但是在python2里,没有这种设定,为了保证代码能在Python2和python3中同时使用,建议统一继承object
class 类型(object):
pass
多态
在多态不同的子类对象调用的父类方法,产生不同的执行结果
如len()函数就是一个多态的例子,传入list和传入str都会返回长度
class Animal(object):
def animal_talk(self,obj):
obj.talk()
class Cat(Animal):
def talk(self):
print ('miaomiaomiao')
class Dog(Animal):
def talk(self):
print ('wangwangwang')
tom = Cat()
wangcai = Dog()
a = Animal()
a.animal_talk(tom)
a.animal_talk(wangcai)
面向对象3
实例属性和实例方法
- 创建的对象叫做类的实例,这个动作叫做实例化
- 对象的属性,叫做实例属性
- 对象调用的方法叫做实例方法
- 在对象中各自都拥有自己的实例属性
类属性和类方法
在python中 一切皆为对象
- 类也是一个特殊的对象,被叫做类对象
- 在程序运行中,类也会被加载到内存中,但是只有一份
- 所以在类中除了定义实例的属性和方法外,类对象还可以拥有自己的属性和方法
- 通过类名的方式就可以访问类的属性或者类的方法
class Dog(object):
count = 0
def __init__(self, name):
self.name = name
Dog.count = Dog.count + 1
dog1 = Dog('xiaoming')
dog2 = Dog('xiaohua')
dog3 = Dog('xiaoting')
print(Dog.count)
Dog.printcount()
类方法
@classmethod
def 类方法名(cls):
pass
- classmethod是修饰器,告诉解释器这是一个类方法
- 类方法的第一个参数是cls(用其他也可以,但是习惯用这个)
class Dog(object):
count = 0
def __init__(self, name):
self.name = name
Dog.count = Dog.count + 1
@classmethod
def printcount(cls):
print (cls.count)
dog1 = Dog('xiaoming')
dog2 = Dog('xiaohua')
dog3 = Dog('xiaoting')
print(Dog.count)
Dog.printcount()
静态方法
在开发过程时,如果既不需要访问实例属性、也不需要访问类属性,就可以把这个方法封装成一个静态方法
class Dog(object):
count = 0
def __init__(self, name):
self.name = name
Dog.count = Dog.count + 1
Dog.printdog()
@staticmethod
def printdog():
print ('我是一只狗')
dog1 = Dog('xiaoming')
方法总结
- 如果需要方法需要访问实例属性,封装为实例方法
- 如果方法不要访问实例属性,需要访问类属性,封装为类方法
- 如果方法不要访问实例属性也不需要访问类属性,封装为静态方法
单例设计模式
设计模式是前人工作的总结和提炼,针对某一特定问题的成熟的解决方案,比如我要实现一个音乐播放器,那么我在这台电脑上只允许创建一个窗口
单例设计模式,让类创建的对象,在系统中只有唯一的一个实例,每次执行类名()返回的对象,内存地址都是相同的,也就是同一个对象
在使用类名() 创建对象时,python的解释器首先会调用 __new__
方法对对象分配空间,这个方法是由object基础提供的内置的静态方法,主要作用有两个,分配内存空间,返回对象的引用,为了实现单例模式,我们要重写这个方法
class QQMusicPlayer(object):
# 定义类属性记录单例对象引用
instance = None
def __new__(cls, *args, **kwargs):
# 1. 判断类属性是否已经被赋值
if cls.instance is None:
cls.instance = super().__new__(cls)
# 2. 返回类属性的单例引用
return cls.instance
依然存在一个问题,每次类名()创建对象的时候,依然会执行init方法,我们需要再做一个判断 6786
class QQMusicPlayer(object):
# 定义类属性记录单例对象引用
instance = None
flag = 0
def __new__(cls, *args, **kwargs):
# 1. 判断类属性是否已经被赋值
if cls.instance is None:
cls.instance = super().__new__(cls)
# 2. 返回类属性的单例引用
return cls.instance
def __init__(self):
if QQMusicPlayer.flag == 0:
print("初始化音乐播放器")
QQMusicPlayer.flag = 1
异常
异常的概念
程序在运行过程中,如果遇到一个错误,那么就会停止程序的运行,并且提示错误信息,这就是异常,提示错误信息的动作,我们通常称为抛出异常
捕获异常
在开发过程中,如果对某些代码的执行不能确定是否能正确运行,那么就可以捕获异常,通过这种方式可以对突发事件做集中的处理,从而保证程序的稳定性和健壮性
try:
尝试执行的代码
except:
出现错误后的处理
try:
num = int(input('请输入整数'))
except:
print ('请输出整数哦')
按错误类型执行代码
try:
num = int(input('请输入整数'))
result = 10 / num
print (result)
except valueError:
print ('请输入正确的整数')
except ZeroDivisionError:
print("除 0 错误")
# 在开发中预判都所有的错误还是有一定的难度,如果希望程序无论出现任何错误都可以继续执行,那么可以再增加一个except
except Exception as result:
print("未知错误 %s" % result)
传递异常
当函数/方法执行出现异常时,会将异常一直传递到函数/方法的调用方,直到主程序,如果在主程序中,都没有异常处理,程序才会被终止
所以,可以在主程序中捕获异常,而不需要在代码中加大量的代码
class Dog:
def chu(self):
print (10/0)
try:
tom = Dog()
tom.chu()
except:
pass
主动抛出异常
在python中提供了异常类,在开发过程中,在某些特定的情况下,我们希望抛出一个异常
a = 0
if a == 0:
raise RuntimeError('运行异常')
模块和包
模块和包的概念
每个以py为结为的文件都是一个模块
包是包含多个模块的文件夹
导入模块
# 导入整个模块,导入后可以使用模块提供的工具,而不需要通过模块名
import 模块1
import 模块2
# 导入模块的部分工具
from 模块1 import 工具名
import random
# 生成随机数
num = random.randint(0, 100)
print(num)
pip 安装第三方模块
我们常用的知名的团队开发的模块和包,我们只需要知道怎么去安装和使用它们就可以了,避免重复造轮子,包括我们后面要学习的pyqt django都是现成的模块
pip install 模块名