写在前面
课程网站:廖雪峰_Python教程
主要内容分为: Python基础、函数编程、高级语法特性、面向对象 ## 都不会太深入(开发人员可能需要很懂
内容很多,其实这可能是我,第四次点开廖老师的网站了。因为想把机器学习的作业做好一点。先前做到数据挖掘跟可视化的地方,人直接尬住。就很吃瘪。
这里主要是,为了给学习使用 NumPy、Pandas还有Matplotlib打下基础。
真正开始做AI相关的科研学习过程中,一定会遇到一些自己以前从来没见过的,函数跟库。不同科研人员编写代码的习惯也不同。
但是问题不大,到时候看文献查文档就是了。
这里再推一波自己去北大软微神仙室友的Python教程:
https://blog.csdn.net/zimuzi2019/article/details/127195751?spm=1001.2014.3001.5502
具体学习方法
- 自己配置开发环境
- 看着我这篇的大纲还有廖老师的博客学习
- 可以不看我写了什么,这篇tutorial其实就是一个语言学习划的提纲
- 一定要自己写代码
面向AI的极简Python学习,我们开始吧!
安装
任何Python的教程都会教,配置开发环境,我就不做。给三种Python环境配置。
Python官网法
Pycharm环境配置
https://www.jetbrains.com/pycharm/
Anaconda环境配置
https://www.anaconda.com/
一般我们安装Anaconda两个方法
- 挂梯子上官网
- 上清华源
vscode
我是用VScode作为开发环境的,其实vscode只是一个文本编辑器,安装插件后,既可以跑ipynb的文件(像jupyter notebook一样)也能跑py文件(其实就是调用CPython解释器)
第三方库
见后文的 安装第三方库
第一个程序
输入与输出 I/O
Output
1 | '''用 print() 在括号中加上字符串,就可以向屏幕上输出指定的文字。 比如输出 'hello_world', 用代码实现如下:''' |
以上接受过个字符串,遇到逗号”,”会输出一个空格
Input
#input 函数的输入,读取到的数据类型为 字符串,要使得其用于其他用途,要进行类型转换。
1 | '''Python 提供了一个 input(),可以让用户输入字符串,并存放到一个变量里''' |
一个交互性比较强的输入输出代码
1 | name = input('please enter your name:') |
格式化输出
学好格式化输出,可以帮你避免 看得懂别人写的代码,自己写不出来的尴尬
一般深度学习打表用的是第三种,f-string 格式化输出
格式化方法1
在Python中,采用的格式化方式和C语言是一致的,用 % 实现,举例如下:
1 | 'Hello,%s' % 'world' |
%运算符就是用来格式化字符串的。在字符串内部,%s表示用字符串替换,%d表示用整数替换,有几个%?占位符,后面就跟几个变量或者值,顺序要对应好。如果只有一个%?,括号可以省略
常见占位符表
整体格式化的形式和C语言相同
占位符 | 替换内容 |
---|---|
%d | 整数 |
%f | 浮点数 |
%s | 字符串 |
%x | 十六进制整数 |
格式化方法2
另一种 格式化字符串输出 的方法是使用字符串的format()方法,它会用传入的参数依次替换字符串内的占位符{0}、{1}…,不过这种方式写起来比%要麻烦得多:
1 | 'Hello, {0}, 成绩提升了 {1:.1f}%'.format('小明', 17.125) |
格式化方法3
以f开头的字符串,称之为f-string,它和普通字符串不同之处在于,字符串如果包含{xxx},就会以对应的变量替换:
1 | 2.5 r = |
上述代码中,{r}被变量r的值替换,{s:.2f}被变量s的值替换,并且:后面的.2f指定了格式化参数(即保留两位小数),因此,{s:.2f}的替换结果是19.62。
比较常见的,打印训练信息的格式化输出。
Python基础
- Python作为计算机编程语言,不能有歧义
- 以#开头的语句是注释,内容任意,解释器会忽略注释。
- 当语句以冒号:结尾时,缩进的语句视为代码块。
数据类型
Python有以下几种,可以直接处理的数据类型
整数
- 程序上的表示方法和数学上的写法一摸一样: 1, 100, -8080, 0
- 十六进制表示法,0x前缀和0-9,a-f表示: 0xff00, 0xa5b4c3d2
- 很大的数字Python允许下划线_分隔。
浮点数
浮点数在计算机内部存储方式与整数不同,不同于整数,浮点数有舍入误差
很大或很小的浮点数,就必须用 科学计数法 表示,把10用e替代: 1.23e9, 1.2e-5 这样
字符串
单引号‘或者双引号“括起来的版本,比如’abc’,’xyz’,如果字符串中有一些特殊字符,用转义字符\来标识
1 | 'I\'m \"OK\"!' |
转义字符 \ 可以转义很多字符,比如 \n 表示换行,\t 表示制表符,字符 \ 本身也要转义,所以 \ 表示的字符就是 \,可以在Python的交互式命令行用 print() 打印字符串看看:
1 | print('I\'m ok.') |
若字符串中有大量的字符需要转义, 为了方便,Python允许用 r’’表示’’内部的字符串默认不转义,r:raw
1 | print('\\\t\\') |
字符串内部有大量换行,用 \n 写在一行内不好阅读,为了简化,Python允许用’’’…’’’的格式表示多行内容
1 | print('''line1 |
在写py文件的时候,不需要写…,这是交互命令行的解释器生成的。
Bool
python的Bool值只有俩,True 和 False,两者都是首字母大写
条件判断的结果也是 Bool值
Bool值的与或非
1 | # and |
空值
空值是Python里的一个特殊的值,用 None 表示。None只是一种特殊的空值,其余的空值还包括 列表、字典等数据类型的空
变量
- 变量名必须是 大小写英文、数字和下划线_的组合,且不用能数字开头
- 在Python语法中 等号 = 是赋值语句,可以把任意数据类型赋值给变量,同一变量可以反复赋值。
- 变量本身类型不固定的语言称之为 动态语言,与之相对应的叫 静态语言
常量
不能改变值的变量,但是 Python没有机制保证常量不被改变。
基本运算:除法&阶乘
Python有三种除法,阶乘的写法也很特别(指与 Matlab 不用,很容易写错
1 | # 浮点除法 |
此外 Python 的不等于写法与C相同
数据结构:List and Tuple
List
List是Python内置的一种数据类型。List是一种有序的集合,可以随时添加和删除其中的元素
创建列表的方法[]
1 | 'Michael', 'Bob','Tracy'] classmates = [ |
- 使用len()函数,就可以获得list元素的个数
index
List 的索引是用[],跟其他编程语言一样(除了matlab),顺序都是从0开始count,所以最后一个元素的index是 len-1
List可以倒序索引[-1],[-2],…倒数第一第二…这样,但是要注意越界的报错。
List方法
- append()
#在List的末尾插入一个元素,List 是一个有序的列表
1 | 'Adam') classmates.append( |
- insert()
#在指定位置插入元素,比如索引号为 1 的位置:
1 | 1, 'Jack') classmates.insert( |
- pop()
#取出(有调出值的过程,然后删除)list末尾元素,用pop()方法,删除指定索引位置的元素,pop(i)
1 | # 就跟 stack 的用法一样 |
可以直接利用索引和赋值来改变列表元素的值
- sort()
#list 可以排序,如果都是字符的话,是字典序从小到大
tuple
tuple 相较 list 唯一的区别在于,无法改变数据元素
tuple 相较 list 更加安全
创建方式()
tuple引用
一样用[]来取引用
tuple方法
因为元素无法更改,没有list所拥有的方法,但是如果元素是list的话,list元素中的元素可以更改
数据结构:dict and set
dict
在一些其他的语言中,叫作map,就是键值对
字典的内部存放顺序与key的放入方式无关
创建方法
1 | 'Michael': 95, 'Bob': 75, 'Tracy': 85} d = { |
dict 键的查找
- ’key’ in d: 返回一个条件判断结果
- 方法get()dict的pop()方法
1
2
3
4'Thomas') d.get(
'Thomas', -1) d.get(
-1
# 如果查找的键,在字典中,会返回 键所对应的值,如果,不存在,要么不输出,要么输出预设的值1
2
3'Adam'] = 67 d[
'Adam') d.pop(
# 再次查找的时候,字典中就不再会有Adam这个键-值对了
与list相比较,dict有几个特点:
- 查找和插入的速度极速,不会随着key的增加而变慢;
- 需要占用大量的内存,内存浪费多。
而list相反。
dict 是用空间来换取时间的一种方法。dict的key必须是不可变对象
set
set与dict类似,也是一组key的集合,但不存储value。
创建set
1 | set([1, 2, 3]) s = |
集合是,元素是无序的且不重复,重复输入,会被语言自动过滤
集合方法
add(key)
1
24) s.add(
# 集合s加入一个元素 4remove(key)
1
24) s.remove(
# 4被拿走集合的交、并
1
2
3s1 & s2
s1 | s2
control flow
if&elif
1 | # 注意冒号部分 以及 缩进 |
循环
Python的循环有两种,一种是for … in 一种是 while
break与continue跟c中的一样
for … in
1 | for x in list: |
有时候,我们只需要一个自然数序列有函数 range(n) 生成一个长度为 n 的自然数递增序列(0-> n-1)
while
1 | while <条件1>: |
函数
调用函数
调用函数,只需要函数的名称和参数
如果传入的参数数量不对,会报错 TypeError
数据类型转换
数据类型转换是 Python 内置的常用函数。
1 | int('123') |
函数的引用
拿函数值做赋值,会生成对函数对引用,就跟 Cpp 中的语法一样,直接“起一个别名”
1 | abs # 变量a指向abs函数 a = |
定义函数
Python的函数定义
1 | def my_abs(x): |
如果函数体内,没有 return 语句,函数执行完毕,也会返回结果,只是结果为 None
import
如果上看的 my_abs()函数定义保存为了 abstest.py 文件,可以在当前目录下启用Python解释器,用 from abstest import my_abs 来导入 my_abs() 函数
pass
定义一个函数,什么也不做,函数体用 pass
1 | def nop(): |
参数检查
*这个section是进阶内容
如何编写报错提示
1 | def my_abs(x): |
多值返回
- return后面多值用,分隔,返回值是一个 tuple
- 取用函数返回值时,多变量同时接收,并且按位置赋值
1 | import math |
函数的参数
这个section比较重要, 之前看一些源码会因为,一些参数设置不熟悉而犯懵逼。
定义函数的时候,我们把参数的名字和位置确定下来,函数的接口定义就完成了。对于函数的调用者来说,只需要知道如何传递正确的参数,以及函数将返回什么样的值就够了,函数内部的复杂逻辑被封装起来,调用者无需了解。
位置参数
就是我们平时最常见的参数,函数输入必须有对应位置参数的输入。
如果缺少,位置参数的输入,系统会报错。
默认参数
在函数设定的时候,就已经设定好默认值的参数。
如果,额外输入该参数值,参数值会被替代。
1 | def power(x, n=2): |
设定默认参数的注意事项
- 位置参数必须在前
- 如何设置参数
传入多个参数时,将变化大的参数设置在前面,将变化小的(甚至大多数可以用默认值替代的参数放在后面)
默认参数一定要指向不变对象!!!!!
1 | # 以下为没有将 默认参数设定为不可改变对象 的一个漏洞例子 |
可变参数
顾名思义:传入参数个数是可变的,允许传入0个参数值
一般输入一个List或者Tuple,而函数体内会有for…in循环对变量进行一个遍历
1 | def calc(*numbers): |
设置方式是,在变量名前加上*,可变参数会自动组装成一个 Tuple
- 可以先将参数值组装成List或Tuple
- 但是在输入参数的时候,要在那个可迭代参数前加上*
1
2
31, 2, 3] nums = [
calc(*nums)
14
关键字参数
关键字参数,会在函数内部自动组装称一个dict
1 | def person(name, age, **kw): |
一般会有一个大杂烩输出(大字典,键值对)
同理,可以先组装称字典再将dict变量传入
传指定参数前,要加上两个**
1 | 'city': 'Beijing', 'job': 'Engineer'} extra = { |
命名关键字参数
关键字参数可以接收任意不受限制的关键字参数。这导致,传入了哪儿些,查找很麻烦。
命名关键字参数,会限制关键字参数的名字“key”
1 | # 限制方式为,在*号之后的都为命名关键字参数 |
- 命名关键字参数必须传入参数名,这和位置参数不同。如果没有传入参数名,调用将报错
- 如果函数定义中已经有了一个可变参数,后面跟着的命名关键字参数就不再需要一个特殊分隔符*了:
1
2def person(name, age, *args, city, job):
print(name, age, args, city, job)
参数组合
参数定义的顺序必须是:位置(必选)参数、默认参数、可变参数、命名关键字参数和关键字参数。
命名关键字在关键字前面 这两者跟文档编写顺序相反
递归函数
因为这是所有语言都有的特性,所以不特别说明。
递归就是:函数调用函数。
高级特性
后补: 我又看了一下,挺重要的。。。挺重要的(打脸)
这个part的语法特性在一些数据科学的工业级教科书上出现过。
还是可以学一下的,但是感觉,不是非常重要,就AI科研学习而言(之前不懂事写的
但是在Python中,代码不是越多越好,而是越少越好。代码不是越复杂越好,而是越简单越好。
基于这一思想,我们来介绍Python中非常有用的高级特性,1行代码能实现的功能,决不写5行代码。请始终牢记,代码越少,开发效率越高。
切片slice
经常取指定索引范围的操作,用循环就非常繁琐,利用切片就能大大简化
1 | 'Michael', 'Sarah', 'Tracy', 'Bob', 'Jack'] L = [ |
一些小trick
1 | 'ABCDEFG'[:3] |
迭代
若给定一个list或者tuple,我们可以用 for…in
Python 的 for 循环抽象程度要高于 C 的 for 循环,因为 Python 的 for 循环不仅可以用在 list 或 tuple 上,还可以作用在其他可迭代对象上
1 | # 字典也可以进行迭代 |
因为 dict 的存储不是按照 list 的方式顺序排列,所以,迭代出的结果顺序很可能不一样。
默认情况下,dict 迭代的是key。如果要迭代value,可以用 for value in d.values(),如果要同时迭代 key 和 value,可以用 for k,v in d.items()。
由于字符串也是可迭代对象,因此,也可以作用于for循环
1 | for ch in 'ABC': |
判断一个对象是否可迭代
方法是通过 collections.abc 模块的 Iterable 类型判断:
1 | from collections.abc import Iterable |
下标循环
这个part太重要了,因为不熟悉,之前看到代码都感觉见过,又想不起来具体是干什么的
1 | for i, value in enumerate(['A', 'B', 'C']): |
for循环其实可以同时使用两个甚至多个变量,比如dict的items()可以同时迭代key和value:
具体做法就是,List中的元素依次与index绑定生成二元素tuple
1 | # 二元 for...in |
列表生成式
List Comprehensions 是 Python 内置的简单且强大的可以用来创建 list 的生成式。
生成 1->10 的整数序列,list(range(1,11))
生成 1->10 各个数值的平方
1
for x in range(1, 11)] [x * x
for 循环后还能加上 if 条件判断
1
2for x in range(1, 11) if x % 2 == 0] [x * x
[4, 16, 36, 64, 100]
列表生成式进阶应用
进阶版,两层循环生成全排列
1
2for m in 'ABC' for n in 'XYZ'] [m + n
['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']生成当前目录下的所有文件和目录名
1
2
3import os # 导入os模块,模块的概念后面讲到
for d in os.listdir('.')] # os.listdir可以列出文件和目录 [d
['.emacs.d', '.ssh', '.Trash', 'Adlm', 'Applications', 'Desktop', 'Documents', 'Downloads', 'Library', 'Movies', 'Music', 'Pictures', 'Public', 'VirtualBox VMs', 'Workspace', 'XCode']使用两变量生成list
1
2
3'x': 'A', 'y': 'B', 'z': 'C' } d = {
'=' + v for k, v in d.items()] [k +
['y=B', 'x=A', 'z=C']把一个list中所有的字符串变成小写
1
2
3'Hello', 'World', 'IBM', 'Apple'] L = [
for s in L] [s.lower()
['hello', 'world', 'ibm', 'apple']
列表生成式的if…else
1 | # if 的列表生成式 |
生成器generator
generator 能够“记住” 生成序列的算法,在需要调用的时候,根据算法依次推导各个值,是一种 用时间换空间 的设计
如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。
创建生成器的两种方法
- 把一个列表生成式的[]改成(),就创建了一个generator
1
2
3
4
5
6for x in range(10)] L = [x * x
L
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
for x in range(10)) g = (x * x
g
<generator object <genexpr> at 0x1022ef630>
- L 与 g 的区别
- 最外层的 [] 和 ()
- L 是一个 list,而 g 是一个generator
可以通过 next() 函数获得 generator 的下一个返回值:
1 | next(g) |
generator 保存的是算法,每次调用 next(g),就计算出 g 的下一个元素的值,直到最后一个元素,此时再次调用会报错
1 | for x in range(10)) g = (x * x |
如果推算算法比较复杂,用类似列表生成式的 for 循环无法实现: 还可以用
2. 函数实现
Fibonacci 就是无法用列表生成式表示的。
1 | def fib(max): |
相比函数的打印,函数实现generator,只需要将 print(b) -> yield b
这里,最难理解的就是generator函数和普通函数的执行流程不一样。普通函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。
请务必注意:调用generator函数会创建一个generator对象,多次调用generator函数会创建多个相互独立的generator。
generator也是可迭代的
1 | for n in fib(6): |
迭代器
可迭代数据类型: list, tuple, dict, set, str
一类是 generator, 包括 生成器 与 带 yield 的 generator function
这些可以直接作用于for循环的对象统称为可迭代对象:Iterable。可以使用isinstance()判断一个对象是否是Iterable对象:
1 | from collections.abc import Iterable |
迭代器(Iterator):可以被 next()函数不断调用并返回下一个值
可以使用isinstance()判断一个对象是否是Iterator对象:
1 | from collections.abc import Iterator |
你可能会问,为什么list、dict、str等数据类型不是Iterator?
这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。
Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。
模块
强烈建议还是看一下 廖老师的网站
为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,这样,每个文件包含的代码就相对较少,很多编程语言都采用这种组织代码的方式。在Python中,一个.py文件就称之为一个模块(Module)。
使用模块的好处
- 提高代码的可维护性。
- 避免函数名和变量名的冲突,但要注意不要与Python内置模块命名冲突
为避免模块名冲突,Python又引入了按目录来组织模块的方法,称为包(package)
廖老师这里写的太好了,强烈建议去看看这篇。
使用模块
以内建的 sys 模块为例,编写一个 hello 模块(廖老师写的)
1 | #!/usr/bin/env python3 |
第1行和第2行是标准注释,第1行注释可以让这个hello.py文件直接在Unix/Linux/Mac上运行,第2行注释表示.py文件本身使用标准UTF-8编码;
第4行是一个字符串,表示模块的文档注释,任何模块代码的第一个字符串都被视为模块的文档注释;
第6行使用__author__变量把作者写进去,这样当你公开源代码后别人就可以瞻仰你的大名;
name & main trick
1 | if __name__=='__main__': |
这个技巧非常重要
当我们在命令行运行hello模块文件时,Python解释器把一个特殊变量__name__置为__main__,而如果在其他地方导入该hello模块时,if判断将失败,因此,这种if测试可以让一个模块通过命令行运行时执行一些额外的代码,最常见的就是运行测试。
作用域
我们可能会定义许多 变量 和 函数,在一个模块中。有的变量,我们只希望在模块内部被调用,这时我们对变量名前后加上 _ 来表示为 private
一般的变量,我们认为是 public的
如模块中的__name__,__auther__就是特殊变量(private),理论上这些不该被调用,但是Python没有防止其被调用的硬性手段。
一个private函数的小例子:
1 | def _private_1(name): |
我们在模块里公开greeting()函数,而把内部逻辑用private函数隐藏起来了,这样,调用greeting()函数不用关心内部的private函数细节,这也是一种非常有用的代码封装和抽象的方法,即:
外部不需要引用的函数全部定义成private,只有外部需要引用的函数才定义为public。
安装第三方模块
pip
- 在Python中,安装第三方模块,是通过包管理工具pip完成的。
- 如果你正在使用Mac或Linux,安装pip本身这个步骤就可以跳过。Windows用户需要在安装Python的时候就勾选pip的安装。
例如,我们要安装一个第三方库——Pillow,在cmd或者bash或者各种shell这些终端里
1 | pip install Pillow |
conda
在使用Python时,我们经常需要用到很多第三方库,例如,上面提到的Pillow,以及MySQL驱动程序,Web框架Flask,科学计算Numpy等。用pip一个一个安装费时费力,还需要考虑兼容性。我们推荐直接使用Anaconda,这是一个基于Python的数据处理和科学计算平台,它已经内置了许多非常有用的第三方库,我们装上Anaconda,就相当于把数十个第三方模块自动安装好了,非常简单易用。
可以从Anaconda官网下载GUI安装包,安装包有500~600M,所以需要耐心等待下载。下载后直接安装,Anaconda会把系统Path中的python指向自己自带的Python,并且,Anaconda安装的第三方模块会安装在Anaconda自己的路径下,不影响系统已安装的Python目录。
安装好Anaconda后,重新打开命令行窗口,输入python,可以看到Anaconda的信息:
可以尝试直接 import numpy 等已安装的第三方模块。
模块搜索路径
当我们试图加载一个模块时,Python会在指定的路径下搜索对应的.py文件,如果找不到,就会报错
默认情况下,Python解释器会搜索当前目录、所有已安装的内置模块和第三方模块,搜索路径存放在sys模块的path变量中:
1 | import sys |
添加路径
直接修改sys.path,添加要搜索的目录:
1
2import sys
'/Users/michael/my_py_scripts') sys.path.append(这种方法是在运行时修改,运行结束后失效。
第二种方法是设置环境变量PYTHONPATH,该环境变量的内容会被自动添加到模块搜索路径中。设置方式与设置Path环境变量类似。注意只需要添加你自己的搜索路径,Python自己本身的搜索路径不受影响。
面向对象
这个章节非常重要,因为,用 PyTorch 框架设置模型的时候,我们需要运用一些面向对象的知识。
面向对象编程 – Object Oriented Programming 是一种 程序设计思想。
把 对象 作为程序的基本单元,对象 包含了 数据 和 操作数据 的函数。
- 面向过程: 计算机程序视为一系列的命令合集,即一组函数的顺序执行。函数->切分的子函数,通过将大块函数切割成小块函数,来降低系统的复杂度
- 面向对象: 把计算机程序视为一组对象的集合。
自定义对象: 类(Class)
- 采用面向对象的程序设计,首先考虑的是将 数据类型 视为一个对象。
- 对象拥有若干个 属性
- 还要内置 方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14class Student(object):
def __init__(self, name, score):
self.name = name
self.score = score
def print_score(self):
print('%s: %s' % (self.name, self.score))
# 与 对象交互 实际上就是调用对象对应的关联函数,我们称之为对象的方法(Method)。面向对象的程序写出来就像这样:
bart = Student('Bart Simpson', 59)
lisa = Student('Lisa Simpson', 87)
bart.print_score()
lisa.print_score()
- 类(Class)是一个抽象的概念
- 实例(Instance)是一个具体的概念
- 方法(Method)是与类相关联的函数
类与实例
实例(Instance)是根据类创建出来的一个个具体的“对象”
1 | class Student(object): |
class后面紧接着是类名,即Student,类名通常是大写开头的单词,紧接着是(object),表示该类是从哪个类继承下来的,继承的概念我们后面再讲,通常,如果没有合适的继承类,就使用object类,这是所有类最终都会继承的类。
创建实例
1 | bart = Student() |
实例的初始化
通过定义一个特殊的__init__方法,在创建实例的时候,就把 name, score 等属性绑上去:
1 | class Student(object): |
这个函数定义后,在创建实例的时候就得,Student后的括号中传入 name 与 score的参数了
- 方法的第一个参数永远是 self,表示实例本身。在方法内部,可以通过 self 指向创建的实例本身。
- 有了初始化方法后,就不能换入空的参数了。
限制访问
函数内部有些属性,不想被访问。就在命名的时候,命名前加上双下划线 __
优点: 隐藏了内部的复杂逻辑
继承与多态
当定义一个 Class 的时候,可以从某个现有的 Class 继承,新的 Class 称为 子类(Subclass),而被继承的 Class 称为基类、父类或超类(Base class, Super class)
继承
继承: 子类可以使用父类定义的方法,获得父类所有的属性。
1 | # 定义 Animal 作为父类 |
- 如果在子类中,定义了与父类同名的方法,会覆盖父类方法。
判断类的类型的方法:
1 | a = list() # a是list类型 |
继承关系中,实例即被视为子类,又被视为父类,但是,作为最小的类,范围最短。
多态
方法的传参中,传入类的类型
1 | # 输入参数为数据的类 |
任何依赖Animal作为参数的函数或者方法都可以不加修改地正常运行,原因就在于多态。
多态的好处: 需要传入Dog、Cat、Tortoise,只需要接收Animal类型,按照Animal类型进行操作即可。由于Animal类型有run()方法,因此,传入的任意类型,只要是Animal类或者子类,就会自动调用实际类型的run()方法,这就是多态的意思:
对于一个变量,我们只需要知道它的类型,无需确切地知道它的子类型,就可以放心地调用父类方法,而具体调用的方法是作用在本身还是子类对象上,由运行时该对象的确切类型决定。
多态真正的威力:调用方只管调用,不管细节,而当新增一种子类时,只要确保方法编写正确,不用管原来的代码是如何调用的。
- 著名的“开闭”原则:
- 对扩展开放:允许新增子类
- 对修改封闭:不需要修改依赖类型的方法函数。
- 继承还可以一级一级地继承下来,就好比从爷爷到爸爸、再到儿子这样的关系。而任何类,最终都可以追溯到根类object,这些继承关系看上去就像一颗倒着的树。
获取对象信息
type()
可以判断 基本数据类型 和 类的类别,还可以判断 函数的类型
1 | type(123) |
*不要求掌握的方法:
1 | import types |
instance()
对于class的继承关系来说,使用type()就很不方便。我们要判断class的类型,可以使用isinstance()函数。
object -> Animal -> Dog -> Husky
1 | a = Animal() |
总是优先使用isinstance()判断类型,可以将指定类型及其子类“一网打尽”。
dir: 获取类所有属性与方法
如果要获得一个对象的所有属性和方法,可以使用dir()函数,它返回一个包含字符串的list,比如,获得一个str对象的所有属性和方法:
1 | dir('ABC') |
仅仅是列出 属性 与 方法 是不够的,配合 getattr(), setattr() 以及 hasattr(),我们可以直接操作一个对象的状态:
1 | hasattr(obj, 'x') # 有属性'x'吗? |
如果试图获取不存在的属性,会抛出AttributeError的错误
1 | # getattr()的勘误机制 |
实例属性、类属性
给实例绑定属性的方法是通过实例变量,或者通过 self 变量:
1 | class Student(object): |
- 定义在类中的属性,类属性。定义后,所有实例都可以访问到。
- 实例属性,属于实例的属性。
- 实例与类属性重名,会覆盖类属性。
第三方模块
- 基本所有第三方模块都会在 https://pypi.org/ 注册,找到模块名 pip 安装。什么?你问我 pip 怎么用? 自己不会上网学啊?
- conda install
虚拟环境
虚拟环境就是,重新开个新号,可以在一个完全干净的python环境里,配置自己需要的开发环境
- virtualenv 配置
- conda 配置
这个一定要去学!!! 看网上的一些 虚拟环境 配置的教程,或者别的,一般conda配置环境比较方便
- Post title: Python_tutorial
- Create time: 2022-03-29 00:52:07
- Post link: Tutorial/python-tutorial/
- Copyright notice: All articles in this blog are licensed under BY-NC-SA unless stating additionally.