2020年Python最新面试题(三):Python基础

1. 谈谈你对Python 编码规范的认识,并写出你知道的编码规范

Python 的规范主要基于以下几个原因:

(1) 大多数程序员的代码可读性差。
(2) 不同的程序员之间的协作很重要,代码可读性必须要好。
(3) 在进行版本升级的时,要基于源码升级。
(4) 不友好的代码会影响 Python 的执行效率,影响项目的整体进度。

目前都使用 PEP8 的 Python 的编码风格。Python 的编码规范主要有以下几点:

1、代码编排

(1) 缩进:4个空格实现缩进,尽量不使用 Tab,禁止混用 Tab 和空格。
(2) 行:每行最大长度不超过79,换行可以使用反斜杠 (\)。最好使用圆括号将换行内容括起来,不建议使用 ;
(3) 空行:类 和 top-level 函数定义之间空两行,类中的方法定义之间空一行,函数内逻辑无关段落之间空一行,其他地方尽量不要再空行。
(4) 空格:括号内的第一个位置,不要空格。紧靠右括号的位置也不要空格。冒号 (: )、逗号(,) 和 分号(;)之前不要加空格。
(5) 括号:对于单元素 tuple 一定要加 , 和 括号。

2、命名规范
module_name
package_name
ClassName
metho_name
ExceptionName
function_name
GLOBAL_CONSTANT_NAME
global_var_name
instance_var_name
function_parameter_name
local_var_name

3、注释规范

(1) 块注释,在一段代码前增加的注释。在 # 后加一空格,段落之间以只有 # 的行间隔。
(2) 行注释,在一句代码后加注释。
(3) 避免无谓的注释。

4、编程建议

(1) 字符串拼接,尽量使用 join。
(2) 单例对象,尽量使用 is、is not,不要使用 ==。
(3) 使用 is not 而不是 not is。
(4) 使用 def 来定义函数,而不是将匿名函数赋给某个变量。
(5) 尽量使代码整齐,简洁。
(6) 使用 isinstance() 来判断 instance 的类型。

2. Python中的 pass 语句的作用是什么?

pass 是一个在 Python 中不会被执行的语句,pass 语句一般作为占位符或者创建占位程序。在复杂语句中,如果一个地方需要暂时被留白,那么就可以使用 pass 语句。示例代码:

age = 17
if age >= 18:
    pass
else:
    print("age<18!未成年!")

3. Python 编程中的 except 有哪些作用?

Python 的 except 用来捕获所有的异常,因为 Python 中的每次错误都会抛出一个异常,所以每个程序的错误都被当作一个运行时的错误。

try...
except...
except...
[else...][finally...]

执行 try 块的语句时,如果引发异常,那么执行过程中会跳到 except 代码块中。对每个 except 分支顺序尝试执行,如果引发的异常与 except 中的异常组匹配,执行相应的语句。如果所有的 except 都不匹配,则异常会抛出到上层调用者。

若 try 下的语句正常执行,则执行 else 代码块。如果发生异常,那么就不会执行。如果存在 finally 语句,finally 代码块最后总是会被执行的。

4. 函数

函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。函数能提高应用的模块性和代码的重复使用率。Python 提供了许多内置函数,例如 print()。也可以自己创建函数,这被称之为用户自定义函数。

函数的目的是把一些复杂的操作进行封装,来简化程序的结构,使其容易阅读。函数在调用前,必须先定义。也可以在一个函数内部定义函数,内部函数只有在外部函数调用时才能被执行。程序调用函数时,转到函数内部执行函数内部的语句,函数执行完毕后,返回到它离开程序的地方,执行程序的下一条语句。

4.1 Python 如何定义一个函数?

用户自定义函数需要遵循以下规则:

(1) 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号()。
(2) 任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。
(3) 函数的第一行语句可以选择性地使用文档字符串,用于存放函数说明。
(4) 函数内容以冒号起始,并且缩进。
(5) return [表达式] 结束函数,选择性地返回一个值给函数调用者。不带表达式的 return 相当于返回 None。
(6) 默认情况下,参数值和参数名称是按函数声明中定义的顺序来匹配的。示例代码如下:

def get_ip(url, headers):
    """
    用于获取指定网站中的ip及端口
    :param url: 抓取网站的链接
    :param headers: 请求头
    :return: None
    """
    response = requests.get(url=url, headers=headers)
    response.encoding = "utf8"  # 设置编码方式
    if response.status_code == 200:  # 判断请求是否成功
        html = etree.HTML(response.text)  # 解析HTML
        # 获取所有带有IP的li标签
        li_list = html.xpath('//div[@class="container"]/div[2]/ul/li')[1:]
        for li in li_list:  # 遍历每行内容
            ip = li.xpath('./span[@class="f-address"]/text()')[0]  # 获取ip
            port = li.xpath('./span[@class="f-port"]/text()')[0]  # 获取端口
            ip_list.append(ip + ":" + port)
            print(f"代理ip为: {ip}, 对应端口为: {port}")

4.2 什么是 lambda 函数?

Python 中有两种定义函数的方式,一种是用关键字 def 进行定义。使用这种方式定义函数时需要指定函数的名称,这类函数被称为普通函数;另外一种是用关键字 lambda 进行定义,不需要指定函数的名字,这类函数被称为 lambda 函数。lambda 函数又称为匿名函数,它是一种单行的小函数,语法简单,简化代码,不会产生命名冲突,也不会占用命名空间。lambda 函数是一个可以接收任意多个参数(包括可选参数)并且返回单个表达式值的函数。lambda 函数返回的表达式不能超过一个。不要试图用 lambda 函数来实现复杂的业务逻辑功能,因为这会使代码变得晦涩难懂。如果有这种需求,那么应该定义为一个普通函数,然后在普通函数里实现复杂的业务逻辑。语法如下:

lambda 参数: 表达式

其中,参数可以有多个,用逗号隔开,冒号右边的表达式只能有一个,并且 lambda 函数返回的是函数对象,所以,使用 lambda 函数时,需要定义一个变量去接收。

在这里插入图片描述
如果需要定义的函数非常简单,例如只有一个表达式,不包含其他命令,那么可以考虑 lambda 函数。否则,建议定义普通函数,毕竟普通函数没有太多限制。

4.3 普通函数和 lambda 函数有什么异同点?

相同点:
(1) 都可以定义固定的方法和程序处理流程。
(2) 都可以包含参数。
不同点:
(1) lambda 函数代码更简洁,但是 def 定义的普通函数更为直观、易理解。
(2) def 定义的是普通函数,而 lambda 定义的是表达式。
(3) lambda 函数不能包含循环或者分支,不能包含 return 语句。
(4) 关键字 lambda 用来创建匿名函数,而关键字 def 用来创建有名称的普通函数。

4.4 Python 的函数参数传递方式是什么?

值传递指的是在调用函数时,将实际参数复制一份传递给形式参数,这样在函数中就可以修改形式参数,而不会影响到实际参数。引用传递指的是,在调用函数时,将实际参数的地址传递给函数,这样在函数中对参数的修改将会直接影响到实际参数。

对于不可变类型(数值型、字符串、元组),因为变量不能被修改,所以运算不会影响到变量自身,而对于可变类型(列表、字典)来说,函数内的运算可能会更改传入的参数变量。所以,对于不可变数据类型来说,可以认为函数的参数传递是值传递,而对于可变数据类型来说,函数的参数传递是引用传递。

def self_add(a):
    a += a


a_int = 1
print(a_int)  # 1
self_add(a_int)
print(a_int)  # 1

a_list = [1, 2]
print(a_list)  # [1,2]
self_add(a_list)
print(a_list)  # [1,2,1,2]

再例如:

def method(value):
    value = 2
    print(id(value))  # 140722991755568
    print(value)  # 2


value = 1
print(id(value))  # 140722991755536
method(value)
print(value)  # 1

4.5 什么是闭包?

内部函数可以引用外部函数的参数和局部变量,当外部函数返回内部函数时,相关参数和变量都保存在返回的函数中,这种特性被称为 闭包(Closure)。闭包是两个函数的嵌套,外部函数返回内部函数的引用,外部函数一定要有参数。闭包的类似格式:

def 外部函数(参数):
	def 内部函数():
		pass
	return 内部函数

闭包有以下几个特点:
(1) 必须有一个内嵌函数。
(2) 内部函数必须引用外部函数的变量 (该函数包含对外作用域而不是全局作用域名字的引用)。
(3) 外部函数的返回值必须是内嵌函数。

闭包与正常函数的区别:
(1) 闭包格式是两个函数的嵌套。
(2) 闭包外部函数的参数可以在内存中保持。
(3) 闭包函数就如同一个 “类”,只有在该闭包函数里的方法才可以使用其局部变量,闭包函数之外的方法是不能读取其局部变量的。这就实现了面向对象的封装性,更安全更可靠,即闭包里面的数据是独有的数据,与外界无影响。
(4) 函数:在函数中,需要使用的全局变量在一定程度上是受到限制的,因为全局变量不仅可以给一个函数使用,其他的函数也可能会使用到,一旦被修改会影响其他函数使用全局变量,所以全局变量不能随便修改,因此在函数的使用中受到一定局限性。示例1:

def func_out(*args):  # 定义外部函数
    def func_in():  # 使用外部函数的args变量
        sum_v = sum(args)
        return sum_v

    return func_in  # 返回内部函数


s = func_out(1, 2, 3, 2)
print(s())  # 真正调用的 func_in 函数 ==> 8

示例2:

def pass_out(score_line):
    def true_score(score):
        if score >= score_line:
            print("合格")
        else:
            print("不合格")

    return true_score


total_score_100 = pass_out(60)
total_score_150 = pass_out(90)
total_score_100(90)  # 合格
total_score_150(60)  # 不合格

4.6 函数中 *args和 **kwargs的作用是什么?

*args和 **kwargs 主要用于函数的定义。当函数的参数不确定时,可以使用 *args和**kwargs 来将不定数量的参数传递给一个函数。这里不定的意思是预先并不知道函数的使用者会传递多少个参数,所以,在这种场景下可以使用这两个关键字。

*args 是用来发送一个非键值对的可变数量的参数列表给一个函数。*args 会接收任意多个参数并把这些参数作为元组传递给函数。*args 没有 key值,以字典形式传递。需要注意的是,函数的参数的顺序:*args 必须在 **kwargs 前面,调用函数传递参数也必须依照此顺序。

(1) *args 示例:

def demo(args_f, *args_v):
    print(args_f)
    for x in args_v:
        print(x, end="")


demo(1, "a", "b", "c", "d")

再例如:

def function(x, y, *args):
    print(x, y, args)


function(1, 2, 3, 4, 5)  # 1 2 (3, 4, 5)

说明传递给函数的是一个元组。
(2) **kwargs 示例

def demo(**args_v):
    for k, v in args_v.items():
        print(k, v)  # name Amo


demo(name="Amo")

再例如:

def function(**kwargs):
    print(kwargs, type(kwargs))


function(a=2)  # {'a': 2} <class 'dict'>

需要注意的是,参数 arg、*args、**kwargs 三个参数的位置是确定的。必须是 (arg,*args,**kwargs") 这个顺序,否则程序会报错。

def function(arg, *args, **kwargs):
    print(arg, args, kwargs)


function(6, 7, 8, 9, a=1, b=2, c=3)  # 6 (7, 8, 9) {'a': 1, 'b': 2, 'c': 3}

关于函数参数的知识点可看博主 Python基础练习 一文中的第45个练习:

在这里插入图片描述

5. 什么是模块? 它有什么好处?

在 Python 中,一个 .py 文件就被称之为一个模块 ( Module )。模块提高了代码的可维护性,同时模块还可以被其他地方引用。一个包含许多 Python 代码的文件夹是一个包。一个包可以包含模块和子文件夹。在 Python 中,模块是搭建程序的一种方式。模块一般分为以下几种:

(1) 内置模块:例如 os、random、time 和 sys 模块。
(2) 第三方模块:别人写好的模块,可以拿来使用,但是使用第三方模块前,需要首先使用 pip 命令 (第三方包管理工具) 安装。
(3) 自定义模块:程序员自己写的模块。

6. 模块有哪几种导入方式?

在 Python 中,用 import 或者 from…import …来导入相应的模块。

(1) 将整个模块(somemodule) 导入,格式为: import somemodule。
(2) 从某个模块中导入某个函数,格式为:from somemodule import somefunction.
(3) 从某个模块中导入多个函数,格式为:from somemodule import firstfunc, secondfunc, thirdfunc。
(4) 将某个模块中的全部函数导入,格式为:from somemodule import *。
(5) 起别名导入,例如:

给模块起别名,如 import random as rr,以后在代码中只能使用别名,不能使用原名。
给函数等起别名,如 from random import randint as rint,以后在代码中只能使用函数别名,不能使用原名。

7. os 和 sys 模块的区别有哪些?

os 模块是负责程序与操作系统的交互,提供了访问操作系统底层的接口,而 sys 模块是负责程序与 Python 解释器的交互,提供了一系列的函数和变量,用于操控 Python 时运行的环境。

8. “name” 属性的作用是什么?

一个模块被另一个程序第一次引入时,其主程序将全部运行。如果想在模块被引入时,模块中的某一程序块不执行,那么此时可以用 “__name__” 属性,当其值是 “__main__” 时,表明该模块自身在运行,否则是被引入,需要注意的是,"__name__" 与 “__main__” 底下是双下划线。示例:

在这里插入图片描述
如果导入该模块后,那么程序运行的结果如下所示:

在这里插入图片描述

9. dir() 函数的作用是什么?

内置函数 dir() 可以找到模块内定义的所有名称,以一个字符列表的形式返回。当内置的 dir() 函数不带参数时,返回当前范围内的变量、方法和定义的类型列表;当带参数时,返回参数的属性、方法列表。如果参数包含方法 __dir__() ,那么该方法将被调用。如果参数不包含 __dir__(),那么该方法将最大限度地收集参数信息。

在这里插入图片描述

10. pip 是什么?

JavaScript 使用 npm 管理软件包,Ruby 使用 gem,以及.NET 使用 NuGet,而在 Python 中,则是用pip 作为 Python 的标准包管理器,使用 pip 命令可以安装和管理不属于 Python 标准库的其他软件包。软件包管理极其重要,所以,自 Python 2.7.9 版本开始,pip 一直被直接包括在 Python 的安装包内,同样还被用于 Python 的其他项目中,这使得 pip 成为每一个 Pythonista (Python 用户) 必备的工具。

Python 的安装包中自带了 pip,所以可以直接使用它。可以通过在控制台中运行以下命令来验证 pip 是否可用:

在这里插入图片描述
这里的输出结果显示了 pip 的版本以及安装位置还有 Python 的版本。可以使用以下命令来升级 pip 软件,注意如果是在 Windows 中权限不够,需要加上 --user :

在这里插入图片描述
可以使用命令 pip list 命令查看环境中安装了哪些软件包:

在这里插入图片描述
命令 pip install 会查找并安装软件包的最新版本 (一般来说为了加快下载速度,我们会加上镜像源),同时还会搜索软件包元数据中的依赖列表,并安装这些依赖以确保软件包满足所有需求。使用 pip 中的 show 命令可以查看包的元数据信息。注意:Windows 中虚拟环境内,不能加 --user,否则会报错。

在这里插入图片描述

11. Python 里面如何生成随机数?

在 Python 中用于生成随机数的模块是 random,在使用前需要使用 import 导入模块。

(1) random.random():生成一个 0~1 之间的随机浮点数。
(2) random.uniform(a,b):生成 [a,b] 之间的浮点数。
(3) random.randint(a,b):生成 [a,b] 之间的整数。
(4) random.randrange(a,b,step):在指定的集合 [a,b) 中,以 step 为基数随机取一个数。
(5) random.choice(sequence):从特定序列中随机取一个元素,这里的序列可以是字符串、列表、元组等。
(6) random.sample():从指定序列中随机获取指定长度的片段。

在这里插入图片描述

12. pickle 模块的作用是什么?

将对象写入文件或者数据库中,称之为数据的持久化存储。序列化 (Serialization) 是将对象的状态信息转换为可以存储或传输的形式的过程。一般将一个对象存储至一个存储媒介,例如档案或是记忆体缓冲等。在网络传输过程中,可以是字节或是 XML 等格式。而字节或 XML 编码格式可以还原完全相等的对象。这个相反的过程又被称为反序列化。

在 Python 中,可以借助 pickle 模块对对象进行序列化或反序列化,可以实现一个对象持久化保存。
(1) 序列化后存入文件:

pickle.dump(对象, 文件对象)  # 序列化后存入文件
pickle.load(文件对象)  # 从文件中反序列化对象

(2) 将对象序列化后,放入字符串:

string = pickle.dumps(对象) # 将对象序列化后,放入字符串 
s2 = pickle.loads(string)  # 从字符串反序列化对象

关于具体及详细的用法可以看博主 Python爬虫数据抽取(一):解析库json及jsonpath pickle 一文。

猜你喜欢

转载自blog.csdn.net/xw1680/article/details/109645083
今日推荐