Python技术迷

互联网公司舒适度排行榜

刚看到个贴子,是关于互联网公司舒适度排行榜的。作为程序员,我第一反应就是:所谓“舒适度”,其实包含了加班强度、办公氛围、薪资福利和个人成长空间这几块。

Image

网友们有人觉得大厂福利好,健身房、三餐、假期都安排得明明白白,但问题是加班文化太重,舒适度往往打折。也有人说中小厂更自在,没那么多制度约束,但随时面临不确定性,甚至一轮融资失败就得收拾东西走人。

从我的角度看,舒适度不能只看“舒服不舒服”,还要看你处在哪个阶段。年轻时拼成长,可能接受996换经验;到了一定阶段,就会更看重节奏和生活平衡。换句话说,“最舒适”的公司不是排行榜上的名字,而是能和你当下目标匹配的地方。【备注:文末可领最新资料】

面试题:无穷方法对象

昨晚十一点多在公司楼下吹风,手机一震,我们组小李问我“东哥,能不能做个对象,随便点啥方法都能用?”我困得眼冒金星,但这玩意儿我还真折腾过,嗯…有点意思,分享下我当时怎么糊的,别太较真哈。

就是那个…“无穷方法对象”,你可以理解成:不管你点 .a.b.c() 还是 .foo(1).bar(x=2),它都不报错,还能把你点过的“路径”记下来,然后统一处理。像调远程接口、拼URL、做DSL(领域小语言)都特顺手。你们想啊,api.users(42).posts.list(page=1) 这种链式,读起来像句子,对吧。

我先给个不太丑的写法,名字…就叫 AnyCall 吧,等等我喝口水…好继续:

classAnyCall:
def__init__(self, path=(), handler=None, cache=None):
        self._path = path
        self._handler = handler or self._default_handler
        self._cache = cache if cache isnotNoneelse {}

def__getattr__(self, name):
# 缓存一下,少创建对象
        key = self._path + (("attr", name),)
if key notin self._cache:
            self._cache[key] = AnyCall(key, self._handler, self._cache)
return self._cache[key]

def__getitem__(self, key):
# 支持 api.users[42] 这种
        k = self._path + (("item", key),)
if k notin self._cache:
            self._cache[k] = AnyCall(k, self._handler, self._cache)
return self._cache[k]

def__call__(self, *args, **kwargs):
# 每次调用都把形参也记录下来
        call_path = self._path + (("call", args, tuple(sorted(kwargs.items()))),)
return self._handler(call_path)

def_default_handler(self, call_path):
# 这里随便定义你的落地逻辑,比如拼URL、发请求、生成SQL
# 先演示一下把路径转成可读字符串
        parts = []
for seg in call_path:
            t = seg[0]
if t == "attr":
                parts.append(f".{seg[1]}")
elif t == "item":
                parts.append(f"[{seg[1]!r}]")
elif t == "call":
                a, kw = seg[1], dict(seg[2])
                parts.append(f"({', '.join(map(repr, a))}{', 'if a and kw else''}" +
f"{', '.join(f'{k}={v!r}'for k,v in kw.items())})")
return"AnyCall" + "".join(parts)

# 用法示例
api = AnyCall()
print(api.users[42].posts.list(page=1))
print(api.files.upload("a.txt").to.bucket("logs").put(overwrite=True))

跑出来会打印类似:

AnyCall.users[42].posts.list(page=1)
AnyCall.files.upload('a.txt').to.bucket('logs').put(overwrite=True)

意思是啥?就是整条调用链被“录”下来了,你可以把 _default_handler 换成真实逻辑,比如把 .users[42].posts.list(page=1) 映射到 /users/42/posts/list?page=1,再 requests.get 一下。有人问了,那个接口叫什么来着…哦对是 API,别笑。

其一,IDE 提示会基本没了,因为方法名都是动态的,自动补全就呵呵了;可以给常用节点包几层“壳”,比如写个 class API(AnyCall): pass,再放一些真实属性。其二,拼链子很爽但容错难,打错 .posst 这种,代码不报错却发了假请求,所以最好在 handler 里加白名单或 schema 校验。其三,频繁分配对象会抖(你懂的),我上面用 _cache 简单做了去重,长链还能复用节点。其四,线程安全,缓存是共享 dict,线上多线程就换成 collections.defaultdict + 锁,或者每线程一份。

如果你想玩更狠的,就在 __call__ 里不直接 return 终值,而是返回新 AnyCall,这样可以“回调再回调”,最后来个 .exec() 统一落地;或者在 __getattr__ 里拦截特定名,比如 .get.post 映射到 HTTP 动词,其他名当路径;再或者加个 .pipe(func),把当前链条吐出去给函数加工,写起来很像流式数据处理。嗯…对了,__getattribute__ 别乱重写,容易把内部属性也吃掉,调不出来你别骂我。

-END-

我为大家打造了一份RPA教程,完全免费:songshuhezi.com/rpa.html

🔥虎哥私藏精品🔥

虎哥作为一名老码农,整理了全网最全《python高级架构师资料合集》,总量高达650GB,点击下方公众号回复关键字 python 全部免费领