更多内容,持续更新中。。。
一、Python基础
文件操作
1.有一个jsonline格式的文件file.txt大小约为10K
def get_lines():
with open('file.txt','rb') as f:
return f.readlines()
if __name__ == '__main__':
for e in get_lines():
process(e) # 处理每一行数据
现在要处理一个大小为10G的文件,但是内存只有4G,如果在只修改get_lines 函数而其他代码保持不变的情况下,应该如何实现?需要考虑的问题都有那些?
def get_lines():
with open('file.txt','rb') as f:
for i in f:
yield i
个人认为:还是设置下每次返回的行数较好,否则读取次数太多。
def get_lines():
l = []
with open('file.txt','rb') as f:
data = f.readlines(60000)
l.append(data)
yield l
Pandaaaa906提供的方法
from mmap import mmap
def get_lines(fp):
with open(fp,"r+") as f:
m = mmap(f.fileno(), 0)
tmp = 0
for i, char in enumerate(m):
if char==b"\n":
yield m[tmp:i+1].decode()
tmp = i+1
if __name__=="__main__":
for i in get_lines("fp_some_huge_file"):
print(i)
要考虑的问题有:内存只有4G无法一次性读入10G文件,需要分批读入分批读入数据要记录每次读入数
据的位置。分批每次读取数据的大小,太小会在读取操作花费过多时间。
https://stackoverflow.com/questions/30294146/python-fastest-way-to-process-large-file
2.补充缺失的代码
def print_directory_contents(sPath):
"""
这个函数接收文件夹的名称作为输入参数
返回该文件夹中文件的路径
以及其包含文件夹中文件的路径
"""
import os
for s_child in os.listdir(s_path):
s_child_path = os.path.join(s_path, s_child)
if os.path.isdir(s_child_path):
print_directory_contents(s_child_path)
else:
print(s_child_path)
模块与包
3.输入日期, 判断这一天是这一年的第几天?
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).days + 1
4.打乱一个排好序的list对象alist?
import random
alist = [1,2,3,4,5]
random.shuffle(alist)
print(alist)
数据类型
5.现有字典 d= {‘a’:24,‘g’:52,‘i’:12,‘k’:33}请按value值进行排序?
sorted(d.items(),key=lambda x:x[1])
x[0]代表用key进行排序;x[1]代表用value进行排序。
6.字典推导式
d = {key:value for (key,value) in iterable}
7.请反转字符串 “aStr”?
print("aStr"[::-1])
8.将字符串 “k:1 |k1:2|k2:3|k3:4”,处理成字典 {k:1,k1:2,…}
# 第一种方法
str1 = "k:1|k1:2|k2:3|k3:4"
def str2dict(str1):
dict1 = {}
for iterms in str1.split('|'):
key, value = iterms.split(':')
dict1[key] = value
return dict1
# 第二种方法(字典推导式)
d = {k: int(v) for t in str1.split("|") for k, v in (t.split(":"),)}
9.请按alist中元素的age由大到小排序
alist = [{'name':'a','age':20},{'name':'b','age':30},{'name':'c','age':25}]
def sort_by_age(list1):
return sorted(alist,key=lambda x:x['age'],reverse=True)
10.下面代码的输出结果将是什么?
list = ['a','b','c','d','e']
print(list[10:])
代码将输出[],不会产生IndexError错误,就像所期望的那样,尝试用超出成员的个数的index来获取某
个列表的成员。例如,尝试获取list[10]和之后的成员,会导致IndexError。然而,尝试获取列表的切
片,开始的index超过了成员个数不会产生IndexError,而是仅仅返回一个空列表。这成为特别让人恶
心的疑难杂症,因为运行的时候没有错误产生,导致Bug很难被追踪到。
11.写一个列表生成式,产生一个公差为11的等差数列
print([x*11 for x in range(10)])
12.给定两个列表,怎么找出他们相同的元素和不同的元素?
list1 = [1,2,3]
list2 = [3,4,5]
set1 = set(list1)
set2 = set(list2)
print(set1 & set2)
print(set1 ^ set2)
13.请写出一段python代码实现删除list里面的重复元素?
l1 = ['b','c','d','c','a','a']
l2 = list(set(l1))
print(l2)
用list类的sort方法:
l1 = ['b','c','d','c','a','a']
l2 = list(set(l1))
l2.sort(key=l1.index)
print(l2)
也可以这样写:
l1 = ['b','c','d','c','a','a']
l2 = sorted(set(l1),key=l1.index)
print(l2)
也可以用遍历:
l1 = ['b','c','d','c','a','a']
l2 = []
for i in l1:
if not i in l2:
l2.append(i)
print(l2)
14.给定两个list A,B ,请用找出A,B中相同与不同的元素
A,B 中相同元素: print(set(A)&set(B))
A,B 中不同元素: print(set(A)^set(B))
企业面试题
15.python新式类和经典类的区别?
a、在python里凡是继承了object的类,都是新式类
b、Python3里只有新式类
c、Python2里面继承object的是新式类,没有写父类的是经典类
d、经典类目前在Python里基本没有应用
e、保持class与type的统一对新式类的实例执行a.class与type(a)的结果是一致的,对于旧式类来说就不
一样了。
f、对于多重继承的属性搜索顺序不一样新式类是采用广度优先搜索,旧式类采用深度优先搜索。
16.python中内置的数据结构有几种?
a、整型 int、 长整型 long、浮点型 float、 复数 complex
b、字符串 str、 列表 list、 元祖 tuple
c、字典 dict 、 集合 set
d、Python3 中没有 long,只有无限精度的 int
17.python如何实现单例模式?请写出两种实现方式?
第一种方法:使用装饰器
def singleton(cls):
instances = {}
def wrapper(*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return wrapper
@singleton
class Foo(object):
pass
foo1 = Foo()
foo2 = Foo()
print(foo1 is foo2) # True
第二种方法:使用基类
New 是真正创建实例对象的方法,所以重写基类的new 方法,以此保证创建对象的时候只生成一个实例
class Singleton(object):
def __new__(cls, *args, **kwargs):
if not hasattr(cls, '_instance'):
cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
return cls._instance
class Foo(Singleton):
pass
foo1 = Foo()
foo2 = Foo()
print(foo1 is foo2) # True
第三种方法:元类,元类是用于创建类对象的类,类对象创建实例对象时一定要调用call方法,因此在调用call时候保证始终只创建一个实例即可,type是python的元类
class Singleton(type):
def __call__(cls, *args, **kwargs):
if not hasattr(cls, '_instance'):
cls._instance = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instance
# Python2
class Foo(object):
__metaclass__ = Singleton
# Python3
class Foo(metaclass=Singleton):
pass
foo1 = Foo()
foo2 = Foo()
print(foo1 is foo2) # True
18.反转一个整数,例如-123 --> -321
class Solution(object):
def reverse(self, x):
if -10 < x < 10:
return x
str_x = str(x)
if str_x[0] != "-":
str_x = str_x[::-1]
x = int(str_x)
else:
str_x = str_x[1:][::-1]
x = int(str_x)
x = -x
return x if -2147483648 < x < 2147483647 else 0
if __name__ == '__main__':
s = Solution()
reverse_int = s.reverse(-120)
print(reverse_int)
19.设计实现遍历目录与子目录,抓取.pyc文件
第一种方法:
import os
def get_files(dir, suffix):
res = []
for root, dirs, files in os.walk(dir):
for filename in files:
name, suf = os.path.splitext(filename)
if suf == suffix:
res.append(os.path.join(root, filename))
print(res)
get_files("./", '.pyc')
第二种方法:
import os
def pick(obj):
if obj.endswith(".pyc"):
print(obj)
def scan_path(ph):
file_list = os.listdir(ph)
for obj in file_list:
if os.path.isfile(obj):
pick(obj)
elif os.path.isdir(obj):
scan_path(obj)
if __name__ == '__main__':
path = input('输入目录')
scan_path(path)
第三种方法:
from glob import iglob
def func(fp, postfix):
for i in iglob(f"{fp}/**/*{postfix}", recursive=True):
print(i)
if __name__ == "__main__":
postfix = ".pyc"
func("K:\Python_script", postfix)
20.一行代码实现1-100之和
count = sum(range(0,101))
print(count)
21.Python-遍历列表时删除元素的正确做法
遍历在新在列表操作,删除时在原来的列表操作
a = [1, 2, 3, 4, 5, 6, 7, 8]
print(id(a))
print(id(a[:]))
for i in a[:]:
if i > 5:
pass
else:
a.remove(i)
print(a)
print('-----------')
print(id(a))
# filter
a = [1, 2, 3, 4, 5, 6, 7, 8]
b = filter(lambda x: x > 5, a)
print(list(b))
列表解析
a=[1,2,3,4,5,6,7,8]
b = [i for i in a if i>5]
print(b)
倒序删除
因为列表总是‘向前移’,所以可以倒序遍历,即使后面的元素被修改了,还没有被遍历的元素和其坐标
还是保持不变的
a = [1, 2, 3, 4, 5, 6, 7, 8]
print(id(a))
for i in range(len(a) - 1, -1, -1):
if a[i] > 5:
pass
else:
a.remove(a[i])
print(id(a))
print('-----------')
print(a)
22.字符串的操作题目
全字母短句 PANGRAM 是包含所有英文字母的句子,比如:A QUICK BROWN FOX JUMPS OVER THE
LAZY DOG. 定义并实现一个方法 get_missing_letter, 传入一个字符串采纳数,返回参数字符串变成一
个 PANGRAM 中所缺失的字符。应该忽略传入字符串参数中的大小写,返回应该都是小写字符并按字
母顺序排序(请忽略所有非 ACSII 字符)
下面示例是用来解释,双引号不需要考虑:
(0)输入: “A quick brown for jumps over the lazy dog”
返回: “”
(1)输入: “A slow yellow fox crawls under the proactive dog”
返回: “bjkmqz”
(2)输入: “Lions, and tigers, and bears, oh my!”
返回: “cfjkpquvwxz”
(3)输入: “”
返回:“abcdefghijklmnopqrstuvwxyz”
def get_missing_letter(a):
s1 = set("abcdefghijklmnopqrstuvwxyz")
s2 = set(a.lower())
ret = "".join(sorted(s1 - s2))
return ret
print(get_missing_letter("python"))
# other ways to generate letters
# range("a", "z")
# 方法一:
import string
letters = string.ascii_lowercase
# 方法二:
letters = "".join(map(chr, range(ord('a'), ord('z') + 1)))
23.可变类型和不可变类型
1、可变类型有list,dict.不可变类型有string,number,tuple.
2、当进行修改操作时,可变类型传递的是内存中的地址,也就是说,直接修改内存中的值,并没有开辟新的内存。
3、不可变类型被改变时,并没有改变原内存地址中的值,而是开辟一块新的内存,将原地址中的值复制过去,对这块新开辟的内存中的值进行操作。
24.is和==有什么区别?
is:比较的是两个对象的id值是否相等,也就是比较俩对象是否为同一个实例对象。是否指向同一个内
存地址
== : 比较的两个对象的内容/值是否相等,默认会调用对象的eq()方法
25.求出列表所有奇数并构造新列表
a = [1,2,3,4,5,6,7,8,9,10]
res = [ i for i in a if i%2==1]
print(res)
26.用一行python代码写出1+2+3+10248
from functools import reduce
#1.使用sum内置求和函数
num = sum([1,2,3,10248])
print(num)
#2.reduce 函数
num1 = reduce(lambda x,y :x+y,[1,2,3,10248])
print(num1)
27.Python中变量的作用域?(变量查找顺序)
函数作用域的LEGB顺序
1.什么是LEGB?
L: local 函数内部作用域
E:enclosing 函数内部与内嵌函数之间
G:global 全局作用域
B:build-in 内置作用
Python在函数里面的查找分为4种,称之为LEGB,也正是按照这是顺序来查找的
28.字符串 “123” 转换成 123 ,不使用内置api,例如 int()
方法一: 利用 str 函数
def atoi(s):
num = 0
for v in s:
for j in range(10):
if v == str(j):
num = num * 10 + j
return num
方法二: 利用 ord 函数
def atoi(s):
num = 0
for v in s:
num = num * 10 + ord(v) - ord('0')
return num
方法三: 利用 eval 函数
def atoi(s):
num = 0
for v in s:
t = "%s * 1" % v
n = eval(t)
num = num * 10 + n
return num
方法四: 结合方法二,使用 reduce ,一行解决
from functools import reduce
def atoi(s):
return reduce(lambda num, v: num * 10 + ord(v) - ord('0'), s, 0)
29.Given an array of integers
给定一个整数数组和一个目标值,找出数组中和为目标值的两个数。你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用。
实例:
给定nums = [2,7,11,15],target=9 因为nums[0]+nums[1] =2+7 =9,所以返回[0,1]
class Solution:
def twoSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
d = {}
size = 0
while size < len(nums):
if target - nums[size] in d:
if d[target - nums[size]] < size:
return [d[target - nums[size]], size]
else:
d[nums[size]] = size
size = size + 1
solution = Solution()
list = [2, 7, 11, 15]
target = 9
nums = solution.twoSum(list, target)
print(nums)
class Solution(object):
def twoSum(self, nums, target):
for i in range(len(nums)):
num = target - nums[i]
if num in nums[i + 1:]:
return [i, nums.index(num, i + 1)]
给列表中的字典排序,假设有如下list对象:
alist=[{“name”:“a”,“age”:20},{“name”:“b”,“age”:30},{“name”:“c”,“age”:25}],将alist中的元素按照age从大到小排序 alist=[{“name”:“a”,“age”:20},{“name”:“b”,“age”:30},{“name”:“c”,“age”:25}]
alist_sort = sorted(alist,key=lambda e: e.__getitem__('age'),reverse=True)
30.python代码实现删除一个list里面的重复元素
def distFunc1(a):
"""使用集合去重"""
a = list(set(a))
print(a)
def distFunc2(a):
"""将一个列表的数据取出放到另一个列表中,中间作判断"""
list = []
for i in a:
if i not in list:
list.append(i)
# 如果需要排序的话用sort
list.sort()
print(list)
def distFunc3(a):
"""使用字典"""
b = {}
b = b.fromkeys(a)
c = list(b.keys())
print(c)
if __name__ == "__main__":
a = [1, 2, 4, 2, 4, 5, 7, 10, 5, 5, 7, 8, 9, 0, 3]
distFunc1(a)
distFunc2(a)
distFunc3(a)
31.统计一个文本中单词频次最高的10个单词?
# 方法一
def test(filepath):
distone = {}
with open(filepath) as f:
for line in f:
line = re.sub("\W+", " ", line)
lineone = line.split()
for keyone in lineone:
if not distone.get(keyone):
distone[keyone] = 1
else:
distone[keyone] += 1
num_ten = sorted(distone.items(), key=lambda x: x[1], reverse=True)[:10]
num_ten = [x[0] for x in num_ten]
return num_ten
# 方法二
# 使用 built-in 的 Counter 里面的 most_common
import re
from collections import Counter
def test2(filepath):
with open(filepath) as f:
return list(map(lambda c: c[0], Counter(re.sub("\W+", " ", f.read()).split()).most_common(10)))
32.请写出一个函数满足以下条件
该函数的输入是一个仅包含数字的list,输出一个新的list,其中每一个元素要满足以下条件:
1、该元素是偶数
2、该元素在原list中是在偶数的位置(index是偶数)
def num_list(num):
return [i for i in num if i % 2 == 0 and num.index(i) % 2 == 0]
num = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
result = num_list(num)
print(result)
33.使用单一的列表生成式来产生一个新的列表
该列表只包含满足以下条件的值,元素为原始列表中偶数切片
list_data = [1,2,5,8,10,3,18,6,20]
res = [x for x in list_data[::2] if x %2 ==0]
print(res)
34.用一行代码生成[1,4,9,16,25,36,49,64,81,100]
[x * x for x in range(1,11)]
35.输入某年某月某日,判断这一天是这一年的第几天?
import datetime
y = int(input("请输入4位数字的年份:"))
m = int(input("请输入月份:"))
d = int(input("请输入是哪一天"))
targetDay = datetime.date(y,m,d)
dayCount = targetDay - datetime.date(targetDay.year -1,12,31)
print("%s是 %s年的第%s天。"%(targetDay,y,dayCount.days))
36.两个有序列表,l1,l2,对这两个列表进行合并不可使用extend
def loop_merge_sort(l1, l2):
tmp = []
while len(l1) > 0 and len(l2) > 0:
if l1[0] < l2[0]:
tmp.append(l1[0])
del l1[0]
else:
tmp.append(l2[0])
del l2[0]
while len(l1)>0:
tmp.append(l1[0])
del l1[0]
while len(l2)>0:
tmp.append(l2[0])
del l2[0]
return tmp
37.给定一个任意长度数组,实现一个函数
让所有奇数都在偶数前面,而且奇数升序排列,偶数降序排序,如字符串’1982376455’,变
成’1355798642’
# 方法一
def func1(l):
if isinstance(l, str):
l = [int(i) for i in l]
l.sort(reverse=True)
for i in range(len(l)):
if l[i] % 2 > 0:
l.insert(0, l.pop(i))
print(''.join(str(e) for e in l))
# 方法二
def func2(l):
print("".join(sorted(l, key=lambda x: int(x) % 2 == 0 and 20 - int(x) or int(x))))
38.写一个函数找出一个整数数组中,第二大的数
def find_second_large_num(num_list):
"""
找出数组第2大的数字
"""
# 方法一
# 直接排序,输出倒数第二个数即可
tmp_list = sorted(num_list)
print("方法一\nSecond_large_num is :", tmp_list[-2])
# 方法二
# 设置两个标志位一个存储最大数一个存储次大数
# two 存储次大值,one 存储最大值,遍历一次数组即可,先判断是否大于 one,若大于将 one 的值给 two,将 num_list[i] 的值给 one,否则比较是否大于two,若大于直接将 num_list[i] 的值给two,否则pass
one = num_list[0]
two = num_list[0]
for i in range(1, len(num_list)):
if num_list[i] > one:
two = one
one = num_list[i]
elif num_list[i] > two:
two = num_list[i]
print("方法二\nSecond_large_num is :", two)
# 方法三
# 用 reduce 与逻辑符号 (and, or)
# 基本思路与方法二一样,但是不需要用 if 进行判断。
from functools import reduce
num = reduce(lambda ot, x: ot[1] < x and (ot[1], x) or ot[0] < x and (x, ot[1]) or ot, num_list, (0, 0))[0]
print("方法三\nSecond_large_num is :", num)
if __name__ == '__main___':
num_list = [34, 11, 23, 56, 78, 0, 9, 12, 3, 7, 5]
find_second_large_num(num_list)
39.阅读一下代码他们的输出结果是什么?
def multi():
return [lambda x : i*x for i in range(4)]
print([m(3) for m in multi()])
正确答案是[9,9,9,9],而不是[0,3,6,9]产生的原因是Python的闭包的后期绑定导致的,这意味着在闭包中的变量是在内部函数被调用的时候被查找的,因为,最后函数被调用的时候,for循环已经完成, i 的值最后是3,因此每一个返回值的i都是3,所以最后的结果是[9,9,9,9]
40.统计一段字符串中字符出现的次数
# 方法一
def count_str(str_data):
"""定义一个字符出现次数的函数"""
dict_str = {}
for i in str_data:
dict_str[i] = dict_str.get(i, 0) + 1
return dict_str
dict_str = count_str("AAABBCCAC")
str_count_data = ""
for k, v in dict_str.items():
str_count_data += k + str(v)
print(str_count_data)
# 方法二
from collections import Counter
print("".join(map(lambda x: x[0] + str(x[1]),
Counter("AAABBCCAC").most_common())))
41.super函数的具体用法和场景
https://python3cookbook.readthedocs.io/zh_CN/latest/c08/p07_calling_method_on_parent_class.html
二、Python高级
元类
42.Python中类方法、类实例方法、静态方法有何区别?
类方法: 是类对象的方法,在定义时需要在上方使用 @classmethod 进行装饰,形参为cls,表示类对象,类对象和实例对象都可调用
类实例方法: 是类实例化对象的方法,只有实例对象可以调用,形参为self,指代对象本身;
静态方法: 是一个任意函数,在其上方使用 @staticmethod 进行装饰,可以用对象直接调用,静态方法
实际上跟该类没有太大关系
43.遍历一个object的所有属性,并print每一个属性名?
class Car:
def __init__(self, name, loss): # loss [价格,油耗,公里数]
self.name = name
self.loss = loss
def getName(self):
return self.name
def getPrice(self):
# 获取汽车价格
return self.loss[0]
def getLoss(self):
# 获取汽车损耗值
return self.loss[1] * self.loss[2]
Bmw = Car("宝马", [60, 9, 500]) # 实例化一个宝马车对象
print(getattr(Bmw, "name")) # 使用getattr()传入对象名字,属性值。
print(dir(Bmw)) # 获Bmw所有的属性和方法
44.写一个类,并让它尽可能多的支持操作符?
class Array:
__list = []
def __init__(self):
print("constructor")
def __del__(self):
print("destruct")
def __str__(self):
return "this self-defined array class"
def __getitem__(self, key):
return self.__list[key]
def __len__(self):
return len(self.__list)
def Add(self, value):
self.__list.append(value)
def Remove(self, index):
del self.__list[index]
def DisplayItems(self):
print("show all items---")
for item in self.__list:
print(item)
45.介绍Cython,Pypy Cpython Numba各有什么缺点
Cython
46.请描述抽象类和接口类的区别和联系
1.抽象类: 规定了一系列的方法,并规定了必须由继承类实现的方法。由于有抽象方法的存在,所以抽象类不能实例化。可以将抽象类理解为毛坯房,门窗,墙面的样式由你自己来定,所以抽象类与作为基类的普通类的区别在于约束性更强
2.接口类:与抽象类很相似,表现在接口中定义的方法,必须由引用类实现,但他与抽象类的根本区别在于用途:与不同个体间沟通的规则,你要进宿舍需要有钥匙,这个钥匙就是你与宿舍的接口,你的舍友也有这个接口,所以他也能进入宿舍,你用手机通话,那么手机就是你与他人交流的接口
3.区别和关联:
1.接口是抽象类的变体,接口中所有的方法都是抽象的,而抽象类中可以有非抽象方法,抽象类是声明
方法的存在而不去实现它的类
2.接口可以继承,抽象类不行
3.接口定义方法,没有实现的代码,而抽象类可以实现部分方法
4.接口中基本数据类型为static而抽象类不是
47.Python中如何动态获取和设置对象的属性?
if hasattr(Parent, 'x'):
print(getattr(Parent, 'x'))
setattr(Parent, 'x',3)
print(getattr(Parent,'x'))
三、内存管理与垃圾回收机制
1、Python内存溢出原因
1、内存中加载的数据量过于庞大,如一次从数据库取出过多数据; 一般比如数据查询未做分页处理。
2、集合类中有对对象的引用,使用完后未清空,使得JVM不能回收。
3、代码中存在死循环或循环产生过多重复的对象实体。
4、使用的第三方软件中的BUG; 一般引用第三方jar包过多会出现此类问题。
5、启动参数内存值设定的过小 这种可能性很小服务器参数设置一般会出现这类问题毕竟都是开发。
2、Python内存溢出的解决方案
第一步:修改JVM启动参数,直接堆内存( -Xms,-Xmx参数一定不要忘记加 )。
第二步:检查错误日志,查看“OutOfMemory”错误前是否有其 它异常或错误。
第三步:对代码进行走查和分析,找出可能发生内存溢出的位置。
49.关于Python内存管理,下列说法错误的是 B
A:变量不必事先声明
B:变量无须先创建和赋值而直接使用
C:变量无须指定类型
D:可以使用del释放资源
50.Python的内存管理机制及调优手段?
内存管理机制: 引用计数、垃圾回收、内存池
引用计数:引用计数是一种非常高效的内存管理手段,当一个Python对象被引用时其引用计数增加1,当其不再被一个变量引用时则计数减1,当引用计数等于0时对象被删除。弱引用不会增加引用计数
垃圾回收:
1、引用计数
引用计数也是一种垃圾收集机制,而且也是一种最直观、最简单的垃圾收集技术。当Python的某个对象
的引用计数降为0时,说明没有任何引用指向该对象,该对象就成为要被回收的垃圾了。比如某个新建
对象,它被分配给某个引用,对象的引用计数变为1,如果引用被删除,对象的引用计数为0,那么该对
象就可以被垃圾回收。不过如果出现循环引用的话,引用计数机制就不再起有效的作用了。
2、标记清除
https://foofish.net/python-gc.html
调优手段:1.手动垃圾回收 2.调高垃圾回收阈值 3.避免循环引用
51.内存泄露是什么?如何避免?
内存泄漏指由于疏忽或错误造成程序未能释放已经不再使用的内存。内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,导致在释放该段内存之前就失去了对该段内存的控
制,从而造成了内存的浪费。
有 del() 函数的对象间的循环引用是导致内存泄露的主凶。不使用一个对象时使用: del object 来
删除一个对象的引用计数就可以有效防止内存泄露问题。
通过Python扩展模块gc 来查看不能回收的对象的详细信息。
可以通过 sys.getrefcount(obj) 来获取对象的引用计数,并根据返回值是否为0来判断是否内存泄露
四、函数
52.python常见的列表推导式?
[表达式 for 变量 in 列表] 或者 [表达式 for 变量 in 列表 if 条件]
53.简述read、readline、readlines的区别?
read 读取整个文件
readline 读取下一行
readlines 读取整个文件到一个迭代器以供我们遍历
54.什么是Hash(散列函数)?
散列函数(英语:Hash function)又称散列算法、哈希函数,是一种从任何一种数据中创建小的数字“指纹”的方法。散列函数把消息或数据压缩成摘要,使得数据量变小,将数据的格式固定下来。该函数将数据打乱混合,重新创建一个叫做散列值(hash values,hash codes,hash sums,或hashes)的指纹。散列值通常用一个短的随机字母和数字组成的字符串来代表
55.python函数重载机制?
函数重载主要是为了解决两个问题。
1、可变参数类型
2、可变参数个数
另外,一个基本的设计原则是,仅仅当两个函数除了参数类型和参数个数不同以外,其功能是完全相同的,此时才使用函数重载,如果两个函数的功能其实不同,那么不应当使用重载,而应当使用一个名字
不同的函数。
好吧,那么对于情况 1 ,函数功能相同,但是参数类型不同,python 如何处理?答案是根本不需要处
理,因为 python 可以接受任何类型的参数,如果函数的功能相同,那么不同的参数类型在 python 中很可能是相同的代码,没有必要做成两个不同函数。
那么对于情况 2 ,函数功能相同,但参数个数不同,python 如何处理?大家知道,答案就是缺省参数。对那些缺少的参数设定为缺省参数即可解决问题。因为你假设函数功能相同,那么那些缺少的参数
终归是需要用的。
好了,鉴于情况 1 跟 情况 2 都有了解决方案,python 自然就不需要函数重载了。
56.手写一个判断时间的装饰器
import datetime
class TimeException(Exception):
def __init__(self, exception_info):
super().__init__()
self.info = exception_info
def __str__(self):
return self.info
def timecheck(func):
def wrapper(*args, **kwargs):
if datetime.datetime.now().year == 2019:
func(*args, **kwargs)
else:
raise TimeException("函数已过时")
return wrapper
@timecheck
def test(name):
print("Hello {}, 2019 Happy".format(name))
if __name__ == "__main__":
test("backbp")
57.写一个函数找出一个整数数组中,第二大的数
已知numpy函数库中max和argmax函数可以得出一个数组中最大的成员以及所在位置:
import numpy as np
arr = [2, 3, 4, 1, 7, 6, 5]
print("# arr中最大的数为{},位于第{}位".format(np.max(arr), np.argmax(arr)+1))
那么如何得到一个数组中第二大的成员呢?
我的思想是:将原数组中最大的成员换为最小的成员,然后再用max和argmax。
arr_ = arr
arr_[np.argmax(arr_)] = np.min(arr)
print(arr_)
print("# arr中最大的数为{},位于第{}位".format(np.max(arr_), np.argmax(arr_)+1))
宽展到第n大的数:
def find_sub_max(arr, n):
for i in range(n-1):
arr_ = arr
arr_[np.argmax(arr_)] = np.min(arr)
arr = arr_
print("# arr中最大的数为{},位于第{}位".format(np.max(arr_), np.argmax(arr_)+1))
find_sub_max(arr, 4)
58.使用Python内置的filter()方法来过滤?
list(filter(lambda x: x % 2 == 0, range(10)))
59.编写函数的4个原则
1.函数设计要尽量短小
2.函数声明要做到合理、简单、易于使用
3.函数参数设计应该考虑向下兼容
4.一个函数只做一件事情,尽量保证函数语句粒度的一致性
60.函数调用参数的传递方式是值传递还是引用传递?
Python的参数传递有:位置参数、默认参数、可变参数、关键字参数。
函数的传值到底是值传递还是引用传递、要分情况:
1、不可变参数用值传递:像整数和字符串这样的不可变对象,是通过拷贝进行传递的,因为你无论如何都不可能在原处改变不可变对象。
2、可变参数是引用传递:比如像列表,字典这样的对象是通过引用传递、和C语言里面的用指针传递数组很相似,可变对象能在函数内部改变。
61.如何在function里面设置一个全局变量
globals() # 返回包含当前作用余全局变量的字典。
global 变量 设置使用全局变量
62.对缺省参数的理解?
缺省参数指在调用函数的时候没有传入参数的情况下,调用默认的参数,在调用函数的同时赋值时,所传入的参数会替代默认参数。
*args 是不定长参数,它可以表示输入参数是不确定的,可以是任意多个。
**kwargs 是关键字参数,赋值的时候是以键值对的方式,参数可以是任意多对在定义函数的时候不确定会有多少参数会传入时,就可以使用两个参数
63.带参数的装饰器?
带定长参数的装饰器
def new_func(func):
def wrappedfun(username, passwd):
if username == 'root' and passwd == '123456789':
print('通过认证')
print('开始执行附加功能')
return func()
else:
print('用户名或密码错误')
return
return wrappedfun
@new_func
def origin():
print('开始执行函数')
origin('root', '123456789')
带不定长参数的装饰器
def new_func(func):
def wrappedfun(*parts):
if parts:
counts = len(parts)
print('本系统包含 ', end='')
for part in parts:
print(part, ' ', end='')
print('等', counts, '部分')
return func()
else:
print('用户名或密码错误')
return func()
return wrappedfun
65.为什么函数名字可以当做参数用?
Python中一切皆对象,函数名是函数在内存中的空间,也是一个对象
66.Python中pass语句的作用是什么?
在编写代码时只写框架思路,具体实现还未编写就可以用pass进行占位,是程序不报错,不会进行任何
操作。
67.有这样一段代码,print c会输出什么,为什么?
a = 10
b = 20
c = [a]
a = 15
答:10对于字符串,数字,传递是相应的值
68.交换两个变量的值?
a, b = b, a
69.map函数和reduce函数?
map(lambda x: x * x, [1, 2, 3, 4]) # 使用 lambda
# [1, 4, 9, 16]
reduce(lambda x, y: x * y, [1, 2, 3, 4]) # 相当于 ((1 * 2) * 3) * 4
# 24
70.回调函数,如何通信的?
回调函数是把函数的指针(地址)作为参数传递给另一个函数,将整个函数当作一个对象,赋值给调用的函数。
71.Python主要的内置数据类型都有哪些? print dir( ‘a ’) 的输出?
内建类型:布尔类型,数字,字符串,列表,元组,字典,集合
输出字符串’a’的内建方法
72.map(lambda x:xx,[y for y in range(3)])的输出?
[0, 1, 4]
73.hasattr() getattr() setattr() 函数使用详解?
hasattr(object,name)函数:
判断一个对象里面是否有name属性或者name方法,返回bool值,有name属性(方法)返回True,否则返回False。
class function_demo(object):
name = 'demo'
def run(self):
return "hello function"
functiondemo = function_demo()
res = hasattr(functiondemo, "name") # 判断对象是否有name属性,True
res = hasattr(functiondemo, "run") # 判断对象是否有run方法,True
res = hasattr(functiondemo, "age") # 判断对象是否有age属性,False
print(res)
getattr(object, name[,default])函数:
获取对象object的属性或者方法,如果存在则打印出来,如果不存在,打印默认值,默认值可选。
注意:如果返回的是对象的方法,则打印结果是:方法的内存地址,如果需要运行这个方法,可以在后面添加括号()
functiondemo = function_demo()
getattr(functiondemo, "name")# 获取name属性,存在就打印出来 --- demo
getattr(functiondemo, "run") # 获取run 方法,存在打印出方法的内存地址
getattr(functiondemo, "age") # 获取不存在的属性,报错
getattr(functiondemo, "age", 18)# 获取不存在的属性,返回一个默认值
setattr(object, name, values)函数:
给对象的属性赋值,若属性不存在,先创建再赋值
class function_demo(object):
name = "demo"
def run(self):
return "hello function"
functiondemo = function_demo()
res = hasattr(functiondemo, "age") # 判断age属性是否存在,False
print(res)
setattr(functiondemo, "age", 18) # 对age属性进行赋值,无返回值
res1 = hasattr(functiondemo, "age") # 再次判断属性是否存在,True
综合使用
class function_demo(object):
name = "demo"
def run(self):
return "hello function"
functiondemo = function_demo()
res = hasattr(functiondemo, "addr") # 先判断是否存在
if res:
addr = getattr(functiondemo, "addr")
print(addr)
else:
addr = getattr(functiondemo, "addr", setattr(functiondemo, "addr", "北京首都"))
print(addr)
74.一句话解决阶乘函数?
reduce(lambda x,y : x*y,range(1,n+1))
75.什么是lambda函数? 有什么好处?
lambda 函数是一个可以接收任意多个参数(包括可选参数)并且返回单个表达式值的函数
1、lambda函数比较轻便,即用即仍,很适合需要完成一项功能,但是此功能只在此一处使用,连名字都很随意的情况下
2、匿名函数,一般用来给filter,map这样的函数式编程服务
3、作为回调函数,传递给某些应用,比如消息处理
76.递归函数停止的条件?
1、递归的终止条件一般定义在递归函数内部,在递归调用前要做一个条件判断,根据判断的结果选择是继续调用自身,还是return,返回终止递归。
终止的条件:判断递归的次数是否达到某一限定值
2、判断运算的结果是否达到某个范围等,根据设计的目的来选择