• 对象:一个自包含的实体,用一组可识别的特性和行为来标识
  • 类:具有相同的属性和功能的对象的抽象的集合
  • 实例:一个真实的对象,实例化就是创建对象的过程
  • 多态:可对不同类型的对象执行相同的操作,而这些操作就像“被施了魔法”一样能够正常运行
  • 封装:对外部隐藏有关对象工作原理的细节
  • 继承:可基于通用类创建专用类

多态

  • 多态可以让我们在不知道变量指向哪种对象时,也能够对其执行操作,且操作的行为将随对象所属的类型(类)而异。每当不知道对象是什么样就能对其执行操作,都是多态在起作用
  • 多态以 继承 和 重写 父类方法 为前提
  • 多态是调用方法的技巧,不会影响到类的内部设计
  • 多态性即向不同的对象发送同一个消息,不同的对象在接收时会产生不同的行为(即方法)
  • 听说Python天然就多态
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Person(object):
def __init__(self,name,sex):
self.name = name
self.sex = sex

def print_title(self):
if self.sex == "male":
print("man")
elif self.sex == "female":
print("woman")

class Child(Person): # Child 继承 Person
def print_title(self):
if self.sex == "male":
print("boy")
elif self.sex == "female":
print("girl")

May = Child("May","female")
Peter = Person("Peter","male")

print(May.name,May.sex,Peter.name,Peter.sex)
# 同一消息
May.print_title()
Peter.print_title()

封装

  • 封装指的是向外部隐藏不必要的细节。与多态有点像,他们都是抽象的原则。多态让你无需知道对象所属的类(对象的类型)就能调用其方法。封装让你无需知道对象的构造就能够使用它。

  • 实现封装可以对类内的属性和方法的访问加以限制。就像C++类使用private、protected一样对类的成员访问进行限制一样

  • 默认情况下,Python中的属性和方法都是公开的,可以在对象外部访问

私有变量

  • Python并没有真正的私有化支持,但可用下划线得到伪私有。
  • 在Python定义私有变量只需在变量名或函数名前加上两个下划线__,例如__name。那种仅限在一个对象内部访问的“私有”变量在Python中并不存在
  • 使用双下划线将方法或属性变为私有时,在内部,Python将以双下划线开头的名字都进行转换,即在开头加上一个下划线和类名。但这样的私有变量或方法还是可以访问的,访问形式如:实例名.类名__变量名、实例名.类名__方法名()
  • 以单下划线开头的时保护成员变量,只有本类和子类成员实例能访问这些变量

VPgYDA.png

继承&&派生

  • 一个新类从已有类那里获得其已有特性,这种现象称为继承。从一个已有类(父类,Python叫超类)产生一个新的子类,称为类的派生。要指顶定超类,可在class语句中的类名后加上超类名,并将其用原括括起来

  • 一个类可以继承多个类(多重继承)。但是,如果多个超类以不同的方式实现了同一个方法(即有多个同名的方法),必须在class语句中小心排列这些类,因为位于前面的类的方法将覆盖位于后面的类的方法

  • 对子类的实例调用方法(或访问其属性)时,如果找不到该方法或者属性,将在父类中查找

  • 在子类中可以重写超类的方法(包括构造函数),重写构造函数时,要确保在子类的构造函数中调用超类的构造函数,否则可能无法正确的初始化对象

  • Python中所有的方法实际上是virtual的

1
2
3
4
5
6
7
8
9
class Person:
def __init__(self,name):
print("我叫{}".format(name))

class Student(Person):
def __init__(self,name):
# 使用super函数调用父类构造函数
super().__init__(name) # 也可以写成这样:Person.__init__(self,name)
print("我是一个学生!")

VPB0O0.png

抽象基类

  • 抽象基类是不能(至少是不应该)实例化的类,其职责是定义子类应该实现的一组抽象方法。Python可通过引入ABC模块实现抽象基类,使用@abstractmethod装饰器将方法标记为抽象的。例如:
1
2
3
4
class Basic{
public:
virtual void talk() const = 0;//纯虚函数
};
1
2
3
4
5
6
from abc import ABC, abstractmethod

class Basic(ABC):
@abstractmethod
def talk(self):
pass
  • 抽象类(即包含抽象方法的类)最重要的特征是不能实例化。如果派生出的类没有重写talk方法,那么派生出的类也是抽象的,不能实例化。

鸭子类型

“鸭子类型”的语言是这么推断的:一只鸟走起来像鸭子、游起泳来像鸭子、叫起来也像鸭子,那它就可以被当做鸭子。也就是说,它不关注对象的类型,而是关注对象具有的行为(方法)。
例如,在不使用鸭子类型的语言中,我们可以编写一个函数,它接受一个类型为鸭的对象,并调用它的走和叫方法。在使用鸭子类型的语言中,这样的一个函数可以接受一个任意类型的对象,并调用它的走和叫方法。如果这些需要被调用的方法不存在,那么将引发一个运行时错误。任何拥有这样的正确的走和叫方法的对象都可被函数接受的这种行为引出了以上表述,这种决定类型的方式因此得名

鸭子类型的关注点在对象的行为,而不在对象的类型

VF9D3V.png

参考:https://zhuanlan.zhihu.com/p/59299729

玩Python这么久了,连Jupyter都不会,有点捞,今天补一补这方面的操作。。。。

Jupyter Notebooks

  Jupyter Notebooks 是一款开源的网络应用,我们可以将其用于创建和共享代码与文档。其提供了一个环境,你无需离开这个环境,就可以在其中编写你的代码、运行代码、查看输出、可视化数据并查看结果。因此,这是一款可执行端到端的数据科学工作流程的便捷工具,其中包括数据清理、统计建模、构建和训练机器学习模型、可视化数据等等。

安装

pip install ipython jupyter

上手上手

在终端输入jupyter notebook启动Jupyter notebooks,它会在默认浏览器中打开,地址是http://localhost:8888/tree。

VCCz7R.md.png

进程 && 线程

进程:进程是操作系统中执行的一个程序,操作系统以进程为单位分配存储空间,每个进程都有自己的地址空间、数据栈以及其他用于跟踪进程执行的辅助数据,操作系统管理所有进程的执行,为它们合理的分配资源。进程可以通过fork或者wpawn的方式来创建新的进程执行其他任务,不过新的进程有自己独立的内存空间和数据栈,所以必须通过进程间的通信机制(IPC,Inter Process Communication)来实现数据共享,具体的方式包括管道、信号、套接字、共享内存等。

线程:进程的一个执行单元。线程在同一个进程中执行,共享程序的上下文。一个进程中的各个线程与主线程共享同一片数据空间,因而相比与独立的进程,线程间的信息共享和通信更为容易。线程一般是以并发的方式执行的。注意在单核CPU系统中,真正的并发是不可能的,所以新城的执行实际上是这样规划的:每个线程执行一小会,然后让步给其他线程的任务(再次排队等候更多的CPU执行时间)。在整个线程的执行过程中,每个线程执行它自己的特定的任务,在必要时和其他进程进行结果通信。

Python多进程(使用multiprocessing)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from time import time, sleep
from random import randint
from multiprocessing import Process

def my_task(name):
sleep_time = randint(1,10)
sleep(sleep_time)
print("你叫了一声%s,它鸟你用了%d秒" % (name, sleep_time))


def main():
start = time()
process_1 = Process(target=my_task, args=["yeshan", ])
process_2 = Process(target=my_task, args=["foel", ])
# 启动进程
process_1.start()
process_2.start()
# 等待进程执行结束
process_1.join()
process_2.join()
end = time()
print("一共花费了%f秒" % (end-start))


if __name__ == '__main__':
main()

EIcIMt.png

我们通过Process类创建了进程对象,通过target参数我们传入一个函数来表示进程启动后要执行的代码,后面的args是一个元组,它代表了传递给函数的参数。
Process对象的start方法用来启动进程,join方法表示等待进程执行结束。

Python多线程(使用threading)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#!/usr/bin/env python
#-*- coding:utf-8 -*-

from time import time, sleep
from random import randint
from threading import Thread


def download(filename):
print("开始下载 %s ..." % filename)
download_time = randint(1,10)
sleep(download_time)
print("下载完成!耗时 %d 秒" % download_time)


def main():
start = time()

t1 = Thread(target=download, args=('黑暗地宫',))
t1.start()

t2 = Thread(target=download, args=('通天',))
t2.start()

t1.join()
t2.join()

end = time()

print("下载总共耗时 %.3f 秒" % (end-start))

if __name__ == '__main__':
main()

VSTFr4.png

继承Thread类,实现自定义线程类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#-*- coding:utf-8 -*-

from time import time, sleep
from random import randint
from threading import Thread


class DownLoadTask(Thread):

def __init__(self, filename):
super().__init__() #初始化父类的构造函数
self._filename = filename # 私有的

def run(self):
print("开始下载 %s ..." % self._filename)
download_time = randint(1,10)
sleep(download_time)
print("%s下载完成!耗时 %d 秒" % (self._filename, download_time))


def main():
strat = time()

t1 = DownLoadTask("从菜鸟到菜鸡")
t1.start()

t2 = DownLoadTask("去哪里啊弟弟")
t2.start()

t1.join()
t2.join()

end = time()

print("下载完成,总共耗费 %.3f 秒" % (end-strat))


if __name__ == '__main__':
main()

VSTiMF.png

线程间的通信

因为多个线程可以共享进程的内存空间,因此要实现多个线程间的通信相对简单,大家能想到的最直接的办法就是设置一个全局变量,多个线程共享这个全局变量即可。但是当多个线程共享同一个变量(我们通常称之为“资源”)的时候,很有可能产生不可控的结果从而导致程序失效甚至崩溃。如果一个资源被多个线程竞争使用,那么我们通常称之为“临界资源”,对“临界资源”的访问需要加上保护,否则资源会处于“混乱”的状态。在这种情况下,“锁”就可以派上用场了。我们可以通过“锁”来保护“临界资源”,只有获得“锁”的线程才能访问“临界资源”,而其他没有得到“锁”的线程只能被阻塞起来,直到获得“锁”的线程释放了“锁”,其他线程才有机会获得“锁”,进而访问被保护的“临界资源”。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
from time import sleep
from threading import Thread, Lock


class Account(object):

def __init__(self):
self._balance = 0
self._lock = Lock()

def deposit(self, money):
# 先获取锁才能获取后面的代码
self._lock.acquire()
try:
# 计算存款后的余额
new_balance = self._balance + money
# 模拟受理存款业务需要0.01秒的时间
sleep(0.01)
# 修改账户余额
self._balance = new_balance
finally:
self._lock.release()

@property
def balance(self):
return self._balance


class AddMoneyThread(Thread):

def __init__(self, account, money):
super().__init__()
self._account = account
self._money = money

def run(self):
self._account.deposit(self._money)


def main():
account = Account()
threads = []
# 创建100个存款的线程向同一个账户中存钱
for _ in range(100):
t = AddMoneyThread(account, 1)
threads.append(t)
t.start()
# 等所有存款的线程都执行完毕
for t in threads:
t.join()
print('账户余额为: ¥%d元' % account.balance)


if __name__ == '__main__':
main()

输出结果为100块,不用锁为2块

Python内置装饰器 property

property装饰器一般存在于类中,可以将一个函数定义成一个属性,属性的值就是该函数return的内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Student(object):
# 把一个方法变成属性
@property
def score(self):
return self._score

# setter把一个方法变成一个可控属性用于赋值
@score.setter
def score(self, value):
if not isinstance(value, int):
raise ValueError('score must be an integer!')
if value < 0 or value > 100:
raise ValueError('score must between 0 ~ 100!')
self._score = value

https://raw.githubusercontent.com/yeshan333/blog_images/master/posts/21.png

https://raw.githubusercontent.com/yeshan333/blog_images/master/posts/22.png


参考:

一篇文章搞懂装饰器的用法

https://github.com/jackfrued/Python-100-Days/blob/master/Day01-15/Day13/%E8%BF%9B%E7%A8%8B%E5%92%8C%E7%BA%BF%E7%A8%8B.md

HTTPie(发音为aitch-tee-tee-pie)是一个命令行HTTP客户端。其目标是使与Web服务的CLI交互尽可能人性化。它提供了一个简单的http命令,允许使用简单自然的语法发送任意HTTP请求,并显示彩色输出。HTTPie可用于测试,调试以及通常与HTTP服务器交互。

HTTPie官方文档

windows下安装

pip install --upgrade httpie

HTTPie的简单使用

一个完整的请求语句的大概样子

http [选项(flags)] [方法] URL [查询字符串/数据字段/首部字段]

HTTPie数据语法

类型 符号 示例
URL参数 == param==value
首部字段 : Name:value
数据字段 = field=value
原生JSON字段 := field:=json
表单上传字段 @ field@dir/file

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 下载文件
$ http --download www.jb51.net/my_file.zip

# 提交表单
$ http -f POST www.jb51.net name='Dan Nanni' comment='Hi there'

# HTTPie的默认数据类型为JSON格式的
$ http PUT example.org name=John email=john@example.org

# 使用代理
$ http --proxy=http:http://10.10.1.10:3128 --proxy=https:https://10.10.1.10:1080 example.org

# 定制请求头
$ http www.test.com User-Agent:Xmodulo/1.0 Referer:http://www.imike.me MyParam:Foo

放着先。。。。。。。。。占个位

最近在弄一个东西,基本的功能已经弄好了,现在想再扩展一起其他功能,但这样势必会改动原有代码,我又不想破坏原有的代码逻辑,方便以后查看。记得Git有个分支工作流可以很好的满足我的需求(๑•̀ㅂ•́)و✧。emmm,很久没发文了,record一下吧。(ノへ ̄、)

使用到的命令

1
2
3
4
5
6
7
8
9
10
11
12
13
$ git branch # 显示所有本地分支
$ git branch <new branch> # 创建新分支
$ git checkout <branch> # 切换到指定分支
$ git branch -d <branch> # 删除本地分支
$ git push --set-upstream origin <branch> # 将本地分支与远程分支关联
$ git push origin --delete <branch> # 删除远程分支

$ git tag -n # 列出所有本地标签以及相关信息
$ git tag <tagname> # 基于最新提交创建标签
& git tag <tagname> -m "备注信息" # 基于最新提交创建含备注信息的标签
$ git tag -d <tagname> # 删除标签
$ git push orign <tagname> # 将指定信息推送到远程仓库
$ git push --tags # 推送所有标签到远程仓库

操作~操作

https://img.vim-cn.com/00/950a7bad9cc5835194268fce6d40a444b7cfcc.png

emmm,顺便试试tag

https://img.vim-cn.com/a4/26dbcd8ed54643c057193aa14d15ade7ef2358.png

Git

emmm,闲来无事,打算了解下神奇vim(用来zhuangbi)。在终端操作很帅(ˉ▽ ̄~)~~!
什么是vim??Vim是从 vi 发展出来的一个文本编辑器。代码补完、编译及错误跳转等方便编程的功能特别丰富,在程序员中被广泛使用。

vi/vim的使用

vi/vim有三种模式:

  • 命令模式:控制光标移动,可对文本进行复制、粘贴、删除和查找等工作。刚启动时就是这个模式。
  • 输入模式:正常的文本录入。
  • 末行模式:保存或退出文档,以及设置编辑环境。又可成为底线命令模式。

常见关系:

  • 一对多关系
  • 多对一关系
  • 多对多关系
  • 一对一关系

一对多关系(一个作者,多篇文章)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
## 一对多关系,单作者-多文章,外键不可少
## 外键(ForeignKey)总在多的那边定义,关系(relationship)总在单的那边定义

class Author(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(70), unique=True)
phone = db.Column(db.String(20))
# articles为关系属性(一个集合,可以像列表一样操作,在关系的出发侧定义
## relationship()函数的第一个参数为关系另一侧的模型名称(Article)
articles = db.relationship('Article')

class Article(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(15), index=True)
body = db.Column(db.Text)
# 传入ForeignKey的参数形式为:"表名.字段名"
## 模型类对应的表名由Flask-SQLAlchemy生成,默认为类名称的小写形式,多个单词通过下划线分隔
author_id = db.Column(db.Integer, db.ForeignKey('author.id')) #

# 外键字段(author_id)和关系属性(articles)的命名没有限制
## 建立关系可通过操作关系属性进行
>>>shansan = Author(name="shansan")
>>>hello = Article(title="Hello world !")
>>>boy = Article(title="Hello Boy !")
>>>db.session.add(shansan) # 将创建的数据库记录添加到会话中
>>>db.session.add(hello)
>>>db.session.add(boy)
>>>shansan.articles.append(hello) # 操作关系属性
>>>shansan.articles.append(boy)
>>>db.session.commit()

请求钩子(Hook)

在客户端和服务器交互的过程中,有些准备工作或扫尾工作需要处理,比如:在请求开始时,建立数据库连接;在请求结束时,指定数据的交互格式。为了让>每个视图函数避免编写重复功能的代码,Flask提供了通用设施的功能,即请求钩子。通过请求钩子,我们可以对请求进行预处理(preprocessing)和后处理>(postprocessing)。

Flask的请求钩子通过装饰器实现,每个钩子可以注册任意多个处理函数,默认的五种请求钩子如下:

钩子 说明
before_first_request 注册一个函数,在处理请求前运行
before_request 注册一个函数,在处理每个请求前运行
after_request 注册一个函数,如果有未处理的一场抛出。会在每个请求结束后运行
teardown_request 注册一个函数,即使有未处理的异常抛出,会在每个请求介绍后执行。如果发生异常,会传入异常对象作为参数注册到函数中
after_this_request 在视图函数内注册一个函数,在这个请求结束后运行

如何将本地项目推送到Github

Tip:在本地要安装好Git,官网:https://git-scm.com/

kzni4K.png

一个学习Git的好地方:https://try.github.io/

在线闯关实战,边练边学的好地方:https://learngitbranching.js.org/

方法一:使用https推送

1
2
3
4
5
6
7
8
9
10
11
12
13
# 步骤
# 1.创建一个目录
mkdir Test
# 2.将当前目录变为git管理仓库
git init
# 3.将文件添加到版本库,这里将目录下的所有文件都添加进去了
git add .
# 4.告诉git将文件提交到仓库
git commit -m "first-commit"
# 5.将当前仓库与远程仓库关联
git remote add orign 远程仓库的https地址 # eg: git remote add https://github.com/ssmath/Test.git
# 6.将仓库内master分支的所有内容推送到远程仓库,这里会使用到Github的账号密码
git push -u orign master
Git