Python——前言(模块、import、注释、标识符、关键字、引用、拷贝、不成文规定、Python2和Python3、Python与C++及Java)

Python——前言(使用的是Python3.X版本)

1、Python的特点

Python不仅是一门脚本语言,也是一门跨平台、开源、免费的解释型高级动态编程语言,被称为胶水语言,可以把多种不同语言编写的程序融合到一起,实现无缝拼接,支持命令式编程和函数式编程两种模式,拥有大量的几乎支持所有领域应用开发的成熟第三方扩展,Python为了体现代码之间逻辑关系,使用缩进来对代码进行分组(一般来说,使用4个空格作为基本缩进单位,虽然也可以使用3个空格作为缩进单位,但不建议那样做)

2、Python模块

基本介绍

Python的模块可以是一个以.py结尾的Python文件,可以是含有多个py文件的文件夹,或者是已被编译为共享库或DLL的c或C++扩展,抑或是使用C编写并链接到python解释器的内置模块,模块能定义函数、类和变量,模块里也能包含可执行的代码,只需要 import module_name 一行代码就可以打开文件 module_name.py ,并将 module_name.py 中的所有函数都复制到 import module_name 这行代码所在的Python文件中

Python的包就是一种特殊的Python模块,但是包往往对应的是一个文件夹

导入模块的方式

  • 从模块中导入Python函数有三种方式
    • from module_name import function_name
      将导入该模块中的function_name这一个函数,这种导入方式下的Python函数,以function_name()形式使用

    • import module_name
      将导入整个模块,这种导入方式下的Python函数,以module_name.function_name()形式使用

    • from module_name import*
      将导入模块中的所有函数,不建议使用,一方面这样会减低代码的可读性,无法区分某一个函数为自定义函数还是从模块中导入的函数;另一方面,这种导入对象的方式会导致命名空间的混乱,如果多个模块中具有同名函数,只有最后一个导入的模块中的那个函数是有效的,其他模块中的同名函数都无法访问
      这种导入方式下的Python函数,以function_name()形式使用

如果如果要导入的函数名可能与程序中现有的名称冲突, 或者函数名太长,则可以在导入时使用 as 进行改名,值得注意的是改名以后,使用原来的名称就无法实现正常访问了

导入自己编写的.py文件

解释器执行import语句的工作流程:

  • 先判断这个模块是不是built-in即内建模块
    • 如果是则直接引入内建模块
    • 如果不是则Python解释器会查看sys.path变量(sys.path在.py文件执行时动态生成)中存储的路径信息找对应的模块

于是我们可以通过向sys.path添加路径来实现.py文件的导入
sys.path是个列表类型对象,可以使用append方法将指定路径进行添加

sys.path.append(r'C:\编程\Python代码\Pytest\Pytest') 
import Pytest       #自己编写的.py文件

sys.path中记录的路径有以下几种:

  • 1.在当前目录,即当前执行的程序文件所在目录下查找
  • 2.环境(用户)变量PYTHONPATH指定的目录, 即.bash_profilec
  • 3.到 Python 默认的安装目录下查找
    寻找的时候,会按照标准模块 sys 的 sys.path 变量保存的顺序去寻找,一旦找到了,就立即停止下来,所以要注意命名冲突的问题

通过打印标准模块 sys 的 sys.path 变量我们可以看到支持查找的所有目录。换句话说,如果要导入的模块没有存储在 sys.path 显示的目录中,那么导入该模块并运行程序时,Python 解释器就会抛出 ModuleNotFoundError(未找到模块)异常

关于import

import就是一个把文件系统中的文件或者文件夹变成Python的模块或者包的过程
import可以分为absolute import和relative import

absolute import:可以根据一个确定的名称去寻找模块,建立模块,并把模块赋值给一个变量。可以类比于通过文件路径中的绝对路径找到一个东西

relative import:根据一个包中的不同模块的相对位置进行模块间的寻找,建立模块,并把模块赋值给一个变量。可以类比于通过文件路径中的相对路径找到一个东西

下面的例子均以import XXX为例进行讲解

absolute import

import的是一个文件(即一个模块)

  • 重点内容

    • 在执行import的时候,会去寻找名字XXX对应的文件,首先会检查自己的缓存,去寻找是否有以及被读取的对应名称模块,如果有的话,就会直接赋值给import语句中的XXX
    • 如果没有,则会先查看其是否为内建模块,如果不是,则按照sys.path保存的路径顺序去寻找,在寻找到这个文件的时候,会在一个单独的命名空间中运行这个文件,即建立一个模块的过程,模块是一个容器,内部可以包含其他对象,在完成模块的建立的时候,会更新缓存,为了再次import这个文件的时候,就不需要再次进行模块的建立了(比如,连续import同一个文件,且文件中具有打印操作,你会发现只会进行一次打印),最后,将模块赋值给import语句中的XXX
    • 在import XXX以后,XXX可以作为一个变量使用了,即我们通过XXX找到了(或者建立了)模块,然后我们又将模块赋值给了XXX
  • 拓展内容

    • 如果使用的是import XXX as YYY,则一整个过程是通过XXX找到了(或者建立了)模块,然后我们又将模块赋值给了YYY,而XXX是未定义
    • 如果使用的是from XXX import A,则一整个过程是是通过XXX找到了(或者建立了)模块,然后我们在这个模块中找到名称为A的对象,赋值给这个A
    • 如果使用的是from XXX import A as B,则一整个过程是是通过XXX找到了(或者建立了)模块,然后我们在这个模块中找到名称为A的对象,最后赋值给了这个B

import的是一个文件夹(即一个包)

  • 重点内容
    • 由于包就是特殊的模块,于是import 包的过程和import 模块的过程是非常相似的,唯一的一个区别就是,在import 模块的时候,我们会将对应的文件代码在一个单独的命名空间中运行了一下,去创建模块,但是在import 包的时候,我们是会去查看这个文件夹下面是否有一个名称为__init__.py的Python文件,如果没有,则不会运行任何Python代码(当然,import XXX的语句还是可以正常运行的)
    • 如果有,则会在一个单独的命名空间中对该文件进行运行,然后使用该命名空间构成一个模块,这个模块就是一个特殊的模块,我们称为包,也就是说,其实也只是导入了一个.py文件,只不过我们是通过寻找名称为XXX的文件夹,然后,导入的名称为__init__.py的Python文件,使用该文件运行,并建立了一个模块,赋值给了XXX罢了
    • 如果使用的是import XXX.H,我们就可以实现importXXX文件夹下面的其他模块(当然,你可以.多次,即可以写成import XXX.H.I.J,即最终导入的是名称为J的模块),这个过程和前面还是类似的,即先找到XXX文件夹,接着去寻找到H名称的文件,然后把XXX.H作为变量,把模块赋值给它
    • 除了这些,在一整个过程中其实也会隐性地将XXX以import XXX的方式进行导入,即会把XXX文件夹下面的名称为__init__.py的Python文件进行导入,如果是以import XXX.H.I.J的方式进行模块导入,则相应地,也会隐性地将H文件夹中的名称为__init__.py的Python文件以import XXX.H的形式导入,将I文件夹中的的名称为__init__.py的Python文件以import XXX.H.I的形式导入,即以import XXX.H.I.J的方式进行模块导入,实际上是导入了4个模块,如果每一个文件夹下都具有一个名称为__init__.py的Python文件的话,同时在对每一个被导入的模块进行dir查询属性的时候,是可以看到被导入的子模块的,比如dir(XXX),可以看到H,dir(XXX.H),可以看到I,dir(XXX.H.I),可以看到J
  • 拓展内容
    • 如果使用的是import XXX.H.I.J as K,则会导致XXX不会被导入(自然XXX.H,XXX.H.I也不会被导入),只有XXX.H.I.J对应的模块被找到,并赋值给了K(即XXX.H.I.J也是未定义的状态)
relative import

absolute import这种模块导入方式的缺点在于,如果中间文件夹的名称发生了变化,就无法找到目标模块了,或者从另一个角度,如果目标模块在很多层的文件夹下,拿import的时候,就要加上非常多的".",代码也会比较复杂
有时我们需要在同一个包中的不同模块之间进行相互导入,这些模块的相互关系是极其稳定的,因为它们同处于一个包中(即一个文件夹中),模块的相对位置不容易发生变化

  • 重点内容
    • 通过from .XXX import YYY,我们可以实现通过本文件(即要执行from .XXX import YYY语句的文件)导入与自身位于同一个包中的名称为XXX的模块中的YYY对象,整个过程是先通过模块的__name__属性和__package__属性找到包(即本本文件和XXX文件所在的文件夹),然后将from .XXX import YYY转化为from 包名.XXX import YYY,即本质就是将一个relative import转化为了一个absolute import,如果直接进行本文件的运行,就会导致此时文件的__name__属性为‘main’而__package__属性为None,,解释器就找不到父级包的任何信息,因此报错
    • 使用from …XXX import YYY,我们可以通过本文件(即要执行from .XXX import YYY语句的文件)导入位于上一级包的名称为XXX的模块中的YYY对象,这个时候,类似地,就需要上一级包也是可以被找到的

3、Python pip命令

pip工具

easy install 和 pip 工具是管理 Python 扩展库的主要方式,其中 pip 用得更多一点
使用 pip 不仅仅可以查看本机已安装的 Python,还可以极其方便地实现 Python 扩展库的安装、升级和卸载等操作

pip常用命令

pip命令解释
pip freeze > requirements.txt将本Python环境中已安装的模块消息快速生成为一个名为requirements.txt的文件(符号>表示进行重定向)
pip install -r requirements.txt从名称为requirements.txt的文件中读取所需安装的扩展库消息并自动进行安装
pip list列出当前环境中的所有已安装的第三方扩展库消息
pip freeze列出当前环境中的所有已安装的第三方扩展库(仅仅就是与pip list打印方式不同)
pip install 第三方模块名==版本号使用pip工具安装指定版本的第三方扩展库
pip install 第三方模块名==版本号 -i https://pypi.tuna.tsinghua.edu.cn/simple使用pip工具安装扩展库时,可以使用-i选项指定从国内服务器上下载和安装,从而实现速度大幅度提高

其中的命令"pip freeze > requirements.txt"和命令"pip install -r requirements.txt"一般联合使用,即同学A交给同学B使用命令pip freeze > requirements.txt得到的具有该项目的环境下所有第三方模块信息的requirements.txt,B直接使用命令pip install -r requirements.txt进行这些模块的安装,使得两个同学的Python虚拟环境完全相同

pip命令运行实例

pip freeze > requirements.txt

在这里插入图片描述

pip list

 pip freeze

在这里插入图片描述

4、Python注释

注释能够大大增强程序的可读性,在代码关键部位加上注释是必要的,方便程序员的理解和阅读
单行注释以井号 (#)开头,在物理行末尾截止
多行注释使用三单引号(‘’'),三双引号(“”"),一般用在注释一段代码的情况
解释器不执行注释内容,注释可以在任何位置

5、Python标识符

Python标识符可以由汉字、英文字母、下划线、数字组成,不能以数字开头。标识符对英文字母的大小写敏感,例如student和Student是不同的变量名

  • 以下划线开头的变量在Python中有特殊含义
    • 以单下划线开头的标识符表示不能直接访问的类属性,需要通过类提供的接口进行访问,即不能使用from module_name import* 方式导入使用
    • 以两个(或更多)下划线开头,而不以两个(或更多)下划线结尾的标识符表示类的私有成员
    • 同时以双下划线开头和结果的标识符表示Python中的特殊方法

不建议使用系统内置的模块名、类型名或函数名以及已导入的模块名及其成员名作变量名,这将会改变其类型和含义(即如果使用了,会导致原来的内置函数无法使用),可以通过dir(builtins)查看所有内置模块、类型和函数

不能使用关键字作变量名,会抛出异常,可以导入keyword模块后使用print(keyword.kwlist)查看所有Python关键字

6、Python关键字

  • pass
    • 提供占位作用,保证程序运行不会报错,可以用来为以后的软件升级预留空间
  • assert
    • 断言,用来确定一个条件必须满足(即判断一个表达式结果的布尔值为True),可用来帮助调试程序,如果不满足(表达式结果的布尔值为False)会抛出异常
  • class
    • 用来定义类对象
  • as
    • 在import、with或者except语句中给对象起别名
  • del
    • 用来使某一个对象的引用计数减一
  • raise
    • 用来显式地抛出异常
  • def、return
    • 分别用来定义函数,返回自定义函数的结果
  • in、is、or、not、and
    • 为Python运算符
  • try、except、finally
    • 在异常处理机制中出现
  • if、else、elif、for、while、continue、break
    • 在程序的组织结构中出现
  • lambda
    • 用于lambda表达式,构造匿名函数
  • await、async
    • 语法糖
  • from、import
    • 在模块导入中出现
  • global、nonlocal
    • 分别用来声明变量为全局变量,非局部变量
  • True、False
    • 布尔类型对象
  • None
    • 空类型对象,如果对一个无返回值的函数取值,则得到None
  • yield
    • 用于yield语句,构成生成器
  • with
    • 用于上下文管理语句,使用上下文管理器
  • __peg_parser__
    • 一个Python3.9的保留字彩蛋,3.8和3.10都没有

7、Python的"引用"与"赋值操作"

给变量赋值None,表示该变量没有指向任何有效东西,其实也就是开发者在写这个代码的时候,也不知道该变量应该指向哪一个对象,或者感觉指向哪一个对象都不太合适

8、Python的深拷贝与浅拷贝

对可变对象进行浅拷贝

Python中的拷贝一般都是浅拷贝,拷贝时,对象包含的子对象不会重新创建一份,而是把该可变对象保存的子对象的引用直接复制过来(即拷贝出来的可变对象和原来对象的子对象是完全相同的,源对象和拷贝对象会引用同一个子对象)

class CPU:          #一个CPU类
    pass

class Computer:     #一个电脑类
    def __init__(self,cpu):
        self.cpu=cpu            #将传入的CPU类的实例对象引用赋值给实例属性cpu

cpu = CPU()                     #实例化出一个CPU类的实例对象
computer = Computer(cpu)        #传入一个CPU类的实例对象,实例化出一个Computer类的实例对象

computer2=copy.copy(computer)   #对Computer类的实例对象进行浅拷贝

print(id(computer),id(computer.cpu))        #打印原来的Computer类的实例对象引用 和 其中的CPU类的实例对象引用
print(id(computer2),id(computer2.cpu))      #打印拷贝后的Computer类的实例对象引用 和 其中的CPU类的实例对象引用

"""
输出结果:
1784174127040 1784174127088
1784189454656 1784174127088
"""

代码解析:

  • 拷贝后的Computer类的实例对象引用 和 原来的Computer类的实例对象引用是不同的,说明是不同的Computer类的实例对象
  • 拷贝后的Computer类的实例对象中的CPU类的实例对象引用 和 原来的Computer类的实例对象中的CPU类的实例对象引用是相同的,说明是同一个CPU类的实例对象

对可变对象进行深拷贝

使用copy模块的deepcopy函数,会递归拷贝对象中包含的子对象(即被拷贝对象中存储的子对象也会被重新创建)。值得注意的是,当子对象皆为可变对象时,源对象和拷贝对象引用的子对象才会不相同(即两个对象存储的id是不同的),如果子对象为不可变对象,是不会创建一个新的子对象的

如果子对象为可变对象

在这里插入代码片

如果子对象为不可变对象

class Computer:     #一个电脑类
    def __init__(self,cpu):
        self.cpu=cpu            #将传入的不可变对象(以字符串为例)引用赋值给实例属性cpu

computer = Computer("CPU")        #传入一个不可变对象(以字符串为例),实例化出一个Computer类的实例对象

computer2=copy.deepcopy(computer)   		#对Computer类的实例对象进行深拷贝

print(id(computer),id(computer.cpu))        #打印原来的Computer类的实例对象引用 和 其中的不可变对象(以字符串为例)
print(id(computer2),id(computer2.cpu))      #打印拷贝后的Computer类的实例对象引用 和 其中的不可变对象(以字符串为例)

"""
输出结果:
2001952352336 2001952336752
2001967483056 2001952336752
"""

9、Python的不成文规定

"不成文规定"是指即使不这样做,程序也可以正常运行(即这些规定并不是硬性要求),但是在专业人士看来,不这样做非常地别扭

类中的方法之间空两行
类和类之间、函数和函数之间空一行
实例方法中的第一个形参取名为cls
类方法中的第一个形参取名为self
实例方法使用实例对象去调用
类方法使用类对象去调用

10、Python2和Python3的区别1

Python 2.x 和 Python 3.x 这两大系列之间的语法相差很大,互不兼容

  • 整型(int)和长整型(long)
    • Python2 中区分,并且使用 int 作为默认的数字类型,数字大小超过一定范围以后会变成 long 类型
    • Python3 不进行区分,只有 int 类型
  • 字符串的格式化方法"f-字符串"
    • 在 Python2 中不存在
    • 在 Python3 中存在
  • 关键字(下面列出了两个版本关键字的不同之处)
    • Python2.7.18 的关键字 print exec
    • Python3.11.1 的关键字 False await None True nonlocal async
  • 默认编码
    • Python2 中为 ASCII 码
    • Python3 中为 UTF-8
  • print
    • Python2 的 print 不一定要以函数形式进行使用,可以使用 print “hello” 的方式输出
    • Python3 的 print 必须以函数形式进行使用,print 语句被 Python3 废弃
  • 新式类和经典类
    • Python2 里面只有写明继承了 object 的类才是新式类,其他的是经典类(就是一些很老的类,自带的功能较少)
    • Python3 里面默认所有类都是继承的 object(即在创建一个类的时候是否有写"(object)"都一样,默认都继承了object类),所以 python3 中的所有类都属于是 Python2 中的新式类
  • 语法上必要的缩进
    • Python2 的缩进机制中,1 个 tab 和 8 个 space 是等价的,所
      以在缩进中可以同时允许 tab 和 space 在代码中共存
    • Python3 使用更加严格的缩进, 1 个 tab 只能找另外一个 tab 替代,因此 tab 和 space 共存会导致报错
  • 不相等操作符
    • Python2 中具有不相等操作符"<>"
    • 不相等操作符"<>“被 Python3 废弃,统一使用”!="
  • 比较操作符
    • Python2 中任意两个对象都可以比较
    • Python3 中只有同一数据类型的对象可以比较
  • 除法操作符"/"
    • Python2 中若为两个整形数进行运算进行的是地板除,但若两个数中有一个为浮点数,则进行的是真除
    • Python3 中整数相除为真除
  • 使用 for 循环时的同名变量值
    • Python2,for 循环会修改外部相同名称变量的值
    • Python3,for 循环不会修改外部相同名称变量的值
  • round 函数不进行精度指定时的返回值类型
    • Python2,round 函数返回 float 类型对象
    • Python3,round 函数返回 int 类型对象

11、Python与C++及Java进行比较

  • Python 和 C++
    • 相同点
      • C++和Python都是面向对象的高级程序设计语言
    • 不同点
      • C++ 是编译型语言,Python 是一门解释型语言
      • C++ 需要手动开辟、手动释放内存,Python 可以自动管理内存
      • C++ 是一种静态类型语言,Python 是一种动态类型语言,即 Python 在编程时,永远不用给任何变量指定数据类型,并且可以随时改变数据类型,而 C++ 写程序时必须声明所有变量的数据类型
      • C++ 运行效率高于Python
  • Python 和 Java2
    • 相同点
      • Java和Python都是面向对象的高级程序设计语言
      • Python 中只有模块(module),类(class)以及函数(def、lambda)才会引入新的作用域,其 它的代码块(如 if/elif/else/、try/except、for/while等)是不会引入新的作用域的,也就是说这些语句内定义的变量,外部也可以访问, 与 Java 类似
      • Python 跟 Java 一样是强类型语言,也就是说它不会根据环境变化自动改变数据类型,不同类型的数据操作时,必须经过强制类型转换为同一类型才能进行运算(弱类型语言在运行时会做隐式做数据类型转换,无需指定类型,默认均为字符型;参与计算会自动隐式转换类型;变量无需事先定义可直接调用)
    • 不同点
      • Java 运行效率高于 Python,尤其是纯 Python 开发的程序,运行效率极低
      • Java 开发偏向于软件工程,团队协同,Python 更适合小型开发
      • Java 是一种静态类型语言,Python 是一种动态类型语言,即 Python 在编程时,永远不用给任何变量指定数据类型,而 Java 写程序时必须声明所有变量的数据类型
      • Java 里的块用大括号对表示,Python 以冒号 + 四个空格缩进表示
      • Java 每行语句以分号结束,Python 可以不写分号
      • 实现同一功能时,Java 要敲的键盘次数一般要比 Python 多
      • Python 函数在传参的时候,形式参数的值可以通过关键字指定,而 Java 方法不可以。Python 函数有默认值参数,而 Java方法 没有
      • Python 的函数定义也可以嵌套,而 Java 不可以

  1. 此处关于Python2和Python3的区别的描述参考了Pang文同学的该博客以及Wangsh@同学的该博客 ↩︎

  2. 此处关于Python和Java区别的描述参考了shengjk1同学的该博客 ↩︎

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python2和Python3的相对引用都是用来引用同一模块中的其他部分或同一包中的其他模块的一种方法。相对引用的作用是使得代码的移植性更好,可以更容易地修改模块或包的结构而不需要修改引用的代码。 在Python2中,相对引用是通过将同一目录中的其他模块或包直接引用为一个相对路径的形式来实现的。例如,如果一个模块在同一目录中有一个叫做"mymodule"的模块,我们可以使用相对引用引用它:from . import mymodule。这种相对引用方式在Python2中是默认的引用方式。 然而,在Python3中,相对引用做了一些改变。Python3不再默认使用相对引用,而是使用绝对引用。绝对引用是指通过完整的包名来引用任何其他模块或包。例如,在包"mypackage"中的模块"mymodule"中,要引用同一包中的另一个模块"anothermodule",可以使用绝对引用:from mypackage import anothermodule。 Python3中的相对引用需要使用特殊的语法来实现。相对引用语法包括使用点"."和双下划线"__"来表示相对路径的偏移量。例如,在模块"mymodule"中,要引用同一包中的另一个模块"anothermodule",可以使用相对引用:from . import anothermodule。这里的点"."表示同一包,而不是当前目录。 总结而言,Python2和Python3在相对引用上的主要区别是,Python2默认使用相对引用,而Python3默认使用绝对引用,但Python3仍然支持使用特殊的相对引用语法。相对引用可以使代码更具可移植性和灵活性,方便修改模块或包结构而不需要修改引用的代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值