一道快速考察 Python 基础的面试题

简介:

一道快速考察 Python 基础的面试题
这是前一阵子群友发在群里的一道面试题,利用 Python 字典的特性,可以巧妙地使用精简代码达成完美解。

题目
将 data 转换成 new_data 这种形式,写出转换过程。

data = {

'a_b_h':1,
'a_b_i':2,
'a_c_j':3,
'a_d':4,
'a_c_k':5,
'a_e':6

}

new_data = {

'a':{
    'b':{
        'h':1,
        'i':2
    },
    'c':{
        'j':3,
        'k':5
    },
    'd':4,
    'e':6
}

}
可以看出,转换的过程是将 key 的下划线进行拆分,然后下划线后边的字符嵌套在前面字符的值中。

感兴趣就打开 IDE,自己先试着解一下。

解题思路
你应该很快想到,主要思路是将下划线 split 后,然后依次使用字符生成内层字典,当达到最后一个字符时将数字作为值。

那么关键点在于,如何不断地获得内层字典去修改呢?实际本题就是考察你是否理解 Python 字典是引用传递这个特性。

什么是引用传递?我们知道 Python 中字典和列表对象都是可变对象,它们的变量传递给另一个变量后,改变对象元素会使得两个变量都会同时改变,比如:

new_data = {}
tmp = {}
new_data['a'] = tmp
print(new_data) # {'a': {}}
tmp['b'] = 1
print(new_data) # {'a': {'b': 1}}
如上,利用这个特性,将内层字典赋值给一个中间变量,然后改变这个中间变量,即可同步修改最终的 new_data 变量。

根据这个思路,初步代码如下:

data = {

'a_b_h':1,
'a_b_i':2,
'a_c_j':3,
'a_d':4,
'a_c_k':5,
'a_e':6

}

new_data = {}

for key, value in data.items():

keys = key.split('_')
tmp = new_data
last = len(keys) - 1  # 最后一个 key 的索引值 
for i, k in enumerate(keys):
    if i == last:
        tmp[k] = value
        continue
    if k not in tmp:
        sub_tmp = {}
        tmp[k] = sub_tmp
        tmp = sub_tmp
    else:
        tmp = tmp[k]

这也是群友给出的第一版答案,这样写并没有多大问题,但是代码比较繁琐,肯定还有优化空间。

我们可以只使用一个中间变量即可,进一步优化:

for field, value in data.items():

keys = field.split('_') 
tmp = new_data 
last = len(keys) - 1
for i, k in enumerate(keys): 
    if k not in tmp:
        tmp[k] = {} if i < last else value
    tmp = tmp[k]  # 将内层 dict 传给 tmp

上面这个代码看似很简洁了,但是仍然还有两个 if 判断,如果不是使用了三元表达式的话,还会更多行。

所以可以进一步优化:

for field, value in data.items():

keys = field.split('_') 
tmp = new_data 
for k in keys[:-1]: 
    tmp = tmp.setdefault(k, {})
tmp[keys[-1]] = value

我们省略掉了 last 来判断最后一个字符的索引,直接通过 keys[:-1] 避开最后一个字符,末尾再单独生成数字键值对。

这里还使用字典的一个内置方法 —— setdefault。

dict.setdefault(key, default=None) 方法和 get 方法类似,只是如果键不存在于字典中,不仅会返回 default 参数的值,还同时会用该值自动生成一个键值对。

if k not in tmp:

tmp[k] = {}

v = tmp[k]

等价于

v = tmp.setdefault(k, {})
最终我们使用了 6 行代码就解出该题,这也是接近最简代码。

如果使用字典引用的特性是合格的话,那么当你用出 setdefault 这个方法后,面试官已经给你打了优秀,所以一定要熟悉这些数据对象的所有内置方法。

本文属于原创,首发于微信公众号「面向人生编程」,如需转载请后台留言。

原文地址https://my.oschina.net/u/4234347/blog/3164258

相关文章
|
4月前
|
NoSQL 数据库 Redis
万字长文Python面试题,找工作就靠这了
万字长文Python面试题,找工作就靠这了
551 0
|
16小时前
|
调度 Python
Python多线程、多进程与协程面试题解析
【4月更文挑战第14天】Python并发编程涉及多线程、多进程和协程。面试中,对这些概念的理解和应用是评估候选人的重要标准。本文介绍了它们的基础知识、常见问题和应对策略。多线程在同一进程中并发执行,多进程通过进程间通信实现并发,协程则使用`asyncio`进行轻量级线程控制。面试常遇到的问题包括并发并行混淆、GIL影响多线程性能、进程间通信不当和协程异步IO理解不清。要掌握并发模型,需明确其适用场景,理解GIL、进程间通信和协程调度机制。
6 0
|
15小时前
|
API Python
Python模块化编程:面试题深度解析
【4月更文挑战第14天】了解Python模块化编程对于构建大型项目至关重要,它涉及代码组织、复用和维护。本文深入探讨了模块、包、导入机制、命名空间和作用域等基础概念,并列举了面试中常见的模块导入混乱、不适当星号导入等问题,强调了避免循环依赖、合理使用`__init__.py`以及理解模块作用域的重要性。掌握这些知识将有助于在面试中自信应对模块化编程的相关挑战。
5 0
|
16小时前
|
UED Python
掌握Python异常处理:面试中的关键考点
【4月更文挑战第14天】本文探讨了Python异常处理在面试中的重要性,涵盖核心概念、常见问题和易错点。异常处理涉及异常、捕获、异常链、自定义异常、finally子句和raise语句。面试中应注意避免过于宽泛的异常捕获、忽视异常链、在finally中误用return、自定义异常设计不实用以及异常处理与业务逻辑混杂等问题。通过理解并解决这些问题,可提升代码健壮性和面试表现。
6 0
|
1月前
|
Unix Java C++
最常见的 35 个 Python 面试题及答案(2018 版)
最常见的 35 个 Python 面试题及答案(2018 版)
51 0
|
1月前
|
存储 机器学习/深度学习 算法
python常用算法,新手必会,面试必出
python常用算法,新手必会,面试必出
36 0
|
3月前
|
存储 算法 Java
Python编程面试题及答案(20例)
Python编程面试题及答案(20例)
21 1
|
3月前
|
机器学习/深度学习 存储 人工智能
50道必备的Python面试题 (建议点赞)
50道必备的Python面试题 (建议点赞)
136 0
|
4月前
|
NoSQL 数据库 Redis
精心整理170道Python面试题,建议先收藏
精心整理170道Python面试题,建议先收藏
252 1
|
4月前
|
NoSQL 数据库 Redis
万字长文Python面试题,年后找工作就靠这了
万字长文Python面试题,年后找工作就靠这了
211 0

热门文章

最新文章