


转自:https://mp.weixin.qq.com/s/2-fUJQeFV7Q1VS_4e78G_A
分享个人经验,保留阅读记录,做时间的朋友
转自:https://mp.weixin.qq.com/s/2-fUJQeFV7Q1VS_4e78G_A
【黑话连篇】
该栏目更多的是揭露事件或对事件的看法,以达到让人精神升华的目的。
转自:https://mp.weixin.qq.com/s/PIv18LskgRKXNqt2chPbQg
对于每个程序开发者来说,调试几乎是必备技能。
代码写到一半卡住了,不知道这个函数执行完的返回结果是怎样的?调试一下看看
代码运行到一半报错了,什么情况?怎么跟预期的不一样?调试一下看看
调试的方法多种多样,不同的调试方法适合不同的场景和人群。
如果你是刚接触编程的小萌新,对很多工具的使用还不是很熟练,那么 print 和 log 大法好
如果你在本地(Win或者Mac)电脑上开发,那么 IDE 的图形化界面调试无疑是最适合的;
如果你在服务器上排查BUG,那么使用 PDB 进行无图形界面的调试应该是首选,详情请戳明哥之前的文章:让代码调试不再难 – pdb
如果你要在本地进行开发,但是项目的进行需要依赖复杂的服务器环境,那么可以了解下 PyCharm 的远程调试,详情请戳明哥之前的文章:不能不会的远程调试技巧
除了以上,今天明哥再给你介绍一款非常好用的调试工具,它能在一些场景下,大幅度提高调试的效率, 那就是 PySnooper
,它在 Github 上已经收到了 13k 的 star,获得大家的一致好评。
有了这个工具后,就算是小萌新也可以直接无门槛上手,从此与 print 说再见~
执行下面这些命令进行安装 PySnooper
$ python3 -m pip install pysnooper
# 或者
$ conda install -c conda-forge pysnooper
# 或者
$ yay -S python-pysnooper
下面这段代码,定义了一个 demo_func 的函数,在里面生成一个 profile 的字典变量,然后去更新它,最后返回。
代码本身没有什么实际意义,但是用来演示 PySnooper 已经足够。
import pysnooper
@pysnooper.snoop()
def demo_func():
profile = {}
profile["name"] = "写代码的明哥"
profile["age"] = 27
profile["gender"] = "male"
return profile
def main():
profile = demo_func()
main()
现在我使用终端命令行的方式来运行它
[root@iswbm ~]# python3 demo.py
Source path:... demo.py
17:52:49.624943 call 4 def demo_func():
17:52:49.625124 line 5 profile = {}
New var:....... profile = {}
17:52:49.625156 line 6 profile["name"] = "写代码的明哥"
Modified var:.. profile = {'name': '写代码的明哥'}
17:52:49.625207 line 7 profile["age"] = 27
Modified var:.. profile = {'name': '写代码的明哥', 'age': 27}
17:52:49.625254 line 8 profile["gender"] = "male"
Modified var:.. profile = {'name': '写代码的明哥', 'age': 27, 'gender': 'male'}
17:52:49.625306 line 10 return profile
17:52:49.625344 return 10 return profile
Return value:.. {'name': '写代码的明哥', 'age': 27, 'gender': 'male'}
Elapsed time: 00:00:00.000486
可以看到 PySnooper 把函数运行的过程全部记录了下来,包括:
代码的片段、行号等信息,以及每一行代码是何时调用的?
函数内局部变量的值如何变化的?何时新增了变量,何时修改了变量。
函数的返回值是什么?
运行函数消耗了多少时间?
而作为开发者,要得到这些如此详细的调试信息,你需要做的非常简单,只要给你想要调试的函数上带上一顶帽子(装饰器) — @pysnooper.snoop()
即可。
@pysnooper.snoop()
不加任何参数时,会默认将调试的信息输出到标准输出。
对于单次调试就能解决的 BUG ,这样没有什么问题,但是有一些 BUG 只有在特定的场景下才会出现,需要你把程序放在后面跑个一段时间才能复现。
这种情况下,你可以将调试信息重定向输出到某一日志文件中,方便追溯排查。
@pysnooper.snoop(output='/var/log/debug.log')
def demo_func():
...
PySnooper 是以函数为单位进行调试的,它默认只会跟踪函数体内的局部变量,若想跟踪全局变量,可以给 pysnooper.snoop()
加上 watch
参数
out = {"foo": "bar"}
@pysnooper.snoop(watch=('out["foo"]'))
def demo_func():
...
如此一来,PySnooper 会在 out["foo"]
值有变化时,也将其打印出来
watch 参数,接收一个可迭代对象(可以是list 或者 tuple),里面的元素为字符串表达式,什么意思呢?看下面例子就知道了
@pysnooper.snoop(watch=('out["foo"]', 'foo.bar', 'self.foo["bar"]'))
def demo_func():
...
和 watch
相对的,pysnooper.snoop()
还可以接收一个函数 watch_explode
,表示除了这几个参数外的其他所有全局变量都监控。
@pysnooper.snoop(watch_explode=('foo', 'bar'))
def demo_func():
...
当你使用 PySnooper 调试某个函数时,若该函数中还调用了其他函数,PySnooper 是不会傻傻的跟踪进去的。
如果你想继续跟踪该函数中调用的其他函数,可以通过指定 depth
参数来设置跟踪深度(不指定的话默认为 1)。
@pysnooper.snoop(depth=2)
def demo_func():
...
当你在使用 PySnooper 跟踪多个函数时,调试的日志会显得杂乱无章,不方便查看。
在这种情况下,PySnooper 提供了一个参数,方便你为不同的函数设置不同的标志,方便你在查看日志时进行区分。
@pysnooper.snoop(output="/var/log/debug.log", prefix="demo_func: ")
def demo_func():
...
效果如下
默认情况下,PySnooper 输出的变量和异常信息,如果超过 100 个字符,被会截断为 100 个字符。
当然你也可以通过指定参数 进行修改
@pysnooper.snoop(max_variable_length=200)
def demo_func():
...
您也可以使用max_variable_length=None它从不截断它们。
@pysnooper.snoop(max_variable_length=None)
def demo_func():
...
PySnooper 同样支持多线程的调试,通过设置参数 thread_info=True
,它就会在日志中打印出是在哪个线程对变量进行的修改。
@pysnooper.snoop(thread_info=True)
def demo_func():
...
效果如下
pysnooper.snoop()
函数有一个参数是 custom_repr
,它接收一个元组对象。
在这个元组里,你可以指定特定类型的对象以特定格式进行输出。
这边我举个例子。
假如我要跟踪 person 这个 Person 类型的对象,由于它不是常规的 Python 基础类型,PySnooper 是无法正常输出它的信息的。
因此我在 pysnooper.snoop()
函数中设置了 custom_repr
参数,该参数的第一个元素为 Person,第二个元素为 print_persion_obj
函数。
PySnooper 在打印对象的调试信息时,会逐个判断它是否是 Person 类型的对象,若是,就将该对象传入 print_persion_obj
函数中,由该函数来决定如何显示这个对象的信息。
class Person:pass
def print_person_obj(obj):
return f"<Person {obj.name} {obj.age} {obj.gender}>"
@pysnooper.snoop(custom_repr=(Person, print_person_obj))
def demo_func():
...
完整的代码如下
import pysnooper
class Person:pass
def print_person_obj(obj):
return f"<Person {obj.name} {obj.age} {obj.gender}>"
@pysnooper.snoop(custom_repr=(Person, print_person_obj))
def demo_func():
person = Person()
person.name = "写代码的明哥"
person.age = 27
person.gender = "male"
return person
def main():
profile = demo_func()
main()
运行一下,观察一下效果。
如果你要自定义格式输出的有很多个类型,那么 custom_repr
参数的值可以这么写
@pysnooper.snoop(custom_repr=((Person, print_person_obj), (numpy.ndarray, print_ndarray)))
def demo_func():
...
还有一点我提醒一下,元组的第一个元素可以是类型(如类名Person 或者其他基础类型 list等),也可以是一个判断对象类型的函数。
也就是说,下面三种写法是等价的。
# 【第一种写法】
@pysnooper.snoop(custom_repr=(Person, print_persion_obj))
def demo_func():
...
# 【第二种写法】
def is_persion_obj(obj):
return isinstance(obj, Person)
@pysnooper.snoop(custom_repr=(is_persion_obj, print_persion_obj))
def demo_func():
...
# 【第三种写法】
@pysnooper.snoop(custom_repr=(lambda obj: isinstance(obj, Person), print_persion_obj))
def demo_func():
...
以上就是明哥今天给大家介绍的一款调试神器(PySnooper
) 的详细使用手册,是不是觉得还不错?
如果你还有其他关于调试的技巧,可以留言区分享出来,一起学习一下~
转自:https://mp.weixin.qq.com/s/ct-nC1rqYZi9i654hsRy5g
一份好的数据分析报告,它一定会经历这几个过程:从一个强烈的好奇心开始,经过细致的数据收集和清理,做过透彻的数据挖掘,形成有严谨的逻辑链和有意思的故事线,匹配简洁明了的数据呈现方式,最后撰写通俗易懂的文字完成全文。
这样写出来的东西,才能打动人心。
今天这篇文章也是如此。
题图和今天文章无关。如果你们来参加我的讲座,你们会听到关于它的讲解,这是一张很有深意的图。
初三的各位战士们最近正在为中考过程中的一个极其重要的节点作准备:一模考。
而父母们也开始琢磨技术层面可以做哪些事情,比如我最近遇到的这个问题:
G大第一反应是冲洋泾的孩子去黄浦肯定不划算吧?那些伪市重点没意义,而黄浦两家八大甚至向明分数也不低。而果然有一个回复就是这样:
中考目前父母唯一能做的技术性操作是落户到外区,然后中考选择户籍地考试。这在中考中完全允许,不受任何歧视,且和学籍高中同学一起参加中考,没有适应性问题。
唯一的障碍是不享受当下和外来的名额分配到校。这需要按照具体情况分析。我们这里假设这个孩子名额分配无望。(事实上到初三上半学期,是否能拿到本校的名额分配已经很明了,做决策时候会非常清楚是否要考虑这个因素。)
由于本区投放到本区的统招批名额一定是最多的,所以当我们说跨区时,真正有意义的是上述的选择户籍地考试。而不是零志愿或者未来的名额到区,那部分名额数量太少,太不稳定,你无法基于那个分数制定策略。
而G大做了定向数据分析,给出的策略如下:
我们首先按照这位题主给的信息,标注出了孩子大概的正常水平,如上图灰色的横线所示。
我们先看进取的这边:上师、大同、上中东显然超出了孩子的范畴。剩下来的洋泾vs格致、川沙vs向明,明显黄浦在性价比上完胜。
我们再看防守这边:东昌+南汇vs敬业+大境的选择。东昌近些年一直保持着很高的性价比;大境2020年高考表现相当不错,因此性价比很突出;通常而言南汇、大境、敬业三校性价比接近,南汇略低。
我们再做一个假设:孩子万一考砸了,这四所学校都掉了,会怎么样?这个答案很明显:高桥中学是一所性价比非常高的学校,远非卢高和光明可比。
这是静态看问题。我们的分析还需要加上动态:以上为了对应2020年高考,我们使用了2017年中考分数。那么此后三年相关学校的中考分数演变又是怎么样的?
可见从2017年以后,我们挑选的一一对应的高中里面,黄浦高中的分数开始翻转偏高,在2019年达到最大差值,而在2020年收窄到几乎一致。
所以如果把中考作为一个市场,那么其中的每一个个体都在充分使自己的利益最大化,并最终使得市场红利趋微。
然而每年却依然会有一些新的机会冒头出来。你不分析,不会知道。
好,讲到这里,你觉得题主该怎么选?
看我的答案之前,各位先自己想一想。
仅以本图庆祝「赛博朋克2077」终于即将发售
这是我的答案:选黄浦户籍地考试,同时想办法勾搭下东昌的自招考。
能够争取一下洋泾的孩子,去黄浦读格致出路更好。向明对比川沙也是一样。
东昌今年第一年得到自招资格,面向全市招生,浦东学籍的娃有优势。以下是G大好友雨心(公众号:上海学区房观察)整理的东昌2020自招初中生源列表:
可见基本是公办学校生源在自招东昌。从这位题主的字里行间我们可以判断她的孩子应该没有为传统强校自招考做过正式准备,所以类似东昌这样的学校相对自招和中考区别没有那么大的学校,可能有些机会。
上文所述,东昌的整体出路在向明以下的浦东+黄浦高中里面最好,如果能进他们的自招班,那么完全有可能获得和上一档高中同样的高考出路,甚至更好。
今天的文章是我第一次尝试微观层面的数据分析,和我此前写的宏观层面数据分析不同。
宏观层面的文章有其优势:和很多人都相关,没事也能看个热闹。但是宏观层面的文章很难帮助读者落到实际操作。无法回答So What
微观层面分析文章正好相反:我可以就某一个细节问题给出细致的分析,并且给出能执行的建议。但是阅读面会很窄。认真写文章结果阅读量小,真心挺难受的。
转自:https://mp.weixin.qq.com/s/_Xee43G5hEKrpicaGURBLA
“辛巴卖假燕窝”的事情,伴随着辛巴的道歉、赔偿,似乎渐渐偃旗息鼓了,但假燕窝的争议却远没有消逝。
燕窝到底有没有营养?燕窝造假现象究竟有多猖獗?燕窝是不是暴利行业?
这些疑问都没有得到一个彻底的回答。
本期显微故事讲述了一群燕窝产业链从业者、及资深燕窝食客,他们之中:
有的人亲赴马来西亚开厂,揭秘燕窝的生产制作流程,也有人以亲身经历,现身说法燕窝究竟有哪些坑……
以下是关于他们的真实故事:
本文来源 | 显微故事
ID | xianweigushi
文 | 殷夕、常宁宁
从25岁开始吃燕窝,我的感受可以用一句话概括:虽然没用,但我乐意。
吃燕窝之前,我就有5年“保健品”历史:补铁、补钙、复合维生素都尝试过,每月花费近千元。
过了25岁,我切切实实感觉到身“开始走下坡路”了,加班多气色差,于是开始投向“贵妇”食品,比如燕窝。
燕窝根据形态分为燕盏、燕条、燕角、燕碎,价格也从之递减。
最开始我不懂燕窝,就从燕碎开始买起。燕盏1克价格在10-50元之间,燕碎就可以低到10块钱以内,营养成分差不到哪儿去。
但燕碎是燕盏在挑毛、清洗或运输过程中破碎部分,形状稀碎、泡发时间长,还要花不少时间挑。
我第一次买燕碎就”踩雷”了——燕碎到手后里面混有大量的草屑、燕毛(后面才知道这是品质最差的草燕)。
我前后挑了1个小时才挑干净,因为品质不好,泡发之后也没剩多少了。
但以次充好卖燕碎,已是行业最良心的手段了,燕盏水就更深了。
燕窝在手工挑毛的过程中会落很多碎片,一般商家会补同级的燕窝碎。
这里就有商家造假,刷胶贴上等级低一些的燕碎,平均每克成本能降4-5元。
等买家意识到上当受骗,燕窝都已经泡发了,自然也无法退货。
还有商家会对燕窝进行漂白:
刚摘下来燕窝是灰色(里面有羽毛、泥巴),得人工清洗挑毛,熟练的工人一天也就挑几盏,所以就催生了燕窝漂白手法。
一般是食用化学试剂去毛,经过处理的燕窝白白亮亮的,没有一丝杂毛。
化学试剂不仅对燕窝的蛋白造成损害,对身体也并不好。如果你看到没有一丝杂质、泡发不好、又容易煮化的燕窝,就可以绕道走了。
现在电商平台上卖的燕窝是造假的重灾区。
因为许多店铺靠“图片”做生意,只要图片上的燕窝和到手的燕窝好看,基本上就不会有维权。
刷胶、固定剂、染色都是常见的手段。
燕窝造假这么多,为什么我还爱吃呢?
因为煮一碗燕窝特别费时间,首先得泡发、挑毛;再隔水煮几个小时,最后换得一碗小小的补品,这么浪费时间的事情非常具有优越感。
只要晒在朋友圈里,绝对会得到无数个“懂生活”、“羡慕”的评论。
“哦,我花几小时炖的燕窝”——这应该是互联网打工人最高级的凡尔赛语言了。
燕窝催生“回收黑产”
只要恶意炒高价格就有不可告人的秘密
小宁 前燕窝卖家
我最早接触燕窝,是2008年跟团去巴厘岛旅游,其中有一个活动是参观燕窝工厂。
在那里我第一次尝试了燕窝,腥而且粘。
但带队的导游却买了很多,还来跟我商量,过海关的时候帮她带一点,免得她被收税。
为何一次要买这么多,不怕过期?导游神秘的笑笑:“我是帮人带的。”
她告诉我,燕窝是一种身份的象征,她都是帮之前的高端旅行团客户带的。导游不仅可以拿人头抽成,如果成交能拿到佣金。
这几年,因工作原因我常往返香港和内地,频繁接到朋友“代购燕窝”的需求,这才弄懂为啥这么多人要交“智商税”。
90年代香港流行吃燕窝,还催生了燕窝造假产业和一整套燕窝销售话术:“长期吃燕窝皮肤好”、“孕妇吃燕窝孩子皮肤白”之类的。
大陆通港政策放开后,燕窝的目标群众转移到了有钱的内地游客身上。
当时国内并不产燕窝,见香港流传着这是名贵食品的话术,内地人买燕窝就跟买奢侈品似的。
找我代购燕窝的“富婆们”分别买两种不同的燕窝:
品质比较好的燕条,留着自己吃;还有一种要燕盏,要求“产品好、包装精美”,这种是用来送人的。
有关系比较好的客户跟我商量过,如果收她燕窝的人来我这里退货,我就按原价把现金返给对方。
行业内有不少人都做类似的“回收生意”,以至于几百元上千块的燕窝炒到上万都有人抢着买。
还有人用这种方式“测试下属忠诚度”,说只要买了这个燕窝就是一个圈子的人,还经常搞燕窝分享会。
这么多年的经验,我得出一个结论:当一个食材,被炒出难以企及的高价时,一定是有见不得人的手在操控。
在马来开燕窝厂利润仅10%
说自己是高利润的燕窝产业必然涉及掺假
阿芳 私家燕创始人
转自:https://mp.weixin.qq.com/s/lqLd6JnNdr4ftwhzGKbDBw