python 必备基础
一 Python 介绍
Python介绍
Python的创始人为吉多·范罗苏姆(Guido van Rossum),如下图,少数几个不秃头的语言创始人。1989年的圣诞节期间,Guido为了打发圣诞节的无聊时光,开始写能够解释Python语言语法的解释器。Python这个名字,来自Guido所挚爱的电视剧Monty Python’s Flying Circus。他希望这个新的叫做Python的语言,能符合他的理想:创造一种C和shell之间,功能全面,易学易用,可拓展的语言。
Python可以应用于众多领域,如:数据分析、组件集成、网络服务、图像处理、数值计算和科学计算等众多领域。目前业内几乎所有大中型互联网企业都在使用Python,如:Youtube、Dropbox、BT、Quora(中国知乎)、豆瓣、知乎、Google、Yahoo!、Facebook、NASA、百度、腾讯、汽车之家、美团等。
一定要注意的一点,我们说的Python,其实说的是Python解释器。
Python解释器发展史
Python刚问世的时候,大多数公司原有的软件是python2.+写的(这不废话吗?),由于开发软件是需要成本的,因此一些公司无法抛弃以前的代码,所以曾经在2008年推出3.+版本的python时,还需要推出2.+版本的升级版本,给公司2.+版本开发的软一段时间过度。但是公司的软件是有生命周期的,历史遗留的2.+开发的软件逐渐会消失,所以2.+版本不再更新了,以后统一都使用3.+版本。
- 1989年,Guido开始写Python语言的编译器。
- 1991年,第一个Python编译器诞生。它是用C语言实现的,并能够调用C语言的库文件。从一出生,Python已经具有了:类,函数,异常处理,包含表和词典在内的核心数据类型,以及模块为基础的拓展系统。
- Granddaddy of Python web frameworks, Zope 1 was released in 1999
- Python 1.0 - January 1994 增加了 lambda, map, filter and reduce.
- Python 2.0 - October 16, 2000,加入了内存回收机制,构成了现在Python语言框架的基础
- Python 2.4 - November 30, 2004, 同年目前最流行的WEB框架Django 诞生
- Python 2.5 - September 19, 2006
- Python 2.6 - October 1, 2008
- Python 2.7 - July 3, 2010
- In November 2014, it was announced that Python 2.7 would be supported until 2020, and reaffirmed that there would be no 2.8 release as users were expected to move to Python 3.4+ as soon as possible
- Python 3.0 - December 3, 2008 (这里要解释清楚 为什么08年就出3.0,2010年反而又推出了2.7?是因为3.0不向下兼容2.0,导致大家都拒绝升级3.0,无奈官方只能推出2.7过渡版本)
- Python 3.1 - June 27, 2009
- Python 3.2 - February 20, 2011
- Python 3.3 - September 29, 2012
- Python 3.4 - March 16, 2014
- Python 3.5 - September 13, 2015
- Python 3.6 - 2016-12-23 发布Python3.6.0版
- Python 3.7 - 2018-6-27 发布Python3.7.0版
- Python 3.8 - 2019-2-4发布了Python 3.8.0.a1测试版
Python解释器的类型
CPython
CPython是使用最广且被的Python解释器。当我们从Python官方网站下载并安装好Python 2.7后,我们就直接获得了一个官方版本的解释器:CPython。这个解释器是用C语言开发的,所以叫CPython。在命令行下运行python就是启动CPython解释器。
IPython
IPython是基于CPython之上的一个交互式解释器,也就是说,IPython只是在交互方式上有所增强,但是执行Python代码的功能和CPython是完全一样的。好比很多国产浏览器虽然外观不同,但内核其实都是调用了IE。CPython用>>>作为提示符,而IPython用In [序号]:作为提示符。
PyPy
PyPy是另一个Python解释器,它的目标是执行速度。PyPy采用JIT技术,对Python代码进行动态编译(注意不是解释),所以可以显著提高Python代码的执行速度。
绝大部分Python代码都可以在PyPy下运行,但是PyPy和CPython有一些是不同的,这就导致相同的Python代码在两种解释器下执行可能会有不同的结果。如果你的代码要放到PyPy下执行,就需要了解PyPy和CPython的不同点。
Jython
Jpython是运行在Java平台上的python解释器,可以直接把Python代码编译成Java字节码执行。
IronPython
IronPython和Jython类似,只不过IronPython是运行在微软.Net平台上的Python解释器,可以直接把Python代码编译成.Net的字节码。
其它语言
C++
#include <iostream>
int main(void)
{
stdout<"hello world";
}
C
#include <stdio.h>
int main(void)
{
printf("\nhello world!");
return 0;
}
JAVA
public class HelloWorld{
// 程序的入口
public static void main(String args[]){
// 向控制台输出信息
System.out.println("hello world!");
}
}
PHP
<?php
echo "hello world!";
?>
Ruby
puts "hello world."
GO
package main
import "fmt"
func main(){
fmt.Printf("hello world!\n");
}
二 注释
注释作用:增加代码的可读性
代码注释分单行和多行注释,单行注释用#,多行注释可以用三对单/双引号,使用三引号注释可以换行。
单行注释
用 #符号
多行注释
'''
三单引号注释
三单引号注释
'''
"""
三双引号多行注释
三双引号多行注释
"""
三 变量
变量的组成
变量可以分为以下三个部分:
变量名(接受变量值) = (赋值符号) 变量值
-
变量名:变量名用来引用变量值,但凡需要用变量值,都需要通过变量名。
-
赋值符号:赋值
-
变量值:存放数据,用来记录现实世界中的某种状态。
# 只有变量名,赋值符号,变量值,会报错,而且毫无意义 name + = 100
变量名的命名规范
变量是有一定的命名规范的一定要记住,定义一个变量其实就是在记录现实世界中的状态,并且存永远不是目的,取才是目的。
变量的命名应该要满足以下三个条件:
-
变量的命名应该能反应变量值所描述的状态。
-
变量名必须由字母数字下划线组合,并且变量名的第一个字符不能是数字。
-
关键字不能声明为变量名。
-
变量名都具有可读性(意思),存不是目的,取才是目的
变量名风格
下划线
age_of_chen = 19
print(age_of_chen)
注意:编程中出现魔鬼变量是对自己和队友的不负责任
变量的三个特征
对于每一个变量,python都提供了这三个方法分别获取变量的三个特征,其中python的内置功能的id(),内存地址不一样,则id()后打印的结果不一样,因为每一个变量值都有其内存地址,而id()是用来反映变量值在内存中的位置,内存地址不同则id不同。
print(x)#获取变量的变量值
print(id(x))#获取变量的id,可以理解成变量在内存中的地址
print(type(x))#获取变量的数据类型,下章会详细介绍数据类型
变量赋值高级
链式赋值
a = b = c = d = 10
print(f'a:{a},b:{b},c:{c},d:{d}')#a:10,b:10,c:10,d:10
输出:a:10,b:10,c:10,d:10
交叉赋值
## 交叉赋值
x = 100
y = 200
x, y = y, x
print(f'x:{x}')
print(f'y:{y}')
输出:
x:100
y:200
解压赋值
将容器类的多个元素一次性赋值给多个变量
变量的内存管理
变量存哪里?
在申请变量的时候,会在内存中申请内存空间,变量值是存在于内存中的。
一个变量,内存就开辟一个内存空间存储这个变量。
垃圾回收机制
1,引用计数
直接引用:直接将变量名跟值联系起来。
间接引用:容器类型存的是索引值和值的内存地址,其引用为间接引用
2,标记清除
变量名存放于内存的:栈区
变量值存放于内存的:堆区
先扫描栈区的变量名,将与之间或直接引用的值标记为存活,其他堆区的值标记为失活。
再清除堆区就清除那些标记失活的
3,分带回收:分代回收的核心思想是:在历经多次扫描的情况下,都没有被回收的变量,
gc机制就会认为,该变量是常用变量,gc对其扫描的频率会降低。
小整数池
对于上一节讲的引用计数,需要注意的是:Python实现int的时候有个小整数池。为了避免因创建相同的值而重复申请内存空间所带来的效率问题。Python解释器会在启动时创建出小整数池,范围是*[-5,256]*,该范围内的小整数对象是全局解释器范围内被重复使用,永远不会被垃圾回收机制回收。
四 运算符
算术运算符
运算符 |
---|
+ |
- |
* |
/ |
% 取余数 |
**(幂)求次方 |
//(取整除,向下取整)如:9//2 =4 |
比较运算符
运算符 |
---|
== |
!= |
<>(不等于,类似!=) |
< |
> |
>= |
<= |
赋值运算符
运算符 |
---|
= |
+= |
-= |
*= |
/= |
%= |
**= |
//= |
逻辑运算符
主要用于逻辑判断,bool,循环等,返回True或False(二元运算符)
运算符 |
---|
and |
or |
not |
身份运算符
身份运算符用于比较两个元素对象的存储单位,通过比较两者id返回布尔值
注意;值相同的id不一定相同,id相同的值一定相同
运算符 | 描述 | 实例 |
---|---|---|
is | is是判断俩个标识符是不是引用自一个对象,类似== | x is y(返回bool值) |
is not | is not是判断俩个标识符是不是引用自不同的对象,类似!= | x is not y(返回bool值) |
位运算符
按位置运算符把数字看作二进制来进行计算的,python中的按位运算法则如下:
下面是变量a为60,b为13.二进制格式如下:
a = 0011 1100
b = 0000 1101
a&b = 0000 1100
a|b = 0011 1101
a^b = 0011 0001
~a = 1100 0011
运算符 | 描述 | 实例 |
---|---|---|
& | 按位与运算符:参与运算的俩个值,如果俩个相应的位都为1,则该位的结果为1,否则为0. | (a&b)输出结果为12,二进制的解释为:0000 1100| |
| | 按位或运算符:只要对应的二进位有一个为1时,结果位就为1. | (a|b)输出结果61,二进制解释:0011 1101 |
^ | 按位异或运算符:当俩对应的二进位相异时,结果为1 | (a^b)输出的结果为49,二进制的解释为:0011 0001 |
~ | 按位取反运算符:对数据的每一个二进制位取反,即把0变成1,把1变成0。~x类似于-x-1. | (~a)输出的结果位-61,二进制解释:1100 0011,在一个有符号二进制的补码形式。 |
<< | 左移动运算符:运算符的各二进制位全部左移若干位,由<< 右边的数字指定了移动的位数,高位丢弃,低位补0. |
a<<2,输出结果为240,二进制解释为:1111 0000 |
>> | 右移动运算符:把>> 左边的运算数的各二进位全部右移若干位,>> 右边的数字指定了移动的位数。 |
a>>2输出结果为15,二进制的解释为:0000 1111 |
成员运算符
除了以上的一些运算符之外,python还支持成员运算符,测试实例中包含了一系列的成员,包括字符串,列表或者元组。
运算符 | 描述 | 实例 |
---|---|---|
in | 如果在指定的序列中找到值饭后True,否则返回False。 | x 在y 的序列中,x in y 返回True |
not in | 如果在指定的序列中没有找到值,返回True,否则返回False | x 不在y的序列中,x not iny 返回True |
python运算符的优先级
运算符 | 描述 |
---|---|
** | 指数(最高优先级) |
~ +- | 按位翻转,一元加号和减号(最后俩个的方法命名为+@和-@) |
*/%// | 乘,除,取模(求余),取整除 |
+- | 加减法 |
>> << | 右移,左移运算符 |
& | 位’AND‘ |
^| | 位运算符 |
<=,<,>,>= | 比较运算符 |
<>,==,!= | 等于运算符 |
=,%=,/=,//=,**=,*=,+=,-= | 等于运算符 |
is,is not | 身份运算符 |
in,not in | 成员运算符 |
not ,and,or | 逻辑运算符 |
五 流程控制
if判断
单分支
# 单分支
# if一般用于判断/选择的场景
# 90以上优秀
score = 95
if score > 90:
print('优秀')
双分支(1)
# 双分支
# if...else
# 90以上优秀,90一下良好
score = 95
# if score > 90:
# print('优秀')
# else:
# print('良好')
双分支(2)
score = 75
# print('优秀') if score > 90 else print('良好')
# 单分支没有,多分支也没有
#结果一 条件 结果二
多分支(1)
## if...elif...elif...else
## 90以上优秀,90-70良好,70以下不及格
# score = 95
# if score > 90:
# print('优秀')
# elif score > 70:
# print('良好')
# else:
# print('及格')
多分支(2)
## if...if...if...if
## 90以上优秀,90-70良好,70以下不及格
score = 95
if score > 90:
print('优秀')
if score > 70 and score < 90:
print('良好')
if score < 60:
print('及格')
while循环
while循环又称为条件循环,所谓的循环就是重复做某件事,当然要给一定的条件限制,不然就永远的循环下去了,成为了死循环。
while循环的格式
while 条件:
code 1
code 2
code 3
...
#可以这样理解
'''
while(当) <条件>:
<需要进行重复的代码块> # 当条件成立时会进行运行,结束完代码块后会再一次判断条件,成立再运行,运行完再判断条件,%
'''
while + break
break就是循环限制的一种哦,意思是直接退出循环
# 可以这样理解
'''
while(当) <条件>:
<需要进行重复的代码块> # 当条件成立时会进行运行,结束完代码块后会再一次判断条件,成立再运行,运行完再判断条件,%
break # 遇到break后终止while循环
'''
while True:
print(1)
print(2)
break
print(3)
#输出:
1
2
while + continue
continue的意思终止本次循环,直接进入下一次循环中
n = 1
while n < 10:
if n == 8:
n += 1
continue
print(n)
n += 1
注意:continue后不能有同级代码
while 循环嵌套
#退出内层循环的while循环嵌套
while True:
name = 'chen'
pwd = '123'
inp_name = input('name:')
inp_pwd = input('pwd:')
if inp_name == name and inp_pwd == pwd:
print('successful')
while True:
cmd = input('请输入命令')
if cmd == 'q':
print(f'{cmd}功能执行')
break
else:
print('不对啊')
print('循环退出')
tag控制循环退出
tag = True
while tag:
name = 'chen'
pwd = '123'
inp_name = input('name:')
inp_pwd = input('pwd:')
if inp_name == name and inp_pwd == pwd:
print('successful')
while tag:
cmd = input('请输入命令')
if cmd == 'q':
tag = False
print(f'{cmd}功能执行')
else:
print('不对啊')
print('循环退出')
while+else
else会在while没有被break的时候才会执行else中的代码
n = 1
while n<3
print(n)
n += 1
else:
print('退出')
#输出:
1
2
退出
for循环
简单的来说for循环更像是遍历,for循环可以遍历任何序列的项目,如一个列表,字典或者一个字符串。for循环的循环次数受限于容器类型的长度,for循环也可以按照索引取值。
for + break
for 循环被直接调出本层循环
name = ['chen','python','nick','shanghai']
for i in name:
if i == 'python':
break
print(i)
#输出:
chen
for+continue
for循环调出本次循环,进入下一次循环
name = ['chen','python','nick','shanghai']
for i in name:
if i == 'python':
continue
print(i)
#输出:
chen
nick
shanghai
for循环的嵌套
外层循环每一次,内层循环所有的。
for i in range(3):
print("----------",i)
for j in range(2):
print("**********",j)
#输出:
---------- 0
********** 0
********** 1
---------- 1
********** 0
********** 1
---------- 2
********** 0
********** 1
for+else
在没有break触发的时候执行else内部的代码
name = ['chen','python','nick','shanghai']
for i in name:
if i == 'python':
continue
print(i)
else:
print('没有了')
#输出:
chen
nick
shanghai
没有了
for循环和while循环的区别
while:
1. 会进入死循环(不可控),尽量少使用while循环
2. 世间万物都可以作为循环的对象
for:
1. 不会进入死循环(可控),尽量使用for循环
2. 只对容器类数据类型+字符串循环(可迭代对象)
六 深浅copy
在python中,对象赋值实际上是对象的引用。当创建一个对象,然后把他赋值给另外一个变量的时候,python并没有拷贝这个对象,而是拷贝了这个对象的引用。
针对列表l1=['a','b','c',['d','e','f']]
一般有三种方法,分别为:拷贝(赋值)、浅拷贝、深拷贝。
注意:拷贝、浅拷贝、深拷贝都是针对可变类型数据而言的
可变不可变数据类型
不可变类型:只要值改变了内地id一定改变 如:数值,字符串,元组
可变类型:内存id不改变的情况下值可以改变 如:列表,字典,集合
拷贝=>赋值
拷贝效果:两个列的可变类型和不可变元素的改变都相互影响
原理:原数据的id多一个引用
l1 = ['a','b','c',['d','e','f']]
l2 = l1
l1.append('g')
print(l1)
#输出:
['a', 'b', 'c', ['d', 'e', 'f'], 'g']
print(l2)
#输出 :
['a', 'b', 'c', ['d', 'e', 'f'], 'g']
浅拷贝=>copy.copy
浅拷贝效果:两个列的可变类型元素的改变相互影响
原理:新列表元素的内存id和原列表元素的内存id一样
import copy
l1 = ['a','b','c',['d','e','f']]
l2 = copy.copy(l1)
l1.append('g')
print(l1)
#输出:
['a', 'b', 'c', ['d', 'e', 'f'], 'g']
print(l2)
#输出:
['a', 'b', 'c', ['d', 'e', 'f']]
l1[3].append('g')
print(l1)
#输出:
['a', 'b', 'c', ['d', 'e', 'f', 'g'], 'g']
print(l2)
#输出:
['a', 'b', 'c', ['d', 'e', 'f', 'g']]
深拷贝=>copy.deepcopy
深拷贝效果:两个列表完全独立,互补干扰
原理:新列表可变类型元素的内存id和原列表元素的内存id不一样
import copy
l1 = ['a','b','c',['d','e','f']]
l2 = copy.deepcopy(l1)
l1.append('g')
print(l1)
#输出:
['a', 'b', 'c', ['d', 'e', 'f'], 'g']
print(l2)
#输出:
['a', 'b', 'c', ['d', 'e', 'f']]
l1[3].append('g')
print(l1)
#输出:
['a', 'b', 'c', ['d', 'e', 'f', 'g'], 'g']
print(l2)
#输出:
['a', 'b', 'c', ['d', 'e', 'f']]