Python3 入门笔记
知识点覆盖不完整,个人自学使用。大部分内容摘录自菜鸟教程和《Python编程: 从入门到实践》
基础知识
编码
- Python源码文件默认是UTF-8编码
标识符
字母数字下划线,字母和下划线开头,大小写敏感
变量
-
python中变量不需要声明,赋值即可使用
-
变量就是变量,它没有类型,我们所说的"类型"是变量所指的内存中对象的类型。
在 python 中,类型属于对象,变量是没有类型的:
a=[1,2,3] a="Runoob"
以上代码中,[1,2,3] 是 List 类型,“Runoob” 是 String 类型,而变量 a 是没有类型,她仅仅是一个对象的引用(一个指针),可以是指向 List 类型对象,也可以是指向 String 类型对象。
-
在 python 中,strings, tuples, 和 numbers 是不可更改的对象,而 list,dict 等则是可以修改的对象。
- **不可变类型:**变量赋值 a=5 后再赋值 a=10,这里实际是新生成一个 int 值对象 10,再让 a 指向它,而 5 被丢弃,不是改变a的值,相当于新生成了a。
- **可变类型:**变量赋值 la=[1,2,3,4] 后再赋值 la[2]=5 则是将 list la 的第三个元素值更改,本身la没有动,只是其内部的一部分值被修改了。
标准数据类型
Python3 中有六个标准的数据类型:
- Number(数字)
- int,bool,float,complex(复数)
- String(字符串)
- List(列表)
- Tuple(元组)
- Set(集合)
- Dictionary(字典)
Python3 的六个标准数据类型中:
- **不可变数据(3 个):**Number(数字)、String(字符串)、Tuple(元组);
- **可变数据(3 个):**List(列表)、Dictionary(字典)、Set(集合)。
常用抽象数据结构
字符串(String)
- python中单引号和双引号使用完全相同。
- 使用三引号(’’'或""")可以指定一个多行字符串。
- 转义符 ‘’
- 反斜杠可以用来转义,使用r可以让反斜杠不发生转义。。 如 r"this is a line with \n" 则\n会显示,并不是换行。
- 按字面意义级联字符串,如"this " "is " "string"会被自动转换为this is string。
- 字符串可以用 + 运算符连接在一起,用 * 运算符重复。
- Python 中的字符串有两种索引方式,从左往右以 0 开始,从右往左以 -1 开始。
- Python中的字符串不能改变。
- Python 没有单独的字符类型,一个字符就是长度为 1 的字符串。
- 字符串的截取的语法格式如下:变量[头下标:尾下标:步长] 左闭右开
print(str) # 输出字符串
print(str[0:-1]) # 输出第一个到倒数第二个的所有字符
print(str[0]) # 输出字符串第一个字符
print(str[2:5]) # 输出从第三个开始到第五个的字符
print(str[2:]) # 输出从第三个开始的后的所有字符
print(str * 2) # 输出字符串两次
print(str + '你好') # 连接字符串
列表(List)
-
列表可以完成大多数集合类的数据结构实现。列表中元素的类型可以不相同,它支持数字,字符串甚至可以包含列表(所谓嵌套)。
-
列表是写在方括号 [] 之间、用逗号分隔开的元素列表。
-
和字符串一样,列表同样可以被索引和截取,列表被截取后返回一个包含所需元素的新列表。
-
截取与字符串一致,但多一个参数:步长。
List[1:4:2]
: 表示从List[1]开始到List[4] ,步长为二,返回1,3增:
List.append(X)
和List.insert(index,X)
删:
del 语句 或 pop() pop(index) 或remove(X)
复制:
list1 = list2[:]
而不是 list1 = list2 这只是让两个变量指向同一个列表,事实上只存在一个列表
-
底层是动态顺序表,即可变长度的数组。
嵌套列表
>>> matrix = [
... [1, 2, 3, 4],
... [5, 6, 7, 8],
... [9, 10, 11, 12],
... ]
#矩阵转置(transpose):
>>> [[row[i] for row in matrix] for i in range(4)]
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
#see 推导式
元组(Tutor)
- 与列表相似,不同点在于元组中的元素不可变。
- 元组使用小括号,列表使用方括号。
- 同样可以对整个元组进行操作,如del删除整个元组和连接、组合、截取、排序
- 可以将列表转换成元组
tuple(seq)
字典(Dictionary)
-
字典是另一种可变容器模型,且值可存储任意类型对象。
-
字典的每个键值(key=>value)对用冒号(:)分割,每个对之间用逗号(,)分割,整个字典包括在花括号(**{})**中
dict = {'Name': 'Runoob', 'Age': 7, 'Class': 'First'} #增 dict[new_key] = 'MIT' #改 dict['Name'] = 'Mike' #删 del dict[key] #删除键key及其值 dict.clear() #清空字典 del dict #删除字典 ''' 使用for循环遍历字典 ''' for key,value in dict.items(): print("Key: "+key) print("Value: "+value) dict.keys() #返回所有键的列表 dict.values() #返回所有值的列表 set(dict.values)#一般用集合来去重
-
键不能重复,值可以重复。创建时如果同一个键被赋值两次,后一个值会被记住
-
键必须不可变,所以可以用数字,字符串或元组充当,而用列表就不行
-
遍历字典时,默认遍历所有键,也可以指定
dict.keys()
方法,该方法返回字典的所有键的一个列表 -
底层是散列哈希表
集合(Set)
集合(set)是一个无序的不重复元素序列。基本功能包括关系测试和消除重复元素
基本操作:
-
创建:
parame = {value01,value02,...} 或者 set(value) #value可以是列表,元组,字典等
-
增加:如果元素已存在,则不进行任何操作
set.add(X)
#单个添加set.update(X) #X可以是列表,元组,字典等,逗号隔开多个参数
- s.update( {“字符串”} ) 将字符串添加到集合中,有重复的会忽略。
- s.update( “字符串” ) 将字符串拆分单个字符后,然后再一个个添加到集合中,有重复的会忽略。
-
删除:
remove(X)
如果X不存在,会发生错误discard(X)
如果X不存在,不会发生错误pop()
对于是字典和字符转换的集合是随机删除元素。当集合是由列表和元组组成时、set.pop() 是从左边删除元素的s.clear()
清空 -
关系测试: 交并补差运算,语法略
-
消除重复元素:
set(value)
None类型
是Python里的特殊类型,大体含义相当于其他语言的NULL。
是Null对象或者是None Type,它只有一个值None。
-
空字符串不是None类型,None类型是NoneType
-
它不支持任何运算也没有任何内建方法.
-
None和任何其他的数据类型比较永远返回False。
-
None有自己的数据类型NoneType。
-
你可以将None复制给任何变量,但是你不能创建其他NoneType对象。
type(None) <class 'NoneType'> None == 0 False None == ' ' False None == None True None == False False
推导式
列表推导式提供了从序列创建列表的简单途径。通常应用程序将一些操作应用于某个序列的每个元素,用其获得的结果作为生成新列表的元素,或者根据确定的判定条件创建子序列。
列表、元组、集合、字典都可以用推导式获得
''' 推导式基本用法 '''
list1 = range(1, 10)
list2 = [x**2 for x in list1]
print(list(list1))
print(list2)
'''
[1, 2, 3, 4, 5, 6, 7, 8, 9]
[1, 4, 9, 16, 25, 36, 49, 64, 81]
'''
list1 = range(1, 10)
list2 = [x/2 for x in list1 if x%2 == 0]
print(list2)
'''
[1.0, 2.0, 3.0, 4.0]
'''
vec1 = [2, 4, 6]
vec2 = [4, 3, -9]
conbination = [(x, y) for x in vec1 for y in vec2]
print(conbination)
'''
[(2, 4), (2, 3), (2, -9), (4, 4), (4, 3), (4, -9), (6, 4), (6, 3), (6, -9)]
'''
'''字典推导 '''
>>> {x: x**2 for x in (2,4,6)}
{2: 4, 4: 16, 6: 36}
Pass语句
Python pass是空语句,是为了保持程序结构的完整性。
pass 不做任何事情,一般用做占位语句
if a>1:
pass #如果没有内容,可以先写pass,但是如果不写pass,就会语法错误
条件测试表达式
-
检查多个条件: 使用
and
表示与,使用or
表示或age >= 21 and age <= 40
age >= 60 or age <= 18
-
检查特定值是否包含在列表中: 使用
x in list
'Audi' in cars
是否不在:
x not in list
'bmw' not in cars
迭代器与生成器
迭代器
- 迭代是Python最强大的功能之一,是访问集合元素的一种方式。
- 迭代器是一个可以记住遍历的位置的对象。
- 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。
it = iter()
函数 返回目标对象的迭代器
val = next(it)
函数,返回下一个值
''' 迭代 '''
while True:
try:
print(next(it),end=" ")
except StopIteration:
sys.exit()
生成器
在 Python 中,使用了 yield 的函数被称为生成器(generator)。
跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。
在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。
调用一个生成器函数,返回的是一个迭代器对象。
''' 生成器函数 实现费波纳茨数列 '''
def fibonacci(n):
a, b, counter = 0, 1, 0
while True:
if counter > n:
return
yield a
c = a + b
a = b
b = c
counter += 1
''' 调用返回的是一个迭代器 '''
f = fibonacci(20)
函数
函数定义
def functionname([formal_args,] *var_args_tuple ):
"函数_文档字符串"
function_suite
return [expression]def 函数名(参数列表):
"文档字符串"
函数体
参数传递
- 传递不可变类型: 如int,字符串,tupors等。 值传递
- 传递可变类型: 如list,set,dictionary等。 引用传递(传地址)
若想函数不修改传入的可变类型的参数,可传入参数的切片拷贝:
fun(list[ : ])
参数类型
必要参数: 必须按照顺序传入,数量不可少
'''必要参数: 必须按照顺序传入,数量不可少'''
def fun1(name,age):
print(name+str(age))
fun1('allen',12)
fun1('allen') #出错
''' 默认参数
注意:如果只打算给其中一部分参数设定默认值,那么应当将其放在靠后的位置(和定义函数时一样,避免歧义),否则会报错。
'''
def fun2(name, age = 35)
pass
fun2('allen') #合法
def fun2(age=35,name) #报错
'''
关键字参数
'''
fun1(name = 'allen', age=12)
fun2(age= 15, name='mike') #合法
'''
不定长参数
加了1个星号 * 的参数会以元组(tuple)的形式导入,存放所有未命名的变量参数,python会自动创建一个空元祖。
'''
def printinfo( arg1, *vartuple ):
print (arg1)
print (vartuple)
printinfo(1,2,3) #1是必要参数,2和3当作元组传入
'''输出:
1
(2,3)
'''
'''加了2个**星号的参数会以字典的形式传入 '''
def printinfo( arg1, **vardict ):
print (arg1)
print (vardict)
printinfo(1, a=2,b=3)
输出:
1
{'a': 2, 'b': 3}
'''如果单独出现星号 * 后的参数必须用关键字传入'''
def fun(a,b,*,c,d)
pass
fun(1,2,c=3,d=4)
返回值: 不带参数值的return语句返回None
匿名函数 (lambda表达式)
- lambda的主体是一个表达式,返回值即为表达式的值。而不是一个代码块。仅仅能在lambda表达式中封装有限的逻辑进去。
- lambda 函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数。
#语法:`lambda [arg1 [,arg2,.....argn]]:expression`
sum = lambda arg1, arg2: arg1 + arg2
#调用sum匿名函数
print ("相加后的值为 : ", sum( 10, 20 ))
闭包函数
**什么是闭包? **
inner函数就是一个闭包函数
闭包将会捕捉内层函数执行所需的整个环境
a = 0 # 全局作用域
def outer(n):
b = n # 闭包函数外的函数中
def inner(d):
c = 2 # 局部作用域
return b + c + d
return inner
sum = outer(3) #type(sum) <class 'function'>
print sum(1) #3 + 2 + 1 = 6
print sum(2) #3 + 2 + 2 = 7
闭包详解:https://www.cnblogs.com/JohnABC/p/4076855.html
Python 里为什么函数可以返回一个函数内部定义的函数? - 陈伟的回答 - 知乎
https://www.zhihu.com/question/25950466/answer/31731502
变量作用域
Python的变量作用域有4种:
- L (Local) 局部作用域
- E (Enclosing) 闭包函数外的函数中
- G (Global) 全局作用域
- B (Built-in) 内置作用域(内置函数所在模块的范围)
以 L –> E –> G –>B 的规则查找,即:在局部找不到,便会去局部外的局部找(例如闭包),再找不到就会去全局找,再者去内置中找。
Python 中只有模块(module),类(class)以及函数(def、lambda)才会引入新的作用域,其它的代码块(如 if/elif/else/、try/except、for/while等)是不会引入新的作用域的,也就是说这些语句内定义的变量,外部也可以访问
if True :
msg = "123"
for i in range(0,1) :
num = 1
print(msg+" " + str(num)) #合法
global 和 nonlocal关键字
global: 表明变量为全局变量
nonglobal: 表明变量为局部变量
模块
模块是一个包含所有你定义的函数和变量的文件,其后缀名是.py。模块可以被别的程序引入,以使用该模块中的函数等功能。这也是使用 python 标准库的方法。
import语句
当解释器遇到 import 语句,如果模块在当前的搜索路径就会被导入。
import matrix
'''这样做并没有把直接定义在matrix中的函数名称写入到当前符号表里,只是把模块matrix的名字写到了那里。
可以使用模块名称来访问函数:'''
m = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
]
print(matrix.transpose(m)) #使用 module.function来调用模块的函数
from … import 语句
从模块中导入指定部分的函数和变量,这种导入的方法不会把被导入的模块的名称放在当前的字符表中
from modname import name1[, name2[, ... nameN]]
from modname import *
导入全部函数和变量
这将把所有的名字都导入进来,但是那些由单一下划线(_)开头的名字不在此例。
__name__属性
每个模块都有一个__name__属性,当其值是’__main__'时,表明该模块自身在运行,否则是被引入。
说明:__name__ 与 __main__ 底下是双下划线
if __name__ == '__main__':
print('模块内部调用')
else:
print('模块外部调用')
包
- 包是一种管理 Python 模块命名空间的形式,采用"点模块名称"。
比如一个模块的名称是 A.B, 那么他表示一个包 A中的子模块 B 。这避免了模块名称冲突的危险。 - 目录只有包含一个叫做 __init__.py 的文件才会被认作是一个包,主要是为了避免一些滥俗的名字(比如叫做 string)不小心的影响搜索路径中的有效模块。
- 最简单的情况,放一个空的 :file:__init__.py就可以了。当然这个文件中也可以包含一些初始化代码或者为(将在后面介绍的)__all__变量赋值。
异常
运行期检测到的错误被称为异常。
try … except 语句: 类似于Java中的try catch语句
类似于Java,如果一个异常没有与任何的except匹配,那么这个异常将被传递到上一层的try语句中。
一个except子句可以同时处理多个异常,这些异常将被放在一个括号里成为一个元组,例如:except (RuntimeError, TypeError, NameError): pass
raise语句
可以使用raise
语句把异常重新抛出,或raise Exception('...')
抛出的异常
try … except… else 语句
如果使用这个子句,那么必须放在所有的except子句之后。这个子句将在try子句没有发生任何异常的时候执行
try … except… finally语句
与Java中的finally语句类似。
import sys
try:
f = open('myfile.txt')
s = f.readline()
i = int(s.strip())
except OSError as err:
print("OS error: {0}".format(err))
except ValueError:
print("Could not convert data to an integer.")
except:
print("Unexpected error:", sys.exc_info()[0]) #查看异常类型
raise
else:
print("no exception catched in try clause")
finally:
f.close()
print("finally clause")
''' 执行顺序 :
异常: try、except、finally、抛出(如果没有异常被捕捉)
无异常:try、else、finally
'''
with … as …语句
类似Java中的 try() catch ,关键词 with 语句就可以保证诸如文件之类的对象在使用完之后一定会正确的执行他的清理方法:
典型用法: with open(filename,mode) as f
将自动执行file对象的close方法。
Python面向对象
和其它编程语言相比,Python 在尽可能不增加新的语法和语义的情况下加入了类机制。
Python中的类提供了面向对象编程的所有基本功能:类的继承机制允许多个基类,派生类可以覆盖基类中的任何方法,方法中可以调用基类中的同名方法。
对象可以包含任意数量和类型的数据。
类定义与类对象
与Java类似,如下:
class ClassName(BaseClassName1, BaseClassName2):
''' 类文档说明 '''
# 公有类变量,相当与Java里的public static成员,属于类
pub_var = 1
# 私有类变量,私有属性在类外部无法直接进行访问
__pri_var = ""
def __init__(self, name):
''' 双下划线,表示类的构造方法,相当于Java里的构造器 '''
self.name = name # 实例变量,属于对象
self.__pri_var = "private"
def describe(self):
''' 普通方法 '''
pass
- 类有一个名为 __init__() 的特殊方法(构造方法),该方法在类实例化时会自动调用
- 类的普通方法都必须传入一个self(约定)实参, 表示当前实例的引用,由Python自动传入,这样Python才知道该调用哪个对象的方法。而 self.class表示类
类属性和方法
Python3 方法总结
-
普通方法:需要传入self,允许对象访问
-
私有方法:两个下划线开头,只能在类内部访问
self._privatemethod
-
静态方法:使用
@staticmethod
装饰,不带 self 参数的方法,类的静态方法可以没有参数,可以直接使用类名调用。 -
类方法:使用
@classmethod
装饰,默认有个 cls 参数,可以被类和对象调用。 -
专有方法:
-
多继承情况下:从左到右查找方法,找到为止,不然就抛出异常
class TestClass: def __init__(self): print("__init__Method Called") def method(self): print("instance's method called") def __pri_method(self): print("private method called") @classmethod def cls_method(cls): print("ClassMethod Called") @staticmethod def static_method(): print("StaticMethod Called") TestClass.cls_method() TestClass.static_method() t = TestClass() t.static_method() t.cls_method() t.method() ''' ClassMethod Called StaticMethod Called __init__Method Called StaticMethod Called ClassMethod Called instance's method called '''
类的专有方法:
部分如下:
- __init__ : 构造函数,在生成对象时调用
- __del__ : 析构函数,释放对象时使用
- __len__: 获得长度
- __cmp__: 比较运算
- __add__: 加运算
运算符重载:
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
return Vector(self.x + other.x, self.y + other.y)
def __mul__(self, other):
return int(self.x * self.y + other.x * other.y)
def __str__(self):
return "<" + str(self.x) + " , "+ str(self.y) + ">"
v1 = Vector(1, 2)
v2 = Vector(2, 3)
print(str(v1) + " + " + str(v2) + " == ", end="")
print(str(v1 + v2))
print(str(v1) + " * " + str(v2) + " == ", end="")
print(str(v1 * v2))
'''
<1 , 2> + <2 , 3> == <3 , 5>
<1 , 2> * <2 , 3> == 8
'''
继承
class Car():
def __init__(self, brand, model, year):
self.brand = brand
self.model = model
self.year = year
def start(self):
print(self.brand + " start!")
electric_car.py
from car import Car
class ElectricCar(Car):
def __init__(self, brand, model, year, battery_size):
super().__init__(brand, model, year)
self.battery_size = battery_size
def start(self):
'''重写'''
print(self.brand + " with " + str(self.battery_size) + "kWh battery start!")
audi = Car("Audi","a8", "2016")
audi.start()
tesla = ElectricCar("Tesla", "Model_S", "2018" , 100)
tesla.start()
'''
Audi start!
Tesla with 100kWh battery start!
'''
常用库
numpy
官方中文文档:https://www.numpy.org.cn/
菜鸟教程: https://www.runoob.com/numpy/numpy-tutorial.html