附答案 | 最强Python面试题之Python基础题(2)
写在之前
大家好呀,我是帅蛋。
Python 面试的时候,会涉及到很多的八股文,我在牛客网连载一个新的系列,叫【最强Python面试题】。
今天是 Python 基础面试题第二弹,大家一定要记得点赞收藏呀!!!
历史文章:
主要内容
这些面试题是我结合自己的经验整理的,主要就是下面这 5 个方面:
- Python 基础面试题
- Python 进阶
- Python 后台开发
- 爬虫
- 机器学习
对每道面试题我都会附带详细的答案,有些我觉得重要的内容会详细讲解,虽然是面试八股文,我还是希望大家不是只“知其然”,更得“知其所以然”。
关于更新频率,每天我会更新 10 道题左右,总共会有差不多 200 道。
无论是准备面试还是自己学习,这份面试题绝对值得你去看,去学习。
大家可以关注我,再关注我,使劲关注我,不要错过每天的更新~
顺便提一句,我所有和面试相关的内容都会放在#帅蛋的面试空间# 中,大家可以关注下这个话题~
以下是正文
Python 基础面试题第二弹正式开始,大家一定要记得点赞收藏,一起加油!
1、Python 中的作用域?
Python 中,一个变量的作用域总是由在代码中被赋值的地方所决定。当 Python 遇到一个变量的话它会按照这的顺序进行搜索:
本地作用域(Local)--->当前作用域被嵌入的本地作用域(Enclosing locals)--->全局/模块作用域
(Global)--->内置作用域(Built-in)。
2、什么是 Python 自省?
Python 自省是 Python 具有的一种能力,使程序员面向对象的语言所写的程序在运行时,能够获得对象的类 Python 型。
Python 是一种解释型语言,为程序员提供了极大的灵活性和控制力。
3、什么是 Python 的命名空间?
命名空间,又名 namesapce,是在很多的编程语言中都会出现的术语,趁着这个题顺便给大家仔细介绍一下。
全局变量 & 局部变量
全局变量和局部变量是我们理解命名空间的开始,我们先来看一段代码:
x = 2 def func(): x = 3 print('func x ---> ',x) func() print('out of func x ---> ',x)
这段代码输出的结果如下:
func x ---> 3 out of func x ---> 2
从上述的结果中可以看出,运行 func(),输出的是 func() 里面的变量 x 所引用的对象 3,之后执行的是代码中的最后一行。这里要区分清楚,前一个 x 输出的是函数内部的变量 x,后一个 x 输出的是函数外的变量 x,两个变量互相不影响,在各自的作用域中起作用。
那个只在函数内起作用的变量就叫 “局部变量”,有了 “局部” 就有相应的 “全部”,但是后者听起来有歧义,所以就叫了 “全局”。
x = 2 def func(): global x = 3 #注意此处 print('func x ---> ',x) func() print('out of func x ---> ',x)
这段代码中比上段代码多加了一个 global x,这句话的意思是在声明 x 是全局变量,通俗点说就是这个 x 和 函数外的 x 是同一个了,所以结果就成了下面这样:
func x ---> 3 out of func x ---> 3
这样乍一看好像全局变量好强,可以管着函数内外,但是我们还是要注意,全局变量还是谨慎使用的好,因为毕竟内外有别,不要带来混乱。
作用域
作用域,用比较直白的方式来说,就是程序中变量与对象存在关联的那段程序,比如我在上面说的, x = 2 和 x = 3 是在两个不同的作用域中。
通常的,作用域是被分为静态作用域和动态作用域,虽然我们说 Python 是动态语言,但是它的作用域属于静态作用域,即 Python 中的变量的作用域是由该变量所在程序中的位置所决定的。
在 Python 中作用域被划分成四个层级,分别是:local(局部作用域),enclosing(嵌套作用域),global(全局作用域)和 built - in(内建作用域)。对于一个变量,Python 也是按照之前四个层级依次在不用的作用域中查找,我们在上一段代码中,对于变量 x,首先搜索的是函数体内的局部作用域,然后是函数体外的全局作用域,至于这段话具体怎么来理解,请看下面的例子:
def out_func(): x = 2 def in_func(): x = 3 print('in_func x ---> ',x) in_func() print('out_func x ---> ',x) x = 4 out_func() print('x == ',x)
上述代码运行的结果是:
in_func x ---> 3 out_func x ---> 2 x == 4
仔细观察一下上面的代码和运行的结果,你就会发现变量在不同的范围内进行搜索的规律,是不是感觉这些都是以前被你忽略的呢?
命名空间
《维基百科》中说 “命名空间是对作用域的一种特殊的抽象”,在这里我用一个比方来具体说明一下:
比如张三在公司 A,他的工号是 111,李四在公司 B,他的工号也是 111,因为两个人在不同的公司,他们俩的工号可以相同但是不会引起混乱,这里的公司就表示一个独立的命名空间,如果两个人在一个公司的话,他们的工号就不能相同,否则光看工号也不知道到底是谁。
其实上面举的这个例子的特点就是我们使用命名空间的理由,在大型的计算机程序中,往往会出现成百上千的标识符,命名空间提供隐藏区域标识符的机制。通过将逻辑上相关的标识符构成响应的命名空间,可以使整个系统更加的模块化。
我在开头引用的《维基百科》的那句话说 “命名空间是对作用域的一种特殊的抽象”,它其实包含了处于该作用域内的标识符,且它本身也用一个标识符来表示。在 Python 中,命名空间本身的标识符也属于更外层的一个命名空间,所以命名空间也是可以嵌套的,它们共同生活在 “全局命名空间” 下。
简言之,不同的命名空间可以同时存在,但是彼此独立,互不干扰。当然了,命名空间因为其对象的不同也有所区别,可以分为以下几种:
1.本地命名空间:模块中有函数或者类的时候,每个函数或者类所定义的命名空间即是本地命名空间,当函数返回结果或者抛出异常的时候,本地命名空间也就结束了。
2.全局命名空间:每个模块创建了自己所拥有的全局命名空间,不同模块的全局命名空间彼此独立,不同模块中相同名称的命名空间也会因为模块的不同而不相互干扰。
3.内置命名空间:当 Python 运行起来的时候,它们就存在了,内置函数的命名空间都属于内置命名空间,所以我们可以在任何程序中直接运行它们。
程序查询命名空间的时候也有一套顺序,依次按照本地命名空间 ,全局命名空间,内置命名空间。
def fun(like): name = 'rocky' print(locals()) fun('python')
访问本地命名空间使用 locals 完成,我们来看一下结果:
{'name': 'rocky', 'like': 'python'}
从上面的结果中可以看出,命名空间中的数据存储的结构和字典是一样的。可能你已经猜到了,当我们要访问全局命名空间的时候,可以使用 globals。
关于命名空间还有一个生命周期的问题,就是一个命名空间什么时候出现,什么时候消失,这个很好理解,就是哪部分被读入内存,哪部分的命名空间就存在了,比如我们在上面说的,Python 启动,内置命名空间就建立。
4、你所遵循的代码规范是什么?
PEP 8 编码风格
Python 代码从第一眼看上去,给人的感觉就是简洁优美,可读性强,也就是我们日常所说的「高颜值」。一方面是因为 Python 自身的优秀设计,比如统一的锁进,没有多余的符号从而让代码变的更加简洁;另一方面就是因为它有着一套较为统一的编码风格,当然它本身只是编码风格方面的建议而不是强制,相应的在编写 Python 代码的编辑器自动提供 PFP 8 检查,当你编写的代码违反了 PEP 8 规范的时候,会给出警告信息和修正的建议。与此同时,还有专门的检查工具对 Python 的代码风格进行检查。
由上,还是建议在编写 Python 代码的时候都遵循 PEP 8 编码规范,毕竟你以后不可能是只一个人写代码,未来不论是在公司或者某些开源项目中,作为其中的一份子,肯定还是要在风格上向大众看齐的。
PEP 8 编码规范详细的给出了 Python 编码的指导,包括什么对齐啦,包的导入顺序啦,空格和注释啦还有命名习惯等方方面面,并且还有详细的事例。
下面我以「包」的导入为例,看一下 PEP 8 给出的具体编程指导。在 Python 中, import 应该一次只导入一个模块,不同的模块应该独立一行:
import pandas import numpy
反面例子:
import pandas,numpy
如果想要从一个模块里面导入多个,也可以像下面这样:
from subprocess import Popen, PIPE
import 语句应该处于源码文件的顶部,位于模块注释和文档字符串之后,全局变量和常量之前。在导入不同的库的时候,应该按照以下的顺序分组,各个分组之间以空行分隔:
导入标准库模块
导入相关第三方库模块
导入当前应用程序/库模块
具体事例如下所示:
import os import time import psutil from test import u_test,my_test
Python 中还支持相对导入和绝对导入,在这里还是强推绝对导入。因为绝对导入的可读性更好一些,也不容易出错,即使出错了也会给出更加详细的错误信息。具体如下所示:
from sub_package import tools from sub_package.tools import msg
当然除了上述以外还有更多对于包的规范的描述,PEP 8 的编码风格指导比较长,并且写的非常详细,所以我就不在这一一介绍了,详细的可以参考 Python 官网上的资料。
pycodestyle 检查代码规范
我在上面说过 PEP 8 只是官方给出的 Python 编码规范,并没有强制要求大家都遵守,但是又由于大家都在用,所以它也就变成了事实上的 Python 代码风格标准,既然都是标准了,那么就应该有工具来检查这个标准,这样可以帮助 Python 小白规范自己的代码,也可以帮助大家在开源或者工作中形成统一的代码风格。
为了达成上述的目的,官方提供了同名的命令行工具来检查 Python 代码是否违反了 PEP 8 规范,并且对违反规范的地方给出了相应的提示信息。
pip install pep8
规范的名字是 PEP 8 ,这个检查代码风格的命令行工具叫 pep8,这个很容易引起大家的困惑,因此 Python 之父建议将 pep8 重新命名为 pycodestyle,下面我们来看一下 pycodestyle 的用法。
首先通过 pip 安装一下:
pip install pycodestyle
对一个或者多个文件运行 pycodestyle,打印检查报告:
通过 --show-source 显示不符合规范的源码,以便程序员进行修改,具体如下所示:
autopep8 格式化代码
autopep8 能够将 Python 代码自动格式化为 PEP 8 风格,它使用 pycodestyle 工具来决定代码中的哪部分需要被格式化,这能够修复大部分 pycodestyle 工具中报告的排版问题。autopep8 本身也是一个用 Python 写的工具,所以我们还是可以用 pip 直接安装:
pip install autopep8
它的使用方式也很简单,具体如下所示:
autopep8 --in-place test_search.py
上述代码如果不带 --in-place 的话,会将 autopep8 格式化以后的代码直接输出到控制台。我们可以用这种方式检查 autopep8 的修改,使用 --in-place 则会直接将结果保存到源文件中。在这我继续用上面的例子中用到的 py 文件,具体如下所示:
上面的例子中,autopep8 顺利的修复了所有的问题,但是如果你这个时候查看源文件的话,你会发现源文件的内容还是和原来一样,并没有被修改。这个时候我们就要用到 --in-place,加上这个选项将不会有任何输出, autopep8 会直接修改源文件。
autopep8 --in-place test_search.py
5、关于 Python 程序的运行方面,有什么手段能提升性能?
1、使用多进程,充分利用机器的多核性能
2、对于性能影响较大的部分代码,可以使用 C 或 C++ 编写
3、对于 IO 阻塞造成的性能影响,可以使用 IO 多路复用来解决
4、尽量使用 Python 的内建函数
5、尽量使用局部变量
6、dict 的 items() 方法与 iteritems() 方法的不同?
items方法将所有的字典以列表方式返回,其中项在返回时没有特殊的顺序
iteritems方法有相似的作用,但是返回一个迭代器对象
7、os.path和sys.path的区别?
os.path是module,包含了各种处理长文件名(路径名)的函数。
sys.path是由目录名构成的列表,Python 从中查找扩展模块( Python 源模块, 编译模块,或者二进制扩展). 启动 Python 时,这个列表从根据内建规则,PYTHONPATH 环境变量的内容, 以及注册表( Windows 系统)等进行初始化。
8、4G 内存怎么读取一个 5G 的数据?
方法一:
通过生成器,分多次读取,每次读取数量相对少的数据(比如 500MB)进行处理,处理结束后
在读取后面的 500MB 的数据。
方法二:
可以通过 linux 命令 split 切割成小文件,然后再对数据进行处理,此方法效率比较高。可以按照行
数切割,可以按照文件大小切割。
在Linux下用split进行文件分割:
模式一:指定分割后文件行数
对与txt文本文件,可以通过指定分割后文件的行数来进行文件分割。
命令:split -l 300 large_file.txt new_file_prefix
模式二:指定分割后文件大小
split -b 10m server.log waynelog
9、输入某年某月某日,判断这一天是这一年的第几天?
使用 Python 标准库 datetime
import datetime def dayofyear(): year = input("请输入年份:") month = input("请输入月份:") day = input("请输入天:") date1 = datetime.date(year=int(year),month=int(month),day=int(day)) date2 = datetime.date(year=int(year),month=1,day=1) return (date1-date2+1).days
10、说明一下 os.path 和 sys.path 分别代表什么?
os.path 主要是用于对系统路径文件的操作。
sys.path 主要是对 Python 解释器的系统环境参数的操作(动态的改变 Python 解释器搜索路径)。
以上就是今天的内容,我是帅蛋,我们明天见~
❤️ 欢迎关注我,有问题,找帅蛋,我最看不得别人迷茫!
❤️ 如果你觉得有帮助,希望爱学习的你不要吝啬三连击哟[点赞 + 收藏 + 评论]~
#帅蛋的面试空间##面试八股文##python面试##秋招##Python#还有小小公众号 【编程文青李狗蛋】,聊聊迷茫吹吹牛皮~