前言
第一部分 Python基础语法
1. 认识Python
1.1 Python 简介
Python 的设计目标: 一门简单直观的语言并与主要竞争者一样强大 开源,以便任何人都可以为它做贡献 代码像纯英语那样容易理解 适用于短期开发的日常任务
Python 的设计哲学: 优雅、明确、简单
Python 开发者的哲学是:用一种方法,最好是只有一种方法来做一件事
可扩展性:如果需要一段关键代码运行得更快或者希望某些算法不公开,可以把这部分程序用 C 或 C++ 编写,然后在 Python 程序中使用它们。
1.2. 第一个Python程序
ASCII 字符只包含 256 个字符,不支持中文
-
Python 2.x 的解释器名称是 python
-
Python 3.x 的解释器名称是 python3
提示:如果开发时,无法立即使用 Python 3.0(还有极少的第三方库不支持 3.0 的语法),建议 先使用 Python 3.0 版本进行开发 然后使用 Python 2.6、Python 2.7 来执行,并且做一些兼容性的处理
-
图形用户界面
-
代码编辑器(支持 代码补全/自动缩进)
-
编译器/解释器
-
调试器(断点/单步执行)
-
……
1.3. PyCharm 的设置
1.3.1 恢复 PyCharm 的初始设置:
-
关闭正在运行的 PyCharm
-
在终端中执行以下终端命令,删除 PyCharm 的配置信息目录:
$ rm -r ~/.PyCharm2016.3
-
重新启动 PyCharm
1.3.2 PyCharm 安装和启动步骤:
-
执行以下终端命令,解压缩下载后的安装包
$ tar -zxvf pycharm-professional-2017.1.3.tar.gz
-
将解压缩后的目录移动到 /opt 目录下,可以方便其他用户使用
/opt 目录用户存放给主机额外安装的软件
$ sudo mv pycharm-2017.1.3/ /opt/
-
切换工作目录
$ cd /opt/pycharm-2017.1.3/bin
-
启动 PyCharm
$ ./pycharm.sh
1.3.3 设置启动图标
-
在专业版中,选择菜单 Tools / Create Desktop Entry... 可以设置任务栏启动图标
-
注意:设置图标时,需要勾选 Create the entry for all users 快捷方式文件 /usr/share/applications/jetbrains-pycharm.desktop
在 ubuntu 中,应用程序启动的快捷方式通常都保存在 /usr/share/applications 目录下
1.3.4 卸载之前版本的 PyCharm
-
删除解压缩目录
$ sudo rm -r /opt/pycharm-2016.3.1/
-
删除家目录下用于保存配置信息的隐藏目录
$ rm -r ~/.PyCharm2016.3/
如果不再使用 PyCharm 还需要将 /usr/share/applications/ 下的 jetbrains-pycharm.desktop 删掉
1.4. 多文件项目的演练
-
开发 项目 就是开发一个 专门解决一个复杂业务功能的软件
-
通常每 一个项目 就具有一个 独立专属的目录,用于保存 所有和项目相关的文件
-
在 PyCharm 中,要想让哪一个 Python 程序能够执行,必须首先通过 鼠标右键的方式执行 一下
-
对于初学者而言,在一个项目中设置多个程序可以执行,是非常方便的,可以方便对不同知识点的练习和测试
-
对于商业项目而言,通常在一个项目中,只有一个 可以直接执行的 Python 源程序
2. 注释
-
注释的作用 使用用自己熟悉的语言,在程序中对某些代码进行标注说明,增强程序的可读性
2.1 单行注释(行注释)
-
以 # 开头,# 右边的所有东西都被当做说明文字,而不是真正要执行的程序,只起到辅助说明作用
print("hello python") # 输出
hello python
为了保证代码的可读性,# 后面建议先添加一个空格,然后再编写相应的说明文字;为了保证代码的可读性,注释和代码之间 至少要有 两个空格。
2.2 多行注释(块注释)
-
要在 Python 程序中使用多行注释,可以用 一对 连续的 三个 引号(单引号和双引号都可以)
""" 这是一个多行注释 在多行注释之间,可以写很多很多的内容…… """ print("hello python")
-
注释不是越多越好,对于一目了然的代码,不需要添加注释
-
对于 复杂的操作,应该在操作开始前写上若干行注释
-
对于 不是一目了然的代码,应在其行尾添加注释(为了提高可读性,注释应该至少离开代码 2 个空格)
-
绝不要描述代码,假设阅读代码的人比你更懂 Python,他只是不知道你的代码要做什么
2.3 代码规范:
-
Python 官方提供有一系列 PEP(Python Enhancement Proposals) 文档,其中第 8 篇文档专门针对 Python 的代码格式 给出了建议,也就是俗称的 PEP 8: 文档地址:https://www.python.org/dev/peps/pep-0008/ 谷歌有对应的中文文档:http://zh-google-styleguide.readthedocs.io/en/latest/google-python-styleguide/python_style_rules/
3. 运算符
3.1 算数运算符
3.2 比较(关系)运算符
Python 2.x 中判断 不等于 还可以使用 <> 运算符 != 在 Python 2.x 中同样可以用来判断 不等于
3.3 赋值运算符
-
在 Python 中,使用 = 可以给变量赋值。在算术运算时,为了简化代码的编写,Python 还提供了一系列的 与 算术运算符 对应的 赋值运算符,注意:赋值运算符中间不能使用空格。
3.4 身份运算符
-
is 用于判断 两个变量引用的对象是否为同一个
-
== 用于判断 引用变量的值 是否相等
3.5 成员运算符
3.6 逻辑运算符
否则只要 x 或者 y 有一个值为 False,就返回 False or x or y 只要 x 或者 y 有一个值为 True,就返回 True
只有 x 和 y 的值都为 False,才会返回 False not not x 如果 x 为 True,返回 False
如果 x 为 False,返回 True
3.7 运算符优先级
-
以下表格的算数优先级由高到最低顺序排列:
<补>程序执行原理
-
操作系统会首先让 CPU 把 Python 解释器 的程序复制到 内存 中
-
Python 解释器 根据语法规则,从上向下 让 CPU 翻译 Python 程序中的代码
-
CPU 负责执行翻译完成的代码
Python 的解释器有多大?
-
执行以下终端命令可以查看 Python 解释器的大小
1. 确认解释器所在位置
$ which python
2. 查看 python 文件大小(只是一个软链接)
$ ls -lh /usr/bin/python
3. 查看具体文件大小
$ ls -lh /usr/bin/python2.7
4. 变量
4.1 变量定义
-
在 Python 中,每个变量 在使用前都必须赋值,变量 赋值以后 该变量 才会被创建
-
可以用 其他变量的计算结果 来定义变量
-
变量名 只有在 第一次出现 才是 定义变量
变量名 = 值
使用交互式方式,如果要查看变量内容,直接输入变量名即可,不需要使用 print 函数 使用解释器执行,如果要输出变量的内容,必须要要使用 print 函数
4.2 变量的类型
-
在 Python 中定义变量是 不需要指定类型(在其他很多高级语言中都需要),Python 可以根据 = 等号右侧的值,自动推导出变量中存储数据的类型
-
数据类型可以分为 数字型 和 非数字型 数字型 整型 (int):Python3中的所有整数都表示为长整数。 因此,长整数没有单独的数字类型。 浮点型(float) 布尔型(bool) :真 True 非 0 数 —— 非零即真,假 False 0。 复数型 (complex):复数是由x + yj表示的有序对的实数浮点数组成,其中x和y是实数,j是虚数单位。 非数字型:有些运算符还支持这些数据类型,详见4.4.5.3 运算符。 字符串(str):加号(+)是字符串连接运算符,星号(*)是重复运算符。 列表(list) 元组(tuple) 字典(dict)
提示:在 Python 2.x 中,整数 根据保存数值的长度还分为: int(整数) long(长整数)
-
使用 type 函数可以查看一个变量的类型
In [1]: type(name)
<补>不同类型变量之间的计算
-
数字型变量 之间可以直接计算
-
在 Python 中,两个数字型变量是可以直接进行 算数运算的
-
如果变量是 bool 型,在计算时 True 对应的数字是 1 False 对应的数字是 0
-
字符串变量 之间使用 + 拼接字符串
-
字符串变量 可以和 整数 使用 * 重复拼接相同的字符串
-
数字型变量 和 字符串 之间 不能进行其他计算
<补>从键盘获取输入信息:input
-
在 Python 中可以使用 input 函数从键盘等待用户的输入
-
用户输入的 任何内容 Python 都认为是一个 字符串
字符串变量 = input("提示信息:")
<补>类型转换函数
price = float(input("请输入价格:"))
<补>格式化输出:print
-
如果希望输出文字信息的同时,一起输出 数据,就需要使用到 格式化操作符
-
% 被称为 格式化操作符,专门用于处理字符串中的格式 包含 % 的字符串,被称为 格式化字符串 % 和不同的 字符 连用,不同类型的数据 需要使用 不同的格式化字符
-
语法格式如下:
print("格式化字符串" % 变量1) print("格式化字符串" % (变量1, 变量2...))
4.4.5 公共方法和变量的高级应用
4.4.5.1 内置函数
4.4.5.2 切片
-
切片 使用 索引值 来限定范围,从一个大的 字符串 中 切出 小的 字符串
-
列表 和 元组 都是 有序 的集合,都能够 通过索引值 获取到对应的数据
-
字典 是一个 无序 的集合,是使用 键值对 保存数据
-
面向过程 —— 怎么做? 把完成某一个需求的 所有步骤 从头到尾 逐步实现根据开发需求,将某些 功能独立 的代码 封装 成一个又一个 函数最后完成的代码,就是顺序地调用 不同的函数特点: 注重 步骤与过程,不注重职责分工如果需求复杂,代码会变得很复杂开发复杂项目,没有固定的套路,开发难度很大!
-
面向对象 —— 谁来做? 相比较函数,面向对象 是更大的封装,根据职责在 一个对象中封装多个方法 在完成某一个需求前,首先确定 职责 —— 要做的事情(方法) 根据 职责 确定不同的 对象,在 对象 内部封装不同的 方法(多个)最后完成的代码,就是顺序地让 不同的对象 调用 不同的方法特点: 注重 对象和职责,不同的对象承担不同的职责更加适合应对复杂的需求变化,是专门应对复杂项目开发,提供的固定套路需要在面向过程基础上,再学习一些面向对象的语法
-
类和对象 类 是对一群具有 相同 特征 或者 行为 的事物的一个统称,是抽象的,特征 被称为 属性,行为 被称为 方法。 对象 是 由类创建出来的一个具体存在,是类的实例化。 在程序开发中,要设计一个类,通常需要满足一下三个要素: 类名 这类事物的名字,满足大驼峰命名法 属性 这类事物具有什么样的特征 方法 这类事物具有什么样的行为
2. 面向对象基础语法
2.1 dir 内置函数和内置方法
-
在 标识符 / 数据 后输入一个点 .,然后按下 TAB 键,iPython 会提示该对象能够调用的方法列表。
-
使用内置函数 dir 传入 标识符 / 数据,可以查看对象内的 所有属性及方法。 提示__方法名__格式的方法是 Python 提供的 内置方法 / 属性。
2.2 定义简单的类(只包含方法)
面向对象是更大的封装,在 一个类中封装多个方法,这样通过这个类创建出来的对象,就可以直接调用这些方法了!
class 类名:
def 方法1(self, 参数列表):
pass
def 方法2(self, 参数列表):
pass
对象变量 = 类名()
在面向对象开发中,引用的概念是同样适用的!
提示:在计算机中,通常使用 十六进制 表示 内存地址。
class Cat:
def __init__(self, new_name):
self.name = new_name print("%s 来了" % self.name)
def __del__(self):
print("%s 去了" % self.name)
def __str__(self):
return "我是小猫:%s" % self.name
tom = Cat("Tom")
print(tom)
注意:__str__方法必须返回一个字符串。
2.3 方法中的 self 参数
class Cat:
"""这是一个猫类"""
def eat(self):
print("小猫爱吃鱼")
def drink(self):
print("小猫在喝水")
tom = Cat()# 给对象设置属性
tom.name = "Tom"
由哪一个对象调用的方法,方法内的 self就是哪一个对象的引用
-
在类封装的方法内部,self 就表示当前调用方法的对象自己,在方法内部: 可以通过 self.访问对象的属性,也可以通过 self.调用对象的其他方法。
-
调用方法时,程序员不需要传递 self 参数。
-
在 类的外部,通过变量名.访问对象的 属性和方法 在 类封装的方法中,通过 self.访问对象的 属性和方法
2.4 初始化方法:init
-
当使用 类名() 创建对象时,会 自动 执行以下操作: 为对象在内存中分配空间 —— 创建对象 为对象的属性设置初始值 —— 初始化方法(__init__)
__init__ 方法是 专门 用来定义一个类具有哪些属性的方法!
-
在 __init__ 方法内部使用 self.属性名 = 属性的初始值 就可以定义属性,定义属性之后,再使用 类创建的对象,都会拥有该属性。
-
在开发中,如果希望在 创建对象的同时,就设置对象的属性,可以对 __init__ 方法进行 改造: 把希望设置的属性值,定义成 __init__方法的参数 在方法内部使用 self.属性 = 形参 接收外部传递的参数 在创建对象时,使用 类名(属性1, 属性2...) 调用
class Cat: def init(self, name): print("初始化方法 %s" % name) self.name = name ... tom = Cat("Tom") ...lazy_cat = Cat("大懒猫") ...
2.5 私有属性和私有方法
-
在实际开发中,对象 的 某些属性或方法 可能只希望 在对象的内部被使用,而 不希望在外部被访问到
-
私有属性 就是 对象 不希望公开的 属性
-
私有方法 就是 对象 不希望公开的 方法
-
在 定义属性或方法时,在 属性名或者方法名前 增加 两个下划线,定义的就是 私有属性或方法:
# 私有属性,外部不能直接访问到
print(xiaofang._Women__age)
# 私有方法,外部不能直接调用
xiaofang._Women__secret()
提示:在日常开发中,不要使用这种方式,访问对象的 私有属性 或 私有方法。
3. 封装、继承和多态
-
封装 根据 职责 将 属性 和 方法 封装 到一个抽象的 类 中
-
继承 实现代码的重用,相同的代码不需要重复的编写
-
多态 不同的对象调用相同的方法,产生不同的执行结果,增加代码的灵活度
3.1 继承
3.1.1 单继承
class 类名(父类名):
pass
-
覆盖 父类的方法:父类的方法实现 和 子类的方法实现完全不同 具体的实现方式,就相当于在 子类中 定义了一个 和父类同名的方法并且实现。
-
对父类方法进行 扩展:子类的方法实现 中 包含 父类的方法实现 在子类中 重写 父类的方法;在需要的位置使用 super().父类方法 来调用父类方法的执行代码;其他的位置针对子类的需求,编写 子类特有的代码实现。
关于 super
-
在 Python 中 super 是一个 特殊的类
-
super()就是使用 super 类创建出来的对象
-
最常 使用的场景就是在 重写父类方法时,调用 在父类中封装的方法实现
调用父类方法的另外一种方式:在 Python 2.x 时,如果需要调用父类的方法,还可以使用以下方式:父类名.方法(self)。目前在 Python 3.x 还支持这种方式,但不推荐使用,因为一旦 父类发生变化,方法调用位置的 类名 同样需要修改。
父类的 私有属性 和 私有方法
私有属性、方法 是对象的隐私,不对外公开,外界 以及 子类 都不能直接访问 私有属性、方法 通常用于做一些内部的事情
3.1.2 多继承
class 子类名(父类名1, 父类名2...):
pass
Python 中的 MRO算法(Method Resolution Order)
-
如果 不同的父类 中存在 同名的方法,子类对象 在调用方法时,会调用 哪一个父类中的方法呢? 提示:开发时,应该尽量避免这种容易产生混淆的情况! —— 如果 父类之间 存在 同名的属性或者方法,应该 尽量避免使用多继承。
-
Python 中针对 类 提供了一个 内置属性__mro__ 可以查看 方法 搜索顺序 在搜索方法时,是按照 mro 的输出结果 从左至右 的顺序查找的 如果在当前类中 找到方法,就直接执行,不再搜索 如果 没有找到,就查找下一个类 中是否有对应的方法,如果找到,就直接执行,不再搜索 如果找到最后一个类,还没有找到方法,程序报错
MRO 是 method resolution order —— 方法搜索顺序,主要用于 在多继承时判断 方法、属性 的调用 路径
新式类与旧式(经典)类
-
新式类:以 object 为基类的类,推荐使用
-
经典类:不以 object为基类的类,不推荐使用
在 Python 3.x 中定义类时,如果没有指定父类,会 默认使用 object作为该类的 基类 —— Python 3.x 中定义的类都是 新式类,在 Python 2.x 中定义类时,如果没有指定父类,则不会以 object 作为 基类。
-
为了保证编写的代码能够同时在 Python 2.x 和 Python 3.x 运行!今后在定义类时,如果没有父类,建议统一继承自 object:
class 类名(object): pass
object 是 Python 为所有对象提供的 基类,提供有一些内置的属性和方法,可以使用 dir(object) 函数查看。
3.2 多态
-
封装 根据 职责 将 属性 和 方法 封装 到一个抽象的 类 中 定义类的准则
-
继承 实现代码的重用,相同的代码不需要重复的编写 设计类的技巧 子类针对自己特有的需求,编写特定的代码
-
多态 不同的 子类对象 调用相同的 父类方法,产生不同的执行结果 增加代码的灵活度 以 继承 和 重写父类方法 为前提 调用方法的技巧,不会影响到类的内部设计
多态 更容易编写出出通用的代码,做出通用的编程,以适应需求的不断变化!
4. 类属性和类方法
4.1 类的结构
Python 中 一切皆对象: class AAA: 定义的类属于 类对象 obj1 = AAA() 属于 实例对象
4.2 类属性和实例属性
属性的获取机制
-
类名.类属性
-
对象.类属性 (不推荐,因为如果使用 对象.类属性 = 值 赋值语句,只会给对象添加一个属性,而不会影响到类属性的值)
4.3 类方法和静态方法
4.3.1 类方法
-
类属性 就是针对 类对象 定义的属性 使用 赋值语句 在 class 关键字下方可以定义 类属性 类属性 用于记录 与这个类相关 的特征
-
类方法 就是针对 类对象 定义的方法 在 类方法 内部可以直接访问 类属性 或者调用其他的 类方法
@classmethod
def 类方法名(cls): pass
-
类方法需要用 修饰器 @classmethod 来标识,告诉解释器这是一个类方法
-
类方法的 第一个参数 应该是 cls 由 哪一个类 调用的方法,方法内的 cls 就是 哪一个类的引用 这个参数和 实例方法 的第一个参数是 self 类似 提示 使用其他名称也可以,不过习惯使用 cls
-
通过 类名. 调用 类方法,调用方法时,不需要传递 cls 参数
-
在方法内部 可以通过 cls. 访问类的属性 也可以通过 cls. 调用其他的类方法
-
定义一个 工具类,每件工具都有自己的 name
-
需求 —— 在 类 封装一个 show_tool_count 的类方法,输出使用当前这个类,创建的对象个数
@classmethod def show_tool_count(cls): """显示工具对象的总数""" print("工具对象的总数 %d" % cls.count)
4.3.2 静态方法
-
在开发时,如果需要在 类 中封装一个方法,这个方法: 既 不需要 访问 实例属性 或者调用 实例方法 也 不需要 访问 类属性 或者调用 类方法
-
这个时候,可以把这个方法封装成一个 静态方法
@staticmethod
def 静态方法名(): pass
-
静态方法 需要用 修饰器 @staticmethod 来标识,告诉解释器这是一个静态方法
-
通过 类名. 调用 静态方法
-
静态方法 show_help 显示游戏帮助信息
-
类方法 show_top_score 显示历史最高分
-
实例方法 start_game 开始当前玩家的游戏
-
实例方法 —— 方法内部需要访问 实例属性 实例方法 内部可以使用 类名. 访问类属性
-
类方法 —— 方法内部 只需要访问 类属性
-
静态方法 —— 方法内部,不需要访问 实例属性 和 类属性
5. 单例
5.1 单例设计模式
-
设计模式 设计模式 是 前人工作的总结和提炼,通常,被人们广泛流传的设计模式都是针对 某一特定问题 的成熟的解决方案 使用 设计模式 是为了可重用代码、让代码更容易被他人理解、保证代码可靠性
-
单例设计模式 目的 —— 让 类 创建的对象,在系统中 只有 唯一的一个实例 每一次执行 类名() 返回的对象,内存地址是相同的
-
单例设计模式的应用场景 音乐播放 对象 回收站 对象 打印机 对象 ……
5.2 静态方法: new
-
使用 类名() 创建对象时,Python 的解释器 首先 会 调用 __new__ 方法为对象 分配空间
-
__new__ 是一个 由 object 基类提供的 内置的静态方法,主要作用有两个: 在内存中为对象 分配空间 返回 对象的引用
-
Python 的解释器获得对象的 引用 后,将引用作为 第一个参数,传递给 __init__ 方法
重写 __new__ 方法 的代码非常固定!
-
重写 __new__ 方法 一定要 return super().__new__(cls),否则 Python 的解释器 得不到 分配了空间的 对象引用,就不会调用对象的初始化方法
-
注意:__new__ 是一个静态方法,在调用时需要 主动传递 cls 参数
5.3 Python 中的单例
-
单例 —— 让 类 创建的对象,在系统中 只有 唯一的一个实例 定义一个 类属性,初始值是 None,用于记录 单例对象的引用 重写 __new__ 方法 如果 类属性 is None,调用父类方法分配空间,并在类属性中记录结果 返回 类属性 中记录的 对象引用
只执行一次初始化工作
-
在每次使用 类名() 创建对象时,Python 的解释器都会自动调用两个方法: __new__ 分配空间 __init__ 对象初始化
-
在对 __new__ 方法改造之后,每次都会得到 第一次被创建对象的引用
-
但是:初始化方法还会被再次调用
-
让 初始化动作 只被 执行一次
-
定义一个类属性 init_flag 标记是否 执行过初始化动作,初始值为 False
-
在 __init__ 方法中,判断 init_flag,如果为 False 就执行初始化动作
-
然后将 init_flag 设置为 True
-
这样,再次 自动 调用 __init__ 方法时,初始化动作就不会被再次执行 了
Tips
'''
**需求**
* 定义 `input_password` 函数,提示用户输入密码
* 如果用户输入长度 < 8,抛出异常
* 如果用户输入长度 >=8,返回输入的密码
'''
def input_password():
# 1\. 提示用户输入密码
pwd = input("请输入密码:")
# 2\. 判断密码长度,如果长度 >= 8,返回用户输入的密码
if len(pwd) >= 8:
return pwd
# 3\. 密码长度不够,需要抛出异常
# 1> 创建异常对象 - 使用异常的错误信息字符串作为参数
ex = Exception("密码长度不够")
# 2> 抛出异常对象
raise ex
try:
user_pwd = input_password()
print(user_pwd)
except Exception as result:
print("发现错误:%s" % result)
在 Python 中针对 None 比较时,建议使用is 判断
在开发时千万不要使用 eval 直接转换 input 的结果,举个例子:
__import__('os').system('ls')
# 等价代码import os
os.system("终端命令")
最后多说一句,小编是一名python开发工程师,这里有我自己整理了一套最新的python系统学习教程,包括从基础的python脚本到web开发、爬虫、数据分析、数据可视化、机器学习等。想要这些资料的可以加小编的python学习交流企鹅群:1075110200,配套资料可以找管理小姐姐免费领取。