Skip to content

Commit d7a75da

Browse files
committed
所有基础文章修改完毕
1 parent 95ad977 commit d7a75da

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+387
-145
lines changed

Article/python10/1.md Article/PythonBasis/python10/1.md

+9-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# 一、Python 的 Magic Method #
22

3-
在 Python 中,所有以 "__" 双下划线包起来的方法,都统称为"魔术方法"。比如我们接触最多的 `__init__` 。魔术方法有什么作用呢?
3+
在 Python 中,所有以 "__" 双下划线包起来的方法,都统称为"魔术方法"。比如我们接触最多的 `__init__`
4+
5+
魔术方法有什么作用呢?
46

57
使用这些魔术方法,我们可以构造出优美的代码,将复杂的逻辑封装成简单的方法。
68

@@ -22,6 +24,10 @@ if __name__ == '__main__':
2224

2325
输出的结果:
2426

25-
![Python 类的魔术方法](http://p1ceh5usj.bkt.clouddn.com/Python%20%E7%B1%BB%E7%9A%84%E9%AD%94%E6%9C%AF%E6%96%B9%E6%B3%95.png)
27+
```
28+
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
29+
```
30+
31+
可以看到,一个类的魔术方法还是挺多的,不过我们只需要了解一些常见和常用的魔术方法就好了。
32+
2633

27-
可以看到,一个类的魔术方法还是挺多的,截图也没有截全,不过我们只需要了解一些常见和常用的魔术方法就好了。

Article/python10/2.md Article/PythonBasis/python10/2.md

+9-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# 二、构造(`__new__`)和初始化(`__init__`) #
22

3-
通过上一篇的内容,我们已经知道定义一个类时,我们经常会通过 `__init__(self)` 的方法在实例化对象的时候,对属性进行设置。比如下面的例子:
3+
通过之前的学习,我们已经知道定义一个类时,我们经常会通过 `__init__(self)` 的方法在实例化对象的时候,对属性进行设置。
4+
5+
比如下面的例子:
46

57
```python
68
#!/usr/bin/env python3
@@ -14,9 +16,11 @@ class User(object):
1416
user=User('两点水',23)
1517
```
1618

17-
实际上,创建一个类的过程是分为两步的,一步是创建类的对象,还有一步就是对类进行初始化。`__new__` 是用来创建类并返回这个类的实例, 而`__init__` 只是将传入的参数来初始化该实例.`__new__` 在创建一个实例的过程中必定会被调用,但 `__init__` 就不一定,比如通过pickle.load 的方式反序列化一个实例时就不会调用 `__init__` 方法。
19+
实际上,创建一个类的过程是分为两步的,一步是创建类的对象,还有一步就是对类进行初始化。
20+
21+
`__new__` 是用来创建类并返回这个类的实例, 而`__init__` 只是将传入的参数来初始化该实例.`__new__` 在创建一个实例的过程中必定会被调用,但 `__init__` 就不一定,比如通过 pickle.load 的方式反序列化一个实例时就不会调用 `__init__` 方法。
1822

19-
![Python类创建的过程](http://upload-images.jianshu.io/upload_images/2136918-a2b39b078cc81841?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
23+
![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-14-Python%E7%B1%BB%E5%88%9B%E5%BB%BA%E7%9A%84%E8%BF%87%E7%A8%8B.png)
2024

2125
`def __new__(cls)` 是在 `def __init__(self)` 方法之前调用的,作用是返回一个实例对象。还有一点需要注意的是:`__new__` 方法总是需要返回该类的一个实例,而 `__init__` 不能返回除了 `None` 的任何值
2226

@@ -57,3 +61,5 @@ if __name__ == '__main__':
5761
其实在实际开发中,很少会用到 `__new__` 方法,除非你希望能够控制类的创建。通常讲到 `__new__` ,都是牵扯到 `metaclass`(元类)的。
5862

5963
当然当一个对象的生命周期结束的时候,析构函数 `__del__` 方法会被调用。但是这个方法是 Python 自己对对象进行垃圾回收的。
64+
65+
File renamed without changes.

Article/python10/4.md Article/PythonBasis/python10/4.md

+15-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,20 @@
11
# 四、对象的描述器 #
22

3-
一般来说,一个描述器是一个有“绑定行为”的对象属性 (object attribute),它的访问控制被描述器协议方法重写。这些方法是 `__get__()`, `__set__()` , 和 `__delete__()` 。有这些方法的对象叫做描述器。
3+
一般来说,一个描述器是一个有“绑定行为”的对象属性 (object attribute),它的访问控制被描述器协议方法重写。
44

5-
默认对属性的访问控制是从对象的字典里面 (`__dict__`) 中获取 (get) , 设置 (set) 和删除 (delete) 。举例来说, `a.x` 的查找顺序是, `a.__dict__['x']` , 然后 `type(a).__dict__['x']` , 然后找 `type(a)` 的父类 ( 不包括元类 (metaclass) ).如果查找到的值是一个描述器, Python 就会调用描述器的方法来重写默认的控制行为。这个重写发生在这个查找环节的哪里取决于定义了哪个描述器方法。注意, 只有在新式类中时描述器才会起作用。在之前的篇节中已经提到新式类和旧式类的,有兴趣可以查看之前的篇节来看看,至于新式类最大的特点就是所有类都继承自 type 或者 object 的类
5+
这些方法是 `__get__()`, `__set__()` , `__delete__()`
66

7-
在面向对象编程时,如果一个类的属性有相互依赖的关系时,使用描述器来编写代码可以很巧妙的组织逻辑。在 Django 的 ORM 中,models.Model中的 InterField 等字段, 就是通过描述器来实现功能的。
7+
有这些方法的对象叫做描述器。
8+
9+
默认对属性的访问控制是从对象的字典里面 (`__dict__`) 中获取 (get) , 设置 (set) 和删除 (delete) 。
10+
11+
举例来说, `a.x` 的查找顺序是, `a.__dict__['x']` , 然后 `type(a).__dict__['x']` , 然后找 `type(a)` 的父类 ( 不包括元类 (metaclass) ).如果查找到的值是一个描述器, Python 就会调用描述器的方法来重写默认的控制行为。
12+
13+
这个重写发生在这个查找环节的哪里取决于定义了哪个描述器方法。
14+
15+
注意, 只有在新式类中时描述器才会起作用。在之前的篇节中已经提到新式类和旧式类的,有兴趣可以查看之前的篇节来看看,至于新式类最大的特点就是所有类都继承自 type 或者 object 的类。
16+
17+
在面向对象编程时,如果一个类的属性有相互依赖的关系时,使用描述器来编写代码可以很巧妙的组织逻辑。在 Django 的 ORM 中,models.Model 中的 InterField 等字段, 就是通过描述器来实现功能的。
818

919
我们先看下下面的例子:
1020

@@ -129,3 +139,5 @@ if __name__ == '__main__':
129139
我们只是修改了 meter ,并且将其赋值成为 int ,但 foot 也修改了。这是 `__set__` 发挥了作用.
130140

131141
描述器对象 (Meter、Foot) 不能独立存在, 它需要被另一个所有者类 (Distance) 所持有。描述器对象可以访问到其拥有者实例的属性,比如例子中 Foot 的 `instance.meter`
142+
143+

Article/python10/5.md Article/PythonBasis/python10/5.md

+8-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
# 五、自定义容器(Container) #
22

3-
经过之前编章的介绍,我们知道在 Python 中,常见的容器类型有: dict, tuple, list, string。其中也提到过可容器和不可变容器的概念。其中 tuple, string 是不可变容器,dict, list 是可变容器。 可变容器和不可变容器的区别在于,不可变容器一旦赋值后,不可对其中的某个元素进行修改。当然具体的介绍,可以看回之前的文章,有图文介绍。
3+
经过之前编章的介绍,我们知道在 Python 中,常见的容器类型有: dict, tuple, list, string。其中也提到过可容器和不可变容器的概念。其中 tuple, string 是不可变容器,dict, list 是可变容器。
44

5-
那么这里先提出一个问题,这些数据结构就够我们开发使用吗?不够的时候,或者说有些特殊的需求不能单单只使用这些基本的容器解决的时候,该怎么办呢?
5+
可变容器和不可变容器的区别在于,不可变容器一旦赋值后,不可对其中的某个元素进行修改。当然具体的介绍,可以看回之前的文章,有图文介绍。
6+
7+
那么这里先提出一个问题,这些数据结构就够我们开发使用吗?
8+
9+
不够的时候,或者说有些特殊的需求不能单单只使用这些基本的容器解决的时候,该怎么办呢?
610

711
这个时候就需要自定义容器了,那么具体我们该怎么做呢?
812

@@ -78,3 +82,5 @@ class FunctionalList:
7882
return self.values[:n]
7983

8084
```
85+
86+

Article/python10/6.md Article/PythonBasis/python10/6.md

+6-2
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,10 @@ num1 >= num2 ? --------> False
107107
|`__xor__(self, other)`|实现了位操作 `^`|
108108

109109

110-
最后,如果对本文感兴趣的,可以关注下公众号:
110+
可以关注下公众号:
111+
112+
这个公号可能很少更新,但是一更新,就是把整理的一系列文章更新上去。
113+
114+
![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-14-WechatIMG697.jpeg)
115+
111116

112-
![公众号](http://twowater.com.cn/images/20171204192251900.gif)
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# 前言 #
2+
3+
有时候修改文章,真的修改到想死。真的很耗时间,很烦的。
4+
5+
好吧,每次都是安慰自己,快完结了,快更新完了。
6+
7+
# 目录 #
8+
9+
![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-14-Python%20%E7%9A%84%20Magic%20Method.png)
10+
11+

Article/python11/1.md Article/PythonBasis/python11/1.md

+13-3
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ DEC = 12
1515

1616
那有没有什么好的方法呢?
1717

18-
这时候我们定义一个 class 类型,每个常量都是 class 里面唯一的实例。正好 Python 提供了 Enum 类来实现这个功能如下:
18+
这时候我们定义一个 class 类型,每个常量都是 class 里面唯一的实例。
19+
20+
正好 Python 提供了 Enum 类来实现这个功能如下:
1921

2022
```python
2123
#!/usr/bin/env python3
@@ -37,6 +39,14 @@ print('\n', Month.Jan)
3739
输出的结果如下:
3840

3941

40-
![Python3 枚举类型的使用](http://p1ceh5usj.bkt.clouddn.com/Python3%20%E6%9E%9A%E4%B8%BE%E7%B1%BB%E5%9E%8B%E7%9A%84%E4%BD%BF%E7%94%A8.png)
42+
![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-14-Python3%20%E6%9E%9A%E4%B8%BE%E7%B1%BB%E5%9E%8B%E7%9A%84%E4%BD%BF%E7%94%A8.png)
43+
44+
我们使用 `Enum` 来定义了一个枚举类。
45+
46+
上面的代码,我们创建了一个有关月份的枚举类型 Month ,这里要注意的是构造参数,第一个参数 Month 表示的是该枚举类的类名,第二个 tuple 参数,表示的是枚举类的值;当然,枚举类通过 `__members__` 遍历它的所有成员的方法。
47+
48+
注意的一点是 , `member.value` 是自动赋给成员的 `int` 类型的常量,默认是从 1 开始的。
49+
50+
**而且 Enum 的成员均为单例(Singleton),并且不可实例化,不可更改**
51+
4152

42-
可见,我们可以直接使用 `Enum` 来定义一个枚举类。上面的代码,我们创建了一个有关月份的枚举类型 Month ,这里要注意的是构造参数,第一个参数 Month 表示的是该枚举类的类名,第二个 tuple 参数,表示的是枚举类的值;当然,枚举类通过 `__members__` 遍历它的所有成员的方法。注意的一点是 , `member.value` 是自动赋给成员的 `int`类型的常量,默认是从 1 开始的。而且 Enum 的成员均为单例(Singleton),并且不可实例化,不可更改

Article/python11/2.md Article/PythonBasis/python11/2.md

+11-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
11
# 二、Enum 的源码 #
22

3-
通过上面的实例可以知道通过 `__members__` 可以遍历枚举类的所有成员。那为什么呢?
3+
通过上面的实例可以知道通过 `__members__` 可以遍历枚举类的所有成员。
44

5-
我们可以先来大致看看 Enum 的源码是如何实现的;Enum 在模块 enum.py 中,先来看看 Enum 类的片段
5+
那有没有想过为什么呢?
6+
7+
当你看到那段代码的时候,有没有想过为什么通过 `__members__` 就能遍历枚举类型的所有成员出来?
8+
9+
10+
我们可以先来大致看看 Enum 的源码是如何实现的;
11+
12+
Enum 在模块 enum.py 中,先来看看 Enum 类的片段
613

714
```python
815
class Enum(metaclass=EnumMeta):
@@ -25,4 +32,5 @@ class EnumMeta(type):
2532
return MappingProxyType(cls._member_map_)
2633
```
2734

28-
首先 `__members__` 方法返回的是一个包含一个 Dict 既 Map 的 MappingProxyType,并且通过 @property 将方法 `__members__(cls)` 的访问方式改变为了变量的的形式,既可以直接通过 `__members__` 来进行访问了
35+
首先 `__members__` 方法返回的是一个包含一个 Dict 既 Map 的 MappingProxyType,并且通过 @property 将方法 `__members__(cls)` 的访问方式改变为了变量的的形式,那么就可以直接通过 `__members__` 来进行访问了
36+

Article/python11/3.md Article/PythonBasis/python11/3.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,10 @@ if __name__ == '__main__':
3838

3939
输出的结果如下:
4040

41-
![Python3 自定义类型的枚举类](http://p1ceh5usj.bkt.clouddn.com/Python3%20%E8%87%AA%E5%AE%9A%E4%B9%89%E7%B1%BB%E5%9E%8B%E7%9A%84%E6%9E%9A%E4%B8%BE%E7%B1%BB.png)
41+
![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-14-Python3%20%E8%87%AA%E5%AE%9A%E4%B9%89%E7%B1%BB%E5%9E%8B%E7%9A%84%E6%9E%9A%E4%B8%BE%E7%B1%BB.png)
4242

4343

4444

4545
通过上面的例子,可以知道枚举模块定义了具有迭代 (interator) 和比较(comparison) 功能的枚举类型。 它可以用来为值创建明确定义的符号,而不是使用具体的整数或字符串。
46+
47+
File renamed without changes.
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# 前言 #
2+
3+
2019年10月14日16:59:38 看了一下,还有五个章节就修改完基础部分了。
4+
5+
干就完事了。
6+
7+
# 目录 #
8+
9+
![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-14-%E6%9E%9A%E4%B8%BE%E7%B1%BB.png)
10+
11+

Article/python12/1.md Article/PythonBasis/python12/1.md

+7-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
在了解元类之前,我们先进一步理解 Python 中的类,在大多数编程语言中,类就是一组用来描述如何生成一个对象的代码段。在 Python 中这一点也是一样的。
44

5+
这点在学习类的章节也强调过了,下面可以通过例子回忆一下:
6+
57
```python
68
class ObjectCreator(object):
79
pass
@@ -30,7 +32,9 @@ class ObjectCreator(object):
3032
pass
3133
```
3234

33-
当程序运行这段代码的时候,就会在内存中创建一个对象,名字就是ObjectCreator。这个对象(类)自身拥有创建对象(类实例)的能力,而这就是为什么它是一个类的原因。但是,它的本质仍然是一个对象,于是我们可以对它做如下的操作:
35+
当程序运行这段代码的时候,就会在内存中创建一个对象,名字就是ObjectCreator。这个对象(类)自身拥有创建对象(类实例)的能力,而这就是为什么它是一个类的原因。
36+
37+
但是,它的本质仍然是一个对象,于是我们可以对它做如下的操作:
3438

3539
```python
3640
class ObjectCreator(object):
@@ -61,3 +65,5 @@ print(objectCreator)
6165
<class '__main__.ObjectCreator'>
6266
<class '__main__.ObjectCreator'>
6367
```
68+
69+

Article/python12/2.md Article/PythonBasis/python12/2.md

+32-7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
# 二、使用 `type()` 动态创建类 #
22

3-
因为类也是对象,所以我们可以在程序运行的时候创建类。Python 是动态语言。动态语言和静态语言最大的不同,就是函数和类的定义,不是编译时定义的,而是运行时动态创建的。在之前,我们先了了解下 `type()` 函数。
3+
因为类也是对象,所以我们可以在程序运行的时候创建类。
4+
5+
Python 是动态语言。
6+
7+
**动态语言和静态语言最大的不同,就是函数和类的定义,不是编译时定义的,而是运行时动态创建的。**
8+
9+
在之前,我们先了了解下 `type()` 函数。
410

511

612
首先我们新建一个 `hello.py` 的模块,然后定义一个 Hello 的 class ,
@@ -11,7 +17,9 @@ class Hello(object):
1117
print('Hello,', name)
1218
```
1319

14-
然后在另一个模块中引用 hello 模块,并输出相应的信息。其中 `type()` 函数的作用是可以查看一个类型和变量的类型。
20+
然后在另一个模块中引用 hello 模块,并输出相应的信息。
21+
22+
其中 `type()` 函数的作用是可以查看一个类型和变量的类型。
1523

1624
```python
1725
#!/usr/bin/env python3
@@ -35,9 +43,19 @@ Hello, Py
3543
<class 'com.twowater.hello.Hello'>
3644
```
3745

38-
上面也提到过,`type()` 函数可以查看一个类型或变量的类型,`Hello` 是一个 `class` ,它的类型就是 `type` ,而 `h` 是一个实例,它的类型就是 `com.twowater.hello.Hello`。前面的 `com.twowater` 是我的包名,`hello` 模块在该包名下。
46+
上面也提到过,`type()` 函数可以查看一个类型或变量的类型,`Hello` 是一个 `class` ,它的类型就是 `type` ,而 `h` 是一个实例,它的类型就是 `com.twowater.hello.Hello`
47+
48+
前面的 `com.twowater` 是我的包名,`hello` 模块在该包名下。
49+
50+
在这里还要细想一下,上面的例子中,我们使用 `type()` 函数查看一个类型或者变量的类型。
51+
52+
其中查看了一个 `Hello` class 的类型,打印的结果是: `<class 'type'>`
3953

40-
在这里还要细想一下,上面的例子中,我们使用 `type()` 函数查看一个类型或者变量的类型。其中查看了一个 `Hello` class 的类型,打印的结果是: `<class 'type'>` 。其实 `type()` 函数不仅可以返回一个对象的类型,也可以创建出新的类型。class 的定义是运行时动态创建的,而创建 class 的方法就是使用 `type()` 函数。比如我们可以通过 `type()` 函数创建出上面例子中的 `Hello` 类,具体看下面的代码:
54+
**其实 `type()` 函数不仅可以返回一个对象的类型,也可以创建出新的类型。**
55+
56+
class 的定义是运行时动态创建的,而创建 class 的方法就是使用 `type()` 函数。
57+
58+
比如我们可以通过 `type()` 函数创建出上面例子中的 `Hello` 类,具体看下面的代码:
4159

4260
```python
4361
# -*- coding: UTF-8 -*-
@@ -83,8 +101,15 @@ Hello, Py
83101
type(类名, 父类的元组(针对继承的情况,可以为空),包含属性的字典(名称和值))
84102
```
85103

86-
好了,了解完具体的参数使用之外,我们看看输出的结果,可以看到,通过 `type()` 函数创建的类和直接写 class 是完全一样的,因为Python 解释器遇到 class 定义时,仅仅是扫描一下 class 定义的语法,然后调用 `type()` 函数创建出 class 的 。
104+
好了,了解完具体的参数使用之外,我们看看输出的结果,可以看到,通过 `type()` 函数创建的类和直接写 class 是完全一样的。
105+
106+
这是因为Python 解释器遇到 class 定义时,仅仅是扫描一下 class 定义的语法,然后调用 `type()` 函数创建出 class 的。
107+
108+
不过一般的情况下,我们都是使用 `class ***...` 的方法来定义类的,不过 `type()` 函数也可以让我们创建出类来。
109+
110+
也就是说,动态语言本身支持运行期动态创建类,这和静态语言有非常大的不同,要在静态语言运行期创建类,必须构造源代码字符串再调用编译器,或者借助一些工具生成字节码实现,本质上都是动态编译,会非常复杂。
111+
112+
**可以看到,在 Python 中,类也是对象,你可以动态的创建类。**
87113

88-
不过一般的情况下,我们都是使用 `class ***...` 的方法来定义类的,不过 `type()` 函数也可以让我们创建出类来。也就是说,动态语言本身支持运行期动态创建类,这和静态语言有非常大的不同,要在静态语言运行期创建类,必须构造源代码字符串再调用编译器,或者借助一些工具生成字节码实现,本质上都是动态编译,会非常复杂。
114+
其实这也就是当你使用关键字 class 时 Python 在幕后做的事情,而这就是通过元类来实现的。
89115

90-
可以看到,在 Python 中,类也是对象,你可以动态的创建类。其实这也就是当你使用关键字 class 时 Python 在幕后做的事情,而这就是通过元类来实现的。

0 commit comments

Comments
 (0)