作者归档:隋辨

真正的互联网,已经死了

1991年8月是万维网向公众开放的时间,实际上万维网仅仅是互联网的一个功能子集。今天的人们习惯了 HTTP、URL 和 HTML 技术,把 URL 叫做链接,把 HTML 页面叫做网页,将万维网称为互联网,也能看出万维网的影响之深远。(下文仍用互联网指代万维网)

今天我们谈到互联网,基本上是指手机上那几个 APP。在中国,手机上又基本上是腾讯系、阿里系、美团系、字节系、百度系的应用,在国外,你又绝无可能离开谷歌、亚马逊、推特、脸书……几个巨无霸公司占据互联网的大部分流量,掌握的垄断的资本,其他的小鱼小虾则在缝隙中生存,这样的现象不分国界。

互联网生意是一场零和游戏,你增加聊微信的时间,就会减少刷淘宝的时间。因为每人每天使用手机的时间有限,所以依靠广告或者电商收取利润的互联网企业必须得做点什么。他们的手段,我们也体验过:一个是收集用户的数据更好地推送广告,另一个是让用户在 APP 上待更长的时间。

因为政府相关法律法规缺失,且惩罚力度较低,所以公司为谋利收集数据,和众多互联网公司共享数据,创建广告联盟,形成精确的用户画像,使广告转化能力大大提高。如何让用户待在 APP 上不走?这一点字节跳动比谁都清楚。字节跳动在近年能与腾讯阿里并肩,除了强大的运营能力,不可缺少的就是算法推荐技术,二者成就了今日头条和抖音,提高了用户在线时间,生生从巨头手里剜下一块肥肉。

如今的用户流量集中在屈指可数的几个地方,互联网企业拥有前所未有的权力。你大可想象,我们去早餐店吃牛肉面,老板却在粉里放罂粟让人上瘾,同时偷偷拿到你身份证号码、手机号、昨天去了哪、前天晚上买了什么……

数据掌握在公司手上,于是你只好去某个特定的网站买会员,看你爱豆的电视剧,却被告知你应该再加钱提前点播。你发文十分钟,收到满屏的评论,突然系统告诉你不知道因为什么法规帖子被删。今天的互联网,就是一个强制的公路收费站,你可以不往那坑坑洼洼的路开,但大家都往那去,你又有什么办法?

互联网之父伯纳斯·李说,互联网正处于「临界点」 ,偏离了最初设想。

但互联网最开始并不是这样的。

在1945年广岛与长崎原子弹爆炸之后,万尼瓦尔 · 布什在论文《和我们想得一样》中表达对科学的担忧——科学正在朝着毁灭而不是相互理解发挥作用, 他在书中畅想道,科技可以造出 memex 这样的机器:它可以存储人类的集体记忆,可以使知识更容易获得。大英百科全书的体积可以缩小到一个火柴盒那么大,一个百万册的图书馆可以压缩到书桌的一端。

受到 memex 的启发,伯纳斯·李发表了论文《关于信息化管理的建议》。随后,他创建世上第一个网站 Info.cern.ch ,并花时间确保欧洲核子研究中心将万维网技术在公共领域免费开放,不设专利。他设想人人都可以创建自己的网页,访问他人的网页。互联网将是一个没有控制中心的网络,会造就一个明达、互动、宽容的世界公民共同体。

万维网雏形论文《关于信息化管理的建议》
万维网雏形论文《关于信息化管理的建议》

初代互联网也的确拥有自由。因为互联网核心设计是,任何人可通过一个网页的超链接跳转另外一网页,设计者仿佛是从「论文的写作要有参考文献,而从参考条目可以找到另一篇论文」获得的灵感。

十几年前,人们纷纷搭建自己的博客( blog ),参加不同论坛,交换各自链接,你常常可以从一个博客找到其他博客的友情链接。人们掌握着自己的数据,依靠着搜索引擎,在一个又一个网站间跳转。

互联网变成今天这个形态,跟智能手机脱不开关系,准确来说,是苹果手机。自2007年 iPhone 第一代横空出世以来,手机都开始拥有了上网能力,并大大降低上网难度。

从微观上说,早期手机互联网页面提供的技术较弱,页面显示效果不佳,比如无法定位 GPS 、 Flash 视频太耗电且存在安全问题、无法在锁屏状态下接收会话等,以至于互联网公司选择开发适配手机的应用而不是网页,来提高互联网服务的体验。互联网公司没有理由,也没有动力,让用户从自己的应用内跳转到其他的网站,美其名曰为「用户安全」着想。作为例子来说,微信封杀淘宝链接,淘宝程序员创造性地想出了淘口令,于是你分享商品只好发火星文了。

从宏观上说,因为手机与通信技术升级,全世界网民数量逐年增加,资本嗅到商机,纷纷涌入互联网公司,没有资本的公司往往胳膊拧不过大腿。要知道,互联网公司的存在,需要人员和服务器,这两样东西每天都在烧钱。因此提供持续服务的互联网企业获得了更多用户,更多用户就意味着更多投资、更多硬件和更好服务(更不用说社交网站或者即时聊天的这类有用户量红利的服务)。更具体地来说,互联网公司并不是软件公司,它不依靠卖软件产品获利,而是靠持续服务赚钱。这就全网流量为少数几个企业所垄断。

互联网公司将用户限制在方寸之地,人们不能再随意地跳转,搜索引擎也不再能搜索到那些数据。营销人员、产品经理也称那些被限制在应用内部的流量为流量池,将网红或 KOL 的带来的流量称为私域流量。所谓移动互联网事实上已不是互联网,只有用户对着几个中心服务器交换数据。

当下应用为适应快速更新应用功能,更多是在原生应用中嵌入网页,还有小程序的出现,都表明当前网页技术足以媲美原生应用,但显然仍是少数应用开放链接跳转。这样看来,如果说网页技术的落后是历史的偶然,那么资本涌入互联网企业并使其垄断就是必然。

互联网公司拥有我们的数据,小则控制我们的见闻,推送相关广告,以谋私利,大则干预现实的进程,操控公投和选举。在可想象的未来,由于智能家居和健康硬件普及,这种干预只会与日俱增。操控他人的人生,简直易如反掌,给他疯狂推送诸如「35岁被裁员了怎么办」的内容,引导网友攻击他的评论,根据他心跳频率判断他是否焦虑,再推送相关的降压产品广告。或者等他出门开着特斯拉,锁死车窗,加大马力,让刹车失灵,最后将事故原因伪造成自动驾驶系统的故障。

互联网中心化的根本原因,大概不是计算机科学的问题,而是社会学的问题。人是不是天生喜欢中心化,天然喜欢统治与被统治?这问题的答案也许还能解释,为什么会有宗教、王权,现代又为什么会有明星、网红。

众 APP 因河为池,以邻为壑,用户成为产品的一部分。而那个自由的互联网世界,远在抖音被封禁之前,早已消逝。

正则表达式-非捕获组的迷思 ( non-capturing group ) (?:)

(?:…)
正则括号的非捕获版本。 匹配在括号内的任何正则表达式,但该分组所匹配的子字符串不能在执行匹配后被获取或是之后在模式中被引用。

这解释真叫人头大。

例一

(aa|bb) 匹配 aabb

结果是

类型 范围 内容
Match 1
Full match 0-2 aa
Group 1. 0-2 aa
Match 2
Full match 2-4 bb
Group 1. 2-4 bb

例二

(aa|bb)+ 匹配 aabb

结果是

类型 范围 内容
Match 1
Full match 0-4 aabb
Group 1. 2-4 bb

第一个先匹配到 aa ,再匹配到 bb 。第二个直接匹配了 aabb 。
第一个和第二个的差别在于,用 + 重复匹配组,后果就是组只会保留最后一个迭代。

例三

我们再试试:

(?:aa|bb)+ 匹配 aabb

类型 范围 内容
Match 1
Full match 0-4 aabb

组保存的消失了?这就是非捕获组的用处,意思就是不保存组的内容到内存中,也就不会标号,于是只会得到匹配。

例四

这个用处是什么呢
先看看这个 Python 代码:

reg = r"(0\d{2})-(\d{7})"

s = "010-3838438"

re.findall(reg, s)

#  Out:[('010', '3838438')]

reg = r"(?:0\d{2})-(?:\d{7})"

s = "010-3838438"

re.findall(reg, s)

#  Out:['010-3838438']

上述差别如何发生?

第一个匹配的结果是

类型 范围 内容
Full match 0-11 010-3838438
Group 1. 0-3 010
Group 2. 4-11 3838438

而第二个匹配的结果是

类型 范围 内容
Full match 0-11 010-3838438

Python 自带的 re 模块函数:

re.findall
对 string 返回一个不重复的 pattern 的匹配列表, string 从左到右进行扫描,匹配按找到的顺序返回。如果样式里存在一到多个组,就返回一个组合列表;就是一个元组的列表(如果样式里有超过一个组合的话)。空匹配也会包含在结果里。

也就是从左到右,按正则表达式,不重复地匹配字符串,返回一个字符串列表。 如果正则表达式有一个或更多的组,返回组的列表,优先返回组。

第一个匹配里有两个组,所以只返回了组。

不得不说这个函数实现的很失败,为什么不把所有结果都返回?

最后一个例子

建议你自己猜一下输出结果:

s = 'exp=50;exp=51;'

re.findall(r'exp=(50|51);', s)

re.findall(r'exp=(?:50|51);', s)




#  Out:['50', '51']

#  Out:['exp=50;', 'exp=51;']

为什么出现这种差别?

前者有两个匹配,每个匹配有一个组。后者只有两个匹配。

因为 findall 总是尽力返回捕获的组,也就是括号内的字符串。(太蠢了)

使用了 (?:) ,它不会保存匹配的组。如果 findall 没有捕获到组,就会返回所有匹配的字符串。

Python 利器之 SQLAlchemy

参考

请参考官方文档:sqlalchemy

SQLAlchemy 是什么

相当于 Java 的 Hibernate 和 Mybatis (我更喜欢MybatisPlus :),是 Python 里数一数二的 ORM框架。
ORM框架,本质上就是程序员懒得写 SQL 语句或者实体对象代码,于是让对象代码生成 SQL 语句或者让 SQL 语句生成对象,形成所谓的对象关系映射的程序框架(Object Relational Mapping)

初始化

初始化填好数据库信息,连接数据库,生成引擎,建立会话就好。当然它还可以连接内存数据库 sqlite 。
echo参数可以控制是否显示数据库操作细节。

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from sqlalchemy import Column, Integer, String

mysql_config = 'mysql+pymysql://%s:%s@%s:%s/%s?charset=utf8' % (username, password, host, port, database_name)
engine = create_engine(mysql_config, echo=False)
Base = declarative_base()
DbSession = sessionmaker(bind=engine, expire_on_commit=False)
session = DbSession()

通过 declarative_base ,框架会处理你的类声明,自动将你的类与数据库表绑定。
如下:User 继承 Base 。

最好在类内声明数据类型。 primary_key 参数代表是否为主键。
tablename 为数据表表名。

class User(Base):
    __tablename__ = 'users'

    id = Column(Integer, primary_key=True)
    name = Column(String)
    fullname = Column(String)
    password = Column(String)

增加

user1 = User(name='lihua', age=18)
session.add(user1)

user2 = User(name='hanmeimei', age=18)
user3 = User(name='songwenhua', age=18)

session.add_all([user1, user2])
session.commit()
# commit 才能提交更改

查找

过滤器有 filter_by 和 filter ,前者用于简单的查询。
filter_by 只支持 = 运算。
filter 支持 ==, >, < ,还支持 like, has, in_, or_, and_ 等自带操作。
查找后要加 all(), first(), 或者 limit() 。

session.query(User).filter_by(id=1).first()
# 代表第一个
# desc(): 降序
session.query(User).order_by(User.id.desc()).all()
# asc():升序
session.query(User).order_by(Users.name.desc(),User.id.asc()).all()

#  例子
query.filter(Address.user == someuser)
query.filter(Address.user != someuser)
query.filter(Address.user == None)
# 名称中包含
query.filter(User.addresses.contains(someaddress))
# 用于多对一关系
query.filter(User.addresses.any(Address.email_address == 'bar'))

删除

User.query.filter(User.id == 123).delete()
session.commit()

修改

只需要查找之后,修改对象的值,commit 就可以了。

p = session.query(ParamClass).filter_by(id=1).first()
p.k1 = k1
session.commit()

flush 和 commit区别

flush 只是将语句发送到数据库内存,这种改变在这个会话可以看见,其他会话则不然。
commit 会提交所有更改,存至磁盘,其他会话也能查询到这种更改。

如何动态绑定表

接下来是重头戏了,由于业务需求,我需要根据情况,将同一类型的对象,存储在不同的表,也就是将数据存多个表,这些表的列名和结构都一致。
Python 的一个特性是可以动态生成类,利用 type() 不仅可以判断数据类型,还可以生成类:

type(类名, 父类的元组(针对继承的情况,可以为空),包含属性的字典(名称和值))

由于框架是根据tablename来绑定表的,而且类的tablename是无法改变的。
于是可以用字典在一开始就把表名和类相关联,Model 是存粹的数据模型,Base 是 declarative_base 而来。这样就可以根据情况来匹配类了。

class User():
    id = Column(Integer, primary_key=True)
    name = Column(String)
    fullname = Column(String)
    password = Column(String)

table_mapper_dict[table_name] = type(
    table_name,
    (Model, Base),
    {'__tablename__': table_name}
)

程序员的巴别塔问题

巴别塔问题,是圣经故事中,人类企图在示拿之地建塔,来传扬自己的名声,以免他们分散到世界各地。上帝知道之后,将他们的语言打乱,再把他们分散到世界各地。于是巴别塔停止修建,人类也因此发生冲突与战乱。

程序员有很多语言,不同的语言还有不同的代码框架和库。在程序员论坛,你基本上丢上一句「xxx是最好的语言」、「xxx吊打xxx」,热度马上就能上来。一些人乐于造轮子,说的是喜欢创造别人已经创造过的工具。大多数人在业务上重复造轮子,对自己来说可以锻炼代码能力,对别人来说通常是一种灾难,自己的轮子没有社区和团队的支持,没有详尽的文档解释,别人要理解代码完全就是头疼了。

每当看见一个新语言/新框架,我就会感慨,程序员怎么那么命苦。别人发明语言,发明框架,我们来学,又是一套新东西,无非是一些语言特性加加减减。有人就说,这个语言实现了xx特性,这样我们编码的速度/程序的性能/语言的易用性又提高了。程序语言不太可能出现什么革命性的升级,除非有一天自然语言处理技术已经能跟上人类的大脑,人们只需要说话就能写程序。别人出书,我们买书,别人演讲,我们学习,别人用新技术完成了kpi,我们下班继续学习。号称完成了xx特性,提高了多少效率,门槛如何如何低,结果就是大家依然要加班,但是加班的位置都更难抢了。十年前,你会写html,用ps切切图,还知道tomcat弄服务器,你就很牛了。现在招聘要求是,高并发、高可用、多线程编程、高性能分布式系统、容器技术。你工资没变高,但是你要学的东西变多了,你气不气,这大概就是技术革新吧。

普通人能为男女平权做些什么

女权运动似乎从来都只是网络上的小打小闹,或被恶化成田园女权被人误解,或被一些自媒体拿着当枪使,或是像李银河那样正经科普。对于普通人而言,还是能做点什么的。

如何理解男权社会?简化来说,不论各个国家的细节如何,都是私有财产出现之后,古代各国男性为了让自己的血脉继承财产,通过道德和制度剥夺了女方的经济能力,从而女性成为「第二性」。正是没有经济能力才使物化成为了可能,四川一些地方采茶业通常都是女性为主,在那更加平等,男人素有「耙耳朵」称号。

男权社会的不合理之处在于,不仅造成女权限制,还给男性带来巨大压力。不少男人会抱怨,女人现在的地位都那么高了,怎么还搞女权呢?男人的压力反而源于男权。男权社会在现代暴露出的逻辑,通常可以借由私有财产来解释,女性出生是父亲的私产,嫁人是丈夫的私产,其把女性当成了工具,而非目的。这样的私产不如男性作为人来的值钱,而且通常要花费很多钱,一次性卖出(彩礼)不值。因此在一些偏远地区,仍然有人打胎,希望来个男孩,仍然有人不停地生,为的是出一个男孩。即便自然状态女性出生率更高,我国男性还是比女性多出三千万。由于男性作为「第一性」,自然能赚钱、聪明、社会地位高成为了优秀品质,加上需求大于供给,女性自然要选择段位高的男性,男性也必须挤破头,所以说男人很难。接着贞操观就成了父权向买方市场讲的故事:一手货很好,二手是烂货,无形中抬高了价值。因为是私产,外在条件变得很重要,内在的品质却成为了附属品。作为将转接丈夫的私产,自然「听话、懂事、可爱」这些看上去顺从的品质列为上陈,因而「女汉子」常常不被舆论接纳。

上述的模型已经可以分辨百分之八十的不平等问题。普通人除了能分辨之外,还能改变自己的观念。作为男性,鄙视衣服言论,平等竞争,杜绝「女司机常出问题、女博士不好惹」的观念。作为女性,不利用自身性别「优势」谋取利益,自立自强不依赖他人。普通人不以贞操观评价好恶,杜绝荡妇羞辱,保持生男生女都一样的观念,不以性别决定公司人事去留,不以性别判断谁适合上学、谁适合学理科,塑造平权的家庭,不以强权剥削弱者。简单来说,男女本质上无差异的领域,不需要性别差异来决定,把人当成目的,而不是工具。

社会大多数认为是对的事情,常被视为真理。让男人女人,放弃各自的那些优势观念,当然是很难的。不管怎样,先做起来,心里埋下种子也可以。希望不再有被打掉的胎儿和不能上桌的儿媳,不再有为彩礼和处女膜沮丧的男性。

她从流水线,坐到了纽约办公室兼谈女权

我曾经听说过这样一个故事,一个农村女生,本来是在工厂打工,经过十年努力成为了纽约的一名程序员。

孙玲是湖南娄底的,跟我相当于老乡了,所以我看到这个故事的时候印象深刻。她是一个农村女生,09年高考完后分数没到二本线,一个郴州的计算机培训机构在他们学校做宣传,她参加了里面一个免费夏令营, 期间她开始感觉编程很美妙。但是因为家境贫困,高中毕业后,她去了深圳工厂里工作。

如果是你,觉得这个工作没什么前途,会怎么做?

她这个时候选择去打听培训机构,然后存了几个月钱,到10年,她在电子厂一边工作,一边学编程,为交学费还办了信用卡。终于在11年,她开始进入it行业,慢慢还信用卡,过上了坐在电脑前打字的生活。

如果是你,感觉自己现在生活很安稳,会怎么做?

她开始学习英语,意识到没有大学文凭也不太好找工作,想提升学历,到了12年,她换了份工资更高的工作,然后边学习英语,边上西安交通大学的远程教育课程。在14年她拿到了大专文凭后,又通过了深圳大学的专升本自考。下半年的时候,她加入了一个有很多外国人的飞盘俱乐部,对英语能力有很大提升。

如果是你,对自己的工作已经很满意了,会怎么选择?

她想出国看看,于是在网上找到了硕士留学项目,可以一边上学,一边工作。因为她刚好有了本科学历,刚好英语能力也提高了,2018年,终于她如愿以偿去美国读硕士,并且在纽约找到了工作。

09年,她高中毕业在电子厂打工,18年,她在纽约谷歌公司上班。其实她是一个普通人,她选择认认真真地做好了一件件小事,培训、考专科、考本科、学英语,就是这一件件小事,用十年时间累积起来,就造成了巨大的改变。不要高估一年的努力,也不要低估十年的坚持。

本来这个故事到这里已经结束了。但是我发觉,因为她是女性,她走的也许是一条更为艰难的道路。昨晚一个朋友告诉我,在他们村里,女性不能上桌吃饭。很多家庭都有好几个孩子,原因是他们会一直生育,直到有男孩为止,导致一家有很多姐妹。因为家庭经济负担不起,所以就让女孩去城里打工养家。更加离谱的是这样的习俗,如果老二是女孩,要么从小把她送人,要么就禁止她结婚。

很多人以为现在不是男权社会了,但事实不是这样。女性成功出生已经是万幸,然后在成长的路上还要被告知,女生的理科就是不行。女生只是空间想象力不如男生,但语言天赋却高于男生,高考里面数学的立体几何题、物理的很难想象的运动题,又占多少分呢?但常常是为了家里的弟弟继续学业,姐姐妹妹要放弃学业去打工。

类似的议题数不胜数。社会上受到性骚扰、性侵害的是不是常常是女性?在职场上,在学校里,在公共空间,是不是女上司、女博士、女司机常常占舆论劣势?结婚之后,是不是女方要受到的压力更大,要花更多时间陪孩子?离婚之后,是不是女性再婚更加困难?

有人会说,男性结婚要买车买房,还要送彩礼,比女性压力大得多。是的,男性如果占据更多优势,代价就是承担更多。当我们在以颜值和年龄度量女性的时候,同样就是在用金钱和权利来衡量男性的价值。这样的价值观下,男人要勤奋包揽一切事业,他不能哭,不能软弱。在那几千万光棍之中,又有多少在这些指标里毫无优势,然后孤独终老呢?男女就像一枚硬币的两面,哪一面朝上,社会的压路机压过来的时候,最开始遭殃的也是那面,最终我们都会陷入泥地。

反过来讲,只有掌握平衡之道,这枚硬币能够向前滚动,历史的车轮也不至于追赶上来,大家也就轻松得多。双方地位平等之后,女人可以不再把有车有房当成唯一标准,不再只盯着存款数额,男人也可以选择带孩子做饭,当个居家宅男。男人不介意当耙耳朵,女人也不会被叫做男人婆,从而二者的负担都能缓和。

不出意外的话,男男女女依然要在这样的社会生活很长时间,不是每个人都会有孙玲那样的幸运,但每个人都有那样的十年用来努力。最后,不论是男人女人,不要因为社会偏见而放弃自我,不要温和地走进那个良夜。