01.python面试之基础

Python 语言与 Perl,C 和 Java 等语言有许多相似之处。但是,也存在一些差异。

python有哪些特点和优点

  • 语法简单
  • 开源免费
  • 高级语言
  • 解释性语言
  • 面向对象编程
  • 模块众多可拓展性强

简述解释型和编译型编程语言?

  • 编译型语言 编译型语言是指程序在执行之前需要一个专门的编译过程,把程序源文件编译为机器语言的文件,运行时不需要重新编译,执行效率高,但缺点是,编译型语言依赖编译器,跨平台性差。
    举例:比如C语言程序的执行过程,要先将后缀为.c的源文件通过编译、链接为后缀为.exe的可执行文件,才能运行。
  • 解释型语言 解释型语言是指源代码不需要预先进行编译,在运行时,要先进行解释再运行。解释型语言执行效率低,但跨平台性好。
    举例:比如Java程序执行过程,我们写好代码,直接运行即可(运行前有解释的过程)。

Python解释器种类以及特点

  • CPython:c语言开发的使用最广的解释器
  • IPython:基于cpython之上的一个交互式计时器 交互方式增强 功能和cpython一样
  • PyPy:目标是执行效率,采用JIT技术,对python代码进行动态编译,提高执行效率
  • JPython:运行在Java上的解释器,直接把python代码编译成Java字节码执行
  • IronPython:运行在微软,.NET 平台上的解释器,把python编译成. NET的字节码

python常见的PEP8规范

代码布局

缩进:

每个缩进级别使用4个空格。

1
2
3
4
def __init__(self):
"""初始化属性"""
self.new_urls = set() # 未爬取的url集合
self.old_urls = set() # 已爬取的url集合
制表符or空格?
  • 空格是首选的缩进方法。
  • Python 3不允许混合使用制表符和空格来缩进。
  • Python 2代码缩进与制表符和空格的混合应转换为使用空格专有。
  • 有研究显示:使用空格缩进的程序员的薪资比使用制表符缩进的程序员的薪资多8%。所以一定要用空格缩进呀。
每行代码的最大长度:
  • 将所有行限制为最多79个字符。
  • Python标准库是保守的,需要将行限制为79个字符(文档字符串/注释为72)。
空白行:
  • 用两个空白行分隔顶层函数和类定义。
  • 类中的方法定义用一个空行分隔。
  • 可以使用额外的空白行(节省空间)来分隔相关功能组。在一堆相关的单行程序(例如一组虚拟执行程序)之间可能会省略空白行。
  • 在函数中使用空行来节省逻辑部分。
  • 恰当的使用空白行可以提高代码的可读性。
源文件编码:
  • 核心Python发行版中的代码应该始终使用UTF-8(或Python 2中的ASCII)。
  • 使用ASCII(Python 2)或UTF-8(Python 3)的文件不应该有编码声明。
  • 但是在Python 2中使用UTF-8编码就需要有编码声明:
    1
    2
    # -*- coding: utf-8 -*-
    #! /usr/bin/env python2
    上面两行代码常放在Python 2代码中的开头,第一行意思是指定源文件以utf-8格式编码,第二行意思是指定源文件的python解释器在环境变量中去寻找。
导入库函数:

若是导入多个库函数,应该分开依次导入:

1
2
import requests
import csv

导入总是放在文件的顶部,在任何模块注释和文档字符串之后,在模块全局变量和常量之前。

1
2
3
4
5
6
7
8
9
10
"""
一种简单的方式是使用模块json来存储数据
"""
# 使用函数json.dump()来存储数据# 函数json.dump()接受两个对象:要存储的数据以及可用于存储数据的文件对象
import json

numbers = [2, 3, 5, 7, 11, 13]
filename = "numbers.json" # 使用文件扩展名.json来指出文件存储的数据为JSON格式
with open(filename, "w") as file_object: # 以写入模式打开文件
json.dump(numbers, file_object)

导入应按以下顺序进行:
① 标准库导入
② 有关的第三方库进口
③ 本地应用程序/库特定的导入

1
2
3
4
5
import sys
import pygamefrom bullet
import Bulletfrom alien
import Alienfrom time
import sleep

从包含类的模块中导入一个类时,通常可以这样写:

1
2
3
4
5
6
7
from settings import Settings
from ship import Ship
import game_functions as gf
from pygame.sprite import Group
from game_stats import GameStats
from button import Button
from scoreboard import Scoreboard

应避免通配符导入(import *),因为它们使名称空间中出现的名称不清楚

字符串

在Python中,单引号字符串和双引号字符串是相同的。这个PEP没有为此提出建议。

对于三引号字符串,常用三个双引号作文档字符串,文档字符串常用在模块的开端用以说明模块的基本功能,或紧跟函数定义的后面用以说明函数的基本功能,关于三引号字符串更多具体的细节,可以查阅其官方文档:

https://www.python.org/dev/peps/pep-0257/

表达式和语句中的空格

在以下情况下避免无关的空格:

① 在括号或大括号内:

1
2
Yes: spam(ham[1], {eggs: 2})
No: spam( ham[ 1 ], { eggs: 2 } )

② 在尾随逗号和后面的右括号之间:

1
2
Yes: foo = (0,)
No: bar = (0, )

③ 在逗号,分号或冒号前面:

1
2
Yes: if x == 4: print x, y; x, y = y, x
No: if x == 4 : print x , y ; x , y = y , x

④ 紧接在开始函数调用的参数列表的开括号之前:

1
2
Yes: spam(1)
No: spam (1)

⑤ 紧接在开始括号之前,开始索引或切片:

1
2
Yes: dct['key'] = lst[index]
No: dct ['key'] = lst [index]

⑥ 在一个赋值(或其他)运算符周围有多于一个的空间来对齐它:

Yes:

1
2
3
x = 1
y = 2
long_variable = 3

No:

1
2
3
x             = 1
y = 2
long_variable = 3
其他建议:

① 总是围绕这些二元运算符在两侧使用一个空格:

1
2
3
赋值(=),扩充赋值(+ =,- = 等),
比较(==,<,>,!=,<>,<=, > =,在,不在,是,是不是),
布尔值(和, 或,不)

② 用于指示关键字参数或默认参数值时,不要在=符号周围使用空格。

Yes:

1
2
def complex(real, imag=0.0):
return magic(r=real, i=imag)

No:

1
2
def complex(real, imag = 0.0):
return magic(r = real, i = imag)

注释

  1. 代码更改时,相应的注释也要随之更改。
  2. 块注释:块注释通常适用于后面的一些(或全部)代码,并缩进到与该代码相同的级别。块注释的每一行都以#和一个空格开始。
  3. 行注释:顾名思义就是对某一语句行进行注释,注释应该与语句至少隔开两个空格,用#和一个空格开始。

命名约定

  1. 采用描述性的命名规则,例如一个实现某种功能的类或函数,那这个类或函数的名字就以相应的功能实现作为命名,简单易懂。
    2.类的命名采用驼峰命名法,即每个单词的首字母大写。
  2. 切勿将字符’l’(小写字母el),’O’(大写字母oh)或’I’(大写字母)作为单个字符变量名称。在一些字体中,这些字符与数字1和零是无法区分的。当试图使用“l”时,请使用“L”。
  3. 函数名称应该是小写的,为了提高可读性,必须使用由下划线分隔的单词。如果函数参数的名称与保留关键字冲突,通常最好追加一个尾部下划线,而不是使用缩写或拼写损坏。

三元运算规则以及应用场景

三元运算符常用于赋值操作,语法为:真 if 表达式 else 假。

is和==的区别

is判断的是内存id是否是同一个,==判断的值是否相等

try except用法和作用

用于异常捕获,如果觉得某段代码可能会触发异常,可以使用try except,没有异常正常走try,有异常走走except

一行代码实现1-100之和

1
2
3
4
5
6
7
8
9
import datetime
import json
import os
import random
import string
import time

sum(range(101))
# 5050
5050

反转一个整数,例如-123 –> -321

1
2
3
4
5
6
7
8
num = -123
result = None
# 如果是负值,取出负号,转为字符串倒序,再拼接负号
if abs(num) != num:
result = str(num)[0] + str(num)[1:][::-1]
else:
result = num
result
'-321'

字符串 “123” 转换成 123,不使用内置api,例如 int()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
s = "151823"
num_dict = {
"0":0,
"1":1,
"2":2,
"3":3,
"4":4,
"5":5,
"6":6,
"7":7,
"8":8,
"9":9
}
result = 0
for index, value in enumerate(s[::-1]):
result += 10**index*num_dict[value]
print(result, type(result))
151823 <class 'int'>

(进阶)字符串 “123.456” 转换成 123.456,不使用内置api,例如 int(),float()等

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
num_dict = {
"0":0,
"1":1,
"2":2,
"3":3,
"4":4,
"5":5,
"6":6,
"7":7,
"8":8,
"9":9
}
s = '123.456'
result = 0
# 判断是否含有小数点
if '.'in s:
integer, decimal = s.split(".")
# 先算小数
for index, value in enumerate(decimal):
# 小数是从10的-1次方开始,-2次方,-3次方……
result += 10**(-index-1)*num_dict[value]
# 再算整数
for index, value in enumerate(integer[::-1]):
# 整数从个位数开始算,10的0次方,1次方,2次方……
result += 10**index*num_dict[value]
else:
# 如果是整数,直接倒序从个位开始,乘以10的0次方、1次方、2次方……
for index, value in enumerate(s[::-1]):
result += 10**index*num_dict[value]
result
123.456

遍历列表时删除元素的正确做法

1
2
3
4
lis = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
for i in lis[::-1]:
lis.remove(i)
lis
[]

求出列表所有奇数并构造新列表

1
2
3
lis = [2, 4, 5, 6, 3, 2, 1, 4, 6, 7, 9, 13, 11, 23]
results = [i for i in lis if i%2==1]
results
[5, 3, 1, 7, 9, 13, 11, 23]

请用一行代码 实现将1-N 的整数列表以3为单位分组

1
2
3
4
lis = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
results = [[x for x in lis[i:i+3]] for i in range(len(lis))[::3]]
results

[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]

Json序列化时,默认遇到中文会转换成unicode,如果想要保留中文怎么办?

1
2
3
4
import json
dic = {"name":"张学友", "age":18}
json_str = json.dumps(dic, ensure_ascii=False)
json_str
'{"name": "张学友", "age": 18}'

Python写9*9乘法表的两种简单方法

1
2
3
4
5
# 方式一:
for i in range(1, 10):
for j in range(1, 11-i):
print(f"{i} x {j} = {i*j}", end=" ")
print()
1 x 1 = 1 1 x 2 = 2 1 x 3 = 3 1 x 4 = 4 1 x 5 = 5 1 x 6 = 6 1 x 7 = 7 1 x 8 = 8 1 x 9 = 9 
2 x 1 = 2 2 x 2 = 4 2 x 3 = 6 2 x 4 = 8 2 x 5 = 10 2 x 6 = 12 2 x 7 = 14 2 x 8 = 16 
3 x 1 = 3 3 x 2 = 6 3 x 3 = 9 3 x 4 = 12 3 x 5 = 15 3 x 6 = 18 3 x 7 = 21 
4 x 1 = 4 4 x 2 = 8 4 x 3 = 12 4 x 4 = 16 4 x 5 = 20 4 x 6 = 24 
5 x 1 = 5 5 x 2 = 10 5 x 3 = 15 5 x 4 = 20 5 x 5 = 25 
6 x 1 = 6 6 x 2 = 12 6 x 3 = 18 6 x 4 = 24 
7 x 1 = 7 7 x 2 = 14 7 x 3 = 21 
8 x 1 = 8 8 x 2 = 16 
9 x 1 = 9 
1
2
3
4
5
6
# 方式二
for i in range(1, 10):
for j in range(1, i+1):
print(f"{j} x {i} = {i*j}", end=" ")
print()

1 x 1 = 1 
1 x 2 = 2 2 x 2 = 4 
1 x 3 = 3 2 x 3 = 6 3 x 3 = 9 
1 x 4 = 4 2 x 4 = 8 3 x 4 = 12 4 x 4 = 16 
1 x 5 = 5 2 x 5 = 10 3 x 5 = 15 4 x 5 = 20 5 x 5 = 25 
1 x 6 = 6 2 x 6 = 12 3 x 6 = 18 4 x 6 = 24 5 x 6 = 30 6 x 6 = 36 
1 x 7 = 7 2 x 7 = 14 3 x 7 = 21 4 x 7 = 28 5 x 7 = 35 6 x 7 = 42 7 x 7 = 49 
1 x 8 = 8 2 x 8 = 16 3 x 8 = 24 4 x 8 = 32 5 x 8 = 40 6 x 8 = 48 7 x 8 = 56 8 x 8 = 64 
1 x 9 = 9 2 x 9 = 18 3 x 9 = 27 4 x 9 = 36 5 x 9 = 45 6 x 9 = 54 7 x 9 = 63 8 x 9 = 72 9 x 9 = 81 

异常模块中try except else finally的相关意义

  • 如果在try except中使用else子句, 那么else必须放在except子句之后,else子句将在try子句没有发生任何异常的时候执行
  • 如果最后使用finally子句,代表无论异常是否发生,最后都会执行finally子句
1
2
3
4
5
6
7
8
9
10
11
12
13
# 无论如何都会执行finally
def func(x, y):
try:
return "try", x/y
except Exception as e:
return "except", e
else:
return "else"
finally:
return "finally"


print(func(4, 6))
finally