菜鸟去面试之三

Author:闫玉良

受疫情影响,让互联网的寒冬更加寒冷,金三银四也凄凄惨惨戚戚。但在这几个月小闫发现,虽然初中级工程师岗位变少,但是高级工程师岗位却依然火爆,丝毫不受影响。让小闫不经想起大四实习时,总经理曾说「社会缺少的并不是人,而是人才。如何提升自己的核心竞争力才是破局之道,强者从不受寒冬影响」当然原话已经记不清,大概就是这么个意思,你懂的 ~

言归正传,今天为大家再带来一些面试题,祝大家事随人愿。

更多精彩文章请关注公众号『Pythonnote』或者『全栈技术精选』

1.通过装饰器装饰的函数如何不改变其自身相关信息

答:可以使用模块 functools 中的 wraps 装饰器来装饰自定义装饰器的内函数。(有点绕口,下面查看示例)正常情况下被装饰的函数,虽然可以使用原函数名进行调用,但实际上此时的函数名指向了装饰器的内函数,可以通过打印 __name__ 以及 __doc__ 属性来验证。使用 wraps 后,被装饰的函数相关信息就会全部保留。

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
from functools import wraps  # <-- 导入模块


# 定义一个装饰器
def eg_decorator(func):
@wraps(func) # <-- 使用装饰器
def wrapper(*args, **kwds):
"""内函数"""
print('我是装饰器啊...')
return func(*args, **kwds)
return wrapper


# 使用定义的装饰器装饰函数
@eg_decorator
def noname():
"""
函数自身
:return: 无返回
"""
print('我是示例函数噻...')


# 调用函数
noname()
# 打印函数的 __name__ 属性
print(noname.__name__)
# 打印函数的文档字符串
print(noname.__doc__)

然后查看输出结果进行验证:

1
2
3
4
5
6
7

我是装饰器啊...
我是示例函数噻...
noname

函数自身
:return: 无返回

2.手写一个类,可以连接 redis 并实现 get 和 set 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import redis


class RedisTest(object):
def __init__(self, ip: str, port: int):
self.conn = redis.Redis(host=ip, port=port, decode_responses=False)

def get(self, key: str) -> str:
return self.conn.get(key)

def set(self, key, value):
self.conn.set(key, value)


redis_obj = RedisTest('127.0.0.1', 6379)
redis_obj.set('name', 'ethanyan')
name = redis_obj.get('name')
print(name) # b'ethanyan'

3.elasticsearch 二次查询

答:elasticsearch 中可以通过 terms lookup (跨索引查询)实现二次查询。例如查询某个用户关注列表中所有用户发表的主帖,如果是拆开查询,需要两步:先查出关注列表,再查询发表的主帖。而使用 terms lookup 查询只需要一步即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
POST my-index-post/_search
{
"query": {
"bool": {
"must": [
{
"terms": {
"user_item_id": {
"index": "my-index-user",
"type": "user",
"id": "0f42d65be1f5287e1c9c26e3728814aa",
"path": "friends"
}
}
}
]
}
}
}

此示例来源于 https://www.playpi.org/2019060601.html

分析一下上面的 DSL 语句,它先利用 id 查询用户索引my-index-user/user,返回关注列表 friends 中的所有 item_id;然后利用上一步骤中返回的 itemt_id 列表,去匹配主帖的 user_item_id 字段,从而查询所有的主帖。

4.语法糖 property

答:python 中提供了一个装饰器 property ,在使用对象的私有属性时,可以不再使用属性的函数的调用方式,而像普通的公有属性一样去使用属性。简单进行举例,假设一个类中有一些私有属性,我们可以通过 set/get 方法,专门来为这些私有属性提供访问接口以及设置属性时的校验操作,增加程序的健壮性和安全性,但这样操作后接口调用比较繁琐,使用装饰器 property 后,再去设置或访问私有属性时,如同正常公有属性一样实现无感操作。

如果需要设计一个「银行账户类」,只需提供姓名和余额的访问与设置操作即可。首先看一下传统的 set/get 方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Account(object):
def __init__(self, name, money):
# 为了安全性考虑,不能向外部直接暴露私密信息
self.__name = name # 帐户人姓名
self.__balance = money # 帐户余额

def get_name(self):
return self.__name

def set_balance(self, money):
if isinstance(money, int):
if money >= 0:
self.__balance = money
else:
raise ValueError('输入的金额不正确')
else:
raise ValueError('输入的金额不是数字')

def get_balance(self):
return self.__balance

如果需要设置账户的余额,就需要调用方法 set_balance,而使用装饰器后,则大大进行了简化:

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
31
32
33
class Account(object):
def __init__(self, name, money):
self.__name = name # 帐户人姓名
self.__balance = money # 帐户余额

# property 只能对获取方法装饰,并且获取方法不需要再写 get
@property
def name(self):
return self.__name

# 如果 property 装饰的属性还有 set 方法,需要写到 get方法后定义
@property
def balance(self):
return self.__balance

# 实现 set 方法, 格式: @xxx.setter ,xxx 要和property装饰的方法名一致
@balance.setter
def balance(self, money):
if isinstance(money, int):
if money >= 0:
self.__balance = money
else:
raise ValueError('输入的金额不正确')
else:
raise ValueError('输入的金额不是数字')


# 可以像共有属性一样进行访问与设置
ac = Account('tom', 10)
print(ac.name)
print(ac.balance)
ac.balance = 1000
print(ac.balance)

5.简单介绍一下 with 语句

答:with 语句是一种简化的语法,适用于对资源进行访问的场合,确保不管使用过程中是否发生异常都会执行必要的「清理」操作,释放资源。比如在连接数据库并进行相关操作后可以自动关闭,无需手动调用。其原理为自动调用了上下文管理器中的关闭语句,内部主要有两个方法构成 __enter____exit____enter__ 方法会在执行 with 后面的语句时执行,一般用来处理操作前的内容。比如一些创建对象,初始化等。__exit__ 方法会在 with 内的代码执行完毕后执行,一般用来处理一些善后收尾工作,比如文件的关闭,数据库的关闭等。

更多精彩文章请关注公众号『Pythonnote』或者『全栈技术精选』

打赏
  • 版权声明: 本博客所有文章除特别声明外,均采用 Apache License 2.0 许可协议。转载请注明出处!

扫一扫,分享到微信

微信分享二维码
  • 页面访问量: 独立访客访问数:
  • 更多精彩文章请关注微信公众号『全栈技术精选』,id 为『Pythonnote』

请我喝杯咖啡吧~

支付宝
微信