1. 程式人生 > >Python面試題,拿offer必知必會(基礎部分)

Python面試題,拿offer必知必會(基礎部分)

概念性問題

python2和python3區別

  • 字元編碼: py3中預設字元編碼是unicode;py2中預設字元編碼是 ASCII,如果檔案中出現了中文,需要在頂部加入coding宣告#coding:utf8
  • 讓使用者輸入:py3中直接使用input(); py2中需要使用raw_input()
  • range和xrange:py3中的range == py2中的 xrange, 返回類似迭代器的東西,節省記憶體空間
  • 語句變函式: py3中為print(), exec() 是一個方法,必須加上括號; py2中為print, exec
  • 資料傳輸: py3中socket傳過來的資料是byte型別 / hashlib包update也需要傳bytes型別的資料; py2中則可以直接傳入str, e.g
# python3
import hashlib
m = hashlib.sha256()
m.update(b"Nobody inspects")

# python2
import hashlib
m = hashlib.md5()
m.update("Nobody inspects")

常見python標準庫

  • math:數學相關的方法
  • datetime:基本日期時間
  • re:正則表示式相關操作
  • copy:深淺拷貝相關操作
  • sqlite3:為SQLite資料庫提供的資料庫介面
  • pickle/json:資料的轉化

Python的is和==

is是對比地址;==是對比值

列表去重

lst = [11,1,1,2,2,3,5,5]
lst = set(lst)
lst = list(lst)
print(lst)

字典操作

  • 刪除字典某個鍵 – del
dct = {1:1, 2:2}
del dct[1]
print(dct)
  • 合併兩個字典 – update()
dct = {1:1, 2:2}
dct1 = {3:3}
dct.update(dct1)
print(dct)
  • 對一個巨大的字典進行遍歷
    py2使用iteritems() ;py3使用items()

列出python中可變資料型別和不可變資料型別,並簡述原理

可變型別(mutable):變數進行append、+=等這種操作後 == 改變了變數的值,而不會新建一個物件,變數引用的物件的地址也不會變化,不過對於相同的值的不同物件,在記憶體中則會存在不同的物件,即每個物件都有自己的地址,相當於記憶體中對於同值的物件儲存了多份,這裡不存在引用計數,是實實在在的物件。

  • list
  • dict
  • set
  • bytearray
  • user-defined classes (除非是特別定義的不可變)
a = [1,2]
b = [1,2]
print(id(a))
print(id(b))

不可變型別(immutable)改變了變數的值 == 新建了一個物件,而對於相同的值的物件,在記憶體中則只有一個物件(一個地址), python的id() 方法讓你明白

  • int
  • float
  • decimal
  • complex
  • bool
  • string
  • tuple
  • range
  • frozenset
  • bytes
a = 3
b = 3
print(id(a))
print(id(b)) # mem addr is same with a
a = 5
print(id(a))

boolx = True
print(id(boolx))
boolx = False
print(id(boolx))

int(“1.4”),int(1.4)輸出結果?

  • int(“1.4”):ValueError: invalid literal for int() with base 10: ‘1.4’
  • int(1.4): 1

簡述*args and **kwargs

  • 為了能讓一個函式接受任意數量的位置引數*
  • 為了接受任意數量的關鍵字引數**
  • *引數只能出現在函式定義中最後一個位置引數後面,而**引數只能出現在最後一個引數
  • 解決的問題:構造一個可接受任意數量引數的函式

__new____init__的區別

  • __new__ 控制類例項建立過程時使用, 會在__init__ 呼叫之前呼叫, 呼叫這個方法之後,會返回一個例項 == __init__ 中的 self
  • __init__ 控制初始化一個類例項, 不會返回任何東西,它只負責初始化一個類例項

大檔案的讀取(也許10G,撐爆記憶體)

with open('x') as f:
    for line in f:
        print(line.replace('a', 'b'))

簡述with原理

不管在處理檔案過程中是否發生異常,都能保證 with 語句執行完畢後已經關閉了開啟的檔案控制代碼。如果使用傳統的 try/finally 正規化,則要使用類似如下程式碼:

somefile = open(r'somefileName')
try:
    for line in somefile:
        print line
        # ...more code
finally:
    somefile.close()

context_expression 要返回一個上下文管理器物件,該物件並不賦值給 as 子句中的 target(s) ,如果指定了 as 子句的話,會將上下文管理器的 __enter__() 方法的返回值賦值給 target(s)。target(s) 可以是單個變數,或者由“()”括起來的元組(不能是僅僅由“,”分隔的變數列表,必須加“()”)。

Python 對一些內建物件進行改進,加入了對上下文管理器的支援,可以用於 with 語句中,比如可以自動關閉檔案、執行緒鎖的自動獲取和釋放等

with context_expression [as target(s)]:
    with-body

字典的拷貝

為什麼不能用 dct1 = dct2 賦值?因為指向的是同一個記憶體地址
針對複合型物件而言,深淺拷貝會有如下區別:
- 淺拷貝:建立一個新複合型物件, 然後將所有原物件包含的其他物件的記憶體引用插入到新物件裡面
- 深拷貝:建立一個新複合型物件, 將所有的原物件的的拷貝值插入到新物件中

迭代器和生成器

  • 可迭代物件:任何你可以用for ... in ... 的物件都是可迭代物件, list,strings, files, sockets…。 當你建立一個list的時候,你一個個的獲取list裡面的值,這就是可迭代物件
 mylist = [1, 2, 3]
 for i in mylist:
    print(i)
  • 迭代器:它是一個帶狀態的物件,他能在你呼叫next()方法的時候返回容器中的下一個值,任何實現了_iter__next_()(python2中實現next())方法的物件都是迭代器, 有人需要的時候才給它生成值返回,沒呼叫的時候就處於休眠狀態等待下一次呼叫。
from itertools import count
counter = count(start=13)
next(counter) # 13
  • 生成器:迭代器的一種, 它不需要寫__iter__()__next__() 方法,只需要一個yield關鍵字, 但是生成器只能迭代一次. 生成器只會在呼叫的時候產生值,他不會提前將值儲存在記憶體中
mygenerator = (x*x for x in range(3))
for i in mygenerator:
    print(i)
  • 面試題:將列表生成式中[]改成() 之後資料結構是否改變? 答案:是,從列表變為生成器
L = [x*x for x in range(10)]
print(L) #[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

g = (x*x for x in range(10)) 
print(g) #<generator object <genexpr> at 0x02FA6F90>

lambda函式

lambda 函式是一種快速定義單行的最小函式,省去了定義函式,只是一個表示式, 它將建立一個匿名函式, lambda arguments: expressionlambda x,y:x*y

func = lambda x,y:x*y
print(func(2,3)) # 6

a=(1,)b=(1),c=(“1”) 分別是什麼型別的資料

(1,)– tuple; (“1”) – str; (1) – int

[1,2,3]+[4,5,6]的結果是多少?

兩個列表相加 == extend
print([1,2,3]+[4,5,6]) # [1, 2, 3, 4, 5, 6]

python傳引數是傳值還是傳址?

傳址

  • 不可變型別(數值型、字串、元組): 因變數不能修改,所以運算不會影響到變數自身
  • 可變型別(列表字典):函式體運算可能會更改傳入的引數變數。

@staticmethod和@classmethod

  • @staticmethod:不需要表示自身物件的self和自身類的cls引數,就跟使用函式一樣。
  • @classmethod也不需要self引數,但第一個引數需要是表示自身類的cls引數。
class MyClass:
    def method(self):
        return 'instance method called', self

    @classmethod
    def classmethod(cls):
        return 'class method called', cls

    @staticmethod
    def staticmethod():
        return 'static method called'
a = MyClass()
\ 例項方法 類方法 靜態方法
a = MyClass() a.foo(x) a.class_foo(x) a.static_foo(x)
MyClass 不可用 MyClass.class_foo(x) MyClass.static_foo(x)

單例模式

確保某一個類只有一個例項存在


class Singleton(object):
    _instance = None
    def __new__(cls, *args, **kw):
        if not cls._instance:
            cls._instance = super(Singleton, cls).__new__(cls, *args, **kw)  
        return cls._instance  

class MyClass(Singleton):  
    a = 1
'''
>>> one = MyClass()
>>> two = MyClass()
>>> one == two
True
>>> one is two
True
>>> id(one), id(two)
(4303862608, 4303862608)
'''

遇到bug如何處理

  • issue中查詢是否有相似bug
  • assert / try-except / IDE單步調式
  • 框架可以查詢原始碼或者查詢官方文件

提高python執行效率的方法

  • 讓關鍵程式碼依賴於外部包:你可以為緊急的任務使用C、C++或機器語言編寫的外部包,這樣可以提高應用程式的效能
  • 使用生成器,因為可以節約大量記憶體
  • 多個if elif條件判斷,可以把最有可能先發生的條件放到前面寫,這樣可以減少程式判斷的次數,提高效率
  • 使用較新的Python版本
  • 在排序時使用鍵(key)

try except else finally

  • try..except..else沒有捕獲到異常,執行else語句
  • try..except..finally不管是否捕獲到異常,都執行finally語句

正則表示式匹配中,(.)和(.?)匹配區別

-(.*)是貪婪匹配,會把滿足正則的儘可能多的往後匹配
-(.*?)是非貪婪匹配,會把滿足正則的儘可能少匹配

正則re.complie作用

封裝一個原本重複使用的正則表示式

prog = re.compile(pattern)
result = prog.match(string)

基礎編碼

統計字串中某字元出現次數

num = 'Hello world'.count('l')  

用兩種方法去空格

strx = "hello world ! this is Python"
strx.replace(" ", "")
print(strx)
strx = strx.split(' ')
strx = ''.join(strx)

函式內部修改全域性變數(並不推薦這種做法)

var = 5
def func():
    global var
    var = 6
print(6)

a=”hello”和b=”世界”編碼成bytes型別

a="hello"
b="世界"
a = b'hello'
b = b.encode(encoding='utf-8')

列表推導式求列表所有奇數並構造新列表,a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

a =  [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
b = [i for i in a if i % 2 != 0]
print(b)

filter方法求出列表所有奇數並構造新列表,a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

a =  [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
b = filter(lambda x: x % 2 != 0, a)
for i in b:
    print(i)

排序

  • 巢狀元組排序從大到小, 按元組第二個欄位排, 第二個欄位相同則按名字
students = [('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]
print(sorted(students, key=lambda s:(s[1],s[2]), reverse=True))
  • 根據字串長度排序
strx = ['hello', 'hi', 'yes', 'fine', 'thanks']
ret = sorted(strx, key=lambda ele:len(ele))
foo = [-5,8,0,4,9,-4,-20,-2,8,2,-4]
ret = sorted(foo, key=lambda ele: (ele<0, abs(ele)))
'''
兩個比較條件:ele<0, abs(ele)
同時有個知識點: True>False
'''

請用datetime模組列印當前時間戳 “2018-04-01 11:38:54”並輸出星期幾

import datetime
current = "Date:%s  Week:%s" % (
        str(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')),
        str(datetime.datetime.now().isoweekday()))
print(current)

生成0-100的隨機數

import random
print(100*random.random()) #隨即小數
print(random.choice(range(0,101)))
print(random.randint(1,100))

s=”info:xiaoZhang 33 shandong”,切分字串輸出[‘info’, ‘xiaoZhang’, ‘33’, ‘shandong’]

import re
s = "info:xiaoZhang 33 shandong"
s = re.split(r':| ', s)

s = “ajldjlajfdljfddd”,去重並從小到大排序輸出”adfjl”

s = "ajldjlajfdljfddd"
lsts = list(set(s))
lsts.sort()
s = ''.join(lsts)