日期: 2021 年 4 月 6 日

为什么很多安卓 APP 都不支持 fcm 推送呢?

*近从 iPhone 换到了安卓,感觉特别不习惯的一点就是很多 APP 的推送都收不到了,必须得挂后台,而且即使挂后台也不能 100% 保证收到。我理解安卓厂商碎片化的现状,但是我自己已经安装了谷歌的框架,所以我希望开发者能走 fcm 推送,这样比较省电,也能保证到达率。我的疑问是,既然开发者可以接那么多第三方 SDK,为什么不能多接一个 fcm 呢?如果所有 app 都接了 fcm 的话,是不是也有 iPhone 的推送体验了。有没有安卓开发老哥来说说,阻碍你们厂的 APP 接入 fcm 推送的根本原因是什么呢?我的个人感觉是,增加推送成功率所能带来的业务收益,应该是远大于多接一个 SDK 的接入成本的吧。

 

41 条回复    2021-02-22 18:23:40 +08:00
moreant
    1

moreant   51 天前   ❤️ 5

fcm 是哪家的服务
sephinh
    2

sephinh   51 天前 via Android

让你强迫保活还能干点别的,给你都推送那不是自找 kill 吗,简单点说就是大家都这么流氓哪我也不能装孙子啊
Xusually
    3

Xusually   51 天前

@moreant Google 自家的 Firebase Cloud Messaging
vencent
    4

vencent   51 天前

@sephinh 问题是感觉开发者好像也不太引导用户去设置自己的 APP 保活,对于使用频次不高的 APP 来说,基本上就等于没推送了呀。
fredcc
    5

fredcc   51 天前 via Android   ❤️ 2

植入了 SDK,可以获取用户的这个那个数据,可以刷这个那个的流量,更不用说交叉唤醒这种,接了 fcm 能获得什么?
f165af34d4830eeb
    6

f165af34d4830eeb   51 天前   ❤️ 1

抛开 fcm 在大陆连接可靠性的问题,无法集成 sdk 保活收集用户信息也是一个方面。而且能用 fcm 的用户一般对 Android 有一定了解,你为了 kpi 给他们推 AD,他们反手就关推送权限 /关小黑屋,出力不讨好的事情那些毒瘤厂才不会做。
f165af34d4830eeb
    7

f165af34d4830eeb   51 天前   ❤️ 1

所以 iOS 的统一推送服务+强 app 审核制度+几乎全球一致的系统,对于某些人(比如我)就是刚需。更不用提 apple pay 能添加全球银行卡的便利性了。
fatelight
    8

fatelight   51 天前   ❤️ 2

小众软件 mipush huaweipush 或者第三方,以及接入第三方广告 sdk,保活,收集数据,各种权限问题
主流软件 微信 QQ 淘宝这种流氓怎么在 Android 上那么乖,厂商都给白名单,要不你微信一样被疯狂杀后台

Android 现在就是死循环,配置不断加( 16G 内存旗舰都有了,12g8g 主流)依旧不够用,无解。
要不忍着用,要不 root 自己搞机(数量占 Android 用户算很少的一部分)

统一推送联盟也是扯蛋,扯了这么多年了

Android 可能就是安装一些破解软件方便了吧,以及多开。还有就是快充。

各有优缺点吧,就看你能忍受什么了

vencent
    9

vencent   51 天前   ❤️ 1

目前我使用的是坚果 R2,因为特别喜欢 smartisanOS,不过基本上收不到除了微信 qq 之外的任何国产 app 推送 hhh,估计是为了保持续航对后台限的非常狠,FCM 倒是工作良好。锤子是接入了统一推送联盟的,但是 app 厂商不跟进…感觉这块得有点强制力来推。mipush 什么的估计不兼容吧。
efsg
    10

efsg   51 天前 via Android

用小米和华为可以告诉你国内主流应用除了 QQ 微信都接入各家了推送,你问为什么他们没接推送你能收到消息是因为保活( QQ *近也接入了华为的推送)
efsg
    11

efsg   51 天前 via Android

QQ 微信不接入推送正是因为鹅厂的垄断地位才敢不顾用户体验,统一推送雷声大雨点小,都 3 年了根本没有一个主流应用接入
janus77
    12

janus77   51 天前 via iPhone

ios 接统一推送是因为只有他一家,没得选
安卓接各大第三方是为了提升推送成功率,但是既然你的国产 rom 已经支持推送了,再加个 fcm 就是多余的了,所以当然不用接 fcm 了
WebKit
    13

WebKit   51 天前 via Android

国产手机建议用小米。基本上只要有推送的基本都支持小米推送。国内推送支持大概是小米>华为>OV 小米推送方面还是不错的。
WebKit
    14

WebKit   51 天前 via Android   ❤️ 1

@fatelight 统一推送联盟一直再推的。只是你不了解而已。华为小米 O V 的手机上就是用的统一推送联盟
james2013
    15

james2013   51 天前 via Android

fcm 在国内没有卵用。
google play 框架在没有梯子或者梯子不稳的情况下,耗电严重。
有几个人专门去弄这种?
我安卓手机都换了 5 个,中间还从美国亚马逊买的 nexus5x,原生系统都水土不服。
talentr9
    16

talentr9   51 天前 via iPhone

不支持 FCM 的软件不用不就行了 又没有强迫你用
S179276SP
    17

S179276SP   51 天前

@janus77 QQ 接入了华为的(真的),微信接入了 fcm (伪的)因为 QQ 基本都放弃了海外用户,海外手机注册全部说不安全禁止注册,自然不会用 fcm
Cielsky
    18

Cielsky   51 天前 via Android

@WebKit 主流手机厂商都接入统一推送联盟了,好像断网也能收到推送。
问题是到现在我也没见到适配的应用?
oovveeaarr
    19

oovveeaarr   51 天前

因为 fcm 在大陆效果本来就不行,更别说他得要应用自启权限才能推送了
既然有自启权限了,我用自己的推送通道不香吗。。
JohnShen927
    20

JohnShen927   51 天前

要不是水果强制要求,哪个厂商会放弃挂后台疯狂小动作的机会.
即使是 fcm 的畅通无阻的区域,流氓们也是动作不断,至少我以前玩脸书那会,这玩意的安卓 app 就是使用体验*差
bao3
    21

bao3   51 天前 via iPhone

看完了还是觉得我继续 apple 生态 b
fox0001
    22

fox0001   51 天前 via Android

国产 app 的话,不支持 fcm,很正常吧
fatelight
    23

fatelight   50 天前

@WebKit 主流 app 都不鸟有啥用
WebKit
    24

WebKit   50 天前 via Android

@fatelight 主流 app 除了腾讯的 qq wx 其他都接入了
vencent
    25

vencent   49 天前

@WebKit 怎么验证一个 app 是否加入了?
WebKit
    26

WebKit   49 天前 via Android

@vencent 可以看它。有没有相应服务,跟广播接收器。就是说有相应的代码组件。
dzyou2007
    27

dzyou2007   49 天前

都说了是国内 App,国内市场能有 GMS 套件的能有多少,一比较就知道答案了
dzyou2007
    28

dzyou2007   49 天前

@S179276SP 且不说 QQ 禁止非 86 注册是否属实,至少这应该是*近才有的事,而 qq 不接入 fcm 是一开始就有的事。另外,二者也没有什么实质关联,这个逻辑就很奇怪。
dzyou2007
    29

dzyou2007   49 天前

@WebKit 华为用的是 hws,小米是 mipush,ov 也有自己对应的产品。只是他们的产品适配了统一推送联盟、他们的平台支持接收和分发来自联盟的消息,但应用接入什么消息平台还是取决于 app 开发者,和系统“用的就是统一推送联盟”还是有区别的。
S179276SP
    30

S179276SP   49 天前 via Android

@dzyou2007 反正注册就是属实的,我就在国外,我几张移动手机卡都不给注册,全部说安全问题,微信注册几次都没问题
zpxshl
    31

zpxshl   49 天前 via Android

@f165af34d4830eeb
6 楼。 无法集成 sdk 保活收集用户信息也是一个方面。 这属于瞎猜测吧。 大厂获取用户信息要依赖推送 sdk ?
除非 fcm 能有效提高推送成功率,否则干嘛要接?接个 mipush 不比 fcm 靠谱很多?
另外,接入 sdk 不仅有开发成本,也有维护成本,它的代码你得看吧,出了啥乱子谁负责? 上次有个大用户量 app 就是因为接了某推送 sdk 出了问题。
f165af34d4830eeb
    32

f165af34d4830eeb   48 天前

@zpxshl 当时描述不太对,实际上想表达的意思是接入 fcm 有额外工作量,还有网络问题 debuff,对于国内大部分开发商属于吃力不讨好的事。
HangoX
    33

HangoX   48 天前

大厂作为刚过推送的开发告诉你为什么不接入 fcm,根本原因用户量不能 cover 接入成本。后台有统计,有 gp 的用户非常少 1%都不到。接入 fcm 不像简单的接入即可,单单说测试成本就要加多一个渠道的测试用例,更何况不同的推送渠道真的差异很多,华为,小米,vivo,oppo,魅族各不相同,还有升级的维护成本,代码量的增加。
而且,当我接入了华为,小米,vivo,oppo,魅族后,fcm 真的没有必要接入了
wagsoft
    34

wagsoft   47 天前

其实应该倒过来考虑,要什么推送?手机作为信息获取工具使用必须是”我要的时候才能给我,我不要就不要随便给“,这才不致于落入信息海洋灭顶
哈哈
kimiler
    35

kimiler   47 天前

现在不会选择 fcm 了,基本上都是多家厂家推送渠道,不需要挂后台也能保证到达率
fairytale
    36

fairytale   47 天前 via iPhone

其实,推送这个就应该运营商搞,wappush 就是个非常棒的接口,只是需要有 sim 卡才行。
woyaojizhu8
    37

woyaojizhu8   47 天前

@wagsoft #34 是的,推送对用户没那么重要,但是现在各家互联网开发者把推送看得很重,为了推广告吧
xiva1209
    38

xiva1209   47 天前

你们都说国内开发的 app 接入了华为、小米、OV 等自家推送渠道,所以不接 fcm,我就奇怪难道国内 app 默认都不需要海外市场吗?还是说他们都认为全球安卓用户都用的国产手机品牌?
Lemeng
    39

Lemeng   46 天前

推送方面是确实,这点苹果还是
shenyuzhi
    40

shenyuzhi   46 天前 via iPhone

@fairytale 没错,运营商级推送才是*省电*可靠的。可是不管 3g4g5g 都没这个功能。
NanTofu
    41

NanTofu   42 天前

很简单,将人力和服务器成本投入到为 90% 常规用户的服务上去。接入 firebase sdk 会一定程度增加 apk 体积(带来推广成本上升),提高崩溃率( firebase 系列 sdk 一直都不是什么高质量库),增加内存消耗,增加启动耗时,所以没有足够受益的 SDK,没人会接入。不要以为各厂都是傻子,不存在一定是有其不合理性。你既然能*,直接用海外版不就好了。

android 有啥办法比较方便的在送修前隐藏个人应用和数据么?

过年的时候手机磕破个角,然后想起来去年买手机的时候买了碎屏险,于是寄回维修,这是前提。
今天上午显示被维修商签收,过了一个多小时就有人打电话来问我手机锁屏密码。。。寻思换个屏幕咋就要开机呢(寄之前以为不会开机,于是就啥都没动就关机取了个 sim 卡),遂询问对方进去想干啥,也不正面回答但不依不挠就是要问,考虑了三秒把锁屏密码给对方了。
这会越想越不是事。。。毕竟各种密码、身份验证器、聊天记录还有多数应用的登陆状态都在上面,折腾了一个多小时才全都退出。
血泪教训

顺便问一下 android 有啥办法比较方便的在送修前隐藏个人应用和数据么,miui 貌似有类似功能

 

28 条回复    2021-02-23 11:24:03 +08:00
xiyuesaves
    1

xiyuesaves   46 天前

备份数据之后重置设备吧,但现在好像就小米能保留和恢复应用的数据
syuraking
    2

syuraking   46 天前

MIUI 的维修功能目前还在内测,没有公开。
不过你放心,小米官方维修的不会要你的数据的,修好就完事了。

我年前碎屏保,修小米 10 屏幕时也一样,屏坏了也没法解锁,那边也电话过来问了,然后我有心之前就装了点东西,发现只是解了锁,运行了 cit,还有打了一个 112 的电话,没其它动作了,关机就寄回来了。

承接维修的是上海全服。

Hancock
    3

Hancock   46 天前

华为,小米,vivo 有这种隐私空间功能,其他手机不清楚
zqz19941106
    4

zqz19941106   46 天前

8848 双密码 双空间
66beta
    5

66beta   45 天前 via Android

不是厂家售后,还是小心点好,备份好了三清刷机再送修
lijialong1313
    6

lijialong1313   45 天前

我记得华为有个啥维修模式,你自己设置个密码,但是不知道有没有用。
murmur
    7

murmur   45 天前

有些维修商要做测试的,毕竟是手艺活,万一屏换好了别的地方干坏了怎么办

当然送修是有风险的

laoyur
    8

laoyur   45 天前

我也感觉这个流程并不好
以前修 360 手机,官方售后,也问你要锁屏密码,他们好像要进去用工程模式啥的跑一遍,相册里我记得还留了一张照片在里面……
qiangmin
    9

qiangmin   45 天前

估计是自动化测试用的,我刷机后,自己会通过拨号面板进自动测试看看有没有硬件异常。
jtshs256
    10

jtshs256   45 天前 via iPad

水果直营换块电池都被要求过取消锁屏密码…结果换完说通不过检测给换了台整机…
cpstar
    11

cpstar   45 天前

自己买屏幕自己换,手机换过四次,平板换过三次
guyeu
    12

guyeu   45 天前

@cpstar 老哥手艺人
scxiazi
    13

scxiazi   45 天前

换屏的时候都需要检测, 不解锁咋测试
delectate
    14

delectate   45 天前

需要测试屏幕和触摸的。
设置—我的设备—全部参数—按 5 次“内核版本”进入 cit—6.触摸屏测试–7.显示屏测试

所以是有必要的。

faqqcn
    15

faqqcn   45 天前

万一手抖,把哪儿的信号线或者排线没装好,到时候给你寄过来,手机没信号,触控断触。

就像你改了某处代码,你能确保其他地方调用的没故障么~

基本的换了屏幕还要检测坏点,断触这些呢。你觉得这些能在锁屏界面完成么

wolong
    16

wolong   45 天前

要也正常,上次去给苹果换电池(保修内),要我清除锁屏密码和退 ID
systemcall
    17

systemcall   45 天前

应该是要用来进 cit 的吧
Android 在启用了硬件加密时,正常情况下,需要锁屏密码才可以解锁 /data 的分区。当然不解锁 /data 的情况下还是有办法测试的,以前很多手机都有独立于 Android 系统的测试程序。不过现在连恢复都建议删掉的情况下,还会留这个模式吗?
Cielsky
    18

Cielsky   45 天前 via Android

华为好像有个维修模式,其他的不清楚
systemcall
    19

systemcall   45 天前

@faqqcn #15
按理来说,使用 OEM 的工具,fastboot 启动一个签名了的 image 就可以了。以前很多手机不进 Android 也可以测试硬件的问题。而且据说苹果的设备,工厂里面是工厂的固件
一些笔记本也有类似的东西。不过大部分笔记本都不会锁死要启动的系统,EC 本来也会有后门,好弄一些
easylee
    20

easylee   45 天前 via Android

小米还是红米?

红米维修部基本都是外包。

ufuf223
    21

ufuf223   45 天前 via Android

工程师基本在维修完毕之后会进系统看看还有没有别的问题,万一有什么其他问题也好及时修理。我有一次在售后换电池就是师傅不小心碰到了前置摄像头排线复检的时候才发现,出了问题拿出去了就不好确定责任了
dingwen07
    22

dingwen07   45 天前 via iPhone

可能是要做一些检测或者和服务器同步硬件数据什么的。但是我上次去修三星他是修好之后拿过来让我解锁的,他的操作我都可以看见。
Repobor
    23

Repobor   45 天前

很正常,解锁后去测试一下屏幕是否正常,免得返修
maojy1989
    24

maojy1989   45 天前

@wolong #16 去换过电池,只是用机器检测手机的时候让我解锁手机,检测完手机屏幕锁了也没退出 ID,直接拿去就换了
Hallujah
    25

Hallujah   45 天前

一般来讲是测试下屏幕完好,但是为啥要含糊不清呢?直接说明白不好吗?这应该是楼主但心的地方了。
wolong
    26

wolong   45 天前

@maojy1989 我本来只换电池的,修回来给我把主板,摄像头,听筒都换了。
Airy
    27

Airy   45 天前

要测试其他功能是否正常,可以去 B 站看看艾奥科技修手机的视频。
yanqiyu
    28

yanqiyu   42 天前 via Android

之前去维修,表示了顾虑,然后维修人员在我面前进行的屏幕检测(

各种国产 Android 发行版不同机型间更新不统一?

说到 iOS,每个终端发布后提供大概 5 年更新(不期待国产 Android 发行版能做到),无论高低端机型在 EOL 前都能收到及时的安全更新和功能更新,*近 A8 的设备还有时会有安全更新。

但是国产 Android 同一品牌的不同终端 EOL 之前居然都做不到版本更新的一致(例如某品牌过气旗舰不如狗)。我个人不是很懂 Android stack 的底层。难道这些安全更新,功能更新东西不应该有一套自动化的 build 系统,进行统一管理吗?

不给升 Android 大版本也就算了,但是 google 的安全更新没听更前起码要跟上吧(两月一更个人觉得不过分)。难道 0day 在这些厂家眼里这么不重要?包括但不限于 hovm

希望能展开讨论。是我太理想化?还是我说的这些并不影响销量?还是有其它技术上的问题等等等

 

27 条回复    2021-03-01 14:23:36 +08:00
codehz
    1

codehz   49 天前   ❤️ 1

因为搞这个不赚钱啊(
gridsah
    2

gridsah   49 天前

一楼正解,搞这个不赚钱。
我主力小米手机的安全补丁还停留在 19 年。
MakeItGreat
    3

MakeItGreat   49 天前 via Android

另一个原因是大家普遍讨厌更新
fhbyljj
    4

fhbyljj   49 天前 via Android

@gridsah 你什么手机?按道理会随着系统更新而更新的,我小米 10P 开发版公测 2 月 1 号 K30U 开发版内测也是 2 月 1 号 都是*新
JensenQian
    5

JensenQian   49 天前 via Android   ❤️ 1

只要能解 bl 锁能刷机基本上热门机型安卓新版本*时间都会有民间的包的更新的,怕就怕某些品牌不能解锁官方也不更新,这就真的大问题了
gridsah
    6

gridsah   49 天前 via Android

@fhbyljj 手持米 6 同期的 MIX2/滑稽。
现在都找不到换手机的理由(当然主要是家境贫寒…
Lonely
    7

Lonely   49 天前 via iPhone

@fhbyljj 你这说的都是新手机。手上有台 MIX 2S,去年就被终止了更新。
ToPoGE
    8

ToPoGE   49 天前 via Android   ❤️ 1

@Lonely @gridsah 主力机 mix2s,买回来*件事情就刷了原生,除了等解锁的 2 天时间用了 MIUI,其余时间就没用过 MIUI,12/12.5 发布都吹动画 NB,实际上原生 aosp 自带的动画就非常好,搞不懂很多厂商都重写了动画,关键又写不好,自带不香吗,aosp 自带动画基本比肩 IOS 了,另外如果 Google 重度用户,原生体验不必 MIUI 差 手持 mix2s 有感而发(:)
ToPoGE
    9

ToPoGE   49 天前 via Android   ❤️ 2

小米在开源这块用的还是非常,非常好的,国外很多大厂都已经不开源,不能解锁了,但是小米还在坚持,感觉以后用 Android 只有小米一家可选了,雷总当年初心还在,毕竟是 ROM 起家的,希望能一直坚持下去
chonger
    10

chonger   49 天前

所以我只用苹果,国产手机基本都是机海战术,一家厂一年几十款高中低机型,怎么可能每款都照顾得过来,今年的旗舰机过几个月就新人换旧人了,过个一年就没人理,再过一年还能有更新包就属*恩浩荡了,真的是过气的凤凰不如鸡,更新率太高,淘汰率也太高。也难怪一个劲的搞快冲,电池还没来得及冲坏估计就换机了。
honeycomb
    11

honeycomb   49 天前 via Android

就是因为这个我不会买国产手机,MIUI 是 adui 所以也落选了
systemcall
    12

systemcall   49 天前 via Android

记得刚开始用国产安卓机的时候,根本没有系统更新,一锤子买卖
不过那个时候一个安卓手机撑不了多久就会卡到受不了。确实不需要系统更新
现在的安卓手机寿命长很多了,才需要系统更新
很多手机是 ODM 的,真正的厂家才有底包,卖给你的那个厂家估计也没有多少资料。感觉应该是这个原因
dinghmcn
    13

dinghmcn   49 天前 via Android   ❤️ 1

google 近几年一直在推动这事,但是进展缓慢,国内不需要 gms 认证会更难
gridsah
    14

gridsah   49 天前

@ToPoGE 我原来用过原生的安卓 6,但是国内的流氓软件太难处理了。现在情况如何?老哥你是怎么处理的?
ToPoGE
    15

ToPoGE   49 天前 via Android

@gridsah 到 Android11 基本可以了,只要你不下载特别流氓的软件,比如国内的浏览器之类的,从 10 开始每个应用可以设置后台限制,打开来,好了不少
fhbyljj
    16

fhbyljj   49 天前 via Android

@Lonely 米 6 和 Mate10 同代吧,Mate10 都停了
fhbyljj
    17

fhbyljj   49 天前 via Android

@chonger 小米和华为都是 2 年更新
lelandsu
    18

lelandsu   49 天前 via Android   ❤️ 2

不赚钱+1 。
另外也费力,并不是像楼主说的脚本自动构建下就好。
用户用的 Android 是上游 Linux 内核,厂家 patch 定制,各类上游驱动,Android 框架层,厂家 Android 应用层,Google 服务集合。按 iOS 跨度 5 年来维护,安全问题可能是其中任何一块,框架层往上还好说,内核或者内核驱动相关的在历史版本上进行修复(如果各方愿意的话)可能要经过好几方*后才由手机厂家处理,一般安全问题如果从历史版本延续到*新版本,都是优先在*新版本上修复,如果版本相差太大,一一移植到各个历史版本更酸爽。
另外,商业上,任何软件更新都不可能构建完就发布,测试流程肯定得走一遍。

iOS 能做有多个原因:手机卖价高,留有足够成本进行生命周期维护。整个系统都是苹果维护,不需要经过多个上游。系统版本集中度更高,没有 Android 跨度高。苹果本身重视。

daozhihun
    19

daozhihun   49 天前   ❤️ 1

1. 用户量变少:一般经过两年甚至更长以后,老机型的用户会急剧减少
2. 新机多,人手不够:这个应该是主因,参考某米某为这两年的新机有多少款
3. 适配麻烦,尤其是在谷歌搞 project treble 之前,要花费很多人力物力,参考你把老的 java 项目升级到 java11 就够折腾了
4. 大部分普通老百姓对这种更新感知不明显,搞不好还费力不讨好
rigortek
    20

rigortek   49 天前 via iPhone

1.*大多数用户不知道什么叫升级!
2.投入大,收获少。

程序员 merge 了要发新版本吧,
新版本要 qa 测试吧,
要自建 ota 升级服务器吧,
运维要发布升级策略吧,
还有可能把用户手机升挂了,
所以不如将财力物力投入到新机器上去

Track13
    21

Track13   48 天前 via Android   ❤️ 2

即使你发布一个什么改动都没有的更新,也会有一大堆人跑出来说这个版本比上个版本费电。

这种情况下,本来就机型多人手不够,厂商自然是选择过了承诺时间就不给更新。

ikas
    22

ikas   48 天前

厂商以利益至上,补丁啥的先别奢求,自己修改添加的功能造成的问题先修完了再说. 至于 aosp 本身为了能够统一更新已经改了很多,可以参考 source.android.google.cn/security
现在*佳实践还是自己解锁安装原生类系统,但是依然没法解决厂商非开源组件 /驱动的更新问题
Lemeng
    23

Lemeng   47 天前

安卓更新太快了?确实有这个问题
rrZ2C
    24

rrZ2C   47 天前   ❤️ 1

Google 的安全补丁做到每 2 个月一更没有任何困难,但是 Google 对国内厂商还是缺少约束能力

海外运营商那种辣鸡手机都能准时收安全补丁

flynaj
    25

flynaj   47 天前 via Android

小米开发版一个星期更新一次,普通人也跟不上。正式版半年左右还正常。
dvbuzhidao1
    26

dvbuzhidao1   42 天前 via Android

@flynaj 安全补丁还是很重要的
BrokenVns
    27

BrokenVns   36 天前

1.Google 不是厂家的直接上游,厂商的代码是从高通 /MTK 拉取的,有问题有需求给高通 /MTK 提 Case,高通 /MTK 提供 Patch 后,厂家 merge 。
2.老项目的大版本更新是很烦的,对于上层开发(驱动以上)来说,基本上就是新项目了。
3.国内型号太多了,人员是有限的,主力都是投入到新的旗舰项目上。没几个人愿意维护各种型号的老项目,更何况非旗舰型号的多半是外包出去的。
以上不一定正确,基于个人认知。

2021年3月下旬流通领域重要生产资料市场价格变动情况

中国统计信息服务中心  卓创资讯   据对全国流通领域9大类50种重要生产资料市场价格的监测显示,2021年3月下旬与3月中旬相比,24种产品价格上涨,25种下降,1种持平。 2021年3月下旬流通领域重要生产资料市场价格变动情况  产品名称 单位 本期价格(元) 比上期 价格涨跌(元) 涨跌幅 (%) 一、黑色金属         螺纹钢(Φ16-25mm,HRB400E) 吨 4775.4 109.6 2.3 线材(Φ6.5mm,HPB300) 吨 4912.5 117.4 2.4 普通中板(20mm,Q235) 吨 5162.9 184.6 3.7 热轧普通薄板(3mm,Q235) 吨 5268.7 223.6 4.4 无缝钢管(219*6,20#) 吨 5614.4 64.1 1.2 角钢(5#) 吨 5074.3 141.6 2.9 二、有色金属         电解铜(1#) 吨 66101.6 -594.4 -0.9 铝锭(A00) 吨 17273.5 -243.4 -1.4 铅锭(1#) 吨 15111.9 346.8 2.3 锌锭(0#) 吨 21743.8 33.8 0.2 三、化工产品         硫酸(98%) 吨 510.0 19.3 3.9 烧碱(液碱,32%) 吨 460.2 16.3 3.7 甲醇(优等品) 吨 2238.2 -39.3 -1.7 纯苯(石油苯,工业级) 吨 6229.9 -185.4 -2.9 苯乙烯(一级品) 吨 8526.2 -421.7 -4.7 聚乙烯(LLDPE,7042) 吨 8940.7 -223.6 -2.4 聚丙烯(T30S) 吨 9426.5 -212.0 -2.2 聚氯乙烯(SG5) 吨 8733.8 -187.4 -2.1 顺丁胶(BR9000) 吨 13607.2 97.9 0.7 涤纶长丝(FDY150D/96F) 吨 7775.0 -328.6 -4.1 四、石油天然气         液化天然气(LNG) 吨 3707.3 213.5 6.1 液化石油气(LPG) 吨 3952.5 34.7 0.9 汽油(95#国VI) 吨 7557.5 -64.6 -0.8 汽油(92#国VI) 吨 7306.8 -70.5 -1.0 柴油(0#国VI) 吨 6045.4 -152.0 -2.5 石蜡(58#半) 吨 7181.3 378.7 5.6 五、煤炭         无烟煤(洗中块) 吨 950.0 0.0 0.0 普通混煤(4500大卡) 吨 525.6 40.2 8.3 山西大混(5000大卡) 吨 605.0 50.0 9.0 山西优混(5500大卡) 吨 688.1 53.1 8.4 大同混煤(5800大卡) 吨 713.1 53.1 8.0 焦煤(主焦煤) 吨 1440.0 -42.9 -2.9 焦炭(二级冶金焦) 吨 2026.0 -271.4 -11.8 六、非金属建材         普通硅酸盐水泥(P.O 42.5袋装) 吨 465.4 5.4 1.2 普通硅酸盐水泥(P.O 42.5散装) 吨 417.4 3.9 0.9 浮法平板玻璃(4.8/5mm) 吨 2279.5 9.0 0.4 七、农产品(主要用于加工)         稻米(粳稻米) 吨 4076.1 -19.4 -0.5 小麦(国标三等) 吨 2538.1 -24.5 -1.0 玉米(黄玉米二等) 吨 2808.2 -41.4 -1.5 棉花(皮棉,白棉三级) 吨 15565.0 -611.9 -3.8 生猪(外三元) 千克 26.0 -1.9 -6.8 大豆(黄豆) 吨 5349.2 -78.4 -1.4 豆粕(粗蛋白含量≥43%) 吨 3299.0 -47.8 -1.4 花生(油料花生米) 吨 9475.0 -81.0 -0.8 八、农业生产资料         尿素(小颗料) 吨 2199.3 25.6 1.2 复合肥(硫酸钾复合肥,氮磷钾含量45%) 吨 2427.3 2.3 0.1 农药(草甘膦,95%原药) 吨 31800.0 1021.4 3.3 九、林产品         天然橡胶(标准胶SCRWF) 吨 13709.5 -891.9 -6.1 纸浆(漂白化学浆) 吨 6161.6 -169.7 -2.7 瓦楞纸(高强) 吨 4180.6 -35.7 -0.8 注:上期为2021年3月中旬。    附注   1.指标解释   流通领域重要生产资料市场价格,是指重要生产资料经营企业的批发和销售价格。与出厂价格不同,生产资料市场价格既包含出厂价格,也包含有经营企业的流通费用、利润和税费等。出厂价格与市场价格互相影响,存在时滞,两者的变动趋势在某一时间段内有可能会出现不完全一致的情况。   2.监测内容   流通领域重要生产资料市场价格监测内容包括9大类50种产品的价格。类别与产品规格说明详见附表。   3.监测范围   监测范围涵盖全国31个省(区、市)300多个交易市场的近2000家批发商、代理商、经销商等经营企业。   4.监测方法   价格监测方法包括信息员现场采价,电话、即时通讯工具和电子邮件询价等。   5.涨跌个数的统计   产品价格上涨、下降、持平个数按照涨跌幅(%)进行统计。   6.发布日期   每月4日、14日、24日发布上一旬数据,节假日顺延。 附表:流通领域重要生产资料市场价格监测产品规格说明表  序号 监测产品 规格型号 说明   一、黑色金属      1   螺纹钢 Φ16-25mm,HRB400E 屈服强度≥400MPa  2 线材 Φ6.5mm,HPB300 屈服强度≥300MPa  3 普通中板 20mm,Q235 屈服强度≥235MPa  4 热轧普通薄板 3mm,Q235 屈服强度≥235MPa  5 无缝钢管 219*6,20# 20#钢材,屈服强度≥245MPa  6 角钢 5# 屈服强度≥235MPa   二、有色金属      7 电解铜 1# 铜与银质量分数≥99.95%  8 铝锭 A00 铝质量分数≥99.7%  9 铅锭 1# 铅质量分数≥99.994% 10 锌锭 0# 锌质量分数≥99.995%   三、化工产品     11  硫酸 98% H2SO4质量分数≥98% 12 烧碱(液碱) 32% NaOH质量分数≥32%的离子膜碱 13 甲醇 优等品 水质量含量≤0.10% 14 纯苯(石油苯) 工业级 苯纯度≥99.8% 15 苯乙烯 一级品 纯度≥99.5% 16 聚乙烯(LLDPE) 7042 熔指:2.0±0.5g/10min 17 聚丙烯 T30S 熔指:3.0±0.9g/10min 18 聚氯乙烯 SG5 K值:66-68 19 顺丁胶 BR9000 块状、乳白色,灰分≤0.20% 20 涤纶长丝 FDY150D/96F 150旦,AA级   四、石油天然气     21 液化天然气 LNG 甲烷含量≥75%,密度≥430kg/m3 22 液化石油气 LPG 饱和蒸汽压1380-1430kPa 23 汽油 95#国VI 国VI标准 24 汽油 92#国VI 国VI标准 25 柴油 0#国VI 国VI标准 26 石蜡 58#半 熔点不低于58℃   五、煤炭     27 无烟煤 洗中块 挥发分≤8% 28 普通混煤 4500大卡 山西粉煤与块煤的混合煤,热值4500大卡 29 山西大混 5000大卡 质量较好的混煤,热值5000大卡 30 山西优混 5500大卡 优质的混煤,热值5500大卡 31 大同混煤 5800大卡 大同产混煤,热值5800大卡 32 焦煤  主焦煤 含硫量<1% 33 焦炭 二级冶金焦 12.01%≤灰分≤13.50%   六、非金属建材     34 普通硅酸盐水泥 P.O 42.5袋装 抗压强度42.5MPa 35 普通硅酸盐水泥 P.O 42.5散装 抗压强度42.5MPa 36 浮法平板玻璃 4.8/5mm 厚度为4.8/5mm的无色透明玻璃   七、农产品(主要用于加工)     37 稻米 粳稻米 杂质≤0.25%,水分≤15.5% 38 小麦 国标三等 杂质≤1.0%,水分≤12.5% 39 玉米 黄玉米二等 杂质≤1.0%,水分≤14.0% 40 棉花(皮棉) 白棉三级 纤维长度≥28mm,白或乳白色 41 生猪 外三元 三种外国猪杂交的肉食猪 42 大豆 黄豆 杂质≤1.0%,水分≤13.0% 43 豆粕 粗蛋白含量≥43% 粗蛋白≥43%,水分≤13.0% 44 花生 油料花生米 杂质≤1.0%,水分≤9.0%   八、农业生产资料     45 尿素 小颗料 总氮≥46%,水分≤1.0% 46 复合肥 硫酸钾复合肥 氮磷钾含量45% 47 农药(草甘膦) 95%原药 草甘膦质量分数≥95%   九、林产品     48 天然橡胶 标准胶SCRWF 杂质含量≤0.05%,灰分≤0.5% 49 纸浆 漂白化学浆 亮度≥80%,黏度≥600cm³/g 50 瓦楞纸 高强 80-160g/m2  

流式布局

流式布局

文章目录
前言
一、流式布局原理
二、二倍精灵图做法
三、渐变背景图
总结
前言
来学习流式布局啦,这里主要制作一个项目来融会贯通流式布局的用法和相关技术。

一、流式布局原理
将盒子的宽度设为百分比,很具屏幕的宽度来进行伸缩,不受固定像素的限制,内容向两侧填充。

代码如下(示例):

<!DOCTYPE html>
<html lang=”en”>
<head>
<meta charset=”UTF-8″>
<meta http-equiv=”X-UA-Compatible” content=”IE=edge”>
<meta name=”viewport” content=”width=device-width, initial-scale=1.0,user-scalable=no,maximum=1.0,minimum=1.0″>
<title>Document</title>
<style>
body {
min-width: 320px;
max-width: 980px;
}
section {
width: 100%;
height: 100px;
background-color: pink;
}
div {
float: left;
width: 50%;
height: 100px;
box-sizing: border-box;
background-color: purple;
}
</style>
</head>
<body>
<section>
<div class=”box1″>

</div>
<div class=”box2″>

</div>
</section>
</body>
</html>

流式布局的优点:
当页面宽度发生变化时,页面布局会随着宽度的变化而变化。
适合移动端网页的制作。

二、二倍精灵图做法
将精灵图大小尺寸缩放为原来的一半,量取此时的坐标位置,background-size的像素值大小也要写原来精灵图的一半。

代码如下(示例):

.search-box .search i {
float: left;
width: 18px;
height: 15px;
margin: 8px 0 0 15px;
background: url(../images/jd-sprites.png) no-repeat -82px 0;
background-size: 200px 200px;

三、渐变背景图
background-image:linear-gradient

代码如下(示例):

/* 渐变轴为45度,从蓝色渐变到红色 */
linear-gradient(45deg, blue, red);

/* 从右下到左上、从蓝色渐变到红色 */
linear-gradient(to left top, blue, red);

/* 从下到上,从蓝色开始渐变、到高度40%位置是绿色渐变开始、*后以红色结束 */
linear-gradient(0deg, blue, green 40%, red);

总结
近几天学习了流动布局来制作移动端网页,具体项目内容就不全部写在这里了,每天坚持学习前端。
%title插图%num

基于pytorch的Bert模型

基于pytorch的Bert模型

代码真的好难啊,就算是照着抄也会错,真的是服了,大半天就只做了这一个事,还好的是*后都敲出来了。

源代码参考网址:https://github.com/aespresso/a_journey_into_math_of_ml/blob/master/04_transformer_tutorial_2nd_part/BERT_tutorial/models/bert_model.py

论文网址:

BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding

 

我的代码:

# data: 20210404
# author: lmt

from __future__ import absolute_import, division, print_function, unicode_literals

import copy
import math
import sys
from io import open
import torch
from torch import nn
from torch.nn import CrossEntropyLoss

def gelu(x):
”’Implementation of the gelu activation function,
For information: OpenAI GPT’s gelu is slightly different (and gives slightly different results):
0.5 * x * (1 +torch.tanh(math.sqrt(2/math.pi) *( x + 0.044715 * torch.pow(x,3)))
”’
return x * 0.5 * (1.0 + torch.erf(x / math.sqrt(2.0)))

ACT2FN = {“gelu”: gelu, “relu”: torch.nn.functional.relu}

class BertConfig(object):
”’configuration class to store the configuration of a BertModel”’
def __init__(self,
vocab_size, #字典字数
hidden_size=384, #隐藏层维度也就是字向量维度
num_hidden_layer = 6, #transformer block 的个数
num_attention_heads = 12, #注意力机制“头”的个数
intermediate_size = 384*4, #feedforward层线性映射的维度
hidden_act=”gelu”, #激活函数
hidden_dropout_prob = 0.4, #dropout的概率
attention_probs_dropout_prob = 0.4,
max_position_embedding = 512 *2,
type_vocab_size = 256, #用来做next sentence预测,这里预留了256个分类,其实我们目前用到的只有0和1
initializer_range = 0.02 #用来初始化模型参数的标准差
):
self.vocab_size = vocab_size
self.hidden_size = hidden_size
self.num_hidden_layer = num_hidden_layer
self.num_attention_heads = num_attention_heads
self.intermediate_size = intermediate_size
self.hidden_act = hidden_act
self.hidden_dropout_prob = hidden_dropout_prob
self.attention_probs_dropout_prob = attention_probs_dropout_prob
self.max_position_embedding = max_position_embedding
self.type_vocab_size = type_vocab_size
self.initializer_range = initializer_range

class BertEmbeddings(nn.Module):
“””LayerNorm层, 见Transformer(一), 讲编码器(encoder)的第1部分”””
“””Construct the embeddings from word, position and token_type embeddings.
“””
def __init__(self, config):
super(BertEmbeddings, self).__init__()
self.word_embeddings = nn.Embedding(config.vocab_size, config.hidden_size, padding_idx=0)
self.token_type_embeddings = nn.Embedding(config.type_vocab_size, config.hidden_size)
# embedding矩阵初始化
nn.init.orthogonal_(self.word_embeddings.weight)
nn.init.orthogonal_(self.token_type_embeddings.weight)

# embedding矩阵进行归一化
epsilon = 1e-8
self.word_embeddings.weight.data = \
self.word_embeddings.weight.data.div(torch.norm(self.word_embeddings.weight, p=2, dim=1, keepdim=True).data + epsilon)
self.token_type_embeddings.weight.data = \
self.token_type_embeddings.weight.data.div(torch.norm(self.token_type_embeddings.weight, p=2, dim=1, keepdim=True).data + epsilon)

# self.LayerNorm is not snake-cased to stick with TensorFlow model variable name and be able to load
# any TensorFlow checkpoint file
self.LayerNorm = BertLayerNorm(config.hidden_size, eps=1e-12)
self.dropout = nn.Dropout(config.hidden_dropout_prob)

def foward(self, input_ids, postional_enc, token_type_ids=None):
“””
:param input_ids: 维度 [batch_size, sequence_length]
:param positional_enc: 位置编码 [sequence_length, embedding_dimension]
:param token_type_ids: BERT训练的时候, *句是0, 第二句是1
:return: 维度 [batch_size, sequence_length, embedding_dimension]
“””
# 字向量查表
words_emdeddings = self.word_embeddings(input_ids)

if token_type_ids is None:
token_type_ids = torch.zeros_like(input_ids)
token_type_embeddings = self.token_type_embeddings(token_type_ids)

embeddings = words_emdeddings + postional_enc +token_type_embeddings
#embeddings: [batch_size, sequence_length, embedding_dimension]
embeddings = self.LayerNorm(embeddings)
embeddings = self.dropout(embeddings)
return embeddings

class BertSelfAttention(nn.Module):
”’自注意力机制层,”’
def __init__(self, config):
super(BertSelfAttention, self).__init__()
#判断embedding dimension 是否可以被num_attention_heads整除
if config.hidden_size % config.num_attention_heads != 0:
raise ValueError(
“The hidden size (%d) is not a multiple of the number of attention”
“heads (%d)” % (config.hidden_size, config.num_attention_heads))
self.num_attention_heads = config.num_attention_heads
self.attention_head_szie = int(config.hidden_size / config.num_attention_heads)
self.all_head_size = self.num_attention_heads * self.attention_head_szie
# Q, K, V线性映射
self.query = nn.Linear(config.hidden_size, self.all_head_size)
self.key = nn.Linear(config.hidden_size, self.all_head_size)
self.value = nn.Linear(config.hidden_size, self.all_head_size)

self.dropout = nn.Dropout(config.attention_probs_dropout_prob)

def trabspose_for_scores(self,x):
# 输入X为QKV中的一个,维度:[batch_size, seq_length, embedding_dim]
# 输出的维度经过reshape和转置:[batch_size, num_heads, seq_length, embedding_dim / num_heads]
new_x_shape = x.size()[:-1] + (self.num_attention_heads, self.attention_head_szie)
x = x.view(*new_x_shape)
return x.permute(0, 2, 1, 3)

def forward(self, hidden_states, attention_mask, get_attention_matrices=False):
# Q, K, V线性映射
# Q, K, V的维度为[batch_size, seq_length, num_heads * embedding_dim
mixed_query_layer = self.query(hidden_states)
mixed_key_layer = self.key(hidden_states)
mixed_value_layer = self.value(hidden_states)
”’把QKV分割成num_heads份,把维度转换为[batch_size, num_heads, seq_length, embedding_dim / num_heads]”’
query_layer = self.trabspose_for_scores(mixed_query_layer)
key_layer = self.trabspose_for_scores(mixed_key_layer)
value_layer = self.trabspose_for_scores(mixed_value_layer)

”’Take the dot product between “query” and “key” to get the raw attention scores
Q与K求点积
”’
attention_scores = torch.matmul(query_layer, key_layer.transpose(-1, -2))
#attention_scores:[batch_size, num_heads, seq_length, seq_length]
#除以K的dimension, 开平方根以归一为标准正态分布
attention_scores = attention_scores / math.sqrt(self.attention_head_szie)
#apply the attention mask is (precomputed for all layers in BertModel forward() function)
attention_scores = attention_scores + attention_mask
# attention_mask 注意力矩阵mask:[batch_size, 1,1,seq_length]
#元素相加后,会广播到维度:[batch_size, num_heads, seq_length, seq_length]

#softmax归一化,得到注意力矩阵
#Normalize the attention scores to probabilities
attention_probs_ = nn.Softmax(dim=-1)(attention_scores)

”’This is actually dropping out entire tokens to attend to, which might seem a bit unusual, but is taken from the original Transformer paper”’
attention_probs = self.dropout(attention_probs_)

#用注意力矩阵加权V
context_layer = torch.matmul(attention_probs, value_layer)
#把加权后的V reshape,得到[batch_size, length, embedding_dimension]
context_layer = context_layer.permute(0, 2,1,3).contiguous()
new_context_layer_shape = context_layer.size()[:-2] + (self.all_head_size,)
context_layer = context_layer.view(*new_context_layer_shape)
#输出attention矩阵用来可视化
if get_attention_matrices:
return context_layer, attention_probs_
return context_layer,None

print(’22’)

class BertLayerNorm(nn.Module):
”’LayerMorm层”’

def __init__(self, hidden_size, eps=1e-12):
”’construct a layernorm module in the TF style (epsilon inside the square root”’
super(BertLayerNorm, self).__init__()
self.weight = nn.Parameter(torch.ones(hidden_size))
self.bias = nn.Parameter(torch.zeros(hidden_size))
self.variance_epsilon = eps

def forward(self,x):
u = x.mean(-1, keepdim=True)
s = (x – u).pow(2).mean(-1, keepdim=True)
x = (x – u) / torch.sqrt(s + self.variance_epsilon)
return self.weight * x + self.bias

class BertSelfOutput(nn.Module):
#封装的LayerNorm和残差连接,用于处理SelfAttention的输出
def __init__(self, config):
super(BertSelfOutput, self).__init__()
self.dense = nn.Linear(config.hidden_size, config.hidden_size)
self.LayerNorm = BertLayerNorm(config.hidden_size, eps=1e-12)
self.dropout = nn.Dropout(config.hidden_dropout_prob)

def forward(self, hidden_states, input_tensor):
hidden_states = self.dense(hidden_states)
hidden_states = self.dropout(hidden_states)
hidden_states = self.LayerNorm(hidden_states + input_tensor)
return hidden_states

class BertAttention(nn.Module):
# 封装的多头注意力机制部分,包括layernorm和残差连接
def __init__(self, config):
super(BertAttention,self)
self.self = BertSelfAttention(config)
self.output = BertSelfOutput(config)

def forward(self, input_tensor, attention_mask, get_attention_matrices=False):
self_output, attention_matrices = self.self(input_tensor, attention_mask, get_attention_matrices)
attention_output = self.output(self_output, input_tensor)
return attention_output, attention_matrices

class BertIntermediate(nn.Module):
#封装的feedforward层和激活层
def __init__(self, config):
super(BertIntermediate, self).__init__()
self.dense = nn.Linear(config.hidden_size, config.intermediate_size)
self.intermediate_act_fn = ACT2FN[config.hidden_size]

def forward(self, hidden_states):
hidden_states = self.dense(hidden_states)
hidden_states – self.intermediate_act_fn(hidden_states)
return hidden_states

class BertOutput(nn.Module):
#封装的layernorm和残差连接,用于处理feedforward层的输出
def __init__(self, config):
super(BertOutput, self).__init__()
self.dense = nn.Linear(config.intermediate_size, config.hidden_size)
self.LayerNorm = BertLayerNorm(config.hidden_size, eps=1e-12)
self.dropout = nn.Dropout(config.hidden_dropout_prob)

def forward(self, hidden_states, input_tensor):
hidden_states = self.dense(hidden_states)
hidden_states = self.dropout(hidden_states)
hidden_states = self.LayerNorm(hidden_states + input_tensor)
return hidden_states

class BertLayer(nn.Module):
#一个transformer block
def __init__(self, config):
super(BertLayer, self).__init__()
self.attention = BertAttention(config)
self.intermediate = BertIntermediate(config)
self.output = BertOutput

def forward(self, hidden_states, attention_mask, get_attention_matrices=False):
# Attention层(包括LayerNorm和残差连接
attention_output, attention_matrices = self.attention(hidden_states, attention_mask, get_attention_matrices = get_attention_matrices)
#Feedforward层
intermediate_output = self.intermediate(attention_output)
#LayerNorm与残差连接输出层
layer_output = self.output(intermediate_output, attention_output)
return layer_output, attention_matrices

print(‘3′)

class BertEncoder(nn.Module):
#transformer blocks * N
def __init__(self, config):
super(BertEncoder, self).__init__()
layer = BertLayer(config)
#复制N个transformer block
self.layer = nn.ModuleList([copy.deepcopy(layer) for _ in range(config.num_hidden_layers)])

def forward(self, hidden_states, attention_mask, output_all_encoded_layers=True, get_attention_matrices = False):
”’
output_all_encoded_layers:是否输出每一个transformer block的隐藏层计算结果
get_attention_matrices:是否输出注意力矩阵,可用于可视化
”’
all_attention_matrices = []
all_encoder_layer = []
for layer_module in self.layer:
hidden_states, attention_matrices = layer_module(hidden_states, attention_mask, get_attention_matrices=get_attention_matrices)
if output_all_encoded_layers:
all_encoder_layers.append(hidden_states)
all_attention_matrices.append(attention_matrices)
if not output_all_encoded_layers:
all_encoder_layer.append(hidden_states)
all_attention_matrices.append(attention_matrices)
return all_encoder_layer, all_attention_matrices

print(‘4′)

class BertPooler(nn.Module):
”’Pooler是把隐藏层(hidden state)中对应#CLS的token的一条提取出来的功能”’
def __init__(self, config):
super(BertPooler, self).__init__()
self.dense = nn.Linear(config.hidden_size, config.hidden_size)
self.activation = nn.Tanh()

def forward(self, hidden_states):
”’we “pool” the model by simply taking the hidden state corresponding
to the first token
”’
first_token_tensor = hidden_states[:, 0]
pooled_output = self.dense(first_token_tensor)
pooled_output = self.activation(pooled_output)
return pooled_output

#线性映射,激活,layernorm
class BertPredictionHeadTransform(nn.Module):
def __init__(self, config):
super(BertPredictionHeadTransform, self).__init__()
self.dense = nn.Linear(config.hidden_size, config.hidden_size)
self.transform_act_fn = ACT2FN[config.hidden_act]
self.LayerNorm = BertLayerNorm(config.hidden_size, eps=1e-12)

def forward(self, hidden_states):
hidden_states = self.dense(hidden_states)
hidden_states = self.transform_act_fn(hidden_states)
hidden_states = self.LayerNorm(hidden_states)
return hidden_states

class BertLMPredictionHead(nn.Module):
def __init__(self, config, bert_model_embedding_weights):
super(BertLMPredictionHead, self).__init__()
#线性映射,激活, layernorm
self.transform = BertPredictionHeadTransform(config)

”’The output weights are the same as the input embedding, but there is an output_only bias for wach token”’
self.decoder = nn.Linear(bert_model_embedding_weights.size(1),
bert_model_embedding_weights.size(0),
bias=False)
”’上面是创建一个线性映射层,把transformer block输出的[batch_size, seq_len, embed_dim]
映射为[batch_size, seq_len, vocab_size],也就是把*后一个维度映射成字典中字的数量,
获取MaskedLM的预测结果,注意这里其实也可以直接矩阵成embedding矩阵的转置,
但一般情况下我们要随机初始化新的一层参数”’

self.decoder.weight = bert_model_embedding_weights
self.bias = nn.parameter(torch.zeros(bert_model_embedding_weights.size(0)))

def forward(self, hidden_states):
hidden_states = self.transform(hidden_states)
hidden_states = self.decoder(hidden_states) + self.bias
return hidden_states

#Bert的训练中通过隐藏层输出masked LM的预测和 Next Sentence的预测

class BertPreTrainingHeads(nn.Module):
”’bert的训练中通过隐藏层输出Masked LM的预测和 Next Sentence的预测”’
def __init__(self, config, bert_model_embedding_weights):
super(BertPreTrainingHeads, self).__init__()
self.predictions = BertLMPredictionHead(config, bert_model_embedding_weights)
”’
把transformer block输出的[batch_size,seq_len, embed_dim]
映射为[batch_size, seq_len, vocab_size]
用来进行MaskedLM预测

”’
self.seq_relationship = nn.Linear(config.hidden_size, 2)
”’用来把pooled_output也就是对应#CLS#的那一条向量映射为2分类
用来进行Next Sentence”’

def forward(self, sequence_output, pooled_output):
prediction_scores = self.predictions(sequence_output)
seq_relationship_score = self.seq_relationship(pooled_output)
return prediction_scores, seq_relationship_score

# 用来初始化模型参数
class BertPreTrainedModel(nn.Module):
”’An abstract class to handle weights initialization and a simple interface for dowloading and loading pretrained models
用来初始化模型参数”’
def __init__(self, config, *inputs, **kwargs):
super(BertPreTrainedModel, self).__init__()
if not isinstance(config, BertConfig):
raise ValueError(
“Parameter config in `{}(config)` should be an instance of class `BertConfig`. ”
“To create a model from a Google pretrained model use ”
“`model = {}.from_pretrained(PRETRAINED_MODEL_NAME)`”.format(
self.__class__.__name__, self.__class__.__name__
))
self.config = config

def init_bert_weights(self, module):
”’Initialize the weight”’
if isinstance(module, (nn.Linear)):
#初始线性映射层的参数为正态分布
module.weight.data.normal_(mean=0.0, std=self.config.initializer_range)
elif isinstance(module, BertLayerNorm):
#初始化layernorm中的alpha为全1, beta为全0
module.bias.data.zero_()
module.weight.data.fill_(1.0)
if isinstance(module, nn.Linear) and module.bias is not None:
#初始化偏置为0
module.bias.data.zero_()
print(‘5′)

class BertModel(BertPreTrainedModel):
”’双向transformer词嵌入表示”’
“””BERT model (“Bidirectional Embedding Representations from a Transformer”).
Params:
config: a BertConfig class instance with the configuration to build a new model
Inputs:
`input_ids`: a torch.LongTensor of shape [batch_size, sequence_length]
with the word token indices in the vocabulary(see the tokens preprocessing logic in the scripts
`extract_features.py`, `run_classifier.py` and `run_squad.py`)
`token_type_ids`: an optional torch.LongTensor of shape [batch_size, sequence_length] with the token
types indices selected in [0, 1]. Type 0 corresponds to a `sentence A` and type 1 corresponds to
a `sentence B` token (see BERT paper for more details).
`attention_mask`: an optional torch.LongTensor of shape [batch_size, sequence_length] with indices
selected in [0, 1]. It’s a mask to be used if the input sequence length is smaller than the max
input sequence length in the current batch. It’s the mask that we typically use for attention when
a batch has varying length sentences.
`output_all_encoded_layers`: boolean which controls the content of the `encoded_layers` output as described below. Default: `True`.
Outputs: Tuple of (encoded_layers, pooled_output)
`encoded_layers`: controled by `output_all_encoded_layers` argument:
– `output_all_encoded_layers=True`: outputs a list of the full sequences of encoded-hidden-states at the end
of each attention block (i.e. 12 full sequences for BERT-base, 24 for BERT-large), each
encoded-hidden-state is a torch.FloatTensor of size [batch_size, sequence_length, hidden_size],
– `output_all_encoded_layers=False`: outputs only the full sequence of hidden-states corresponding
to the last attention block of shape [batch_size, sequence_length, hidden_size],
`pooled_output`: a torch.FloatTensor of size [batch_size, hidden_size] which is the output of a
classifier pretrained on top of the hidden state associated to the first character of the
input (`CLS`) to train on the Next-Sentence task (see BERT’s paper).
Example usage:
“`python
# Already been converted into WordPiece token ids
input_ids = torch.LongTensor([[31, 51, 99], [15, 5, 0]])
input_mask = torch.LongTensor([[1, 1, 1], [1, 1, 0]])
token_type_ids = torch.LongTensor([[0, 0, 1], [0, 1, 0]])
config = modeling.BertConfig(vocab_size_or_config_json_file=32000, hidden_size=768,
num_hidden_layers=12, num_attention_heads=12, intermediate_size=3072)
model = modeling.BertModel(config=config)
all_encoder_layers, pooled_output = model(input_ids, token_type_ids, input_mask)
“`
“””
def __init__(self, config):
super(BertModel, self).__init__(config)
self.embeddings = BertEmbeddings(config)
self.encoder = BertEncoder(config)
self.pooler = BertPooler
self.apply(self.init_bert_weights)

def forward(self, input_ids, positionl_enc, token_type_ids=None, attention_mask=None, output_all_encoded_layers=True, get_attention_matrices=False):
if attention_mask is None:
#torch.LongTensor
#attention_mask = torch.ones_like(input_ids)
attention_mask = (input_ids > 0)
# attention_mask [batch_size, length]
if token_type_ids is None:
token_type_ids = torch.zeros_like(input_ids)
”’
# We create a 3D attention mask from a 2D tensor mask.
# Sizes are [batch_size, 1, 1, to_seq_length]
# So we can broadcast to [batch_size, num_heads, from_seq_length, to_seq_length]
# this attention mask is more simple than the triangular masking of causal attention
# used in OpenAI GPT, we just need to prepare the broadcast dimension here.
”’
extended_attention_mask = attention_mask.unsqueeze(1).unsqueeze(2)
”’
# 注意力矩阵mask: [batch_size, 1, 1, seq_length]
# Since attention_mask is 1.0 for positions we want to attend and 0.0 for
# masked positions, this operation will create a tensor which is 0.0 for
# positions we want to attend and -10000.0 for masked positions.
# Since we are adding it to the raw scores before the softmax, this is
# effectively the same as removing these entirely.
”’
extended_attention_mask = extended_attention_mask.to(dtype=next(self.parameters()).dtype) #fp16 compatibility
extended_attention_mask = (1.0 – extended_attention_mask) * -10000.0
#给注意力矩阵里padding的无效区域加一个很大的负数的偏置,为了使softmax之后这些无效区域仍然为0,不参与后续计算

#embedding层
embedding_output = self.embeddings(input_ids, positionl_enc, token_type_ids)
#经过所有定义的transformer block之后的输出
encoded_layers, all_attention_matrices = self.encoder(embedding_output,
extended_attention_mask,
output_all_encoded_layers=output_all_encoded_layers,
get_attention_matrices=get_attention_matrices)
#可输出所有层的注意力矩阵用于可视化
if get_attention_matrices:
return all_attention_matrices
#[-1]为*后一个transformer block的隐藏层的计算结果
sequence_output = encoded_layers[-1]
#pooled_output为隐藏层中CLS对应的token的一条向量
pooled_output = self.pooler(sequence_output)
if not output_all_encoded_layers:
encoded_layers = encoded_layers[-1]
return encoded_layers, pooled_output

class BertForPreTraining(BertPreTrainedModel):
“””BERT model with pre-training heads.
This module comprises the BERT model followed by the two pre-training heads:
– the masked language modeling head, and
– the next sentence classification head.
Params:
config: a BertConfig class instance with the configuration to build a new model.
Inputs:
`input_ids`: a torch.LongTensor of shape [batch_size, sequence_length]
with the word token indices in the vocabulary(see the tokens preprocessing logic in the scripts
`extract_features.py`, `run_classifier.py` and `run_squad.py`)
`token_type_ids`: an optional torch.LongTensor of shape [batch_size, sequence_length] with the token
types indices selected in [0, 1]. Type 0 corresponds to a `sentence A` and type 1 corresponds to
a `sentence B` token (see BERT paper for more details).
`attention_mask`: an optional torch.LongTensor of shape [batch_size, sequence_length] with indices
selected in [0, 1]. It’s a mask to be used if the input sequence length is smaller than the max
input sequence length in the current batch. It’s the mask that we typically use for attention when
a batch has varying length sentences.
`masked_lm_labels`: optional masked language modeling labels: torch.LongTensor of shape [batch_size, sequence_length]
with indices selected in [-1, 0, …, vocab_size]. All labels set to -1 are ignored (masked), the loss
is only computed for the labels set in [0, …, vocab_size]
`next_sentence_label`: optional next sentence classification loss: torch.LongTensor of shape [batch_size]
with indices selected in [0, 1].
0 => next sentence is the continuation, 1 => next sentence is a random sentence.
Outputs:
if `masked_lm_labels` and `next_sentence_label` are not `None`:
Outputs the total_loss which is the sum of the masked language modeling loss and the next
sentence classification loss.
if `masked_lm_labels` or `next_sentence_label` is `None`:
Outputs a tuple comprising
– the masked language modeling logits of shape [batch_size, sequence_length, vocab_size], and
– the next sentence classification logits of shape [batch_size, 2].
Example usage:
“`python
# Already been converted into WordPiece token ids
input_ids = torch.LongTensor([[31, 51, 99], [15, 5, 0]])
input_mask = torch.LongTensor([[1, 1, 1], [1, 1, 0]])
token_type_ids = torch.LongTensor([[0, 0, 1], [0, 1, 0]])
config = BertConfig(vocab_size_or_config_json_file=32000, hidden_size=768,
num_hidden_layers=12, num_attention_heads=12, intermediate_size=3072)
model = BertForPreTraining(config)
masked_lm_logits_scores, seq_relationship_logits = model(input_ids, token_type_ids, input_mask)
“`
“””
def __init__(self, config):
super(BertPreTrainedModel,self).__init__(config)
self.bert = BertModel(config)
self.cls = BertPreTrainingHeads(config, self.bert.embeddings.word_embeddings.weight)
self.apply(self.init_bert_weights)
self.vocable_size = config.vocab_size
self.next_loss_func = CrossEntropyLoss()
self.mlm_loss_func = CrossEntropyLoss(ignore_index=0)

def compute_loss(self, predictions, labels, num_class=2, ignore_index=-100):
loss_func = CrossEntropyLoss(ignore_index=ignore_index)
return loss_func(predictions.view(-1, num_class), labels.view(-1))

def forward(self, input_ids, positional_enc, token_type_ids=None, attention_mask=None,
masked_lm_labels=None,next_sentence_label=None):
sequence_output, pooled_output = self.bert(input_ids, positional_enc, token_type_ids, attention_mask, output_all_encoded_layers=False)
mlm_preds, next_sen_preds = self.cls(sequence_output, pooled_output)
return mlm_preds, next_sen_preds

print(‘6’)

编码和字符格式化

Python基础学习(七)编码和字符格式化

文章目录
1.中文编码
1.1 Python2编码问题
1.2 奇怪的Windows
2.字符格式化
2.1 %格式化
2.2 format格式化
1.中文编码
1.1 Python2编码问题
#!/usr/bin/python
print(‘Python学习’)

Python 文件中如果未指定编码,在执行过程会出现报错:

File “test.py”, line 2
SyntaxError: Non-ASCII character ‘\xe4’ in file test.py on line 2, but no encoding declared; see http://www.python.org/peps/pep-0263.html for details

指定编码后

#!/usr/bin/python
#coding=utf-8 #指定编码方式utf-8
print(‘Python学习’)
运行结果:
Python学习

1.2 奇怪的Windows
python2.x 脚本加上 # — coding: UTF-8 — 或者 #coding=utf-8 后windows 命令提示符下输出中文字符串还会出现乱码。

解决方法需要先使用 decode(“utf-8”) 转换成 utf-8 编码,然后使用 encode(“gbk”) 转换成 gbk
编码,才能在 windows 命令提示符下正常输出中文。 原因是 windows 命令提示符的显示编码为 gbk 编码。 在命令提示符下使用
chcp 查询编码。 “活动代码页:936” 代表命令提示符的编码为 “gbk” “活动代码页:65001” 代表命令提示符的编码为
“utf-8”

代码演示:

#coding=utf-8
s=”我是中文 ”
print s.decode(“utf-8”).encode(“gbk”)

2.字符格式化
2.1 %格式化
#coding=utf-8
s=’Sam’
n = 1
print (‘我叫 %s,我已经 %d 岁了’%(s,n)) #如果遇到字符‘%’,用‘%%’表示‘%’
运行结果:
我叫 Sam,我已经 1 岁了

2.2 format格式化
#coding=utf-8
s=’Sam’
n = 1
print (‘我叫 {},我已经 {} 岁了’.format(s,n))
运行结果:
我叫 Sam,我已经 1 岁了

python 循环,字符串切片练习题

python 循环,字符串切片练习题

 

 

Thear are 10 problems waited for you to complete.These questions are so easy,all given from my python teacher chosen from after-class exercise. Here i just record my exercising course,and the code block is below.

illustration:every case here I used two ways to complete.one is used for circle ,its form as for i in range (a,b),and another is used while circle.personally,I prefer the first way than the latter one,mostly because its more convient and easy.we can achieve what we wanted in few lines

 

#case1:输出所有的三位水仙花数,其各位数字立方和等于该数本身

#1.

for i in range(100,1000):

a=str(i)

if (i==int(a[0])**3+int(a[1])**3+int(a[2])**3):

print(i)

#2.

data=100

 

while data<=999:

a=data//100

c=(data%100)//10

b=data%10

if data==a**3+b**3+c**3:

print(data)

data=data+1

#case2:求1-1000之间能被13整除的*大的那个数

#1.

for i in range(1,1001):

if i%13==0:

num=i

print(num)

#2.

data=1

while data%13==0:

num=data  #设置一个新变量用于保存*大值

data=data+1

print(data)

#case3:键盘上输入n,求1+1/2+1/3+…..+1/n

#1.

n=eval(input(“请输入一个整数:”))

sum=0

for i in range(1,n+1):

sum=sum+1/i

print(sum)

#2.

n=eval(input(“请输入一个整数:”))

i=1

sum=0

while i<=n:

sum=sum+1/i

i+=1

print(sum)

#case4有数列2/3、4/5、6/8、10/15、16/25、26/41….求此数列前30项的和:

#1.

a,b=2,3

sum=2/3

for i in range(1,30):

a,b=b+1,a+b

sum=sum+a/b

#print(sum)

#2.

a,b=2,3

sum=2/3

i=1

while i<30:

a,b=b+1,a+b

sum=sum+a/b

i+=1

print(sum)

#case5:键盘输入i,打印九九乘法表的第i行

#先来练习打印整个9*9乘法表:

for a in range(1,10):

for b in range(1,10):

if b<=a:

result=a*b

print(“{}*{}={}”.format(b,a,result),end=’ ‘)

if b==a:

print()

#1、

n=eval(input(“please input an integer in 1-9:”))

for a in range(1,10):

for b in range(1,10):

if b<=a:

result=a*b

if n==a:

print(“{}*{}={}”.format(b,a,result),end=’ ‘)

 

#2.

n=eval(input(“please input an integer in 1-9:”))

if n<1 or n>9:

print(“the data you input is invalid!”)

else:

j=1

while j<=n:

print(“{}*{}={}”.format(j,n,j*n),end=’ ‘)

j=j+1

#case6:计算pi的值 pi≈4*(1-1/3+1/5-1/7+…….)

#1、

pi=0

sign=1

for i in range(1,500):

pi=(1+(sign*1/(2*i+1)))

sign=-sign

print(pi*4)

#2.

pi=0

sign=1

i=0

while i<=500:

pi=1+(sign*1/(2*i+1))

sign=-sign

i+=1

print(pi*4)

#case7:展示斐波那契数列前n项

#1、

n=eval(input(“你想展示前几项?请输入一个>2的数:”))

a=b=1

result=[a,b]

for i in range(3,n+1):

a,b=b,a+b

result.append(b)

print(result)

#2.前n项和

n=eval(input(“how many times you wang to calculate?,please input:”))

result=[1,1]

i=2

while i<=n:

result.append(result[-1]+result[-2])

i=i+1

print(sum(result))

#case8:输入m,n,计算m和n的*大公约数和*小公倍数

#1、

m,n=eval(input(“input m,n:”))

max_fac=1

a=max(m,n)

for i in range(1,a):

if m%i==0 and n%i==0:

max_fac=i

print(“*大公约数是:{}”.format(max_fac))

print(“*小公倍数是:{}”.format(m*n/max_fac))

 

#2.

m,n=eval(input(“input m,n:”))

i=1

max_fac=1

while i<=m and i<=n:

if m%i==0 and n%i==0:

max_fac=i

i+=1

print(“*大公约数是:{}”.format(max_fac))

print(“*小公倍数是:{}”.format(m*n/max_fac))

#case9:设置一个密码hello,用户登录(三次机会尝试)

#1、

pass_word=’hello’

 

pass_input=input(‘请您输入密码,您有3次机会’)

i=1  #i 设置为输入的次数

while i<3 and pass_input!=pass_word:

print(‘您输入的密码不正确.’)

pass_input=input(‘请您输入密码,您还有{}次机会’.format(3-i))

i=i+1

if pass_input==pass_word:

print(‘密码正确,欢迎登陆’)

else:

print(‘您已经输入错误三次,无法登陆!’)

i=0

#case10:删掉该段的标点符号和数字

#s = “What\’s a package, project, or release?We use a number of terms to describe software available on PyPI, like project, release, file, and package. Sometimes those terms are confusing because they\’re used to describe different things in other contexts. Here’s how we use them on PyPI:A project on PyPI is the name of a collection of releases and files, and information about them. Projects on PyPI are made and shared by other members of the Python community so that you can use them.A release on PyPI is a specific version of a project. For example, the requests project has many releases, like requests 2.10 and requests 1.2.1. A release consists of one or more files.A file, also known as a package, on PyPI is something that you can download and install. Because of different hardware, operating systems, and file formats, a release may have several files (packages), like an archive containing source code or a binary wheel.”

#1、

s = ”'”What\’s a package, project, or release?

We use a number of terms to describe software available

on PyPI, like project, release, file, and package. Sometimes those

terms are confusing because they\’re used to describe different things

in other contexts. Here’s how we use them on PyPI:A project on PyPI is

the name of a collection of releases and files, and information about them.

Projects on PyPI are made and shared by other members of the Python

community so that you can use them.A release on PyPI is a specific

version of a project. For example, the requests project has many releases,

like requests 2.10 and requests 1.2.1. A release consists of one or more

files.A file, also known as a package, on PyPI is something that you can

download and install. Because of different hardware, operating systems,

and file formats, a release may have several files (packages), like an archive

containing source code or a binary wheel.””’

i=0

while i<len(s):

if s[i] in [‘\\’,”‘”,’.’,’?’,’1′,’2′,’:’,'(‘,’)’,’,’,'”‘]:

s=s.replace(s[i],”)

i=i+1

print(s)

#2.

i=0

while i<len(s):

if  not( s[i].isalpha() or s[i]==’ ‘):

s=s.replace(s[i],”)

i=i+1

print(s)

 

用pythonic的方法思考

改善python——用pythonic的方法思考

1. 知道你使用的python的版本
命令行

python -version

程序内

import sys

print(sys.version_info)
print(sys.version)

2. 遵循PEP8的风格
Python Enhancement Proposal #8

在线文档 http://www.python.org/dev/peps/pep-0008/
规则例子
space空格
缩进使用spaces 代替 tabs
每一级的缩进使用四个spaces
每行79个字符或者更少
长表达式换行也要缩进四个空格
函数与函数、类与类之间 必须被两个空行分开
类的函数需要被一行空行分开
不要在列表索引、函数调用或关键字参数赋值周围放空格
在变量赋值的前后放且仅放一个空格
命名
函数、变量和属性应采用小写下划线格式
私有实例属性应该采用__double_leading_下划线格式
类和异常应该大写
模块级常量应该是ALL_CAPS格式
类中的实例方法应该使用self作为*个参数的名称
类方法应该使用cls作为*个参数的名称
表达式和语句
使用内联否定(if a is not b)代替肯定的否定(if not a is b)
不要通过检查长度来检查空值(如[]或”)(if len(somelist) == 0), 而使用if not somelist
同上条,非空值使用 if somelist
避免单行的 if for while
import 总放在*前面
在导入模块时,总是使用模块的*对名称
如果必须进行相对导入,则使用显式语法from . import foo
导入应该按以下顺序分节:标准库模块,第三方模块,你自己的模块。
3. 知道 bytes、str和unicode之间的差别
字符串的表达
版本 表达方法
python2 unicode 和 str
python3 bytes 和 str
区分
有很多的方法可以将Unicode转为二进制数据,*常见的方法就是UTF-8
python 3 中的 str 实例 和python2 中的 unicode实例没有相关的二进制编码
Unicode–>二进制:encode
二进制–>Unicode: decode
确保类型返回一致
python3
# 始终返回str
def to_str(bytes_or_str):
return bytes_or_str.decode(‘utf-8’) if isinstance(bytes_or_str,bytes) else bytes_or_str

# 始终返回bytes
def to_bytes(bytes_or_str):
return bytes_or_str.encode(‘utf-8’) if isinstance(bytes_or_str,str) else bytes_or_str

4. 写辅助函数而不是复杂函数表达式
可读性

在python中很容易写一个表达式完成功能。例如解析URL

from urllib.parse import parse_qs
my_values = parse_qs(‘red=5&blue=0&green=’,
keep_blank_values=True)

print(repr(my_values))
>>>
{‘red’: [‘5’], ‘green’: [”], ‘blue’: [‘0’]}

目标:获得qs中*个数字,没有则返回0

复杂的表达式
red = my_values.get(‘red’, [”])
red = int(red[0]) if red[0] else 0

辅助函数
def get_first_int(values, key, default=0):
found = values.get(key, [”])
if found[0]:
found = int(found[0])
else:
found = default
return found

5. 知道如何对序列进行切片
切片可以很简单的实现于 list、str和bytes

切片可以扩展到任何实现了__getitem__和__setitem__特殊方法的Python类

基本语法

somelist[start:end]
切片之后不是同一对象

>>> a=[1,2,3,4,5,6]
>>> b=a[2:]
>>> b[2]=c
>>> id(a)
1991199427968
>>> id(b)
1991199443264
>>> a
[1, 2, 3, 4, 5, 6]
>>> b
[3, 4, 99, 6]

6. 避免在单个切片中使用start、end和stride
stride 为 -1 常用于反转字符串

>>> a=’abcdefg’
>>> a[::-1]
‘gfedcba’

但是遇到非ASC-II编码时候容易出错
>>> w=’谢谢’
>>> x=w.encode(‘utf-8’)
>>> x[::-1].decode(‘utf-8’)
Traceback (most recent call last):
File “<stdin>”, line 1, in <module>
UnicodeDecodeError: ‘utf-8’ codec can’t decode byte 0xa2 in position 0: invalid start byte

尽量不要同时使用负值,难以理解

7. 使用列表推导式而不是map和filter
# 求 a 中 偶阶方
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# 1. 简单的方法 列表推倒式子
even_square = [x**2 for x in a if x%2==0] # [4, 16, 36, 64, 100]

#2. 复杂的map搭配filter方法
alt=map(lambda x: x**2, filter(lambda x: x%2 ==0,a))

字典和set中的列表推导式
# 反转字典
res_dict={value,key for key,value in dict}

8. 避免在列表表达式中使用2个以上的表达式
难以阅读

matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
filtered = [[x for x in row if x % 3 == 0]
for row in matrix if sum(row) >= 10]
print(filtered)
>>>
[[6], [9]]

9. 考虑用于大型推导式的生成器表达式
第七点中如果用于读取文件中的行数value = [len(x) for x in open(‘/tmp/my_file.txt’)]

文件大的时候会占用大量内存
使用生成器进行替代

it = (len(x) for x in open(‘/tmp/my_file.txt’))
print(it)
>>>
<generator object <genexpr> at 0x101b81480>
print(next(it))
print(next(it))
>>>
100
57

生成器的另一个强大之处在于可以结合在一起

roots = ((x, x**0.5) for x in it)

print(next(roots))
>>>
(15, 3.872983346207417)

10. 使用enumerate而不是range
enumerate用惰性生成器包装任何迭代器
这个生成器生成一对循环索引和迭代器中的下一个值
flavor_list = [‘vanilla’, ‘chocolate’, ‘pecan’, ‘strawberry’]

#遍历列表的range 方法
for i in range(len(flavor_list)):
flavor = flavor_list[i]
print(‘%d: %s’ % (i + 1, flavor))

# 简便方法:enumerate
for i, flavor in enumerate(flavor_list):
print(‘%d: %s’ % (i + 1, flavor))

# 可以指定开始位置
for i, flavor in enumerate(flavor_list, 1):
print(‘%d: %s’ % (i + 1, flavor))

11. 使用zip并行处理迭代器
zip用一个惰性生成器包装了两个或多个迭代器。
zip生成器生成元组,其中包含每个迭代器的下一个值
names = [‘Cecilia’, ‘Lise’, ‘Marie’]
letters = [len(n) for n in names]

# 获得*长的名字并记下字母数

# 方法1:range
longest_name = None
max_letters = 0
for i in range(len(names)):
count = letters[i]
if count > max_letters:
longest_name = names[i]
max_letters = count

#方法2:enumerate
for i, name in enumerate(names):
count = letters[i]
if count > max_letters:
longest_name = name
max_letters = count

#方法3:zip
for name, count in zip(names, letters):
if count > max_letters:
longest_name = name
max_letters = count

注意点:如果您不确定zip的列表的长度是否相等,可以考虑使用itertools内置模块中的zip_longest函数
12.避免在for和while循环之后出现else块
else 会在正常退出时候执行,而在break时候不会执行

# else被执行
for i in range(3):
print(‘Loop %d’ % i)
else:
print(‘Else block!’)
>>>
Loop 0
Loop 1
Loop 2
Else block

# else 未被执行
for i in range(3):
print(‘Loop %d’ % i)
if i == 1:
break
else:
print(‘Else block!’)
>>>
Loop 0
Loop 1

13. 利用try/except/else/finally中的每个块
UNDEFINED = object()
def divide_json(path):
handle = open(path, ‘r+’) # May raise IOError
try:
data = handle.read() # May raise UnicodeDecodeError
op = json.loads(data) # May raise ValueError
value = (
op[‘numerator’] /
op[‘denominator’]) # May raise ZeroDivisionError
except ZeroDivisionError as e:
return UNDEFINED
else:
op[‘result’] = value
result = json.dumps(op)
handle.seek(0)
handle.write(result) # May raise IOError
return value
finally:
handle.close() # Always runs 无论如何都会被执行

推荐稳定 BGP 机房

推荐稳定 BGP 机房,访客集中在北上广沿海地区

ivmm 1
ivmm 2017-06-14 08:07:24 +08:00
阿里云华东 1 华北 3

如果不做游戏,那就华东 1 吧
kmahyyg 2
kmahyyg 2017-06-14 08:16:14 +08:00 via Android
找 kana
kmahyyg 3
kmahyyg 2017-06-14 08:17:32 +08:00 via Android
eyun.ac.cn 企鹅 28 八 5497 二 32
lzjygn 4
lzjygn 2017-06-14 12:13:59 +08:00
美团云吧
quanidc 5
quanidc 2017-06-16 10:23:50 +08:00
客户在北上广深的话那就北上广深的 BGP *好了啊,北京上海的 BGP 带宽比较贵,推荐用深圳的,性价比稍微高点,需要的话可以详细聊聊哈
d754903977 6
d754903977 2017-06-17 19:07:23 +08:00
萌百现在腾讯云用的不是挺好嘛
wintab 7
wintab 2017-06-18 17:13:27 +08:00 via Android
eflycloud.com 10m 以上 bgp 超优惠
wangzhangwei 8
wangzhangwei 2017-06-19 10:50:21 +08:00
如果是阿里云选择北京 2 区(机房在北京),1 区青岛,3 区是张家口。如果自己有服务器要托管建议北京电信运营商的机房,比如兆维、上地、马驹桥都是电信核心骨干机房,比自建机房、联通要稳定的多,出口带宽也*大。线路首选北京 BGP,北京的 BGP 做的时间早,很成熟,全国来讲价格也是*便宜的,如果能拿到 IP 地址,要测试一下是不是北京本地出口 BGP 线路,包含外地的 BGP 线路不如本地 BGP 稳定。
cyearsir 9
cyearsir 2017-06-20 10:38:22 +08:00
https://store.imcloud.tw/cart.php 台灣的看看考慮不
bclerdx 10
bclerdx 2017-08-06 22:42:26 +08:00
@wangzhangwei 北京 BGP 有这么牛逼?

xingshi8 11
xingshi8 2017-10-20 15:22:00 +08:00
朋友,有需要稳定 BGP,可以联系我 2881711411
idcwk 12
idcwk 2018-11-23 15:36:04 +08:00
独立服务器联系我 82520043

友情链接: SITEMAP | 旋风加速器官网 | 旋风软件中心 | textarea | 黑洞加速器 | jiaohess | 老王加速器 | 烧饼哥加速器 | 小蓝鸟 | tiktok加速器 | 旋风加速度器 | 旋风加速 | quickq加速器 | 飞驰加速器 | 飞鸟加速器 | 狗急加速器 | hammer加速器 | trafficace | 原子加速器 | 葫芦加速器 | 麦旋风 | 油管加速器 | anycastly | INS加速器 | INS加速器免费版 | 免费vqn加速外网 | 旋风加速器 | 快橙加速器 | 啊哈加速器 | 迷雾通 | 优途加速器 | 海外播 | 坚果加速器 | 海外vqn加速 | 蘑菇加速器 | 毛豆加速器 | 接码平台 | 接码S | 西柚加速器 | 快柠檬加速器 | 黑洞加速 | falemon | 快橙加速器 | anycast加速器 | ibaidu | moneytreeblog | 坚果加速器 | 派币加速器 | 飞鸟加速器 | 毛豆APP | PIKPAK | 安卓vqn免费 | 一元机场加速器 | 一元机场 | 老王加速器 | 黑洞加速器 | 白石山 | 小牛加速器 | 黑洞加速 | 迷雾通官网 | 迷雾通 | 迷雾通加速器 | 十大免费加速神器 | 猎豹加速器 | 蚂蚁加速器 | 坚果加速器 | 黑洞加速 | 银河加速器 | 猎豹加速器 | 海鸥加速器 | 芒果加速器 | 小牛加速器 | 极光加速器 | 黑洞加速 | movabletype中文网 | 猎豹加速器官网 | 烧饼哥加速器官网 | 旋风加速器度器 | 哔咔漫画 | PicACG | 雷霆加速