最早博客图床用的是七牛云,每个月有免费的10G HTTP流量对于这个根本没人看的站来说绰绰有余。后来上了 HTTPS 之后就只好给七牛交几毛钱使用费。然而近几年域名备案政策严格。未备案的域名已经无法使用国内的云服务了。只好选择自己搭建图床系统。其中Chevereto应该算是最好用的了。之前好像用的 Docker 安装。这次尝试了下直接安装。因为不熟悉 PHP 网站部署踩了一点坑……
首先安装依赖(不含Nginx 和 Mysql)
1 |
|
对于怎么启动一个 PHP 服务,可以参考 DigitalOcean 的文章How To Install Linux, Nginx, MySQL, PHP (LEMP stack) on Ubuntu 18.04
安装 Chevereto 的话,比起网上的下载源码安装。我更推荐使用官网的在线安装脚本 https://chevereto.com/free
1 |
|
然后添加 Nginx 配置文件。
1 |
|
Nginx 配置生效后,就可以打开网址。配置站点名,数据库,初始超级用户,等待自动安装完成了。
]]>前些天发现自己的几台服务器年久失修,在修理的时候手滑把数据都删了……那就从头来过吧,辣鸡服务商最高只提供14.04的系统,那 DD 做个18.04,再重新加上各种优化,记笔记水几篇文章?
由于 apt 即使引入了第三方源安装 Nginx 的版本也很低,为了实践最新的特性,只好从源码编译安装 Nginx。
Nginx 依赖 openssl
(SSL加密),pcre
(prel正则库)和zlib
(压缩库)。其中 openssl
更新比较快,也采用源码方式引入。
sudo apt install -y build-essential libpcre3 libpcre3-dev zlib1g-dev unzip git
wget https://www.openssl.org/source/openssl-1.1.1a.tar.gztar zxf openssl-1.1.1a
Brotli 是 Google 开源的高效的压缩算法。性能比 gzip 好很多
git clone https://github.com/google/ngx_brotlicd ngx_brotligit submodule update --init
wget https://nginx.org/download/nginx-1.15.8.tar.gztar zxf nginx-1.15.8.tar.gz
为了保持习惯(apt 安装的 nginx)一致,我指定了 nginx 的配置,日志,pid 文件路径。加入了之前下载的ngx_brotli
和openssl
。启用了http_v2
和http_ssl
这两个HTTP/2相关模块,http_gzip_static
支持预编译压缩文件(抄Jerry Qu的,自己并没有用上),stream
支持 TCP/UDP转发
./configure \--prefix=/etc/nginx \--conf-path=/etc/nginx/nginx.conf \--sbin-path=/usr/local/bin/nginx \--pid-path=/run/nginx.pid \--http-log-path=/var/log/nginx/access.log \--error-log-path=/var/log/nginx/error.log \ --add-module=../ngx_brotli \ --with-openssl=../openssl-1.1.1a --with-openssl-opt='enable-tls1_3' \ --with-http_v2_module \--with-http_ssl_module \--with-http_gzip_static_module \--with-streammakesudo make install
都用18.04了,那就用systemd
来管理吧,配置文件都是 Nginx 官网抄的
vim /etc/systemd/system/nginx.service
[Unit]Description=The NGINX HTTP and reverse proxy serverAfter=syslog.target network.target remote-fs.target nss-lookup.target[Service]Type=forkingPIDFile=/run/nginx.pidExecStartPre=/usr/local/bin/nginx -tExecStart=/usr/local/bin/nginxExecReload=/usr/local/bin/nginx -s reloadExecStop=/bin/kill -s QUIT $MAINPIDPrivateTmp=true[Install]WantedBy=multi-user.target
sudo systemctl daemon-reloadsudo systemctl start nginxsudo systemctl status nginx # 启动后查看下服务是否正常sudo systemctl enable nginx # 开机自启
# user nobody;worker_processes auto;pid /run/nginx.pid;events {use epoll;worker_connections 809044;accept_mutex off;multi_accept off;}http {### Basic Settings##include /etc/nginx/mime.types;default_type application/octet-stream;charsetUTF-8;sendfileon;tcp_nopushon;tcp_nodelayon;keepalive_timeout 65;types_hash_max_size 2048;server_names_hash_max_size 4096;# server_tokens off;server_names_hash_bucket_size 128;client_max_body_size 2m;# server_name_in_redirect off;server_tokens off;### SSL Settings##ssl_ciphersECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:DES-CBC3-SHA;ssl_prefer_server_ciphers on;ssl_protocolsTLSv1 TLSv1.1 TLSv1.2 TLSv1.3;### Logging Settings##log_formatkd_access_log'$remote_addr - $remote_user [$time_local] "$request" ''$status $body_bytes_sent "$http_referer" ''"$http_user_agent" "$http_x_forwarded_for" ''$upstream_addr $upstream_response_time $request_time';access_log /var/log/nginx/access.log kd_access_log;error_log /var/log/nginx/error.log;### Gzip Settings##gzipon;gzip_varyon;gzip_comp_level6;gzip_buffers16 8k;gzip_min_length1000;gzip_proxiedany;gzip_disable"msie6";gzip_http_version1.0;gzip_typestext/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript image/svg+xml;# 如果编译时添加了 ngx_brotli 模块,需要增加 brotli 相关配置brotlion;brotli_comp_level6;brotli_typestext/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript image/svg+xml;### Virtual Host Configs##include /etc/nginx/conf.d/*.conf;include /etc/nginx/sites-enabled/*;}
server {listen 443 ssl http2 fastopen=3 reuseport; # 这里有个问额:第二个网站配置时只能写 listen 443; 否则会报错,但是 http2 特性也是能用的,还没找到原因server_name blog.kdwycz.com;access_log /var/log/nginx/blog.access.log kd_access_log;error_log /var/log/nginx/blog.error.log;location / {alias /home/kdwycz/blog/;}ssl_session_cache shared:SSL:10m;ssl_session_timeout 60m;ssl_session_tickets on;# ssl_staplingon;# ssl_stapling_verifyon;# ssl_trusted_certificate;ssl_certificate /home/kdwycz/certs/cert.pem;ssl_certificate_key /home/kdwycz/privkey.pem;}server {listen 80;server_name blog.kdwycz.com;if ($request_method = GET) { return 301 https://$server_name$request_uri;}return 308 https://$server_name$request_uri;}
在各处参考(抄袭)之下完成了看似很不错的 Nginx 配置,但是很多原理层面的东西还是模糊的。近期在看更深入的 Nginx 教程。慢慢补全文中的坑吧
(个人理解)传统的设计模式是为了解决C++/Java在面对组织大量代码的经验汇总,以及弥补一些语言语法本身的缺陷。而之后出现的编程语言从发明之初就解决了C++/Java的一部分问题。很多设计模式在Python中是语法的一部分。所以对于Python来说设计模式非常的弱化(这就是你工作三年还没系统学过设计模式的理由? →_→)
不过既然是前人套路的总结,了解下还是能扩宽自己的思路的。更多的还是为了方便的和其他工程师聊天吧(说模式的名字一脸懵逼,了解了实现方式后才知道都是自己做过的东西)
这篇文章是基于《Python编程实战:运用设计模式、并发和程序库创建高质量程序》设计模式部分的总结,结合了一些其他地方的资料。
对于初学者来说,遵照KISS和DRY原则就足够了。没有写过大量代码就去学习怎么组织大量代码的方法是事倍功半的。
创建型模式提供了一些创建对象的套路
总觉得《Python编程实战》的代码diagram*.py有点问题:工厂方法create_diagram接受的参数是产品类,而不是通过参数判断实例化哪个产品类。那要你有何用?
关于简单工厂/工厂/抽象工厂模式的区别见参考资料一
举个栗子,健身房管理SaaS很常见的一个需求是根据用户提供的excel表格向系统中导入数据。excel表格的格式有很多(只讨论文件格式,内容格式是规定好的):xls,xlsx,csv等等。都是要从表格中获取数据,但是不同文件格式要调用不同的库来处理。所以我们有了三种表格的操作类
class BaseSheet(object): def open(self, file_path): raise NotImplementedError def save(self, data): raise NotImplementedErrorclass XLSSheet(BaseSheet): def open(self, file_path): # 调用xlrd实现open方法 pass def save(self, data): # 调用xlwt实现save方法 passclass XLSXSheet(BaseSheet): # 调用openpyxl实现open和save方法 passclass CSVSheet(BaseSheet): # 调用csv实现open和save方法 pass
工厂模式就是实现一个工厂类(方法),用于调用不同的Sheet类(实例化对象,调用类/对象的方法等)
class SheetFactory(object): SHEET_DICT = { 'xls': XLSSheet, 'xlsx': XLSXSheet, 'csv': CSVSheet, } @classmethod def get_sheet(cls, extensions) if extensions not in cls.SHEET_DICT: raise Exception('不支持的文件类型') return cls.SHEET_DICT[extensions]
如果一个对象实例化非常的复杂(需要很多的参数,调用很多方法才能成功的实例化这个对象)。那么可以实现一个建造者类(方法)来实例化这个对象
如何复制一个对象?deepcopy
走起啊
《Python编程实战》总结了几种对象实例化的方法(有些东西看看就好,不要去学)
class Point: __slots__ = ('x', 'y') def __init__(x, y): self.x = x self.y = ydef make_object(Class, *args, **kwargs): return Class(*args, **kwargs)point1 = Point(1, 2)point2 = eval('%s(%d, %d)' % ('Point', 2, 4)) # Riskypoint3 = getattr(sys.modules[__name__], "Point")(3, 6)point4 = globals()['Points'](4, 8)point5 = make_object(Point, 5, 10)point6 = copy.deepcopy(point5)point6.x = 6point6.y = 12point7 = point1.__class__(7, 16)
单例模式可以很方便的管理全局唯一的状态或者全局变量,Python怎么实现单例也是个很经典的问题了。还衍生出了Brog模式
基于元类的单例实现
# 基类定义class SingletonMetaclass(type): def __init__(self, *args, **kwargs): self.__instance = None super().__init__(*args, **kwargs) def __call__(self, *args, **kwargs): if self.__instance is None: self.__instance = super(SingletonMetaclass, self).__call__(*args, **kwargs) return self.__instance else: return self.__instance# 单例类class Foo(metaclass=SingletonMetaclass): """注意: 根据Singleton的定义, 构造函数一般需要使用默认的构造函数""" def get_addr(self): return id(self)
修改__new__
方法实现单例
class Singleton(object): __instance = None def __new__(cls, *args, **kw): if not cls.__instance: cls.__instance = super().__new__(cls, *args, **kw) return cls.__instanceclass Foo(Singleton): pass
一个实现方法类似的装饰器
# singleton装饰器def singleton(cls, *args, **kw): instances = {} def _singleton(): if cls not in instances: instances[cls] = cls(*args, **kw) return instances[cls] return _singleton# 单例类@singletonclass Foo(object): pass
定义完类直接实例化,要啥自行车
class _MySingleton(object): """ 我们使用下划线开头, 告诫调用者, 不要直接 new 也不要来访问这个class """ def __init__(self, name, age): self._name = name self._age = age def print_name(self): print(self._name)# 可以定制多个全局实例S1 = _MySingleton('s1', 22)S2 = _MySingleton('s2', 11)# 之后只需要import S1, S2就好了
最后说下Brog模式: python中对象的所有属性存放在__dict__
中,直接更改它来实现单例
class Borg(object): __shared_state = {} def __init__(self, *args, **kwargs): self.__dict__ = self.__shared_state# 另一个装饰器的版本def borg(cls): cls.__shared_state = {} orig_init = cls.__init__ def new_init(self, *args, **kwargs): self.__dict__ = cls.__shared_state orig_init(self, *args, **kwargs) cls.__init__ = new_init return cls@borgclass TestBorg(object): def say_borg(self): print "i am borg"
结构型模式提供了一些继承重写对象,合并分拆对象的套路
前面说到的Excel操作类。如果我们已经有了一个OldXLSSheet
类能完成Excel文件操作,但是它的方法并不是open
,save
,无法直接被使用。
我们可以继承这个类,用父类的其他方法来实现我们想要的open
,save
方法。
还是前面说到的表格操作类,工厂模式关注的是类的创建;桥接模式关注的是在其他的类里面可以调用任何一种表格操作类的open
,save
方法,而不用关心调用的是哪个表格操作类以及它们的具体实现(毕竟实现了一样的方法/接口)
组合模式是一个对象可以把多个对象组合在一起,可以增加,移除,遍历子对象(类似二叉树?)
对于Python来说,Dict对象是天然的组合模式(感觉并没有什么用的样子)
如果一个类的方法过于晦涩难用,或者缺乏安全性检查,或者输出不友好:可以再写几个好用的方法来取代它们(和适配器模式做的事情一样,目的不同)
一些很小而且功能相同的对象,可以只给每个类实例化一个对象,然后共享它(似乎想到了单例的某种实现?
某个对象在一个无法触及到的地方(另一个项目?)想要调用它的方法和数据。需要一个本地的Proxy对象,通过网络调用实现目的。RPC的既视感~
代理模式也可以用作单元测试,所需要的类尚未开发完毕,缺失很多方法的时候。“模拟对象”可以提供所有的方法/功能,用桩(stub)来表示那些缺失的功能。
书上还举了一个ImageProxy
类的例子。Image
类提供了各种在画布上绘制图形的方法。而ImageProxy
的对应方法只会把操作记下来,并不会直接执行。直到调用保存方法的时候,才会去依次执行绘制方法并保存。lazy loading
行为型模式提供了组织程序运行过程的套路
一个事件可以被很多事件处理程序类来处理。每个时间处理程序类只需要关注自己属否处理,怎么处理这个事件;以及是否交给后面的程序类继续处理这个事件。
最常见的责任链模式应该就是管道(pipeline)了吧
类似于GUI软件,支持保持做过的每一个操作,撤销和重试,延迟执行,以及宏机制。之前的ImageProxy
已经有一点这个意思了。
自己写一个DSL的样子。。。略过吧
参考Python标准的迭代器
又是个很适合GUI的模式:两组互相通讯的类不需要知道对方的实现,只通过中间层进行通讯(是不是很像代理模式?
备忘录模式可以在不破坏封装的前提下把一个对象保存和读取(序列化和反序列化)
有一目标物(subject,即observable),有众多观察者(observers)关注其异动;
目标物维护观察者列表,故若要新增观察者,则需向此目标物注册该新观察者;
当目标物有状态变化时,会主动通知在其注册的所有观察者,方式为:以for循环调用所有观察者的notify()方法;故所有观察者都需要有notify()方法
然后抽象出观察者和目标基类
在调用对象的同一个方法时,这个方法会根据对象中某个属性的值完成不同的行为(也可能根据属性的值调用不同的方法
策略模式能把一系列“可互换”的算法封装起来,并根据用户需求来选择使用哪一种
模版方法模式定义了一个算法步骤,其中一些步骤依赖子类的实现。可以通过调用不同的子类还完成不同的实现方式
怎么看都是同一个需求不同层面上的实现
对于一组固定的数据,可以使用不同的访问者类来对这些数据进行不同的操作。目标是不耦合数据和操作
好像一开始看书还会把每个模式的代码实现都写下,后面的越看越觉得无聊就不想写了(虽然确实扩宽了思路)。可能是很多设计模式更适合解决客户端开发遇到的问题而我日常开发并没有遇到这些问题,或是Python设计之初就内置了很多设计模式让我觉得这些东西都是理所当然的。
当然以上对设计模式的理解都是非常粗浅的。还需要多看一些他人多心得和代码。不过作为对组织代码的指导来说,设计原则(类似KISS,SOLID)还是更加普适一些
和冷冰冰的概念比起来,这本书更像是经验丰富的老司机们的重构项目经验之谈.适合1-3年的工程师审视自己的项目,找出问题所在,并结合书上的方案去解决问题
剩下的监控,持续集成工具放最后一章来说
重构最大的问题从来就不是重构代码本身
首先要和团队成员达成共识,虽然很少有人是绝对的传统主义者或者反传统主义者.但是身上或多或少有这两类人的影子(处于两者之间吧)
传统主义者是一个强烈反对任何形式变化的开发者.他们认为重构让我们的开发人员花费太多精力在任务之外的事情,并且重构会带来不必要的风险
反传统主义者厌恶一切遗留代码.但是过度的重构也会带来新的bug,并且过度重写团队中其他人的代码会带来互相埋怨和士气的降低
小范围的代码调整并不需要耗费工作计划中可见的时间,但是大规模的重构是需要的.
根据难度/风险和痛点/价值的象限来判断,当然是先捡软柿子捏
重写一般情况下都是不现实的
当然,如果重构无法实现目的或者整个公司的技术栈转向,重写可能是更好的选
在绞杀者模式的重写中,新系统围绕现有系统构建,截取其输入和输出,并逐渐承担越来越多的功能,直到最终原有系统静静地消亡
漫无目的的重构带来过度修改,整个重构工程开始了却无法收尾,最后只好放弃所有的改动
一般情况下要重构的代码都是要有单元测试的,这样可以方便的知道重构会不会带来回归问题.然而大多数需要重构的代码都没单元测试
把大的单体服务分层,或拆分成多个小服务
将一个有多种功能职责的模块分解为多个小模块,每个模块的职责单一,有显示的接口供其他模块进行调用
各种Web应用程序架构的比较
架构 | 技术优势 | 技术挑战 | 组织优势 | 组织挑战 |
---|---|---|---|---|
单体 | 低延时 开发简单 没有重复的模型/验证 | 伸缩 由于代码库过大引发的复杂度 意想不到的交互的危险 | 特性内沟通的开销低 | 失败的恐惧 特性间沟通的开销大 |
前后端分离 | 能够单独的扩展前端和后端 将业务逻辑与表示分离 能够复用后端并构建多个前端 | 由于网络调用引起的复杂度 | 专业性 能够更快的迭代前端 通往面向服务架构的阶梯 | 沟通开销 知识壁垒 前后端开发相互阻塞 |
面向服务架构(SOA) | 细粒度的伸缩性 隔离 封装 | 运维开销 延时 服务发现 追踪/调试/日志记录 热点服务 API文档,客户端 集成测试 数据碎片 | 自治 | 自治程度的困境 重复工作的风险 |
微服务 | 与面向服务架构一样,只会更多 | 与面向服务架构一样,只会更多 隐形耦合的风险 | 由于有界上下文会产生更多的自治 | 意味着需要DevOps 需要一个平台团队 需要思维方式的重要切换 |
一个好的迁移方法是实现一个转换层,新系统的数据通过转换层和旧的数据库进行通信
特性和共享现有数据库是完全相反的
麻烦点在于新旧系统同时使用期间的数据同步问题
面对一个复杂系统开发环境的构建, Vagrant+Ansible大法好
用Ansible保持所有环境的一致性
Jenkins持续集成和自动化
上线的自动化
一个成功的软件项目有很多因素,高质量的源代码只是其中之一
源代码的改进只是重构的一小部分:团队沟通交流,维护开发工具链,自动化配置,持续集成和审查对于维护软件的质量更加重要
虽然看起来大家都很乐于分享正在工作的软件和知识,但是事实上有效的信息很少.每一个人都是知识的孤岛,一个开发人员的离职会使团队丢失大量有价值的信息
编写技术文档
促进团队沟通
开一篇文章总结下自己用过的VPS吧,不断更更新中
Vultr: https://www.vultr.com/
近年来风头正劲的厂商,地区的选择很多服务器质量也不错。而且和下面两家比最大的优势是有月付$2.5的服务器。个人搭个翻墙和小网站绰绰有余。不过月付$2.5的服务器日常处于没货状态。建议论坛收一个账号或者提前注册好账号等着优惠消息(一般放货后很快就卖完了。这家经常会有新注册账号首次充值送$20的活动,不少人在薅羊毛
DigitalOcean: https://www.digitalocean.com
我最早使用国外VPS用的就是DigitalOcean,因为Github学生包送了100刀余额(现在只送50刀了),让我免费的用了近两年。而且这家店帮助页面有大量的环境配置文章。我经常搜软件安装配置方法的时候找到他们的文章
Linode: https://www.linode.com/
御三家最老牌的厂商,据说稳定性最好,然而早年被太多的人用来翻墙导致IP被封锁严重,我曾试过开了四五个IP都是被墙的,默哀
GCE && AWS && Azure
一般个人用不起,而且服务器配置起来也有很多定制的地方。功能强大但是需要点时间入门。如果我以后有正式些的服务要挂出来在考虑付费= =
不过这些厂商在推广期都会有些免费的蛋糕:GCE和AWS都有新用户免费一年的活动。
物美价廉服务商的代表。有便宜的机器而且稳定性不错。虽然只有美国节点(最近有了香港节点)但是VPS开通后可以自由的切换节点。有CN2优化线路和一键部署翻墙功能(???)听说老板是中国人。
代表作是早已失传的$3.99 $4.99 $5.99 $9.99年付的主机,我在论坛上求了好久终于200块钱收到了一个。现在可以买到最便宜的是年付$19.99的服务器。和vultr一样日常没货。建议论坛收一个账号或者提前注册好账号等着优惠消息。这家有长期的优惠码,网上找一个输进去能有9.5的折扣
Virmach:https://virmach.com
传说中的价格屠夫,失传的低价服务器有$1年付的,$3两年付的……。能买到的机器有$4年付的,某些时候促销会放出来。
不仅仅是低配置服务器价格便宜,高配置服务器也有很多低价。我前两天在论坛上收了三个Virmach的账号,各自有一个8G内存的VPS。打算拿来挂一些吃内存的服务:Sentry,ELK什么的。
不过这家据说稳定性不好,而且TOS非常严格:单位时间内使用CPU,IO过高都会被停止服务,严重的时候会被封号。我目前还没发现不稳定和触犯TOS的情况……有消息再更新吧
打算长期持有的:
临时使用:
自从半年接了一个扎手的需求,博客就一直没更新过~然而更新的是这样的水文章真是惭愧。虽然我已经写了四五篇文章和读书笔记的草稿了,然而都是写一半挖坑没填完的……
其实这也是一篇厚颜无耻的AFF文。不爽的话可以把链接里面的推广ID去掉
]]>首先上一张成品图
初学Python的时候,常常因为Windows上出的各种问题抓狂,于是安装了Linux双系统。实习后很快买了台二手的Macbook。然而给其他萌新无论安利双系统,虚拟机,vagrant还是Macbook效果都不好。毕竟不是每个人都有修电脑满级的动手能力的。初学编程本来就要吸收很多知识。再加上不熟悉的系统和软件产生的问题。本来简单易学的知识也变得麻烦起来……
歪个楼,虽然很多人推荐Vim,Emacs,Sublime等编辑器,但是对于初学者而言上手成本低的IDE是更好的选择。专注于学习Python本身,足够熟练了再折腾Linux命令,编辑器使用是更好的选择。而对于IDE的选择,某些凑数的文章能列举十个八个的。其实唯一好的选择是Pycharm,而且学生可以免费获取到Professional版,没必要去搜盗版。
16年微软推出了Win10的Linux子系统(之后用WSL代替)。但是当时WSL需要预览版系统才安装且体验非常差。我安装也没怎么用过。一年过去,到今年五月的创造者更新时,WSL已经完善了很多,可以跑起Python和Node.js的工具链了。对于依赖*nix环境的开发人员,Windows已经可以部分取代MacOS和Ubuntu来换取更好的桌面体验(更多的可购买电脑选择)了。
为了方便萌新,把安装过程摘录如下
bash
,按照提示文字操作即可(是否使用当前时区选yes;用户名密码自己填)然后就进入了Linux的shell环境了。之后想进入的话还是在Powershell里面输入bash
Windows的C盘根目录对应在shell里面是/mnt/c/
,权限为777;而Linux的根目录在Windows里面是C:\Users\你的用户名\AppData\Local\lxss
。我对于文件共享的建议是文件和代码按照Windows的使用习惯放,把相关的文件夹软连接到wsl的home目录。
对于初学者来说,更多的情况是编码用Windows下的Pycharm,运行代码用wsl的环境。然而Pycharm需要代码的运行环境来进行静态检查,自动跳转等对初学者极其有帮助的功能。我们需要让Pycharm能够访问到wsl下的Python运行环境:
/etc/ssh/sshd_config
允许密码登录1 |
|
1 |
|
1 |
|
以下内容根据需要自选使用,用上好工具可以提升效率和心情,没有的话也无大碍
windows下面的终端环境无论是cmd还是powershell都是瞎眼般的配色和字体,而且很难改。在之前有一个还是不错的终端软件叫cmder。但是如果只是用wsl的话,我们有更好的选择wsl-terminal。
还有一个邪教:刚才不是开了ssh服务么,那么就能用ssh软件比如putty,xshell等直接连接127.0.0.1就好了,体验也很不错。
只安利两套字体包:
基于微软雅黑的YaHei Consolas Hybrid 1.12,有良好的中文体验(我设置成了系统默认字体
还有一个是Powerline Fonts,包含了各种有Powerline表情的编程字体。用过ohmyzsh和Powerline的都知道。下载后运行目录下的install.ps1
安装到系统。
刚才已经说过了:文件和代码按照Windows的使用习惯放,把相关的文件夹软连接到wsl的home目录
1 |
|
目前还不支持,只能考虑用曲线救国的方案:开启启动一个脚本,调起shell脚本启动服务。下面是一个例子
一个放在启动项里面的vbs脚本
1 |
|
home目录下的 autostart.sh 文件
1 |
|
sudo默认情况下是需要输入密码的,我们可以编辑/etc/sudoers
来避免输入密码
1 |
|
在使用中总会遇到一些奇怪的问题:Google搜一下,问问身边的人,实在不行就去开发组的Github上面提issue。
我刚安装的时候遇到了一个网络的灵异问题,搜索不到答案。最后去提issue得到了两个人热心的回复,虽然最后是自己重装系统后才发现因为我安装了火绒杀毒软件造成的不兼容……
话说上次买Mac的时候并不是很开心,期望的高性能不存在的,升级的东西除了指纹识别剩下的我也没有需求,反倒价格长了不少;MacOS近两年持续的负优化以及软件的不走心(Chrome迷之崩溃和占了1.6G内存的微信等);再加上这个平台的封闭的原罪,让我越发的想逃离.可是无论是Linux还是有子系统的WIN10或是带安卓的ChromeOS距离实用还差了不少.直到前些天看到了Windows10创意者更新,WSL已经能完整运行Python和Node工作流,让我动了迁移平台的心思.在虚拟机里面工作了一天之后,我便把Macbook在闲鱼上挂了出去,并且拍下了Surface Book(当然也是二手的)
15年10月,苹果的发布会十分平淡,而微软发布了令世人震撼的产品Surface Book,时至今日看到发布会的宣传视频还令人感到震撼(虽然有硬伤还那么贵,之后说).因为开发用,所以8G内存是必须的;Surface Book i5 8G 940m的价格已经算是探底.所以就入手了(大不了新的发售了再把旧的卖掉
首先,SB没有指纹识别,取而代之的是摄像头虹膜识别.只是用来登录系统的话,虹膜识别比起指纹体验还要更好一些:开盖或是随便按一个键然后看一眼就好了.毕竟Windows电脑加了指纹也只能用来开机(迷之片面,UWP支持Window Hello的应用也不少).失去了好用的1Password的我选择了KeePass.感受开源社区的强大力量(1p官方说windows端缺少人力短时间做不到支持windows hello,然而KeePass却有支持的uwp客户端)
在Win8的时代,uwp以及新版的开始屏幕是非常弱鸡的,虽然当时我很喜欢并且替换调了用了四五年的音速启动.到今天,uwp应用质量有了长足的进步,一些以来电容笔的重度应用给我带来的震撼不亚于刚用上iPad时.而且系统对uwp应用的统一调度带来的体验甚至超过了Android和iOS:我使用网易云音乐和Podcasts听音频,调节音量时发现可以在两个应用间自由切换.或许之后我在选择安装软件会优先用uwp的了
在触摸板上面,Windows也有了长足的进步.相比于15款的Mac已经不落下风了(不过16款Mac大触摸板用起来真爽)。整体的续航也给人了惊喜(多谢mac负优化的帮衬)
谈一下革命性的可分离设计。讲道理这样做是有硬伤的。能分离使用的只有独显(或许未来能在底座上放格外的16G内层条?),于是大量的配件都在屏幕那边。能做到不到800g的重量令人十分满意。但是电池容量和整机厚度就是血崩。而且和底座差不多的重量整体不算轻而且显得有些头重脚轻了,我把电脑放支架上使用的习惯凸显了这个问题。而且第一代电脑使用的940m明显有些不够用。既然底座没有散热压力为什么不上高一些的卡呢(然后就有了增强版的gtx965m)想想13寸轻薄本的最强配置还是挺有诱惑力的。
屏幕部分续航差,至少能充电不是?但是独家的磁吸线我也不想来回拿着走。要是能改成type-c就好了。还能接外设传输数据
那杆触摸笔被传的很神。但我是个实体笔用的都不多的人。感觉在屏幕上做笔记还是有点意思的。前两天有人无聊在公司群里发了到中学几何题。我直接放大图片就在屏幕上演算了(没算出来捂脸逃)。但是感觉灵敏度触感还是差了点。听说前两天新发布的Surface Pro是4096级的压感和20ms响应。或许会好很多(开始期待下一台电脑了
至于铰链,感觉还是有些不稳。至于无法合拢是完全的优点-还记得被键盘膜上指纹沾染屏幕支配的恐惧了吗?
虽然发布快两年了,bug也修了不少。但是我还是遇到了睡眠睡死过去,黑屏等不得不让人重启电脑的事情。和越来越不稳定的MacOS菜鸡互啄。
系统更新的话,小更新还好。大版本更新动辄半小时以上而且没有时间提醒。让我不知道它在更新还是死机了。
弱鸡的字体渲染和丑的不能看的shell。话说微软的同学这么多年对着cmd和powershell瞎眼的配色不累么。
和之前买二手mac一样,看起来如同初始化的系统总会遇到各种奇奇怪怪的问题。恢复出厂设置后也没有那么纯净。最后只好下载原厂的镜像文件重装。
贴上我暂时遇到的吧,全量数据总结在 我遇到Windows的坑 - 为知笔记
只是日常用的话,小问题还是要比Mac多的。多查资料来解决就好,毕竟这是个比烂的世界…
笔记本刚升级 win10 创造者更新,电脑经常莫名其妙的风扇呜呜响,查看任务管理器发现有一个叫 服务主机:task scheduler 的进程占用 CPU 50%-70%,总的 CPU 占用达90%多。通过任务管理器,手动关闭服务显示拒绝访问,只有重启服务才会关掉,风扇不再响,但是过了一会,它又自己启动了。而且不关的话,这个服务自己不会自动关闭,一直占用 CPU。
尝试在服务管理里禁用这个服务,但是属性显示是灰色,不可以设置。在计算机管理的任务计划程序里找到了task scheduler文件夹,但是内容是空的。
网上说这个服务是有用的,禁用会增加系统不稳定性,但是现在的问题是这个服务在持续不断的运行,一直不停,而且占用 CPU 风扇一直不停,该怎么解决呢,要找办法禁用这个服务吗?还是说是因为某些计划任务导致的,禁掉相关的计划任务就行呢?
回复:
了解到您遇到了关于系统进程的问题。请问您的系统中是否自行设置过计划任务?系统中是否安装有三方的安全管理软件?当前尝试执行以下操作,查看效果。若安装有三方的安全管理软件,请先卸载。1.Windows+r,输入:msconfig2.点击”服务”标签卡,选择”隐藏所有的微软服务”,然后点击全部禁用(若您启用了指纹识别功能,请不要关闭相关服务)3.点击”启动”标签卡, 点击”打开任务管理器”,然后禁用全部启动项并确定4. 重启设备。若弹出“系统配置实用程序”的时候,选中此对话框中的”不再显示这条信息”并点击确定5.Windows+x,打开“命令提示符(管理员),执行以下命令:DISM/Online /Cleanup-image /ScanhealthDISM/Online /Cleanup-image /RestorehealthSfc /scannow若无效,请打开任务管理器,点击详细信息,找到该服务的PID码。然后Windows+x,打开命令提示符(管理员),执行命令:tasklist /svc,找到相同PID码的task scheduler ,检查是何程序在占用CPU,然后将该界面截图上传。
Antimalware Service Executable CPU占用高
This is exactly the solution that most of the users that arrive here are looking for. There is an immediate drop in CPU usage by the service in question.
For those that don’t understand I’ll outline it a bit better:
Open Windows Defender
Open the “Settings” tab
Select “Excluded Files and Locations”
Select “Browse”
Navigate to C:\Program Files\Windows Defender\MsMpEng.exe (Unless Windows Defender is installed elsewhere for whatever reason)
Select “OK”
Select “Add”
Select “Save Changes”
The result should be immediate.
最近做了个需求,运营把微信公众号登各种来源的文章直接粘到我们的富文本编辑器上面。但是图片因为源站的防盗链挂掉了。于是需要把图片上传到又拍云上面:用BeautifulSoup把html中的图片链接解析出来,伪造HTTP_REFERER把图片下载到内存再上传到CDN
某天报了个奇怪的bug:文章图片被替换后,只有iOS设备无法正常加载图片,其他设备都正常。查了大半天错之后终于发现是iOS不是原生支持WebP格式图片的,而文章来源的微信公众号文章的图片都是WebP格式
讲道理虽然WebP是Google发明并推广的,不支持的浏览器也不少。但是当今Chrome内核已经是事实上的垄断了……于是兼容性被忽视了
有趣的是源站的文章图片显示正常,应该是微信公众号新闻根据不同设备的UA把图片转换格式了吧(大厂的黑科技真多→_→
一开始查到了imghdr
模块,使用起来倒是很简单:
1 |
|
只是这个库对文件类型的支持比较弱鸡,只识别以下格式。新一点的格式都无法识别
随后看了下Pillow的文档,很惊喜的发现了
Python Imaging Library 支持绝大多数的图片格式. 囊括了30多种. 虽然对写的支持稍微少了一些, 但是大部分的交换格式都是支持的.open() 方法使用文件内容来区分不同的文件, 除非你指定格式, 否则 save() 方法使用文件名来识别所需格式.
真是图片处理的瑞士军刀,话说当时在学校玩图像识别的时候为什么没有多看看Pillow的文档→_→
1 |
|
代码上线到生产环境报错,看了下生产环境的Pillow版本是2.5.1,升级到最新版后解决
7:10 早上带着一群多肉植物到公司,无法骑车。于是叫了辆滴滴专车。全程手捧花盆无法顾及到浅浅的裤兜。下车后下意识摸一下兜发现手机不在,然而汽车已经扬长而去…
7:40 到公司借了个手机,发现没有手机号滴滴登不上,电话找人工客服9点才上班→_→。还好微信绑着是google voice能登上,打开电脑定位手机,看着手机随着车转啊转啊…心态爆炸早上的锻炼也鸽了
用小米找回服务锁定了手机,填上了同事的电话。心想如果司机没发现手机的话应该算是安全。况且我还有手机一直在车上的证据(事后证明毫无卵用
8:00 话说小米会云端存储通话记录短信什么的。然而登录需要短信验证(找回手机的功能就不需要)虽然是个很贴心很好的设计…(如果当时能拿到司机手机号的话找回手机就会方便许多了
话说我前两天还在玩一个叫pushbullet的弱鸡软件,可以向手机发推送以及把手机的推送短信同步到电脑。然而看起来被后台杀掉了
9:00 终于等到滴滴客服上班的点,打电话询问。客服说联系司机后尽快回复。我挂电话后放心的出去买早点了…回来后发现手机被关机,定位也消失了。随后再问滴滴客服,他们说还没联系到司机。
此时我发现手机有可能找不回来,想清除手机数据。但是完全没有可能了…
后来他们回电说问过了司机和上车的几个乘客。他们都说没看到。对于我的质疑,客服表现的非常热情和礼貌…
10:30 然后只能想想怎么止损了,请了半天假以后先跑去营业厅去挂失sim卡。联通电信营业厅的排队都让我等到崩溃…
11:30 终于补办好sim卡,用公司的测试机恢复了正常使用账号的能力= =,这时滴滴和司机师傅的回复都是没看到手机。我对了下手上的资料,决定去公安局报警
12:30 去了讲台派出所,民警说798丢的东西归酒仙桥派出所管~于是我跟着导航跑了过去。酒仙桥派出所的民警听说是滴滴打车上遗失的物品,和同事交流滴滴的事情归谁管的问题= =。不过也非常的热情和礼貌…
看起来不找滴滴撕的话毫无办法,然而我对撕逼完全不在行
坐在派出所的椅子上整理思绪,除了下单购买一个小米6红米以外,对于一个root过而且开了usb调试的安卓手机来说,密码也不再安全…
这时候接到了一个陌生电话,说是捡到了手机的乘客,此时在北京南站。准备归还手机。他说打个专车把手机送过来。要我加微信事后把打车费给他= =
一个小时后,我收到了遗失的手机。有趣的是,联系他时说到我在公安局的时候他表现的很紧张。而且收到手机后我发现sim卡被拔了(并不是关机
毕竟是还回了手机,我非常感激的格外转了个200的微信红包给他,希望他下次捡到东西也能费力的联系归还吧
想想相对于十年前,我们拥有了无限潜力的工具:能够自动定位,和当时计算机性能一般强大的手机;能够追踪每一段行程的出租车。这两者重合在一起。又给我带来更多的快乐(白学家被拉出去打了),应该能杜绝丢手机了吧。然而这在一个人不承认面前完全没有用。各家的工具互相不承认数据,也无法及时查阅和导出。并且这些作为举证在政府部门那里可能起到的还是副作用(你去找那些公司嘛)想想还是会撕逼或者找外国人代报案要强得多→_→
事后想想,对于这件事起到最关键作用的还应该是滴滴了吧。虽然不知道他们是怎么问司机和乘客的。最后一个乘客联系司机要到了我的手机号。
或许看起来无法解锁的手机也是归还的契机?
记得移动互联网的上半场,账号还是可以用邮箱注册的。手机号只是辅助工具(PC时代的特征),然而之后的公司只允许手机号注册了…看起来是个无比英明的决定:与生俱来的实名制需求;顺带收集到了用户的核心资料;无所不至的强大推送(短信);在也不需要记密码的便捷登录;得到的,本该是像梦境一般幸福的时间……但是,为什么,会变成这样呢……
我能用google voice手机号替代的软件,都换用了。然而在突如其来的打击面前,还是非常的无力(毕竟能设置的是少数)。想想未来还是很需要一张(可能是虚拟)的手机卡注册各种应用。我能从自己任何一个设备访问到,私有部署或是可信的公有云都好
Mac和原生Android都有个很强大的功能:全盘加密。如果不知道密码的话,最多能清空磁盘,而不能获取到数据(虽然对于磁盘性能有损失)。小米的设置里面没看到
手机root过的话,而且开着usb调试。就有锁屏密码被绕过的可能性。后来问了下公司的安卓开发@纸团同学,他说没有USB指纹验证的话,电脑无法直接操纵手机的…但是也不知道有没有其他黑科技
最让我担心的除了联系人数据之外,还有两个关乎身家性命的软件:1password 和 btsync (至于支付软件,sim卡挂失之后可以算作是安全了)1password管理着我所有的密码,银行卡cv2码,而且开了指纹解锁(虽然更换指纹后指纹解锁失效,但是毕竟root了);btsync有个人资料的同步,而且不能远程解除一个端的访问权限,一个端泄密的话,目前看来只能放弃这个key,所有资料取消同步后买一个新的授权来用。
对于Android系统的安全性,还请指教= =我之后没必要时不会再开usb调试了
bug:在小米云服务的『设备定位』功能,可以启动手机的丢失模式。但是填写过提示文字和手机号后,再次修改没有生效。
建议1:如果你很在意手机中的数据的话,强烈建议在锁定手机后马上点击『清除数据』。锁定手机的状态是不会解除的。Google的相关功能我没有实验过…
]]>近期利用空闲时间(jia ban)把自己负责健身会议管理系统Django版本从1.6升级到了1.10,Python版本从2.7升级到了3.6。总结下升级的过程和遇到的问题吧(然而拖了两周才动笔基本忘得差不多了Orz
先说结论,赶时间的话之后的内容就没必要看了(反正写的也不好= =
每个项目使用的语法特性不一样,升级的版本也不同。对于不大的项目,一个比较好的方式是对于本地能正常运行的项目,升级完依赖包后启动,然后google+stackoverflow驱动改提示的错误,直到能正常使用为止。
其实刚到公司实习的时候见着老旧的依赖版本就想着能不能升级,由于经验不足和处理的过于激进失败了。一年多后才想起可以再尝试下
介绍下项目背景,会议系统是公司里代码量最小(Pyhton代码近2万行),也没有历史包袱,和其他项目之间依靠RPC协议通信的项目。基本实现了前后端分离,除了最早期的几个移动端页面。大部分代码都是业务相关的API,使用了内部的(伪)RESTful框架。迁移相对比较容易。
首先升级Django以及其他依赖包的版本,把依赖的包都升级到最新的版本,启动项目= =,毫无悬念的失败了。google+stackoverflow驱动改错下跌跌撞撞的改完能整除启动项目……居然完全可用。再解了数据库迁移的坑Django版本迁移就成功了。
关于数据库迁移,如果是新起一个实例的话就是用新的数据库迁移方法,只要保证APP下有migration这个包就行了。已经在线上运行的实例就麻烦些,要先去线上删掉旧的migration文件。
然后是Python版本的升级,替换茫茫然的unicode字符串和__future__
就已经很坑了,还好有自动化工具帮我们完成这件事,我使用了自带的工具2to3,转换效果还是相当好的。剩下的地方基本都是str和bytes的问题了
之前也看了很多人写的升级备忘。不过每个人使用的语法特性不一样,升级的版本也不同。除非是翻译文档,否则没人写的全的(所以我偷懒把写的提纲删了,参考资料里有一些他人的踩坑记录)
Django1.7之后提供了内建的数据库迁移工具,可以把south从INSTALLED_APPS移除了
和新的项目一样
1 |
|
- 确保south中的migration全部被应用了
- 从 INSTALLED_APPS中移除south
- 删除每个app下migration目录中的所有文件, 除了init.py
- 运行python manager.py makemigrations, Django会初始化migration
- 运行python manager.py migrate –fake, django将migration文件标记为已应用
from __future__ import division, unicode_literals, print_function
hasattr(self.order_by, '__iter__')
-> isinstance(self.order_by, (list, tuple))
value.has_key('selected')
-> 'selected' in value
except Exception, err:
-> except Exception as err:
map(lambda x: x.to_json(), meeting_objs)
-> [x.to_json() for x in meeting_objs]
import cStringIO StringIO
-> import io
import urllib
-> import urllib.request, urllib.parse, urllib.error
大部分Python项目都会有一个requirements.txt
,用来记录项目的依赖。主要的写法如下所示
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
pip freeze
会附带上一些不需要的包,以及某些包依赖的包~
requirements.txt
,讲道理为什么不直接写呢,要通过第三方包来做一层转换一般项目会分为开发环境,测试环境,生产环境等……依赖的包会不同。推荐在文件夹下为每个环境建立一个requirements.txt
文件。公有的包存在base.txt
供引用
1 |
|
由于上面提到的工具并不好用~还是推荐手动维护依赖列表。毕竟pip
安装后马上去编辑下依赖文件也不是什么麻烦事→_→
pip文档 Requirements Files
Two Scoops of Django
Django | requirement.txt 生成
pigar
引用Github的包-爆栈网
很久以前就开始看这本书,但是英语渣一直看的磕磕巴巴,但是最坑的是慢慢的发现我只是期望Django作为提供API的后端,对这个大而全的框架并不需要了解这么多……暂时的总结发出来吧,慢慢填坑(完全没有什么参考价值,除了这本书值得一看)
essary to read an entire function or method.
作者也对其中某一点提出了反对:虽说愚蠢的一致性是没有脑袋的妖怪,但是在一个某些地方不遵循PEP8的项目中,最好还是保持和之前代码的风格一致。
可以使用如flake8之类工具自动检查项目是否遵循PEP8
这里给出了三种import方法
Code | Import Type | Usage |
---|---|---|
from core.views import FoodMixin | absolute import | Use when importing from outside the current app |
from .models import WaffleCone | explicit relative | Use when importing from another module in the current app |
from models import WaffleCone | implicit relative | Often used when importing from another module in the current app, but not a good idea |
相关文章:《编写高质量代码:改善Python的91个建议》 19 && 20 节
不要依赖IDE吗(没看懂)
在开发和生产环境使用相同的数据库引擎。有如下的好处
推荐PostgreSQL(然而国内变有没有多少人用)
还有个好用的工具 virtualenvwrapper
Vagrant or Docker
1 |
|
一个看起来很强大的一直在更新的项目模版
和本书配套的方案
django-admin.py startproject --template=https://github.com/imkevinxu/django-kevin/archive/master.zip --extension=py,md,html,json,coveragerc PROJECT_NAME
Unix philosophy: Write programs that do one thing and do it well. – 每一个App只专注于一件事
除了标准的模块,本书还提供了一些别的惯用模块命名
behaviors.py : An option for locating model mixins per subsection 6.5.1.
constants.py :A good name for placement of app-level settings.If there are enough of them involved in an app, breaking them out into their own module can add clarity to a project.
decorators.py Where we like to locate our decorators. For more information on decorators, see section 9.3.
db/ Used in many projects for any custom model fields or components.
fields.py is commonly used for form fields, but is sometimes used for model fields when there isn’t enough field code to justify creating a db/ package.
factories.py Where we like to place our test data factories. Described in brief in subsection 22.3.5
helpers.py What we call helper functions. These are where we put code extracted from views (sub-section 16.3.3) and models (section 6.5) to make them lighter. Synonymous with utils.py
managers.py When models.py grows too large, a common remedy is to move any custom model managers to this module.
signals.py While we argue against providing custom signals (see chapter 28), this can be a useful place to put them.
utils.py Synonymous with helpers.py
viewmixins.py View modules and packages can be thinned by moving any view mixins to this module. See section 10.2.
基本原则:
对于配置文件,一个常见做法是使用一个不走版本控制的local_settings.py
文件。但是这样做有如下坏处:
local_settings.py
文件不符合 不要重复自己的代码 这一原则我们可以使用多个互相继承的配置文件来适应本地,测试,生产环境。使用django-environ
这个包来保存数据库地址等信息
当然,不想引入第三方库的话,json,xml,yaml都可以取代env文件
最后,不要对目录进行硬编码→_→
使用以下工具
不继承,写多遍
优点是简单明了
缺点是非常多的重复代码,难以维护
1 |
|
抽象基类继承,子类有基类的所有属性和方法
优点是抽象程度高,不需要引入外键
缺点是基类不能直接拿来用
1 |
|
多表继承, 子类有一个基类的外键
引入外键带来的查询效率变低
并不推荐
1 |
|
为一个类扩展方法(并不知道怎么翻译
不同的数据被映射到一个类的时候用
1 |
|
这是两种设计数据库表的模式,Normalization对应的数据属于干净非冗余型,而Denormalization则允许数据冗余或者同样的数据存储于多处。下面主要列出了Normalization的优点和缺点,
优点:
缺点:
综合以上的优缺点,Normalization模式比较适合的场合是更新操作比较频繁的应用,即write-heavy。同样的Denormalization则适合于read-heavy。
Null
和Blank
Field Type | Setting null=True | Setting blank=True |
---|---|---|
CharField, TextField,SlugField,EmailField,CommaSeparatedInteger-Field,UUIDField | 不推荐,Django默认是空字符串 | 如果期望允许空值,可以使用 |
FileField, ImageField | 不推荐,Django以MEDIA_ROOT 配置为默认路径 | 同上 |
BooleanField | 使用NullBooleanField | 不推荐 |
IntegerField, FloatField, DecimalField, DurationField | 可以 | 可以 |
DateTimeField, DateField, TimeField | 可以 | 可以 |
ForeignKey,ManyToManyField,OneToOneField | 可以 | 可以 |
_meta
APIget()找不到数据的时候
1 |
|
get()找到多个的时候
1 |
|
1 |
|
不要把模版加载等东西写在url配置里面
遵循以下规则
遵循以上规则
讲道理在提供API的情况下并不需要这些标准View(时代的眼泪
howdoi是一个命令行中查询编程问题的工具,使用stackoverflow和google检索出最适合问题的答案并显示其中的代码部分
虽说是个200多行的小工具,还是能学到一些东西的。比如CLI工具的写法,选取网页中的元素(爬虫基础),如何打包发布一个工具等等
command_line_runner
入口函数,调用 get_parser
处理了传入的参数,并对显示版本号,清除缓存做单独处理。有传入查询的话调用howdoi
处理,否则返回帮助文档。
howdoi
把查询拼成了一个字符串,并且去掉了问号。(_get_instructions
)然后进行查询:_get_links
返回google搜索到的stackoverflow链接;get_answer
用来获取链接中的问题答案:如果命令需要返回链接就直接返回,否则开始解析网页中的回答部分。如果回答部分包括代码就_format_output
来输出,普通文本直接输出。完成查询流程
Python标准库中用来解析参数的工具。我之前使用过看起来更优雅的click。但是在对外发布包的话。没有第三方依赖也是很好的选择
1 |
|
看起来是一个查找路径的库,比更为人熟知的os.listdir()
再过滤要优雅太多。还有一个glob.iglob
方法返回的是一个迭代器,适合文件数量很大的情况
一个神奇的给网络查询加缓存的包。我很诧异它在没有影响requests正常使用的情况下怎么加缓存的。就去看了下源代码。原来是通过hook来实现
是一个用jQuery语法对xml进行操作的库。用法非常简洁
代码高亮工具(不知道怎么演示的路过)
1 |
|
作者使用了sys模块中的version来判定版本。我以前见到的代码大多是try下面import看是否异常。
1 |
|
requests-cache/compat.py 做的更进一步了些,判断了Python小版本,系统环境和解释器
虽然很早就想看源代码总结,但是直接促使我写这篇文章的确是看到别人对这个项目的阅读博文……写的时候并没有参考(写完看看也没有他写的好T_T)一开始还想把流程画成图,尝试了hexo的绘图插件和手绘后放弃,其实还是不晓得如何梳理结构。好在这个项目逻辑非常简单。给我更多的帮助是发现了些以前没用过的库
Comparing Python Command-Line Parsing Libraries - Argparse, Docopt, and Click
]]>update:农历年关总结看起来也是有好处的,回到家里感受到更加无聊和现实的气氛,能多写一点东西
今年看起来和往年都不相同,毕业后的第一年回家再也没被问学业如何。取而代之的是工作啊,赚多少钱啊,什么时候买房子结婚之类的更加无聊的问题;再加上带上了女朋友回家,问题变得愈发尖锐势利了起来;很开心不用被给红包的同时,好像已经有后辈的小孩子需要我发红包了。人生果然是越来越艰难的……
事实上日常生活也是在慢慢的从学园过度到社会,犹如二维世界向三维世界的变化般(高中到大学算是一维变到二维吧)。令人眼花缭乱而不知要领。更多的遇到了喜欢的事情中包含了并不喜欢的细节,更多的遇到了世界恶意的一面。然而我喜欢这真实而丑陋的世界,而不是虚假的美好。令我感到害怕的是,我看起来做的不好:看起来熟悉工作用的技术后,已经很长时间没有扩展新的技能;之前雄心勃勃的计划也大多在搁置;即使能力范围能的正常工作也没有很稳的解决掉~sad
在和chiyuan闲聊时,提及了做APP权限时的延期。在被安慰了下抗住了压力之后,他说:毕竟是正式员工了,要要求高一些。心里一惊,之前觉得实习的时候已经在独立做一个项目的后端开发了,正式工应该也差不多。细思之下,发现当时完全是easy模式:一个流程简单到极点的项目,也没经过大改需求带来的逻辑坑;大部分的开发量都是用内部的Model Services来写增删改查API,写起来和写文档难度没差到哪里去;和其他项目数据同步的部分直接被chiyuan写完了(后来发现了迷之bug);稍微麻烦点的需求就多看了两天,好在前端更慢些胆战心惊的没误进度。现在看起来也是十分羞耻,虽然对于当时还没参与过一个正式的项目的我来说是不小的成长,但是想想我被招进去应该不是被赋予如此低的期望的= =
看起来完美的抗住了第一波之后,之后便发现了欠缺之处。技术上的话除了知道的东西太少,面过于窄了之外,对于面向对象开发的抽象能力不足是更大的问题。看懂了chiyuan写的Model Service,只有不到100行但是能使写API如同写文档般方便(然而暂时没支持反射出文档来),后来我看了Django部分源代码发现这些代码和框架本身的风格非常相似。完全能看懂的我并不知道怎么从零开始设计出这样的小框架来;做需求时也发现不少C语言面向过程风格的代码,没有扩展性也不优雅;虽然很自信复杂逻辑运算的需求公司里没人写的过我,然而一年了也没遇到类似的需求(想想这种需求只能出现在竞赛题里面吧,还是送分用的)
其他的东西分小标题来
写代码毕竟是要人来用的。我遇到对系统基本逻辑的修改时,一般反应是对不适用的逻辑斩草除根,代码全局搜索替换成新逻辑并且拉着前端改接口,还会遇到一堆堆的bug;而chiyuan一般会写新逻辑的时候做旧版兼容。我觉得这样是给以后开发留坑而且让代码很脏,而且兼容带来的bug不会报错,只能由客户反馈慢慢来解。还不如废弃掉旧逻辑在测试时接受Sentry报错修复来得直接。然而在结果上来看这样并不好。如果客户用的不好的话,再优雅的实现又有何意义呢~况且粗暴的废弃旧逻辑让前端和移动端都觉得很头疼,我把本该自己这层屏蔽掉的东西抛给了他们。就有了标题的总结
本来觉得大家沟通为什么会成问题呢,都是计算机相关专业。后来发现不同工种的人思维方式简直不在一个位面。后来总结了下
这个需求多长时间做完呢?一天吧……
然而半天时间都在应付客户经理提出的问题,快到晚饭点了还没开始做需求。事后反思下,那些事情时间累加的话远远没有那么长,但是时间都去哪里了呢?沟通是需要花时间的,尤其是使用IM软件而不是当面聊的情况。而且反映问题的同学一般第一次没有附带足够的上下文。我就要去问,他们就找客户问。一来二去时间就过去了= =。最近想做一些改变,每次都告诉他们反映问题最好附带怎样的上下文,减少沟通时间。以及不急的问题统一时间解决。
还有的就是deadline是第一生产力的坏习惯,总是deadline那天生产力明显高于之前。没有仔细拆分任务分配到每一天。导致滑水后到加班
只举一个栗子吧~有时候做感觉很蛋疼而且没什么人会用的需求时,只会考虑技术实现的问题……(偷懒不想多写了
技术进步慢是个麻烦的问题。暂时只打算开始阅读经典项目的源代码,希望带来一些改变吧。
去年做meeting项目后台的时候,感觉需要api文档,于是找了下相关工具,就发现了ApiDoc。当时感觉勉强够用但是有很多缺陷,而且最好的Api文档生成方式应该是自动生成而非手写,所以只想临时用一下也没有安利的动力。不过随着越写越多,到今天(2016-11-19)已经有147个API使用了ApiDoc文档(好像换起来挺麻烦的)而且之前觉得是坑的地方也能通过实践来避免。于是就有了这个……来让大家一起避(lai)开(ru)坑
首先,任何介绍都不如官方的文档 APIDOC - Inline Documentation for RESTful
这是一个通过在Api方法中写注释,可以生成静态网页形式的API文档。有如下的优点
@ApiDefine
来创建注释块到处引用1 |
|
尤其在PUT/POST接口,参数可能在URL中,可能在URL后面的Query里面,还可能在请求体中。如果文档不加以区分会让前端很困惑。然后我发现了apiParam支持分组(所以并不是缺陷,只是我当时没发现这个feature)
在一个分类下,只能按照字符顺序来排。为了让文档美观些,我对API的命名是 二级模块名-操作资源名-操作 比如上一个例子
二级模块名可以换成操作人身份(如果不同身份的人访问同一资源使用不同的API)。理论上可以扩展出无限层,但是心智负担略大,并不推荐
如果发现自己的分类有毒,看起来就要改一堆的文档。所以要提前规划好
@apiError
可以列举出现错误时的返回
@apiSampleRequest
@apiParamExample
@apiSuccessExample
@apiErrorExample
这些参数可以帮助前端更好的了解Api在输入实际参数的行为。
以上特性由于比较耗时&&小KD同学刚接触ApiDoc的时候没看到,所以没有使用过
从开始学Python开始,折腾各种环境虚拟机双系统花了不少时间。实习后发现同事用的都是Mac,想想不需要折腾环境就能方便的工作,而且日常的软件也很方便确实是程序员终极的工作环境。然而当时看起来新款电脑马上就要出,所以就想等下新款(其实是当时没钱没信用卡额度)这一等就是一年多。中间BuyersGuide,9to5Mac之类的网站刷了数百次(现在想想真是迷之浪费时间)
等过了15年10月发布会,16年春季发布会,WWDC,秋季发布会。终于等到了看起来被人骂的最多的一代电脑。我倒是对路人骂的最多的Touch Bar和全Type-c口无感,只是期望性能强一些,能有指纹识别再好不过了。然而性能并不怎么样(英特尔AMD快来背锅
开箱后觉得和之前看起来区别不大,能感受到边框遍窄了一点,然而和XPS比还是差了些;触摸板大了一些(事实上大了很多);和leader的上一代15寸对比发现确实轻薄了一些;至于哪个Touchbar,单独说。
Touchbar是被吐槽最多的点了吧,没卵用的东西还取消了实体esc键而被广大的vim党吐槽(反正我不是vim党)。不过实际使用起来发现虚拟的esc键和下面的实体键盘除了不方便盲打以外手感也差不了多少(我能说神舟的键盘手感都比这个好么?)不过够用,反正工作时候有机械键盘。
这让我想起了我刚接触电脑配置的时候,那会笔记本的键盘正在从传统键盘(现在已经见不到了)向巧克力键盘过渡,当时用户一片唱衰之声,为了轻薄而牺牲键盘手感觉得很可惜。这么多年过去了,如今的用户大多忘记了以前笔记本类似台式机的长键程键盘,熟悉了巧克力键盘(曾经帮小白买个几十块钱的台式机键盘,小白在敲了几下后觉得巧克力键盘手感好)。这次估计又是一次轮回吧
再说Touch Bar,有人拿联想曾经的失败例子来说。但是苹果对开发者的影响力只有微软谷歌能比拟,远远超过OEM厂(不到一个月QQ,网易云音乐就已经适配了)。而且实际体验起来也不是那么的鸡肋。调下音量亮度锁屏,输入emoji表情什么的还挺方便的(虽然我宁愿没这个特性换价格便宜点)
和Touch Bar一起的指纹识别居然没被重点关注~指纹真是个极好的特性,PC十年前就有产品支持(然而并没有用,除了解锁电脑以外)。像苹果这样账号密码要求特别多导致密码很长的账号体系,能指纹代替密码输入实在是太赞。再加上1Password等软件在第一时间适配。感觉没有换其他平台等动力了
第二个被吐槽的点就是只有四个Type-c(其实是雷电3,并没有买得起的设备支持)口了吧。我对此也是无感:一年前买的手机Nexus 6p就是Type-c接口,买的U盘也是两个口都能插的,剩下的就买些数据线就好了。也不要喷官网贵啊,毕竟这个第三方数据线很多的,比之前没什么人用的雷电2口强上太多。
但事实上接口数量少了很多,虽然用不完。而且两组Type-c口离的很近,如果两个设备都有格外的宽度的话就会挤不下(下图)
至于hub的话,听说Type-c(雷电3)接口有多种版本,之前联想戴尔惠普出的雷电3扩展坞并不能用。如是V2EX各种逛之后在美亚挑了一个Satechi的Type-C hub,转运20天到手。使用体验很完美。除了线有点短电脑在架子上的时候hub拖地
我对电脑有游戏性能的要求的,虽然玩的游戏没有显卡杀手类的。所以很期待Mac的显卡性能强一些,这样我就能用一台电脑解决所有问题。农企460显卡看起来比核弹厂960m性能高(差)一点。加上Mac系统游戏性能减成。不过尝试下Dota2还是很流畅。文明6的话就只能开中特效了。虽然发热十分感人。
听说轻薄是以电池容量减半为代价的,而且新版系统迷之吃电量。大概新电脑开Chrome,iTerm2和PyCharm只能撑不到5小时吧,sad
岂止是大~和外置触摸板差不多大了。体验非常感人。这方面苹果还是把PC厂甩出了几条街
以前一直以为键盘两边的音箱是占地方用的,还特别丑。希望下一代能超窄边框把音箱那两条去掉。听了这一代电脑的外放以后……我十分后悔之前买了蓝牙小音箱
虽然可以用各种包管理工具安装,但是八成不会是最新版(这里brew好评)
sudo brew/apt/yum install tmux
这里有一篇文章讲 如何从源码安装tmux
下面盗的图形象的说明了三元素之间的关系
Tumx的所有快捷键都以Ctrl+b
打头(默认设置下).然后松开再按其他键输入指令.这一点很像Emacs.我们管它叫做Prefix Key
接下来说的所有快捷键都以prefix
来代表Prefix Key
感觉列举快捷键并不好记,还是以几个典型场景来说下最简单的用法吧(其实是我也没背下来几个快捷键)
扩展命令第一次看文章可以略过~
操作 | 快捷键 |
---|---|
打开tmux | $ tmux |
关闭tmux | $ exit; |
吐槽:以上内容看起来和tmux完全没关系嘛~
操作 | 快捷键 |
---|---|
临时断开会话(将来能重连) | prefix d |
列出所有tmux会话 | $ tmux ls or prefix s |
选择一个会话打开 | $ tmux a -t 名字(默认是数字) |
扩展命令
操作 | 快捷键 |
---|---|
在后台建立新会话 | tmux new -s session -d |
查看/切换session | prefix s |
重命名当前Session | prefix $ |
操作 | 快捷键 |
---|---|
垂直拆分出一个新窗格 | prefix " |
水平拆分出一个新窗格 | prefix % |
切换窗格 | prefix 方向键 or prefix o |
扩展操作
操作 | 快捷键 |
---|---|
调整窗格大小 | prefix 不松开Ctrl,方向键 |
关闭所有窗格 | prefix ! |
关闭当前光标处的窗格 | prefix x |
显示一个钟表 | prefix t |
修改窗格名 | prefix , |
操作 | 快捷键 |
---|---|
创建一个新的窗口 | prefix c |
切换到下一个窗口 | prefix n |
切换到上一个窗口 | prefix p |
直接跳到你按的数字所在的窗口 | prefix 数字 |
退出当前窗口(仅有一个窗口会退出session) | prefix & |
其实最后一条和最早的那个exit;
是一样的→_→
目前最流行的配置应该是gpakosz/.tmux
了,主要有以下特性:
C-a
为 Prefix key, 更加顺手上两张图感受下:
安装教程还是上作者的Github Repo链接吧: [https://github.com/gpakosz/.tmux](https://github.com/gpakosz/.tmux]
文章编辑中
曾经某宏凯童鞋为了防止登录请求被抓包自己写了个很复杂的加密通信方式,为此还用可逆加密存密码 →_→ 然而这并没有什么用。为什么不用https呢?
接着前面的说~之前计算机网络课第一节实验课老师总是让学生用Wireshark抓教务在线登录的包以及局域网其他同学登录的包,一脸嫌弃的说明文传密码会被拦截,要用md5加密敏感数据……
其实这并没有什么用,因为一样能拦截。除了不知道密码明文之外和知道密码没有任何区别
最大的好处是防止运营商劫持~毕竟是加密传输数据
还有一个隐形的好处(说不定)能抵消加密带来的性能损失:一些目前基于HTTPS的加速技术比如HTTP2能提高性能
对于个人来说有很多免费的HTTPS证书提供商可以选择,除了本文采用的 Let’s Encrypt 以外,我还在个人网站上见过 Comodo 的证书~然后某软妹币童鞋用了沃通的证书Chrome提示危险 →_→
之前有人在V2EX发帖说 Let’s Encrypt 是2015年最期待的产品。免费的HTTPS证书且支持自动更新。对于个人用户来说是再好不过的选择
凌晨即将睡觉的时候,打开了QQ看下信息.一个大三的学妹问我想找Python后台的工作,应该具备哪些知识或者能力~
想想马尔代夫和北京三小时的时差,并没有马上回复的必要,可是自己却睡不着了.想想去年这会,自己也是如此,希望短期内掌握后端的各种知识,但是由于比较作死的性格(折腾最新版的工具)以及很烂的英语水平.看各种教程和开源软件无法深入,最后找到实习的时候也没有一个完整的项目经历,到真正负责项目的时候已经是实习半年后的事情了…
同事还在熟睡,我尽量轻声的穿上衣服去外面走了一圈.和在大堂值班的工作人员用蹩脚的英语寒暄了下,到码头看星星~一边梳理思路.后端开发需要怎样的技能树,如何拾级而上…(话说星空真是很美.满天都是星云)
记得之前看过一篇有趣的文章 写给那些傻傻的,想做服务器开发的应届生在谜一般的片面之下也说出了很多事实:
个人理解的后端开发的日常是数据库增删改查, 数据处理, Restful Api.但是远不能覆盖业务需求.比如需要定时任务(linux crontab, 当然lazy-loading也能解决,有点脏),某些数据库查询太慢要加缓存,某些数据处理任务过于耗时要引入消息队列,还有诸如错误监控,服务器状态监控等等(怎么开始偏运维了Orz)…如果做前端的话,只要把自己这边业务逻辑写好就能应付大多数情况了吧(不对的话求喷).而后端要懂点数据库,玩转Linux,知道各种轮子用法等等
我觉得校招后端开发要有三方面的能力~重要性递减
而公司招人的话,毕竟招人是要做项目.项目经验是第一优先级的.而且不是玩具项目,是经得起生产环境检验的项目.这一点很多人都没有,包括我.补齐的话想想可以抱大腿可以参与开源项目也可以对着大型教程做完改…
很难想象一个对自己使用的语言和框架不熟悉的话,写出来的代码会是什么鬼样子所以语言和框架的相关知识很重要好好刷官方文档和相关书籍就是.多看多写
基础知识的话比较见仁见智很多”实战派”不喜欢基础知识.而且基础知识的作用不会很快的显现出来.毕竟优化的算法和底层的数据都被封装进了各种轮子.初级开发的话,需要底层知识的需求不到10%.有句话我是很认同的程序的组成部分不是数据结构和算法,而是搜索引擎和英语.
不过人总是要有追求的,10%也不是很低的概率(数字是我编的).一次无意听到前端讨论数据处理逻辑,发现一个O(nlogn)的问题被他们写成了O(n^2).就去纠正了下.一个有追求的工程师一定会把基础知识夯实的.
像我们公司面试技术不会问基础知识,知乎的话特别喜欢问基础知识~看公司和人的性格了.要是我以后面试别人,基础知识一定会问的.其实能把基础知识学的特别好的人,也不会被上面两条纠结住.只是辛苦了天赋一般非常努力学基础知识而没有积累项目经历的同学
在搜索hexo的时候看到一个人的博客 读立写生 看起来并不是程序员,却使用 Jekyll,Github,七牛云…博客内容也是包罗万象.而且有一段时间博客是日更的~其中有一篇文章是每天写一千字的练习.我很赞同这个行为,但是无法输出这么多
每一次当中发言时的语塞,或是想写什么东西却无从下笔.看起来表达能力非常欠缺.缺什么补什么吧~所以写博客.复习记录自己的经历.
]]>前些天做数据库操作玩崩了,需要从备份库把数据导入到线上库.话说之前只用过Django的ORM操作数据库.而自己玩的环境是Python3,强迫症促使我找到了这个库~
PyMySQL的性能和MySQLdb几乎相当,看起来性能是可以接受的
配置好参数即可~一开始看官方文档获取到的中文数据乱码,后来发现要制定字符集
import pymysqlconfig = { 'host':'127.0.0.1', 'port':3306, 'user':'root', 'password':'', 'db':'meeting', 'charset':'utf8mb4', }# Connect to the databaseconnection = pymysql.connect(**config)
from pymysql import cursors# 执行sql语句try: with connection.cursor() as cursor: # 执行sql语句,进行查询 sql = 'SELECT id, username, phone FROM users WHERE is_enable = 1' cursor.execute(sql) # 获取查询结果 result = cursor.fetchone() print(result)finally: connection.close();
# 执行sql语句try: with connection.cursor() as cursor: # 执行sql语句,插入记录 sql = 'INSERT INTO employees (first_name, last_name, hire_date, gender, birth_date) VALUES (%s, %s, %s, %s, %s)' cursor.execute(sql, ('Robin', 'Zhyea', tomorrow, 'M', date(1989, 6, 14))); # 没有设置默认自动提交,需要主动提交,以保存所执行的语句 connection.commit()finally: connection.close();
]]>