Python 学习笔记(01) 基础知识
1.1 计算机语言
计算机无法理解高级语言,更无法直接执行高级语言。所以使用任何高级语言编写的程序如果想被计算机执行需要被转换为机器语言,其中转换包括两种方式:编译及解释,由此高级语言也被划分为编译型语言以及解释型语言。
1.1.1 编译
编译(Compile)的过程是把整个源程序代码翻译成另外一种代码,翻译后的代码等待被执行或者被优化等等,发生在运行之前,产物是另一份代码。
整个编译过程可以分为两部分:编译及链接。
源代码(.c .cpp)文件先通过预处理器进行初步修改形成预编译文件(.i),预编译文件再经过编译器形成汇编代码(.s),汇编代码通过汇编器形成目标代码(.o),上述过程可以概括为编译。链接则是将源代码生成的目标代码文件、库文件与其他目标代码文件通过链接器形成可执行程序(.exe)。
1.1.2 解释
解释(Interpret)的过程是把源程序代码一行一行的读懂,然后一行一行的执行,发生在运行时,产物是运行结果。
整个解释过程可以分为两部分:翻译及运行。
源代码在翻译模块中逐条取出语句进行语义分析和语法分析,若错误则输出错误信息,反之则直接生成机器语言代码。生成的机器语言代码直接在运行模块输出结果,继续取下一条语句完成整个流程。
1.1.3 编译型语言
使用专门的编译器并针对特定的平台,将高级语言源程序一次性编译成可被该平台硬件执行的机器码,并包装成该平台所能识别的可执行性程序的格式。典型的编译型语言包括C、C++。
特点
在编译型语言写的程序运行之前需要专门的编译过程,将源代码翻译成机器语言的文件如.exe格式等,再次运行只需要直接运行.exe文件即可。由于只需要进行一次编译,运行时脱离开发环境,编译型语言的执行效率较高。但编译型语言生成文件一般与特定平台绑定(windows、linux、ios)无法移植到其他平台。
1.1.4 解释型语言
使用专门的解释器对源程序逐行解释成特定平台的机器码且立即执行,代码在执行时才被解释器逐行进行动态翻译与执行而不是在执行之前就完成翻译。典型的解释性语言包括Python、Ruby、PHP。
特点
解释型语言不需要实现进行编译,其直接将源代码解释成机器码并立即执行(不需要生成.exe文件),因此只要某一平台提供了相应解释器即可运行程序,具有较高的平台兼容性。同时由于每次运行都需要将源代码解释为机器码再运行,解释型语言的效率较低且程序执行速度较慢。
什么叫做脚本语言?
简单来说脚本语言是读一行执行一行无需关注下一行的语言,程序代码即是最终的执行文件,只是这个过程需要解释器的参与,所以说脚本语言与解释型语言有很大的联系。脚本语言通常是被解释执行的,而且程序是文本文件。
1.2 python语言基础
1.2.1 python语言特点
1)python属于解释型脚本语言,内置高级数据结构(列表、元组、集合、字典);
2)作为面向对象的编程语言,python可以实现数据与逻辑之间相互分离,便于拓展维护;
3)作为一种动态语言,python本身设置变量数据类型不固定且可以随意转换;
4)python使用默认编码为UTF-8。
1.2.2 python语言基本规则
1.2.2.1 注释
注释(Comments)用来向用户提示或解释某些代码的作用及功能,python解释器在执行代码时会忽略注释不做任何处理。
在调试(Debug)程序过程中,注释还可以用来临时移除无用的代码。
一般情况下合理的代码注释应该占源代码的1/3左右,其最大作用在于提高程序的可读性,便于后期维护。
# python使用'#'作为单行注释的符号,从'#'开始直到这行结束的所有内容都将被解释器视为注释
# 说明多行代码时一般将注释放在代码的上一行,这里用于说明输出不同字符串
print('字符串1')
print('字符串2') # 说明单行代码的功能时一般将注释放在代码的右侧,这里用于说明输出字符串
"""
多行注释指的是一次性注释程序中多行的内容
python使用三个连续的单引号或双引号注释多行内容
这里面的内容全是注释内容
要注意python的多行注释不支持嵌套
"""
在调试过程中,可以使用注释使python解释器忽略有问题的代码,如果程序可以正常执行则可以判定注释的代码存在错误。这样可以缩小错误所在的范围,提高调试程序的效率。
1.2.2.2 换行
在输出结果时为保证检查清晰且观看美观,一般会使用换行符。
print("Result: 1 2 3 4\nSum: 10\n")
Out:
Result: 1 2 3 4
Sum: 10
除此之外,编写代码时经常遇到一行的内容过多导致阅读困难的情况,此时应使用’\'作为连接符,表示继续上一行的内容。
sketch = mdb.models['Model-1'].\
ConstrainedSketch(name='__profile__', sheetSize=200.0)
需要注意的是,当换行处在()、[]、{}中时,不需要使用连接符,直接换行即可。
sketchTransform = modelPart.MakeSketchTransform(sketchPlane=faces[3], sketchUpEdge=edges[0],
sketchPlaneSide=SIDE1, sketchOrientation=RIGHT,
origin=(0.0, cylinderHeight, 0.0))
1.2.2.3 缩进
在python中,不同于C、C++的编写方式,缩进不仅仅是为了美观,更是用于区分代码块的重要工具。缩进包括使用空格以及Tab两种方式,在常规编辑器中Tab缩进一般为四个空格的长度。
for(int i = 0; i > 10; i++)
{
printf("%d", i);
}
for i in range(0, 10):
print(i)
以上两种分别为C语言以及python语言的输出数字0~9,其中c语言使用{}来确定一个代码块,而python使用缩进来确定一个代码块。
for i in range(0, 10):
print(i)
print(i + 1)
Out:
0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
for i in range(0, 10):
print(i)
print(i + 1)
Out:
0,1,2,3,4,5,6,7,8,9,10
1.2.2.4 空行
空行的作用主要是为了区分不同函数、类,用于标记一个代码块结束。
def fuction_1():
pass
def fuction_2():
pass
1.2.3 变量赋值
x = 1 # 普通赋值
x += 1 # 增量赋值
x = x + 1 # 同上,两种写法
x = y = z = 1 # 多元赋值,同一个引用被赋值给x, y, z
x, y, z = 1, 2, 'a' # 多元赋值,按照顺序依次赋值给对应变量
x,y = y,x # 交换赋值,x的值与y的值进行交换
1.3 python对象模型概述
在python中不再区分基本类型以及对象,所有基本类型内部均由对象实现,并且python使用对象模型来存储数据,一个整数是一个对象,一个字符串也是一个对象。
a = 1024
b = 'abc'
其中python中的两种基本对象为类型对象以及实例对象,由类型对象实例化可以得到一个实例对象。
类型对象主要包括常见的变量类型,如整数类型、字符串类型、浮点数类型、通过class关键字定义的类等等。
面向对象理论中的‘类’和‘对象’这两个基本概念在python的内部都是通过对象来实现的。
1.3.1 python对象特性
1)身份
每个对象在创建后即完成了赋值,同时拥有专属的id用于判断是否为【同一对象的引用】。
id() 函数返回指定对象的唯一 id,在创建时已分配给对象。id 是对象的内存地址,并且在每次运行程序时都不同。(除了某些具有恒定
唯一 id 的对象,比如 -5 到 256 之间的整数)
x = 1
print(id(x))
Out:
140721250311936
2)类型
type()函数返回指定对象的类型。
x = 1
print(type(x))
Out:
<class 'int'>
3)值
实例对象的具体赋值
1.3.2 类型、对象体系
a是一个整数对象(实例对象),其类型是整数类型(类型对象)。
a = 1
type(a)
isinstance(a, int) # 判定实例函数
Out:
<class 'int'>
True
其中整数类型(类型对象)也有其类型对象。
type(int)
Out:
<class 'type'>
由此可以看到整数类型的类型还是一种类型,即为类型对象的类型对象。type这种类型对象比较特殊,它的实例对象还是类型对象。
除此之外,python还定义了一种特殊类型object,所有其他类型都继承于object,也就是说object是所有类型的基类。
issubclass(int, object) # 判定子类函数
Out:
True
同时类型对象中包括通过class关键字创建的类也就是自定义类型,以一个简单的动物类为例,并创建一个动物实例:
class Dog(object):
def yelp(self):
print('yelp')
dog = Dog()
type(dog)
type(Dog)
issubclass(Dog, object)
Out:
<class '__main__.Dog'>
<class 'type'>
True
所创建的dog实例属于Dog类型,而Dog类型的类型对象为type,其基类为object。
在原先Dog类的基础上创建一个子类Sleuth:
class Sleuth(Dog):
def bark(self):
print('bark')
sleuth = Sleuth()
type(sleuth)
type(Sleuth)
issubclass(Sleuth, Dog)
issubclass(Sleuth, object)
Out:
<class '__main__.Sleuth'>
<class 'type'>
True
True
至此可以得到一个包括整数对象、整数类型、自定义类对象、自定义类类型、自定义子类对象、自定义子类类型以及type、object的关系图表:
理论上来说object作为所有类型的基类其本质上也算作一种类型,而type作为所有类型的类型其本质上也属于一种类型。另外由于object是所有类型的基类,理论上也是type的基类。
但对于存在继承关系的类,成员属性和成员方法查找需要回溯继承链不断查找基类,而继承链必须有一个终点否则将造成死循环,因此object自身并没有基类。
总结来说,所有类型的类型都是type包括type本身,而所有类型的基类都收敛于object,但不包括object本身。
1.3.3 可变数据对象与不可变数据对象
在讨论可变数据对象与不可变数据对象之前,首先需要明确python中的变量的定义。
a = 1
b = a
id(a)
id(b)
Out:
140721250311936
140721250311936
由上面已经介绍过的id()函数可知返回的是该对象的内存地址,而当我们将a的值赋值给b后发现两个变量的内存地址是相同的。
相较于python,C语言中不同变量的内存地址是不同且相对独立的,在赋值的时候实际上是提取了a的内存地址中的值再将其拷贝到b的内存地址。
int a = 1;
int b = 0;
b = a;
由此可知,在python中,变量只是一个与对象相关联的名字,而变量赋值只是将当前对象与另一个名字相关联,两个变量所连接的对象是同一个。
用现实生活中的书架和书的例子来解释,C语言中不同的变量相当于书架的不同两层,而赋值则是相当于复制一本一层的书放到二层上;而python中的变量赋值则是相当于称呼书架的一层为二层,此时书架一层同时拥有两个名字。
因此在python内部,变量只是一个名字保存指向实际对象的指针进而与对象之间进行绑定,变量赋值只拷贝指针,并不拷贝指针背后的对象。
**指针: **某个变量的内存地址。
1.3.3.1 不可变数据对象
a = 1
id(a)
a += 1
id(a)
Out:
140721250311936
140721250311968
从以上这段代码可以看出,整数变量a在定义之后进行了一次自增操作,但自增前后变量a的内存地址发生了变化。这是由于在python中整数类型是不可变类型,对应的整数对象也是不可变数据对象。不可变数据对象是指在对象创建后的整个生命周期中,其值都不可修改。
因此实际上在对这种不可变数据对象进行修改时,完成的操作是python为新数值创建了一个新对象,变量名重新与新对象进行了绑定,也就是修改了指向内存地址的指针;而原先的对象如果不涉及其他引用(没有别的变量名)则会被释放掉。
1.3.3.2 可变数据对象
相对于不可变数据对象,可变数据对象的定义是在对象创建后其值可以进行修改,典型的例子就是列表(list)类型实例对象。
list_1 = [1, 2]
id(list_1)
list_1.append(3)
id(list_1)
Out:
4385900424
4385900424
以上这段代码是向已经创建好的列表中添加一个新元素,其值为3。可以发现添加操作前后,列表的内存地址并未发生更改。实际上,列表对象内部维护了一个动态数组,存储元素对象的指针(内存地址),而原先定义的列表实例对象的变量名仅仅指向该列表的表头,该表头实际并未指向任何列表内元素。
1.3.4 动态类型
python中所使用的对象模型可以被定义为动态类型,其核心思想是将引用与对象之间进行分离。引用可以随时指向一个新的对象,对象名即为指向这一对象的引用。
如果存在多个引用指向一个对象的情况,如果其中一个引用的值发生了变化,实际上这个引用将指向一个新的对象,而不影响其他引用的指向。
动态对象类型包括可变数据对象以及不可变数据对象,可变数据对象通过引用其中元素改变对象自身,本质上是包含了【多个引用】的对象,每个引用指向一个对象;不可变数据对象不能改变对象本身,只能改变引用的指向。
1.4 python标识符
我们将python对各种变量、方法、函数等在计算机语言中允许在命名时使用的字符序列成为标识符。也可以说,凡是自己可以起名字的地方都可以叫做标识符,其主要作用就是作为变量、函数、类、模块以及其他对象的名称。
1.4.1 python标识符的命名规则
1)python标识符由26个英文字母的大小写、0~9、下划线(_) 组成;
2)python标识符不能以数字开头,即第一个字符只能为字母/下划线(_);
3)python标识符严格区分大小写;
4)python标识符不能包含空格、@、%以及$等特殊字符;
5)不能以系统保留关键字作为标识符。
1.4.2 python标识符的命名注意事项
1)标识符应尽量采取有意义且简短的名称;
2)当作为模块名时,应尽量短小,并全部使用小写字母,可以使用下划线分割多个字母;
3)当作为包名时,应尽量短小,并全部使用小写字母,不推荐使用下划线;
4)当作为类名时,单词首字母需大写;
5)模块内部的类名,可以采用**“下划线+首字母大写”**的形式;
6)函数名、类中属性名、类中方法名,应全部使用小写字母,多个单词之间可以用下划线进行分割;
7)常量命名应全部使用大写字母,单词之间可以使用下划线进行分割。
1.4.3 python关键字
在python中定义了一组关键字,这些关键字作为保留字,不能用作变量名、函数名或任何其他标识符。
import keyword
keyword.kwlist # 查看所有关键字
keyword.iskeyword() # 判断是否为关键字
关键字 | 描述 | 关键字 | 描述 |
---|---|---|---|
and | 逻辑运算符 | as | 创建别名 |
assert | 用于调试 | break | 跳出循环 |
class | 定义类 | continue | 继续循环的下一个迭代 |
def | 定义函数 | del | 删除对象 |
elif | 等同于else if | else | 用于条件语句 |
except | 处理异常,发生异常时如何执行 | False | 布尔值,比较运算的结果 |
finally | 处理异常,无论是否存在异常,都将执行一段代码 | for | 创建for循环 |
from | 导入模块的特定部分,from…import… | global | 声明全局变量 |
if | 写一个条件语句 | import | 导入模块 |
in | 检查列表、元组等结构中是否存在某个值 | is | 测试两个变量是否相等 |
lambda | 创建匿名函数 | None | 表示null值 |
nonlocal | 声明非局部变量 | not | 逻辑运算符 |
or | 逻辑运算符 | pass | 一条什么都不做的语句 |
raise | 产生异常 | return | 退出函数并返回值 |
True | 布尔值,比较运算的结果 | try | try…except… |
while | 创建while循环 | with | 用于简化异常处理 |
yield | 结束函数,返回生成器 |
1.4.4 内建函数
除了关键字以外,python还有一组内建函数,同样不建议作为标识符。
当打开python解释器之后,会自动导入一些模块,这些即为内建函数以及一些异常和其他属性,都是作为__builtins__模块的成员定义的,在程序开始前解释器会对其进行自动导入,在使用时看作全局变量。
实际上,__builtins__模块是对__builtin__模块的引用,两者主要的区别在于是否在主模块下进行操作。如果代码操作并不在主模块中,__builtins__就是对__builtin__.__dict__的一个引用。
函数名 | 描述 | 函数名 | 描述 |
---|---|---|---|
abs() | 返回数的绝对值 | all() | 如果可迭代对象中的所有项均为true,则返回True |
any() | 如果可迭代对象中的任何项为true,则返回True | ascii() | 返回对象的可读版本,用转义字符替换none-ascii字符 |
bin() | 返回数的二进制 | bool() | 返回指定对象的bool值 |
bytearray() | 返回字节数组 | bytes() | 返回字节对象 |
callable() | 如果指定的对象是可调用的,则返回True,否则返回False | chr() | 返回指定Unicode代码中的字符 |
classmethod() | 把方法转换为类方法 | compile() | 把指定的源作为对象返回,准备执行 |
complex() | 返回复数 | delattr() | 从指定对象中删除指定的属性或方法 |
dict() | 返回字典(数组) | dir() | 返回指定对象的属性和方法的列表 |
divmod() | 当参数1除以参数2时,返回商和余数 | enumerate() | 获取集合(如元组)并将其作为枚举对象返回 |
eval() | 评估并执行表达式 | exec() | 执行指定的代码或对象 |
filter() | 使用过滤器函数排除可迭代对象中的项目 | float() | 返回浮点数 |
format() | 格式化指定值 | frozenset() | 返回frozenset对象 |
getattr() | 返回指定属性的值(属性或方法) | globals() | 以字典形式返回当前全局符号表 |
hasattr() | 如果指定对象拥有指定的属性或方法,返回True | hash() | 返回指定对象的哈希值 |
help() | 执行内建的帮助系统 | hex() | 返回数的十六进制 |
id() | 返回对象的内存地址 | input() | 允许用户进行输入 |
int() | 返回整数 | isinstance() | 如果参数1是参数2的实例,返回True |
issubclass() | 如果参数1是参数2的子类,返回True | iter() | 返回迭代器对象 |
len() | 返回对象的长度 | list() | 返回列表 |
locals() | 返回当前本地符号表的更新字典 | map() | 返回指定的迭代器,其中指定的函数应用于每个项目 |
max() | 返回可迭代对象中的最大项目 | memoryview() | 返回内存视图对象 |
min() | 返回可迭代对象中的最小项目 | next() | 返回可迭代对象的下一项 |
object() | 返回新对象 | oct() | 返回数的八进制 |
open() | 打开文件并返回文件对象 | ord() | 转换表示指定字符的Unicode整数 |
pow() | 返回参数1的参数2次幂的值 | print() | 打印标准输出 |
property() | 获取、设置、删除属性 | range() | 返回数字序列,从0开始且默认以1为增量 |
repr() | 返回对象的可读版本 | reversed() | 返回反转的迭代器 |
round() | 对数值进行四舍五入 | set() | 返回新的集合对象 |
setattr() | 设置对象的属性或方法 | slice() | 返回切割后对象 |
sorted() | 返回排序列表 | @staticmethod | 设置类中的静态方法 |
str() | 返回字符串对象 | sum() | 对迭代器中的项目进行求和 |
super() | 返回表示父类的对象 | tuple() | 返回元组 |
type() | 返回对象的类型 | vars() | 返回对象的属性和属性值的字典对象 |
zip() | 从两个或多个迭代器返回一个迭代器 |
1.4.5 专用下划线标识符
python语言中,以下划线开头的标识符具有特殊含义。
1)以单下划线开头的标识符( _xxx )表示不能访问的类属性,无法通过from…import…进行导入,只能通过类提供的接口进行访问;
2)以双下划线作为开头和结尾的标识符( __xxx__ )为专用标识符;
# 表示主程序模块
if __name__ == '__main__':
...
3)以双下划线开头的标识符( __xxx )表示类的私有变量,仅用于类中,不能进行访问。
1.5 python输入输出
parameter_1 = input('输入数字1:') # 读取键盘输入,可以接收python表达式,返回运算结果
parameter_2 = 2
print(parameter_1, parameter_2) # 依次打印其中的值,遇到【,】将输出一个空格
Out:
1 2
index = list(map(int,input().split())) # 这种方式可以输入任意个int型的数字,在这里采用列表来存储。