diff --git a/Article/python10/1.md b/Article/PythonBasis/python10/1.md similarity index 52% rename from Article/python10/1.md rename to Article/PythonBasis/python10/1.md index 867d1831..42a13271 100644 --- a/Article/python10/1.md +++ b/Article/PythonBasis/python10/1.md @@ -1,6 +1,8 @@ # 一、Python 的 Magic Method # -在 Python 中,所有以 "__" 双下划线包起来的方法,都统称为"魔术方法"。比如我们接触最多的 `__init__` 。魔术方法有什么作用呢? +在 Python 中,所有以 "__" 双下划线包起来的方法,都统称为"魔术方法"。比如我们接触最多的 `__init__` 。 + +魔术方法有什么作用呢? 使用这些魔术方法,我们可以构造出优美的代码,将复杂的逻辑封装成简单的方法。 @@ -22,6 +24,10 @@ if __name__ == '__main__': 输出的结果: -![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) +``` +['__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__'] +``` + +可以看到,一个类的魔术方法还是挺多的,不过我们只需要了解一些常见和常用的魔术方法就好了。 + -可以看到,一个类的魔术方法还是挺多的,截图也没有截全,不过我们只需要了解一些常见和常用的魔术方法就好了。 diff --git a/Article/python10/2.md b/Article/PythonBasis/python10/2.md similarity index 75% rename from Article/python10/2.md rename to Article/PythonBasis/python10/2.md index 18af9f42..db00b527 100644 --- a/Article/python10/2.md +++ b/Article/PythonBasis/python10/2.md @@ -1,6 +1,8 @@ # 二、构造(`__new__`)和初始化(`__init__`) # -通过上一篇的内容,我们已经知道定义一个类时,我们经常会通过 `__init__(self)` 的方法在实例化对象的时候,对属性进行设置。比如下面的例子: +通过之前的学习,我们已经知道定义一个类时,我们经常会通过 `__init__(self)` 的方法在实例化对象的时候,对属性进行设置。 + +比如下面的例子: ```python #!/usr/bin/env python3 @@ -14,9 +16,11 @@ class User(object): user=User('两点水',23) ``` -实际上,创建一个类的过程是分为两步的,一步是创建类的对象,还有一步就是对类进行初始化。`__new__` 是用来创建类并返回这个类的实例, 而`__init__` 只是将传入的参数来初始化该实例.`__new__` 在创建一个实例的过程中必定会被调用,但 `__init__` 就不一定,比如通过pickle.load 的方式反序列化一个实例时就不会调用 `__init__` 方法。 +实际上,创建一个类的过程是分为两步的,一步是创建类的对象,还有一步就是对类进行初始化。 + +`__new__` 是用来创建类并返回这个类的实例, 而`__init__` 只是将传入的参数来初始化该实例.`__new__` 在创建一个实例的过程中必定会被调用,但 `__init__` 就不一定,比如通过 pickle.load 的方式反序列化一个实例时就不会调用 `__init__` 方法。 -![Python类创建的过程](http://upload-images.jianshu.io/upload_images/2136918-a2b39b078cc81841?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) +![](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) `def __new__(cls)` 是在 `def __init__(self)` 方法之前调用的,作用是返回一个实例对象。还有一点需要注意的是:`__new__` 方法总是需要返回该类的一个实例,而 `__init__` 不能返回除了 `None` 的任何值 @@ -57,3 +61,5 @@ if __name__ == '__main__': 其实在实际开发中,很少会用到 `__new__` 方法,除非你希望能够控制类的创建。通常讲到 `__new__` ,都是牵扯到 `metaclass`(元类)的。 当然当一个对象的生命周期结束的时候,析构函数 `__del__` 方法会被调用。但是这个方法是 Python 自己对对象进行垃圾回收的。 + + diff --git a/Article/python10/3.md b/Article/PythonBasis/python10/3.md similarity index 100% rename from Article/python10/3.md rename to Article/PythonBasis/python10/3.md diff --git a/Article/python10/4.md b/Article/PythonBasis/python10/4.md similarity index 74% rename from Article/python10/4.md rename to Article/PythonBasis/python10/4.md index bf45a9d6..49eb1b00 100644 --- a/Article/python10/4.md +++ b/Article/PythonBasis/python10/4.md @@ -1,10 +1,20 @@ # 四、对象的描述器 # -一般来说,一个描述器是一个有“绑定行为”的对象属性 (object attribute),它的访问控制被描述器协议方法重写。这些方法是 `__get__()`, `__set__()` , 和 `__delete__()` 。有这些方法的对象叫做描述器。 +一般来说,一个描述器是一个有“绑定行为”的对象属性 (object attribute),它的访问控制被描述器协议方法重写。 -默认对属性的访问控制是从对象的字典里面 (`__dict__`) 中获取 (get) , 设置 (set) 和删除 (delete) 。举例来说, `a.x` 的查找顺序是, `a.__dict__['x']` , 然后 `type(a).__dict__['x']` , 然后找 `type(a)` 的父类 ( 不包括元类 (metaclass) ).如果查找到的值是一个描述器, Python 就会调用描述器的方法来重写默认的控制行为。这个重写发生在这个查找环节的哪里取决于定义了哪个描述器方法。注意, 只有在新式类中时描述器才会起作用。在之前的篇节中已经提到新式类和旧式类的,有兴趣可以查看之前的篇节来看看,至于新式类最大的特点就是所有类都继承自 type 或者 object 的类。 +这些方法是 `__get__()`, `__set__()` , 和 `__delete__()` 。 -在面向对象编程时,如果一个类的属性有相互依赖的关系时,使用描述器来编写代码可以很巧妙的组织逻辑。在 Django 的 ORM 中,models.Model中的 InterField 等字段, 就是通过描述器来实现功能的。 +有这些方法的对象叫做描述器。 + +默认对属性的访问控制是从对象的字典里面 (`__dict__`) 中获取 (get) , 设置 (set) 和删除 (delete) 。 + +举例来说, `a.x` 的查找顺序是, `a.__dict__['x']` , 然后 `type(a).__dict__['x']` , 然后找 `type(a)` 的父类 ( 不包括元类 (metaclass) ).如果查找到的值是一个描述器, Python 就会调用描述器的方法来重写默认的控制行为。 + +这个重写发生在这个查找环节的哪里取决于定义了哪个描述器方法。 + +注意, 只有在新式类中时描述器才会起作用。在之前的篇节中已经提到新式类和旧式类的,有兴趣可以查看之前的篇节来看看,至于新式类最大的特点就是所有类都继承自 type 或者 object 的类。 + +在面向对象编程时,如果一个类的属性有相互依赖的关系时,使用描述器来编写代码可以很巧妙的组织逻辑。在 Django 的 ORM 中,models.Model 中的 InterField 等字段, 就是通过描述器来实现功能的。 我们先看下下面的例子: @@ -129,3 +139,5 @@ if __name__ == '__main__': 我们只是修改了 meter ,并且将其赋值成为 int ,但 foot 也修改了。这是 `__set__` 发挥了作用. 描述器对象 (Meter、Foot) 不能独立存在, 它需要被另一个所有者类 (Distance) 所持有。描述器对象可以访问到其拥有者实例的属性,比如例子中 Foot 的 `instance.meter` 。 + + diff --git a/Article/python10/5.md b/Article/PythonBasis/python10/5.md similarity index 87% rename from Article/python10/5.md rename to Article/PythonBasis/python10/5.md index 64f03124..90cf5251 100644 --- a/Article/python10/5.md +++ b/Article/PythonBasis/python10/5.md @@ -1,8 +1,12 @@ # 五、自定义容器(Container) # -经过之前编章的介绍,我们知道在 Python 中,常见的容器类型有: dict, tuple, list, string。其中也提到过可容器和不可变容器的概念。其中 tuple, string 是不可变容器,dict, list 是可变容器。 可变容器和不可变容器的区别在于,不可变容器一旦赋值后,不可对其中的某个元素进行修改。当然具体的介绍,可以看回之前的文章,有图文介绍。 +经过之前编章的介绍,我们知道在 Python 中,常见的容器类型有: dict, tuple, list, string。其中也提到过可容器和不可变容器的概念。其中 tuple, string 是不可变容器,dict, list 是可变容器。 -那么这里先提出一个问题,这些数据结构就够我们开发使用吗?不够的时候,或者说有些特殊的需求不能单单只使用这些基本的容器解决的时候,该怎么办呢? +可变容器和不可变容器的区别在于,不可变容器一旦赋值后,不可对其中的某个元素进行修改。当然具体的介绍,可以看回之前的文章,有图文介绍。 + +那么这里先提出一个问题,这些数据结构就够我们开发使用吗? + +不够的时候,或者说有些特殊的需求不能单单只使用这些基本的容器解决的时候,该怎么办呢? 这个时候就需要自定义容器了,那么具体我们该怎么做呢? @@ -78,3 +82,5 @@ class FunctionalList: return self.values[:n] ``` + + diff --git a/Article/python10/6.md b/Article/PythonBasis/python10/6.md similarity index 93% rename from Article/python10/6.md rename to Article/PythonBasis/python10/6.md index 1af49bd8..22ab4b42 100644 --- a/Article/python10/6.md +++ b/Article/PythonBasis/python10/6.md @@ -107,6 +107,10 @@ num1 >= num2 ? --------> False |`__xor__(self, other)`|实现了位操作 `^`| -最后,如果对本文感兴趣的,可以关注下公众号: +可以关注下公众号: + +这个公号可能很少更新,但是一更新,就是把整理的一系列文章更新上去。 + +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-14-WechatIMG697.jpeg) + -![公众号](http://twowater.com.cn/images/20171204192251900.gif) diff --git a/Article/PythonBasis/python10/Preface.md b/Article/PythonBasis/python10/Preface.md new file mode 100644 index 00000000..a1cd4e08 --- /dev/null +++ b/Article/PythonBasis/python10/Preface.md @@ -0,0 +1,11 @@ +# 前言 # + +有时候修改文章,真的修改到想死。真的很耗时间,很烦的。 + +好吧,每次都是安慰自己,快完结了,快更新完了。 + +# 目录 # + +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-14-Python%20%E7%9A%84%20Magic%20Method.png) + + diff --git a/Article/python11/1.md b/Article/PythonBasis/python11/1.md similarity index 51% rename from Article/python11/1.md rename to Article/PythonBasis/python11/1.md index 49d3528c..0ebc3eeb 100644 --- a/Article/python11/1.md +++ b/Article/PythonBasis/python11/1.md @@ -15,7 +15,9 @@ DEC = 12 那有没有什么好的方法呢? -这时候我们定义一个 class 类型,每个常量都是 class 里面唯一的实例。正好 Python 提供了 Enum 类来实现这个功能如下: +这时候我们定义一个 class 类型,每个常量都是 class 里面唯一的实例。 + +正好 Python 提供了 Enum 类来实现这个功能如下: ```python #!/usr/bin/env python3 @@ -37,6 +39,14 @@ print('\n', Month.Jan) 输出的结果如下: -![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) +![](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) + +我们使用 `Enum` 来定义了一个枚举类。 + +上面的代码,我们创建了一个有关月份的枚举类型 Month ,这里要注意的是构造参数,第一个参数 Month 表示的是该枚举类的类名,第二个 tuple 参数,表示的是枚举类的值;当然,枚举类通过 `__members__` 遍历它的所有成员的方法。 + +注意的一点是 , `member.value` 是自动赋给成员的 `int` 类型的常量,默认是从 1 开始的。 + +**而且 Enum 的成员均为单例(Singleton),并且不可实例化,不可更改** + -可见,我们可以直接使用 `Enum` 来定义一个枚举类。上面的代码,我们创建了一个有关月份的枚举类型 Month ,这里要注意的是构造参数,第一个参数 Month 表示的是该枚举类的类名,第二个 tuple 参数,表示的是枚举类的值;当然,枚举类通过 `__members__` 遍历它的所有成员的方法。注意的一点是 , `member.value` 是自动赋给成员的 `int`类型的常量,默认是从 1 开始的。而且 Enum 的成员均为单例(Singleton),并且不可实例化,不可更改 diff --git a/Article/python11/2.md b/Article/PythonBasis/python11/2.md similarity index 73% rename from Article/python11/2.md rename to Article/PythonBasis/python11/2.md index 14f36d6a..105cff44 100644 --- a/Article/python11/2.md +++ b/Article/PythonBasis/python11/2.md @@ -1,8 +1,15 @@ # 二、Enum 的源码 # -通过上面的实例可以知道通过 `__members__` 可以遍历枚举类的所有成员。那为什么呢? +通过上面的实例可以知道通过 `__members__` 可以遍历枚举类的所有成员。 -我们可以先来大致看看 Enum 的源码是如何实现的;Enum 在模块 enum.py 中,先来看看 Enum 类的片段 +那有没有想过为什么呢? + +当你看到那段代码的时候,有没有想过为什么通过 `__members__` 就能遍历枚举类型的所有成员出来? + + +我们可以先来大致看看 Enum 的源码是如何实现的; + +Enum 在模块 enum.py 中,先来看看 Enum 类的片段 ```python class Enum(metaclass=EnumMeta): @@ -25,4 +32,5 @@ class EnumMeta(type): return MappingProxyType(cls._member_map_) ``` -首先 `__members__` 方法返回的是一个包含一个 Dict 既 Map 的 MappingProxyType,并且通过 @property 将方法 `__members__(cls)` 的访问方式改变为了变量的的形式,既可以直接通过 `__members__` 来进行访问了 \ No newline at end of file +首先 `__members__` 方法返回的是一个包含一个 Dict 既 Map 的 MappingProxyType,并且通过 @property 将方法 `__members__(cls)` 的访问方式改变为了变量的的形式,那么就可以直接通过 `__members__` 来进行访问了 + diff --git a/Article/python11/3.md b/Article/PythonBasis/python11/3.md similarity index 87% rename from Article/python11/3.md rename to Article/PythonBasis/python11/3.md index c61a6ee3..ea4a78da 100644 --- a/Article/python11/3.md +++ b/Article/PythonBasis/python11/3.md @@ -38,8 +38,10 @@ if __name__ == '__main__': 输出的结果如下: -![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) +![](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) 通过上面的例子,可以知道枚举模块定义了具有迭代 (interator) 和比较(comparison) 功能的枚举类型。 它可以用来为值创建明确定义的符号,而不是使用具体的整数或字符串。 + + diff --git a/Article/python11/4.md b/Article/PythonBasis/python11/4.md similarity index 100% rename from Article/python11/4.md rename to Article/PythonBasis/python11/4.md diff --git a/Article/PythonBasis/python11/Preface.md b/Article/PythonBasis/python11/Preface.md new file mode 100644 index 00000000..3d40a7ea --- /dev/null +++ b/Article/PythonBasis/python11/Preface.md @@ -0,0 +1,11 @@ +# 前言 # + +2019年10月14日16:59:38 看了一下,还有五个章节就修改完基础部分了。 + +干就完事了。 + +# 目录 # + +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-14-%E6%9E%9A%E4%B8%BE%E7%B1%BB.png) + + diff --git a/Article/python12/1.md b/Article/PythonBasis/python12/1.md similarity index 88% rename from Article/python12/1.md rename to Article/PythonBasis/python12/1.md index f29f4b7b..782a61a7 100644 --- a/Article/python12/1.md +++ b/Article/PythonBasis/python12/1.md @@ -2,6 +2,8 @@ 在了解元类之前,我们先进一步理解 Python 中的类,在大多数编程语言中,类就是一组用来描述如何生成一个对象的代码段。在 Python 中这一点也是一样的。 +这点在学习类的章节也强调过了,下面可以通过例子回忆一下: + ```python class ObjectCreator(object): pass @@ -30,7 +32,9 @@ class ObjectCreator(object): pass ``` -当程序运行这段代码的时候,就会在内存中创建一个对象,名字就是ObjectCreator。这个对象(类)自身拥有创建对象(类实例)的能力,而这就是为什么它是一个类的原因。但是,它的本质仍然是一个对象,于是我们可以对它做如下的操作: +当程序运行这段代码的时候,就会在内存中创建一个对象,名字就是ObjectCreator。这个对象(类)自身拥有创建对象(类实例)的能力,而这就是为什么它是一个类的原因。 + +但是,它的本质仍然是一个对象,于是我们可以对它做如下的操作: ```python class ObjectCreator(object): @@ -61,3 +65,5 @@ print(objectCreator) ``` + + diff --git a/Article/python12/2.md b/Article/PythonBasis/python12/2.md similarity index 58% rename from Article/python12/2.md rename to Article/PythonBasis/python12/2.md index df5019c3..fa5715c3 100644 --- a/Article/python12/2.md +++ b/Article/PythonBasis/python12/2.md @@ -1,6 +1,12 @@ # 二、使用 `type()` 动态创建类 # -因为类也是对象,所以我们可以在程序运行的时候创建类。Python 是动态语言。动态语言和静态语言最大的不同,就是函数和类的定义,不是编译时定义的,而是运行时动态创建的。在之前,我们先了了解下 `type()` 函数。 +因为类也是对象,所以我们可以在程序运行的时候创建类。 + +Python 是动态语言。 + +**动态语言和静态语言最大的不同,就是函数和类的定义,不是编译时定义的,而是运行时动态创建的。** + +在之前,我们先了了解下 `type()` 函数。 首先我们新建一个 `hello.py` 的模块,然后定义一个 Hello 的 class , @@ -11,7 +17,9 @@ class Hello(object): print('Hello,', name) ``` -然后在另一个模块中引用 hello 模块,并输出相应的信息。其中 `type()` 函数的作用是可以查看一个类型和变量的类型。 +然后在另一个模块中引用 hello 模块,并输出相应的信息。 + +其中 `type()` 函数的作用是可以查看一个类型和变量的类型。 ```python #!/usr/bin/env python3 @@ -35,9 +43,19 @@ Hello, Py ``` -上面也提到过,`type()` 函数可以查看一个类型或变量的类型,`Hello` 是一个 `class` ,它的类型就是 `type` ,而 `h` 是一个实例,它的类型就是 `com.twowater.hello.Hello`。前面的 `com.twowater` 是我的包名,`hello` 模块在该包名下。 +上面也提到过,`type()` 函数可以查看一个类型或变量的类型,`Hello` 是一个 `class` ,它的类型就是 `type` ,而 `h` 是一个实例,它的类型就是 `com.twowater.hello.Hello`。 + +前面的 `com.twowater` 是我的包名,`hello` 模块在该包名下。 + +在这里还要细想一下,上面的例子中,我们使用 `type()` 函数查看一个类型或者变量的类型。 + +其中查看了一个 `Hello` class 的类型,打印的结果是: `` 。 -在这里还要细想一下,上面的例子中,我们使用 `type()` 函数查看一个类型或者变量的类型。其中查看了一个 `Hello` class 的类型,打印的结果是: `` 。其实 `type()` 函数不仅可以返回一个对象的类型,也可以创建出新的类型。class 的定义是运行时动态创建的,而创建 class 的方法就是使用 `type()` 函数。比如我们可以通过 `type()` 函数创建出上面例子中的 `Hello` 类,具体看下面的代码: +**其实 `type()` 函数不仅可以返回一个对象的类型,也可以创建出新的类型。** + +class 的定义是运行时动态创建的,而创建 class 的方法就是使用 `type()` 函数。 + +比如我们可以通过 `type()` 函数创建出上面例子中的 `Hello` 类,具体看下面的代码: ```python # -*- coding: UTF-8 -*- @@ -83,8 +101,15 @@ Hello, Py type(类名, 父类的元组(针对继承的情况,可以为空),包含属性的字典(名称和值)) ``` -好了,了解完具体的参数使用之外,我们看看输出的结果,可以看到,通过 `type()` 函数创建的类和直接写 class 是完全一样的,因为Python 解释器遇到 class 定义时,仅仅是扫描一下 class 定义的语法,然后调用 `type()` 函数创建出 class 的 。 +好了,了解完具体的参数使用之外,我们看看输出的结果,可以看到,通过 `type()` 函数创建的类和直接写 class 是完全一样的。 + +这是因为Python 解释器遇到 class 定义时,仅仅是扫描一下 class 定义的语法,然后调用 `type()` 函数创建出 class 的。 + +不过一般的情况下,我们都是使用 `class ***...` 的方法来定义类的,不过 `type()` 函数也可以让我们创建出类来。 + +也就是说,动态语言本身支持运行期动态创建类,这和静态语言有非常大的不同,要在静态语言运行期创建类,必须构造源代码字符串再调用编译器,或者借助一些工具生成字节码实现,本质上都是动态编译,会非常复杂。 + +**可以看到,在 Python 中,类也是对象,你可以动态的创建类。** -不过一般的情况下,我们都是使用 `class ***...` 的方法来定义类的,不过 `type()` 函数也可以让我们创建出类来。也就是说,动态语言本身支持运行期动态创建类,这和静态语言有非常大的不同,要在静态语言运行期创建类,必须构造源代码字符串再调用编译器,或者借助一些工具生成字节码实现,本质上都是动态编译,会非常复杂。 +其实这也就是当你使用关键字 class 时 Python 在幕后做的事情,而这就是通过元类来实现的。 -可以看到,在 Python 中,类也是对象,你可以动态的创建类。其实这也就是当你使用关键字 class 时 Python 在幕后做的事情,而这就是通过元类来实现的。 \ No newline at end of file diff --git a/Article/python12/3.md b/Article/PythonBasis/python12/3.md similarity index 56% rename from Article/python12/3.md rename to Article/PythonBasis/python12/3.md index f1c66b4a..0db692d4 100644 --- a/Article/python12/3.md +++ b/Article/PythonBasis/python12/3.md @@ -1,8 +1,12 @@ # 三、什么是元类 # -通过上面的介绍,终于模模糊糊的带到元类这里来了。可是我们到现在还不知道元类是什么东东。 +通过上面的介绍,终于模模糊糊的带到元类这里来了。可是我们到现在还不知道元类是什么鬼东西。 -我们创建类的时候,大多数是为了创建类的实例对象。那么元类呢?元类就是用来创建类的。也可以换个理解方式就是:元类就是类的类。 +我们创建类的时候,大多数是为了创建类的实例对象。 + +那么元类呢? + +**元类就是用来创建类的。也可以换个理解方式就是:元类就是类的类。** 通过上面 `type()` 函数的介绍,我们知道可以通过 `type()` 函数创建类: @@ -10,11 +14,21 @@ MyClass = type('MyClass', (), {}) ``` -实际上 `type()` 函数是一个元类。`type()` 就是 Python 在背后用来创建所有类的元类。 +**实际上 `type()` 函数是一个元类。** + +`type()` 就是 Python 在背后用来创建所有类的元类。 那么现在我们也可以猜到一下为什么 `type()` 函数是 type 而不是 Type呢? -这可能是为了和 str 保持一致性,str 是用来创建字符串对象的类,而 int 是用来创建整数对象的类。type 就是创建类对象的类。你可以通过检查 `__class__` 属性来看到这一点。Python 中所有的东西,注意喔,这里是说所有的东西,他们都是对象。这包括整数、字符串、函数以及类。它们全部都是对象,而且它们都是从一个类创建而来。 +这可能是为了和 str 保持一致性,str 是用来创建字符串对象的类,而 int 是用来创建整数对象的类。 + +type 就是创建类对象的类。 + +你可以通过检查 `__class__` 属性来看到这一点。 + +Python 中所有的东西,注意喔,这里是说所有的东西,他们都是对象。 + +这包括整数、字符串、函数以及类。它们全部都是对象,而且它们都是从一个类创建而来。 ```python # 整形 @@ -52,7 +66,9 @@ print(mEat.__class__) ``` -可以看到,上面的所有东西,也就是所有对象都是通过类来创建的,那么我们可能会好奇,`__class__` 的 `__class__` 会是什么呢?换个说法就是,创建这些类的类是什么呢? +可以看到,上面的所有东西,也就是所有对象都是通过类来创建的,那么我们可能会好奇,`__class__` 的 `__class__` 会是什么呢? + +**换个说法就是,创建这些类的类是什么呢?** 我们可以继续在上面的代码基础上新增下面的代码: @@ -72,6 +88,15 @@ print(mEat.__class__.__class__) ``` -认真观察,再理清一下,上面输出的结果是我们把整形 `age` ,字符创 `name` ,函数 `fu` 和对象实例 `mEat` 里 `__class__` 的 `__class__` 打印出来的结果。也可以说是他们类的类打印结果。发现打印出来的 class 都是 type 。 +认真观察,再理清一下,上面输出的结果是我们把整形 `age` ,字符创 `name` ,函数 `fu` 和对象实例 `mEat` 里 `__class__` 的 `__class__` 打印出来的结果。 + +也可以说是他们类的类打印结果。发现打印出来的 class 都是 type 。 + +一开始也提到了,元类就是类的类。 + +也就是元类就是负责创建类的一种东西。 + +你也可以理解为,元类就是负责生成类的。 + +**而 type 就是内建的元类。也就是 Python 自带的元类。** -一开始也提到了,元类就是类的类。也就是元类就是负责创建类的一种东西。你也可以理解为,元类就是负责生成类的。而 type 就是内建的元类。也就是 Python 自带的元类。 \ No newline at end of file diff --git a/Article/python12/4.md b/Article/PythonBasis/python12/4.md similarity index 80% rename from Article/python12/4.md rename to Article/PythonBasis/python12/4.md index a98f6d6d..2376a9b6 100644 --- a/Article/python12/4.md +++ b/Article/PythonBasis/python12/4.md @@ -1,6 +1,14 @@ # 四、自定义元类 # -到现在,我们已经知道元类是什么东东了。那么,从始至终我们还不知道元类到底有啥用。只是了解了一下元类。在了解它有啥用的时候,我们先来了解下怎么自定义元类。因为只有了解了怎么自定义才能更好的理解它的作用。 +到现在,我们已经知道元类是什么鬼东西了。 + +那么,从始至终我们还不知道元类到底有啥用。 + +只是了解了一下元类。 + +在了解它有啥用的时候,我们先来了解下怎么自定义元类。 + +因为只有了解了怎么自定义才能更好的理解它的作用。 首先我们来了解下 `__metaclass__` 属性 @@ -8,11 +16,15 @@ metaclass,直译为元类,简单的解释就是: 当我们定义了类以后,就可以根据这个类创建出实例,所以:先定义类,然后创建实例。 -但是如果我们想创建出类呢?那就必须根据metaclass创建出类,所以:先定义metaclass,然后创建类。 +但是如果我们想创建出类呢? + +那就必须根据metaclass创建出类,所以:先定义metaclass,然后创建类。 连接起来就是:先定义metaclass,就可以创建类,最后创建实例。 -所以,metaclass允许你创建类或者修改类。换句话说,你可以把类看成是metaclass创建出来的“实例”。 +所以,metaclass 允许你创建类或者修改类。 + +换句话说,你可以把类看成是 metaclass 创建出来的“实例”。 ```python class MyObject(object): @@ -20,7 +32,11 @@ class MyObject(object): […] ``` -如果是这样写的话,Python 就会用元类来创建类 MyObject。当你写下 `class MyObject(object)`,但是类对象 MyObject 还没有在内存中创建。Python 会在类的定义中寻找 `__metaclass__` 属性,如果找到了,Python 就会用它来创建类 MyObject,如果没有找到,就会用内建的 type 函数来创建这个类。如果还不怎么理解,看下下面的流程图: +如果是这样写的话,Python 就会用元类来创建类 MyObject。 + +当你写下 `class MyObject(object)`,但是类对象 MyObject 还没有在内存中创建。P + +ython 会在类的定义中寻找 `__metaclass__` 属性,如果找到了,Python 就会用它来创建类 MyObject,如果没有找到,就会用内建的 type 函数来创建这个类。如果还不怎么理解,看下下面的流程图: ![__metaclass__的介绍](https://user-gold-cdn.xitu.io/2017/9/6/06c5a4390887abd3d79401848742f5ce) @@ -43,7 +59,9 @@ class Foo(Bar): 答案就是:可以创建一个类的东西。那么什么可以用来创建一个类呢?type,或者任何使用到 type 或者子类化 type 的东东都可以。 -元类的主要目的就是为了当创建类时能够自动地改变类。通常,你会为API 做这样的事情,你希望可以创建符合当前上下文的类。假想一个很傻的例子,你决定在你的模块里所有的类的属性都应该是大写形式。有好几种方法可以办到,但其中一种就是通过在模块级别设定`__metaclass__` 。采用这种方法,这个模块中的所有类都会通过这个元类来创建,我们只需要告诉元类把所有的属性都改成大写形式就万事大吉了。 +**元类的主要目的就是为了当创建类时能够自动地改变类。** + +通常,你会为API 做这样的事情,你希望可以创建符合当前上下文的类。假想一个很傻的例子,你决定在你的模块里所有的类的属性都应该是大写形式。有好几种方法可以办到,但其中一种就是通过在模块级别设定`__metaclass__` 。采用这种方法,这个模块中的所有类都会通过这个元类来创建,我们只需要告诉元类把所有的属性都改成大写形式就万事大吉了。 幸运的是,`__metaclass__` 实际上可以被任意调用,它并不需要是一个正式的类。所以,我们这里就先以一个简单的函数作为例子开始。 @@ -141,4 +159,5 @@ class UpperAttrMetaclass(type): * 拦截类的创建 * 修改类 -* 返回修改之后的类 \ No newline at end of file +* 返回修改之后的类 + diff --git a/Article/python12/5.md b/Article/PythonBasis/python12/5.md similarity index 69% rename from Article/python12/5.md rename to Article/PythonBasis/python12/5.md index 3feaa97c..c6a0ad7a 100644 --- a/Article/python12/5.md +++ b/Article/PythonBasis/python12/5.md @@ -19,7 +19,11 @@ guy = Person(name='bob', age='35') print guy.age ``` -这并不会返回一个 IntegerField 对象,而是会返回一个 int,甚至可以直接从数据库中取出数据。这是有可能的,因为 models.Model 定义了 `__metaclass__` , 并且使用了一些魔法能够将你刚刚定义的简单的Person类转变成对数据库的一个复杂 hook。Django 框架将这些看起来很复杂的东西通过暴露出一个简单的使用元类的 API 将其化简,通过这个 API 重新创建代码,在背后完成真正的工作。 +这并不会返回一个 IntegerField 对象,而是会返回一个 int,甚至可以直接从数据库中取出数据。 + +这是有可能的,因为 models.Model 定义了 `__metaclass__` , 并且使用了一些魔法能够将你刚刚定义的简单的Person类转变成对数据库的一个复杂 hook。 + +Django 框架将这些看起来很复杂的东西通过暴露出一个简单的使用元类的 API 将其化简,通过这个 API 重新创建代码,在背后完成真正的工作。 Python 中的一切都是对象,它们要么是类的实例,要么是元类的实例,除了 type。type 实际上是它自己的元类,在纯 Python 环境中这可不是你能够做到的,这是通过在实现层面耍一些小手段做到的。 @@ -28,6 +32,6 @@ Python 中的一切都是对象,它们要么是类的实例,要么是元类 [https://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python](https://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python) -最后如果对本文有兴趣,可以关注公众号: -![公众号](http://twowater.com.cn/images/20171204192251900.gif) + + diff --git a/Article/PythonBasis/python12/Preface.md b/Article/PythonBasis/python12/Preface.md new file mode 100644 index 00000000..327c0790 --- /dev/null +++ b/Article/PythonBasis/python12/Preface.md @@ -0,0 +1,13 @@ +# 前言 # + +Python 界的领袖 Tim Peters 说的: + +> 元类就是深度的魔法,99% 的用户应该根本不必为此操心。如果你想搞清楚究竟是否需要用到元类,那么你就不需要它。那些实际用到元类的人都非常清楚地知道他们需要做什么,而且根本不需要解释为什么要用元类。 + + +所以,这篇文章,认真阅读一遍就好了。 + +# 目录 # + +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-14-%E5%85%83%E7%B1%BB.png) + diff --git a/Article/python13/1.md b/Article/PythonBasis/python13/1.md similarity index 55% rename from Article/python13/1.md rename to Article/PythonBasis/python13/1.md index 15f15744..65392887 100644 --- a/Article/python13/1.md +++ b/Article/PythonBasis/python13/1.md @@ -2,20 +2,34 @@ 线程与进程是操作系统里面的术语,简单来讲,每一个应用程序都有一个自己的进程。 -操作系统会为这些进程分配一些执行资源,例如内存空间等。在进程中,又可以创建一些线程,他们共享这些内存空间,并由操作系统调用,以便并行计算。 +操作系统会为这些进程分配一些执行资源,例如内存空间等。 -我们都知道现代操作系统比如 Mac OS X,UNIX,Linux,Windows 等可以同时运行多个任务。打个比方,你一边在用浏览器上网,一边在听敲代码,一边用 Markdown 写博客,这就是多任务,至少同时有 3 个任务正在运行。当然还有很多任务悄悄地在后台同时运行着,只是桌面上没有显示而已。对于操作系统来说,一个任务就是一个进程(Process),比如打开一个浏览器就是启动一个浏览器进程,打开 PyCharm 就是一个启动了一个 PtCharm 进程,打开 Markdown 就是启动了一个 Md 的进程。 +在进程中,又可以创建一些线程,他们共享这些内存空间,并由操作系统调用,以便并行计算。 -虽然现在多核 CPU 已经非常普及了。可是由于 CPU 执行代码都是顺序执行的,这时候我们就会有疑问,单核 CPU 是怎么执行多任务的呢? +我们都知道现代操作系统比如 Mac OS X,UNIX,Linux,Windows 等可以同时运行多个任务。 -其实就是操作系统轮流让各个任务交替执行,任务 1 执行 0.01 秒,切换到任务 2 ,任务 2 执行 0.01 秒,再切换到任务 3 ,执行 0.01秒……这样反复执行下去。表面上看,每个任务都是交替执行的,但是,由于 CPU的执行速度实在是太快了,我们肉眼和感觉上没法识别出来,就像所有任务都在同时执行一样。 +打个比方,你一边在用浏览器上网,一边在听敲代码,一边用 Markdown 写博客,这就是多任务,至少同时有 3 个任务正在运行。 + +当然还有很多任务悄悄地在后台同时运行着,只是桌面上没有显示而已。 + +对于操作系统来说,一个任务就是一个进程(Process),比如打开一个浏览器就是启动一个浏览器进程,打开 PyCharm 就是一个启动了一个 PtCharm 进程,打开 Markdown 就是启动了一个 Md 的进程。 + +虽然现在多核 CPU 已经非常普及了。 + +可是由于 CPU 执行代码都是顺序执行的,这时候我们就会有疑问,单核 CPU 是怎么执行多任务的呢? + +其实就是操作系统轮流让各个任务交替执行,任务 1 执行 0.01 秒,切换到任务 2 ,任务 2 执行 0.01 秒,再切换到任务 3 ,执行 0.01秒……这样反复执行下去。 + +表面上看,每个任务都是交替执行的,但是,由于 CPU的执行速度实在是太快了,我们肉眼和感觉上没法识别出来,就像所有任务都在同时执行一样。 真正的并行执行多任务只能在多核 CPU 上实现,但是,由于任务数量远远多于 CPU 的核心数量,所以,操作系统也会自动把很多任务轮流调度到每个核心上执行。 有些进程不仅仅只是干一件事的啊,比如浏览器,我们可以播放时视频,播放音频,看文章,编辑文章等等,其实这些都是在浏览器进程中的子任务。在一个进程内部,要同时干多件事,就需要同时运行多个“子任务”,我们把进程内的这些“子任务”称为线程(Thread)。 -由于每个进程至少要干一件事,所以,一个进程至少有一个线程。当然,一个进程也可以有多个线程,多个线程可以同时执行,多线程的执行方式和多进程是一样的,也是由操作系统在多个线程之间快速切换,让每个线程都短暂地交替运行,看起来就像同时执行一样。 +由于每个进程至少要干一件事,所以,一个进程至少有一个线程。 + +当然,一个进程也可以有多个线程,多个线程可以同时执行,多线程的执行方式和多进程是一样的,也是由操作系统在多个线程之间快速切换,让每个线程都短暂地交替运行,看起来就像同时执行一样。 那么在 Python 中我们要同时执行多个任务怎么办? @@ -35,4 +49,9 @@ 同时执行多个任务通常各个任务之间并不是没有关联的,而是需要相互通信和协调,有时,任务 1 必须暂停等待任务 2 完成后才能继续执行,有时,任务 3 和任务 4 又不能同时执行,所以,多进程和多线程的程序的复杂度要远远高于我们前面写的单进程单线程的程序。 -因为复杂度高,调试困难,所以,不是迫不得已,我们也不想编写多任务。但是,有很多时候,没有多任务还真不行。想想在电脑上看电影,就必须由一个线程播放视频,另一个线程播放音频,否则,单线程实现的话就只能先把视频播放完再播放音频,或者先把音频播放完再播放视频,这显然是不行的。 \ No newline at end of file +因为复杂度高,调试困难,所以,不是迫不得已,我们也不想编写多任务。 + +但是,有很多时候,没有多任务还真不行。 + +想想在电脑上看电影,就必须由一个线程播放视频,另一个线程播放音频,否则,单线程实现的话就只能先把视频播放完再播放音频,或者先把音频播放完再播放视频,这显然是不行的。 + diff --git a/Article/python13/2.md b/Article/PythonBasis/python13/2.md similarity index 93% rename from Article/python13/2.md rename to Article/PythonBasis/python13/2.md index 28add5af..19b1d413 100644 --- a/Article/python13/2.md +++ b/Article/PythonBasis/python13/2.md @@ -23,6 +23,8 @@ Python 提供两个模块进行多线程的操作,分别是 `thread` 和 `thre 前者是比较低级的模块,用于更底层的操作,一般应用级别的开发不常用。 +因此,我们使用 `threading` 来举个例子: + ```python #!/usr/bin/env python3 # -*- coding: UTF-8 -*- @@ -178,11 +180,17 @@ r_lock = threading.RLock() ## 4、Condition 条件变量 ## -实用锁可以达到线程同步,但是在更复杂的环境,需要针对锁进行一些条件判断。Python 提供了 Condition 对象。使用 Condition 对象可以在某些事件触发或者达到特定的条件后才处理数据,Condition 除了具有 Lock 对象的 acquire 方法和 release 方法外,还提供了 wait 和 notify 方法。线程首先 acquire 一个条件变量锁。如果条件不足,则该线程 wait,如果满足就执行线程,甚至可以 notify 其他线程。其他处于 wait 状态的线程接到通知后会重新判断条件。 +实用锁可以达到线程同步,但是在更复杂的环境,需要针对锁进行一些条件判断。 + +Python 提供了 Condition 对象。 + +**使用 Condition 对象可以在某些事件触发或者达到特定的条件后才处理数据,Condition 除了具有 Lock 对象的 acquire 方法和 release 方法外,还提供了 wait 和 notify 方法。** -其中条件变量可以看成不同的线程先后 acquire 获得锁,如果不满足条件,可以理解为被扔到一个( Lock 或 RLock )的 waiting 池。直达其他线程 notify 之后再重新判断条件。不断的重复这一过程,从而解决复杂的同步问题。 +线程首先 acquire 一个条件变量锁。如果条件不足,则该线程 wait,如果满足就执行线程,甚至可以 notify 其他线程。其他处于 wait 状态的线程接到通知后会重新判断条件。 -![Condition](http://p1ceh5usj.bkt.clouddn.com/Condition.png) +其中条件变量可以看成不同的线程先后 acquire 获得锁,如果不满足条件,可以理解为被扔到一个( Lock 或 RLock )的 waiting 池。直到其他线程 notify 之后再重新判断条件。不断的重复这一过程,从而解决复杂的同步问题。 + +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-14-Condition.png) 该模式常用于生产者消费者模式,具体看看下面在线购物买家和卖家的示例: @@ -382,3 +390,5 @@ for i in t1: ## 6、后台线程 ## 默认情况下,主线程退出之后,即使子线程没有 join。那么主线程结束后,子线程也依然会继续执行。如果希望主线程退出后,其子线程也退出而不再执行,则需要设置子线程为后台线程。Python 提供了 `setDeamon` 方法。 + + diff --git a/Article/python13/3.md b/Article/PythonBasis/python13/3.md similarity index 92% rename from Article/python13/3.md rename to Article/PythonBasis/python13/3.md index 88fc1ec8..eddfdce5 100644 --- a/Article/python13/3.md +++ b/Article/PythonBasis/python13/3.md @@ -1,6 +1,10 @@ # 进程 # -Python 中的多线程其实并不是真正的多线程,如果想要充分地使用多核 CPU 的资源,在 Python 中大部分情况需要使用多进程。Python 提供了非常好用的多进程包 multiprocessing,只需要定义一个函数,Python 会完成其他所有事情。借助这个包,可以轻松完成从单进程到并发执行的转换。multiprocessing 支持子进程、通信和共享数据、执行不同形式的同步,提供了 Process、Queue、Pipe、Lock 等组件。 +Python 中的多线程其实并不是真正的多线程,如果想要充分地使用多核 CPU 的资源,在 Python 中大部分情况需要使用多进程。 + +Python 提供了非常好用的多进程包 multiprocessing,只需要定义一个函数,Python 会完成其他所有事情。 + +借助这个包,可以轻松完成从单进程到并发执行的转换。multiprocessing 支持子进程、通信和共享数据、执行不同形式的同步,提供了 Process、Queue、Pipe、Lock 等组件。 ## 1、类 Process ## @@ -47,7 +51,7 @@ if __name__ == "__main__": 输出的结果: -![多进程输出结果](http://p1ceh5usj.bkt.clouddn.com/%E5%A4%9A%E8%BF%9B%E7%A8%8B%E8%BE%93%E5%87%BA%E7%BB%93%E6%9E%9C.gif) +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-14-%E5%A4%9A%E8%BF%9B%E7%A8%8B%E8%BE%93%E5%87%BA%E7%BB%93%E6%9E%9C.gif) ## 2、把进程创建成类 ## @@ -83,7 +87,7 @@ if __name__ == '__main__': 输出结果如下: -![创建进程类](http://p1ceh5usj.bkt.clouddn.com/%E5%88%9B%E5%BB%BA%E8%BF%9B%E7%A8%8B%E7%B1%BB.gif) +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-14-%E5%88%9B%E5%BB%BA%E8%BF%9B%E7%A8%8B%E7%B1%BB.gif) ## 3、daemon 属性 ## @@ -309,3 +313,5 @@ if __name__ == '__main__': 写进 Queue 的值为:四点水 从 Queue 读取的值为:四点水 ``` + + diff --git a/Article/PythonBasis/python13/Preface.md b/Article/PythonBasis/python13/Preface.md new file mode 100644 index 00000000..c5cc5c9e --- /dev/null +++ b/Article/PythonBasis/python13/Preface.md @@ -0,0 +1,9 @@ +# 前言 # + +学编程,谁没有为线程折腾过啊。 + +# 目录 # + +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-14-%E8%8D%89%E6%A0%B9%E5%AD%A6Python%EF%BC%88%E5%8D%81%E4%B8%89%EF%BC%89%20%E7%BA%BF%E7%A8%8B%E5%92%8C%E8%BF%9B%E7%A8%8B.png) + + diff --git a/Article/python14/1.md b/Article/PythonBasis/python14/1.md similarity index 100% rename from Article/python14/1.md rename to Article/PythonBasis/python14/1.md diff --git a/Article/python14/2.md b/Article/PythonBasis/python14/2.md similarity index 97% rename from Article/python14/2.md rename to Article/PythonBasis/python14/2.md index 65c018a0..8f8e8d59 100644 --- a/Article/python14/2.md +++ b/Article/PythonBasis/python14/2.md @@ -9,7 +9,7 @@ 举个例子,比如你使用 `C[ET]O` 匹配到的是 CEO 或 CTO ,也就是说 `[ET]` 代表的是一个 E 或者一个 T 。像上面提到的 `[a-z]` ,就是所有小写字母中的其中一个,这里使用了连字符 “-” 定义一个连续字符的字符范围。当然,像这种写法,里面可以包含多个字符范围的,比如:`[0-9a-fA-F]` ,匹配单个的十六进制数字,且不分大小写。注意了,字符和范围定义的先后顺序对匹配的结果是没有任何影响的。 -其实说了那么多,只是想证明,字符集一对方括号 “[]” 里面的字符关系是或关系,下面看一个例子: +其实说了那么多,只是想证明,字符集一对方括号 “[]” 里面的字符关系是"或(OR)"关系,下面看一个例子: ```Python diff --git a/Article/python14/3.md b/Article/PythonBasis/python14/3.md similarity index 100% rename from Article/python14/3.md rename to Article/PythonBasis/python14/3.md diff --git a/Article/python14/4.md b/Article/PythonBasis/python14/4.md similarity index 100% rename from Article/python14/4.md rename to Article/PythonBasis/python14/4.md diff --git a/Article/python14/5.md b/Article/PythonBasis/python14/5.md similarity index 100% rename from Article/python14/5.md rename to Article/PythonBasis/python14/5.md diff --git a/Article/python14/6.md b/Article/PythonBasis/python14/6.md similarity index 100% rename from Article/python14/6.md rename to Article/PythonBasis/python14/6.md diff --git a/Article/PythonBasis/python14/Preface.md b/Article/PythonBasis/python14/Preface.md new file mode 100644 index 00000000..1d7b6d6c --- /dev/null +++ b/Article/PythonBasis/python14/Preface.md @@ -0,0 +1,5 @@ +# 目录 # + +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-14-%E4%B8%80%E6%AD%A5%E4%B8%80%E6%AD%A5%E4%BA%86%E8%A7%A3%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F.png) + + diff --git "a/Article/python14/\345\270\270\347\224\250\347\232\204\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.md" "b/Article/PythonBasis/python14/\345\270\270\347\224\250\347\232\204\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.md" similarity index 100% rename from "Article/python14/\345\270\270\347\224\250\347\232\204\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.md" rename to "Article/PythonBasis/python14/\345\270\270\347\224\250\347\232\204\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.md" diff --git "a/Article/python14/\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.png" "b/Article/PythonBasis/python14/\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.png" similarity index 100% rename from "Article/python14/\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.png" rename to "Article/PythonBasis/python14/\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.png" diff --git "a/Article/python14/\350\215\211\346\240\271\345\255\246Python\357\274\210\345\215\201\345\233\233\357\274\211 \344\270\200\346\255\245\344\270\200\346\255\245\344\272\206\350\247\243\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.png" "b/Article/PythonBasis/python14/\350\215\211\346\240\271\345\255\246Python\357\274\210\345\215\201\345\233\233\357\274\211 \344\270\200\346\255\245\344\270\200\346\255\245\344\272\206\350\247\243\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.png" similarity index 100% rename from "Article/python14/\350\215\211\346\240\271\345\255\246Python\357\274\210\345\215\201\345\233\233\357\274\211 \344\270\200\346\255\245\344\270\200\346\255\245\344\272\206\350\247\243\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.png" rename to "Article/PythonBasis/python14/\350\215\211\346\240\271\345\255\246Python\357\274\210\345\215\201\345\233\233\357\274\211 \344\270\200\346\255\245\344\270\200\346\255\245\344\272\206\350\247\243\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.png" diff --git a/Article/python15/1.md b/Article/PythonBasis/python15/1.md similarity index 95% rename from Article/python15/1.md rename to Article/PythonBasis/python15/1.md index 6ce644d5..8809f64f 100644 --- a/Article/python15/1.md +++ b/Article/PythonBasis/python15/1.md @@ -91,7 +91,7 @@ print(time) 这里最直接的表现就是全局变量 `time` 至此至终都没有修改过,这里还是用了 `nonlocal` 关键字,表示在函数或其他作用域中使用外层(非全局)变量。那么上面那段代码具体的运行流程是怎样的。我们可以看下下图: -![Python 闭包解决](http://p1ceh5usj.bkt.clouddn.com/python15/Python%20%E9%97%AD%E5%8C%85%E8%A7%A3%E5%86%B3.png) +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-14-Python%20%E9%97%AD%E5%8C%85%E8%A7%A3%E5%86%B3.png) 这种内部函数的局部作用域中可以访问外部函数局部作用域中变量的行为,我们称为: 闭包。更加直接的表达方式就是,当某个函数被当成对象返回时,夹带了外部变量,就形成了一个闭包。k @@ -146,6 +146,5 @@ print(f.__closure__[0].cell_contents) 闭包的过程其实好比类(父函数)生成实例(闭包),不同的是父函数只在调用时执行,执行完毕后其环境就会释放,而类则在文件执行时创建,一般程序执行完毕后作用域才释放,因此对一些需要重用的功能且不足以定义为类的行为,使用闭包会比使用类占用更少的资源,且更轻巧灵活。 -欢迎打开微信扫一扫,关注微信公众号: -![微信公众号](http://twowater.com.cn/images/20171204192251900.gif) + diff --git a/Article/python16/1.md b/Article/PythonBasis/python16/1.md similarity index 95% rename from Article/python16/1.md rename to Article/PythonBasis/python16/1.md index 3a0b8e5c..8316e9d6 100644 --- a/Article/python16/1.md +++ b/Article/PythonBasis/python16/1.md @@ -210,6 +210,4 @@ print_args('两点水', sex='男', age=99) ``` -至此,[草根学 Python](https://github.com/TwoWater/Python) 入门系列文章结束了。如果感兴趣的话,可以关注微信公众号,回复 “Python” 获取更多的 Python 学习资料。 -![微信公众号](http://twowater.com.cn/images/20171204192251900.gif) diff --git a/Article/PythonBasis/python3/List.md b/Article/PythonBasis/python3/List.md index f0dce64e..059adb86 100644 --- a/Article/PythonBasis/python3/List.md +++ b/Article/PythonBasis/python3/List.md @@ -143,7 +143,7 @@ print(name) ## 5、怎么删除 List(列表) 里面的元素 ## -那竟然这样,肯定会有人中途退出的。 +那既然这样,肯定会有人中途退出的。 那么我们就需要在列表中,把他的名字去掉。 @@ -197,6 +197,7 @@ print(name) |list.index(obj)|从列表中找出某个值第一个匹配项的索引位置| |list.insert(index, obj)|将对象插入列表| |list.pop(obj=list[-1])|移除列表中的一个元素(默认最后一个元素),并且返回该元素的值| +|list.remove(obj)|移除列表中的一个元素(参数是列表中元素),并且不返回任何值| |list.reverse()|反向列表中元素| |list.sort([func])|对原列表进行排序| diff --git a/Article/PythonBasis/python3/tuple.md b/Article/PythonBasis/python3/tuple.md index beb0efb3..d5b842a6 100644 --- a/Article/PythonBasis/python3/tuple.md +++ b/Article/PythonBasis/python3/tuple.md @@ -144,7 +144,7 @@ del tuple1 |(1, 2, 3) + (4, 5, 6)|(1, 2, 3, 4, 5, 6)|连接| |('Hi!',) * 4|('Hi!', 'Hi!', 'Hi!', 'Hi!')|复制| |3 in (1, 2, 3)|True|元素是否存在| -|for x in (1, 2, 3): print x,|1 2 3|迭代| +|for x in (1, 2, 3): print(x)|1 2 3|迭代| ## 7、元组内置函数 ## diff --git a/Article/PythonBasis/python4/Preface.md b/Article/PythonBasis/python4/Preface.md index 692d38ba..318dc462 100644 --- a/Article/PythonBasis/python4/Preface.md +++ b/Article/PythonBasis/python4/Preface.md @@ -2,7 +2,7 @@ 上一篇文章出现了个明显的知识点错误,不过感谢有个网友的提出,及时进行了修改。也希望各位多多包涵。 -(2019年09月01日15:28:00) 在修改文章的时候,发现自己两年前写的像屎一样, 忍不住还在群里吐槽一番。 +>注:(2019年09月01日15:28:00) 在修改文章的时候,发现自己两年前写的像屎一样, 忍不住还在群里吐槽一番。 ![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-09-01-072923.png) diff --git a/Article/PythonBasis/python5/Cycle.md b/Article/PythonBasis/python5/Cycle.md index 5eb983dd..d8567c35 100644 --- a/Article/PythonBasis/python5/Cycle.md +++ b/Article/PythonBasis/python5/Cycle.md @@ -1,12 +1,31 @@ # 二、循环语句 # -一般编程语言都有循环语句,循环语句允许我们执行一个语句或语句组多次。 + + +## 1、什么是循环语句 ## + +一般编程语言都有循环语句,为什么呢? + +那就问一下自己,我们弄程序是为了干什么? + +那肯定是为了方便我们工作,优化我们的工作效率啊。 + +而计算机和人类不同,计算机不怕苦也不怕累,也不需要休息,可以一直做。 + +你要知道,计算机最擅长就是做重复的事情。 + +所以这时候需要用到循环语句,循环语句允许我们执行一个语句或语句组多次。 循环语句的一般形式如下: ![python循环语句](http://upload-images.jianshu.io/upload_images/2136918-eaaae2fbfec3330f?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) -Python 提供了 for 循环和 while 循环,当然还有一些控制循环的语句: + +在 Python 提供了 for 循环和 while 循环。 + +这里又有一个问题了,如果我想让他运行了一百次之后停止,那该怎么做呢? + +这时候需要用到一些控制循环的语句: |循环控制语句|描述| |------|------| @@ -14,128 +33,249 @@ Python 提供了 for 循环和 while 循环,当然还有一些控制循环的 |continue|在语句块执行过程中终止当前循环,跳出该次循环,执行下一次循环| |pass|pass 是空语句,是为了保持程序结构的完整性| +这些控制语句是为了让我们告诉程序什么时候停止,什么时候不运行这次循环。 -## 1、While 循环语句 ## -```python -count = 1 -sum = 0 -while (count <= 100): - sum = sum + count - count = count + 1 -print(sum) -``` -输出的结果: +## 2、 for 循环语句 ## -```txt -5050 -``` +我们先来看下 for 循环语句。 -当然 while 语句时还有另外两个重要的命令 continue,break 来跳过循环,continue 用于跳过该次循环,break 则是用于退出循环 +它的流程图基本如下: -比如,上面的例子是计算 1 到 100 所有整数的和,当我们需要判断 sum 大于 1000 的时候,不在相加时,可以用到 break ,退出整个循环 -```python -count = 1 -sum = 0 -while (count <= 100): - sum = sum + count - if ( sum > 1000): #当 sum 大于 1000 的时候退出循环 - break - count = count + 1 -print(sum) -``` +![for循环的流程图](http://upload-images.jianshu.io/upload_images/2136918-a0728c1c488238af?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) -输出的结果: -```txt -1035 +基本的语法格式: + +```python +for iterating_var in sequence: + statements(s) ``` -有时候,我们只想统计 1 到 100 之间的奇数和,那么也就是说当 count 是偶数,也就是双数的时候,我们需要跳出当次的循环,不想加,这时候可以用到 break +那么我们根据他的基本语法格式,随便写个例子测试一下: + ```python -count = 1 -sum = 0 -while (count <= 100): - if ( count % 2 == 0): # 双数时跳过输出 - count = count + 1 - continue - sum = sum + count - count = count + 1 -print(sum) +for letter in 'Hello 两点水': + print(letter) ``` -输出的语句: +输出的结果如下: ```txt -2500 +H +e +l +l +o + +两 +点 +水 ``` -在 Python 的 while 循环中,还可以使用 else 语句,while … else 在循环条件为 false 时执行 else 语句块 +从打印结果来看,它就是把字符串 `Hello 两点水` 一个一个字符的打印出来。 + +那如果我们把字符串换为字典 dict 呢? + +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-09-07-094741.png) + +你会发现只打印了字典 dict 中的每一个 key 值。 + +很多时候,我都是建议大家学到一个新的知识点,都多去尝试。 + +你尝试一遍,自己观察出来的结论,好过别人说十遍。 + +如果你不知道怎么去试? + +可以根据我们的例子举一反三,比如上面的 for 循环,试了字符串,字典,那我们之前学的基本数据类型还有什么呢? + +不记得可以再返回去看看,可以把所有的基本类型都拿去尝试一下。 + +比如,你试了之后,会发现整数和浮点数是不可以直接放在 for 循环里面的。 + +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-09-07-095313.png) -比如: + + + + + +## 3、 range() 函数 ## + +for 循环还常常和 range() 函数搭配使用的。 + +如果不知道 range() 函数 , 我们直接通过一段程序来理解。 ```python -count = 0 -while count < 5: - print (count) - count = count + 1 -else: - print (count) +for i in range(3): + print(i) ``` -输出的结果: +打印的结果为: -```txt +``` 0 1 2 -3 -4 -5 ``` -## 2、 for 循环语句 ## +可见,打印了 0 到 3 。 - for循环可以遍历任何序列的项目,如一个列表或者一个字符串 +使用 range(x) 函数,就可以生成一个从 0 到 x-1 的整数序列。 -它的流程图基本如下: +如果是 `range(a,b)` 函数,你可以生成了一个左闭右开的整数序列。 +其实例子中的 `range(3)` 可以写成 `range(0,3)`, 结果是一样的。 -![for循环的流程图](http://upload-images.jianshu.io/upload_images/2136918-a0728c1c488238af?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) +其实使用 range() 函数,我们更多是为了把一段代码重复运行 n 次。 -基本的语法格式: +这里提个问题,你仔细观察 range() 函数,上面说到的不管是 1 个参数的,还是 2 个参数的都有什么共同的特点? + +不知道你们有没有发现,他都是每次递增 1 的。 + +`range(3)` 就是 0 ,1,2 ,每次递增 1 。 + +`range(3,6)` 就是 3 ,4 ,5 ,也是每次递增 1 的。 + +那能不能每次不递增 1 呢? + +比如我想递增 2 呢? + +在程序的编写中,肯定会遇到这样的需求的。而 python 发展至今,range 函数肯定也会有这种功能。 + +所以 range 函数还有一个三个参数的。 + +比如 `range(0,10,2) ` , 它的意思是:从 0 数到 10(不取 10 ),每次间隔为 2 。 + +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-09-09-065854.png) + + + + + + +## 4、While 循环语句 ## + +While 循环和 for 循环的作用是一样的。 + +我们先来看看 While 循环语句的样子。 + +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-09-07-083137.png) + +程序输出的结果是: + +```txt +5050 +``` + +这个例子是计算 1 到 100 所有整数的和。 + + + +## 5、for 循环和 whlie 循环的区别 ## + +之前也提到过了,如果一种语法能表示一个功能,那没必要弄两种语法来表示。 + +竟然都是循环,for 循环和 while 循环肯定有他们的区别的。 + +那什么时候才使用 for 循环和 while 循环呢? + +* for 循环主要用在迭代可迭代对象的情况。 + +* while 循环主要用在需要满足一定条件为真,反复执行的情况。 +(死循环+break 退出等情况。) + +* 部分情况下,for 循环和 while 循环可以互换使用。 + +例如: + +```python +for i in range(0, 10): + print(i) + + +i = 0 +while i < 10: + print(i) + i = i + 1 +``` + +虽然打印的结果是一样的,但是细细品味你会发现,他们执行的顺序和知道的条件是不同的。 + + + +## 6、嵌套循环 ## + +循环语句和条件语句一样,都是可以嵌套的。 + +具体的语法如下: + +**for 循环嵌套语法** ```python for iterating_var in sequence: + for iterating_var in sequence: + statements(s) statements(s) ``` -实例: +**while 循环嵌套语法** ```python -for letter in 'Hello 两点水': - print(letter) +while expression: + while expression: + statement(s) + statement(s) ``` -输出的结果如下: +除此之外,你也可以在循环体内嵌入其他的循环体,如在 while 循环中可以嵌入 for 循环, 反之,你可以在 for 循环中嵌入 while 循环 + +比如: + +当我们需要判断 sum 大于 1000 的时候,不在相加时,可以用到 break ,退出整个循环。 + +```python +count = 1 +sum = 0 +while (count <= 100): + sum = sum + count + if ( sum > 1000): #当 sum 大于 1000 的时候退出循环 + break + count = count + 1 +print(sum) +``` + +输出的结果: ```txt -H -e -l -l -o +1035 +``` -两 -点 -水 +有时候,我们只想统计 1 到 100 之间的奇数和,那么也就是说当 count 是偶数,也就是双数的时候,我们需要跳出当次的循环,不想加,这时候可以用到 break + +```python +count = 1 +sum = 0 +while (count <= 100): + if ( count % 2 == 0): # 双数时跳过输出 + count = count + 1 + continue + sum = sum + count + count = count + 1 +print(sum) ``` -有 while … else 语句,当然也有 for … else 语句啦,for 中的语句和普通的没有区别,else 中的语句会在循环正常执行完(即 for 不是通过 break 跳出而中断的)的情况下执行,while … else 也是一样。 +输出的语句: + +```txt +2500 +``` + +还有: ```python for num in range(10,20): # 迭代 10 到 20 之间的数字 @@ -163,28 +303,11 @@ for num in range(10,20): # 迭代 10 到 20 之间的数字 19 是一个质数 ``` -## 3、嵌套循环 ## - -Python 语言允许在一个循环体里面嵌入另一个循环。上面的实例也是使用了嵌套循环的,这里就不给出实例了。 - -具体的语法如下: -**for 循环嵌套语法** +当然,这里还用到了 `for … else` 语句。 -```python -for iterating_var in sequence: - for iterating_var in sequence: - statements(s) - statements(s) -``` +其实 for 循环中的语句和普通的没有区别,else 中的语句会在循环正常执行完(即 for 不是通过 break 跳出而中断的)的情况下执行。 -**while 循环嵌套语法** +当然有 `for … else` ,也会有 `while … else` 。他们的意思都是一样的。 -```python -while expression: - while expression: - statement(s) - statement(s) -``` -除此之外,你也可以在循环体内嵌入其他的循环体,如在 while 循环中可以嵌入 for 循环, 反之,你可以在 for 循环中嵌入 while 循环 diff --git a/Article/PythonBasis/python5/If.md b/Article/PythonBasis/python5/If.md index caa2246a..d113f597 100644 --- a/Article/PythonBasis/python5/If.md +++ b/Article/PythonBasis/python5/If.md @@ -1,14 +1,19 @@ # 一、条件语句 # + +## 1、什么是条件语句 ## + + Python 条件语句跟其他语言基本一致的,都是通过一条或多条语句的执行结果( True 或者 False )来决定执行的代码块。 -Python 程序语言指定任何非 0 和非空(null)值为 True,0 或者 null为 False。 +Python 程序语言指定任何非 0 和非空(null)值为 True,0 或者 null 为 False。 执行的流程图如下: ![if语句流程图](http://upload-images.jianshu.io/upload_images/2136918-4ee2486190450a1a?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) -## 1、if 语句的基本形式 ## + +## 2、if 语句的基本形式 ## Python 中,if 语句的基本形式如下: @@ -19,7 +24,7 @@ else: 执行语句…… ``` -前面也提到过,Python 语言有着严格的缩进要求,因此这里也需要注意缩进,也不要少写了冒号 `:` 。 +之前的章节也提到过,Python 语言有着严格的缩进要求,因此这里也需要注意缩进,也不要少写了冒号 `:` 。 if 语句的判断条件可以用>(大于)、<(小于)、==(等于)、>=(大于等于)、<=(小于等于)来表示其关系。 @@ -43,7 +48,7 @@ else : 不及格 ``` -上面也说道,非零数值、非空字符串、非空 list 等,判断为True,否则为False。因此也可以这样写: +上面也说到,非零数值、非空字符串、非空 list 等,判断为 True,否则为 False。因此也可以这样写: ```python num = 6 @@ -51,7 +56,27 @@ if num : print('Hello Python') ``` -## 2、if 语句多个判断条件的形式 ## +输出的结果如下: + +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-09-07-072713.png) + +可见,把结果打印出来了。 + +那如果我们把 `num ` 改为空字符串呢? + +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-09-07-072941.png) + +很明显,空字符串是为 False 的,不符合条件语句,因此不会执行到 `print('Hello Python')` 这段代码。 + +还有再啰嗦一点,提醒一下,在条件判断代码中的冒号 `:` 后、下一行内容是一定要缩进的。不缩进是会报错的。 + +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-09-07-073432.png) + +冒号和缩进是一种语法。它会帮助 Python 区分代码之间的层次,理解条件执行的逻辑及先后顺序。 + + + +## 3、if 语句多个判断条件的形式 ## 有些时候,我们的判断语句不可能只有两个,有些时候需要多个,比如上面的例子中大于 60 的为及格,那我们还要判断大于 90 的为优秀,在 80 到 90 之间的良好呢? @@ -94,9 +119,21 @@ else : 良好 ``` -## 3、if 语句多个条件同时判断 ## -Python 不像 Java 有 switch 语句,所以多个条件判断,只能用 elif 来实现,但是有时候需要多个条件需同时判断时,可以使用 or (或),表示两个条件有一个成立时判断条件成功;使用 and (与)时,表示只有两个条件同时成立的情况下,判断条件才成功。 + +## 4、if 语句多个条件同时判断 ## + +有时候我们会遇到多个条件的时候该怎么操作呢? + +比如说要求 java 和 python 的考试成绩要大于 80 分的时候才算优秀,这时候该怎么做? + +这时候我们可以结合 `or` 和 `and` 来使用。 + +or (或)表示两个条件有一个成立时判断条件成功 + +and (与)表示只有两个条件同时成立的情况下,判断条件才成功。 + +例如: ```python # -*-coding:utf-8-*- @@ -122,3 +159,20 @@ if ( java >= 80 and java < 90 ) or ( python >= 80 and python < 90): ``` 注意:if 有多个条件时可使用括号来区分判断的先后顺序,括号中的判断优先执行,此外 and 和 or 的优先级低于 >(大于)、<(小于)等判断符号,即大于和小于在没有括号的情况下会比与或要优先判断。 + +## 5、if 嵌套 ## + +if 嵌套是指什么呢? + +就跟字面意思差不多,指 if 语句中可以嵌套 if 语句。 + +比如上面说到的例子,也可以用 if 嵌套来写。 + +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-09-07-080557.png) + +当然这只是为了说明 if 条件语句是可以嵌套的。如果是这个需求,我个人还是不太建议这样使用 if 嵌套的,因为这样代码量多了,而且嵌套太多,也不方便阅读代码。 + + + + + diff --git a/Article/PythonBasis/python5/Preface.md b/Article/PythonBasis/python5/Preface.md index ce4be8b1..34b1d5cc 100644 --- a/Article/PythonBasis/python5/Preface.md +++ b/Article/PythonBasis/python5/Preface.md @@ -1,10 +1,16 @@ # 前言 # -第一次建学习群,而且是 Python 的学习群,虽然之前深入学习和工作都是 Android 相关的,最近学起来 Python ,真的很好玩,所以创了个微信群,希望童鞋们进群学习讨论。也可以直接加我微`androidwed`拉进群。也欢迎大家在 [Gitbook](https://www.readwithu.com/) 中提出文章的不足。 +通常都听到别人说,计算机很牛逼,很聪明,其实计算机一点都不聪明,光是你要跟他沟通,都会气 shi 你,聪明的是在写程序的你。 -![Python学习群](http://upload-images.jianshu.io/upload_images/2136918-f3f0c60ce12e5a92?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) +写程序就是跟计算机沟通,告诉它要做什么。 + +竟然是这样,那么肯定缺少不了一些沟通逻辑。比如你要告诉计算机在什么情况下做什么?或者在哪个时间点做什么? + +这都需要用到逻辑判断。这一章节,主要就是说这个。 # 目录 # -![草根学Python(五) 条件语句和循环语句](http://upload-images.jianshu.io/upload_images/2136918-32902eec93d9ffc1?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-09-09-%E6%9D%A1%E4%BB%B6%E8%AF%AD%E5%8F%A5%E5%92%8C%E5%BE%AA%E7%8E%AF%E8%AF%AD%E5%8F%A5.png) + + diff --git a/Article/PythonBasis/python6/1.md b/Article/PythonBasis/python6/1.md new file mode 100644 index 00000000..332f72e5 --- /dev/null +++ b/Article/PythonBasis/python6/1.md @@ -0,0 +1,101 @@ +# 一、Python 自定义函数的基本步骤 # + + + + +## 1、什么是函数 ## + +函数,其实我们一开始学 Python 的时候就接触过。 + +不过我们使用的大多数都是 Python 的内置函数。 + +比如基本每个章节都会出现的 `print()` 函数。 + +而现在,我们主要学习的是自定义函数。 + +**各位有没有想过为什么需要函数呢?** + +如果要想回答这个问题,我们需要先了解函数是什么? + +函数就是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。 + +没错,函数其实就是把代码抽象出来的代码段。 + +那为什么要抽象出来呢? + +**方便我们使用,方便我们重复使用。** + +**函数的本质就是我们把一些数据喂给函数,让他内部消化,然后吐出你想要的东西,至于他怎么消化的,我们不需要知道,它内部解决。** + +怎么理解这句话呢? + +举个例子,好比每次用到的 print 函数,我们都知道这个函数的作用是可以把我们的数据输出到控制台,让我们看到。所以 `print('两点水')` , 我们想打印 `两点水` 出来,就把 `两点水` 这个数据喂给 `print` 函数,然后他就直接把结果打印到控制台上了。 + + + + + + + +## 2、怎么自定义函数 ## + +怎么自定义函数? + +要知道怎么定义函数,就要知道函数的组成部分是怎样的。 + +```python +def 函数名(参数1,参数2....参数n): + 函数体 + return 语句 +``` + +这就是 Python 函数的组成部分。 + +所以自定义函数,基本有以下规则步骤: + +* 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号() +* 任何传入参数和自变量必须放在圆括号中间。圆括号之间可以用于定义参数 +* 函数的第一行语句可以选择性地使用文档字符串(用于存放函数说明) +* 函数内容以冒号起始,并且缩进 +* return [表达式] 结束函数,选择性地返回一个值给调用方。不带表达式的 return 相当于返回 None。 + +语法示例: + +```python +def functionname( parameters ): + "函数_文档字符串" + function_suite + return [expression] +``` + +实例: + +1. def 定义一个函数,给定一个函数名 sum +2. 声明两个参数 num1 和 num2 +3. 函数的第一行语句进行函数说明:两数之和 +4. 最终 return 语句结束函数,并返回两数之和 + +```python +def sum(num1,num2): + "两数之和" + return num1+num2 + +# 调用函数 +print(sum(5,6)) +``` + +输出结果: + +```python +11 +``` + + + + + + + + + + diff --git a/Article/python6/3.md b/Article/PythonBasis/python6/2.md similarity index 66% rename from Article/python6/3.md rename to Article/PythonBasis/python6/2.md index 758ac4dc..bc3e8361 100644 --- a/Article/python6/3.md +++ b/Article/PythonBasis/python6/2.md @@ -1,6 +1,8 @@ -# 三、函数返回值 # +# 二、函数返回值 # -通过上面的学习,可以知道通过 return [表达式] 语句用于退出函数,选择性地向调用方返回一个表达式。不带参数值的 return 语句返回 None。 +通过上面的学习,可以知道通过 return [表达式] 语句用于退出函数,选择性地向调用方返回一个表达式。 + +**不带参数值的 return 语句返回 None。** 具体示例: @@ -51,4 +53,16 @@ print (tuple1) (2.0, 1) ``` -认真观察就可以发现,尽管从第一个输出值来看,返回了多个值,实际上是先创建了一个元组然后返回的。回忆一下,元组是可以直接用逗号来创建的,观察例子中的 ruturn ,可以发现实际上我们使用的是逗号来生成一个元组。 +认真观察就可以发现,尽管从第一个输出值来看,返回了多个值,实际上是先创建了一个元组然后返回的。 + +回忆一下,元组是可以直接用逗号来创建的,观察例子中的 ruturn ,可以发现实际上我们使用的是逗号来生成一个元组。 + +Python 语言中的函数返回值可以是多个,而其他语言都不行,这是Python 相比其他语言的简便和灵活之处。 + +**Python 一次接受多个返回值的数据类型就是元组。** + +不知道此刻你还记不记得元组的相关知识,如果不记得,建议现在立刻写几个例子回忆一下,比如如何获取元组的第一个元素出来。 + + + + diff --git a/Article/python6/4.md b/Article/PythonBasis/python6/3.md similarity index 56% rename from Article/python6/4.md rename to Article/PythonBasis/python6/3.md index e807b771..2d3b8ccd 100644 --- a/Article/python6/4.md +++ b/Article/PythonBasis/python6/3.md @@ -1,9 +1,28 @@ -# 四、函数的参数 # +# 三、函数的参数 # -## 1、默认值参数 ## + + + +## 1、函数的参数类型 ## + +设置与传递参数是函数的重点,而 Python 的函数对参数的支持非常的灵活。 + +主要的参数类型有:默认参数、关键字参数(位置参数)、不定长参数。 + +下面我们将一一了解这几种参数。 + + + + +## 2、默认参数 ## 有时候,我们自定义的函数中,如果调用的时候没有设置参数,需要给个默认值,这时候就需要用到默认值参数了。 +默认参数,只要在构造函数参数的时候,给参数赋值就可以了 + +例如: + + ```python # -*- coding: UTF-8 -*- @@ -27,9 +46,17 @@ print_user_info( '三点水' , 25 ) 昵称:三点水 年龄:25 性别:男 ``` -可以看到,当你设置了默认参数的时候,在调用函数的时候,不传该参数,就会使用默认值。但是这里需要注意的一点是:**只有在形参表末尾的那些参数可以有默认参数值**,也就是说你不能在声明函数形参的时候,先声明有默认值的形参而后声明没有默认值的形参。这是因为赋给形参的值是根据位置而赋值的。例如,def func(a, b=1) 是有效的,但是 def func(a=1, b) 是 无效 的。 +从输出结果可以看到,当你设置了默认参数的时候,在调用函数的时候,不传该参数,就会使用默认值。 + +但是这里需要注意的一点是:**只有在形参表末尾的那些参数可以有默认参数值**,也就是说你不能在声明函数形参的时候,先声明有默认值的形参而后声明没有默认值的形参。 -默认值参数就这样结束了吗?还没有的,细想一下,如果参数中是一个可修改的容器比如一个 lsit (列表)或者 dict (字典),那么我们使用什么来作为默认值呢?我们可以使用 None 作为默认值。就像下面这个例子一样: +这是因为赋给形参的值是根据位置而赋值的。例如,def func(a, b=1) 是有效的,但是 def func(a=1, b) 是 无效 的。 + +默认值参数就这样结束了吗? + +还没有的,细想一下,如果参数中是一个可修改的容器比如一个 lsit (列表)或者 dict (字典),那么我们使用什么来作为默认值呢? + +我们可以使用 None 作为默认值。就像下面这个例子一样: ```python # 如果 b 是一个 list ,可以使用 None 作为默认值 @@ -39,13 +66,21 @@ def print_info( a , b = None ): return; ``` -认真看下例子,会不会有这样的疑问呢?在参数中我们直接 `b=[]` 不就行了吗?也就是写成下面这个样子: +认真看下例子,会不会有这样的疑问呢?在参数中我们直接 `b=[]` 不就行了吗? + +也就是写成下面这个样子: ```python def print_info( a , b = [] ): return; ``` -对不对呢?运行一下也没发现错误啊,可以这样写吗?这里需要特别注意的一点:**默认参数的值是不可变的对象,比如None、True、False、数字或字符串**,如果你像上面的那样操作,当默认值在其他地方被修改后你将会遇到各种麻烦。这些修改会影响到下次调用这个函数时的默认值。 +对不对呢? + +运行一下也没发现错误啊,可以这样写吗? + +这里需要特别注意的一点:**默认参数的值是不可变的对象,比如None、True、False、数字或字符串**,如果你像上面的那样操作,当默认值在其他地方被修改后你将会遇到各种麻烦。 + +这些修改会影响到下次调用这个函数时的默认值。 示例如下: @@ -73,7 +108,9 @@ print_info(2) 认真观察,你会发现第二次输出的值根本不是你想要的,因此切忌不能这样操作。 -还有一点,有时候我就是不想要默认值啊,只是想单单判断默认参数有没有值传递进来,那该怎么办?我们可以这样做: +还有一点,有时候我就是不想要默认值啊,只是想单单判断默认参数有没有值传递进来,那该怎么办? + +我们可以这样做: ```python _no_value =object() @@ -83,15 +120,25 @@ def print_info( a , b = _no_value ): print('b 没有赋值') return; ``` -这里的 `object` 是python中所有类的基类。 你可以创建 `object` 类的实例,但是这些实例没什么实际用处,因为它并没有任何有用的方法, 也没有任何实例数据(因为它没有任何的实例字典,你甚至都不能设置任何属性值)。 你唯一能做的就是测试同一性。也正好利用这个特性,来判断是否有值输入。 -## 2、关键字参数 ## +这里的 `object` 是 python 中所有类的基类。 你可以创建 `object` 类的实例,但是这些实例没什么实际用处,因为它并没有任何有用的方法, 也没有任何实例数据(因为它没有任何的实例字典,你甚至都不能设置任何属性值)。 你唯一能做的就是测试同一性。也正好利用这个特性,来判断是否有值输入。 + + + + +## 3、关键字参数(位置参数) ## + +一般情况下,我们需要给函数传参的时候,是要按顺序来的,如果不对应顺序,就会传错值。 + +不过在 Python 中,可以通过参数名来给函数传递参数,而不用关心参数列表定义时的顺序,这被称之为关键字参数。 + +使用关键参数有两个优势 : -在 Python 中,可以通过参数名来给函数传递参数,而不用关心参数列表定义时的顺序,这被称之为关键字参数。使用关键参数有两个优势 : +* 由于我们不必担心参数的顺序,使用函数变得更加简单了。 -一、由于我们不必担心参数的顺序,使用函数变得更加简单了。 +* 假设其他参数都有默认值,我们可以只给我们想要的那些参数赋值 -二、假设其他参数都有默认值,我们可以只给我们想要的那些参数赋值 +具体看例子: ```python # -*- coding: UTF-8 -*- @@ -117,10 +164,19 @@ print_user_info( name = '两点水' ,sex = '女', age = 18 ) 昵称:两点水 年龄:18 性别:女 ``` -## 3、不定长参数 ## -有时我们在设计函数接口的时候,可会需要可变长的参数。也就是说,我们事先无法确定传入的参数个数。Python 提供了一种元组的方式来接受没有直接定义的参数。这种方式在参数前边加星号 `*` 。如果在函数调用时没有指定参数,它就是一个空元组。我们也可以不向函数传递未命名的变量。 + + +## 4、不定长参数 ## + +或许有些时候,我们在设计函数的时候,我们有时候无法确定传入的参数个数。 + +那么我们就可以使用不定长参数。 + +Python 提供了一种元组的方式来接受没有直接定义的参数。这种方式在参数前边加星号 `*` 。 + +如果在函数调用时没有指定参数,它就是一个空元组。我们也可以不向函数传递未命名的变量。 例如: @@ -146,10 +202,12 @@ print_user_info( '两点水' ,18 , '女', '打篮球','打羽毛球','跑步') 昵称:两点水 年龄:18 性别:女 爱好:('打篮球', '打羽毛球', '跑步') ``` -通过输出的结果可以知道,`*hobby`是可变参数,且 hobby其实就是一个 tuple (元祖) +通过输出的结果可以知道,`*hobby`是可变参数,且 hobby 其实就是一个 tuple (元祖) + +可变长参数也支持关键字参数(位置参数),没有被定义的关键参数会被放到一个字典里。 -可变长参数也支持关键参数,没有被定义的关键参数会被放到一个字典里。这种方式即是在参数前边加 `**`,更改上面的示例如下: +这种方式即是在参数前边加 `**`,更改上面的示例如下: ```python @@ -177,7 +235,8 @@ print_user_info( name = '两点水' , age = 18 , sex = '女', hobby = ('打篮 通过对比上面的例子和这个例子,可以知道,`*hobby`是可变参数,且 hobby其实就是一个 tuple (元祖),`**hobby`是关键字参数,且 hobby 就是一个 dict (字典) -## 4、只接受关键字参数 ## + +## 5、只接受关键字参数 ## 关键字参数使用起来简单,不容易参数出错,那么有些时候,我们定义的函数希望某些参数强制使用关键字参数传递,这时候该怎么办呢? @@ -201,6 +260,7 @@ print_user_info( name = '两点水' ,age = 18 , sex = '女' ) print_user_info('两点水',age='22',sex='男') ``` -通过例子可以看,如果 `age` , `sex` 不适用关键字参数是会报错的。 +通过例子可以看,如果 `age` , `sex` 不使用关键字参数是会报错的。 + +很多情况下,使用强制关键字参数会比使用位置参数表意更加清晰,程序也更加具有可读性。使用强制关键字参数也会比使用 `**kw` 参数更好且强制关键字参数在一些更高级场合同样也很有用。 -很多情况下,使用强制关键字参数会比使用位置参数表意更加清晰,程序也更加具有可读性。使用强制关键字参数也会比使用 `**kw` 参数更好且强制关键字参数在一些更高级场合同样也很有用。 \ No newline at end of file diff --git a/Article/python6/2.md b/Article/PythonBasis/python6/4.md similarity index 87% rename from Article/python6/2.md rename to Article/PythonBasis/python6/4.md index 76ba52c2..e9b7b6e4 100644 --- a/Article/python6/2.md +++ b/Article/PythonBasis/python6/4.md @@ -1,4 +1,4 @@ -# 二、函数传值问题 # +# 四、函数传值问题 # 先看一个例子: @@ -18,12 +18,17 @@ print( b ) 1 ``` -这里可能有些人会有疑问,为啥不是通过函数`chagne_number`更改了 b -的值吗?为啥没有变化,输出的结果还是 1 ,这个问题很多编程语言都会讲到,原理解释也是差不多的。 +先看看运行的结果? + +想一下为什么打印的结果是 1 ,而不是 1000 ? + +其实把问题归根结底就是,为什么通过函数 `chagne_number` 没有更改到 b 的值? + +这个问题很多编程语言都会讲到,原理解释也是差不多的。 这里主要是函数参数的传递中,传递的是类型对象,之前也介绍了 Python 中基本的数据类型等。而这些类型对象可以分为可更改类型和不可更改的类型 -在 Python 中,字符串,整形,浮点型,tuple 是不可更改的对象,而 list , dict 等是可以更改的对象。 +**在 Python 中,字符串,整形,浮点型,tuple 是不可更改的对象,而 list , dict 等是可以更改的对象。** 例如: @@ -78,7 +83,6 @@ def chagne_list( b ): b = [1,2,3,4,5] chagne_list( b ) print( '最后输出 b 的值:{}' .format( b ) ) - ``` 输出的结果: @@ -88,3 +92,5 @@ print( '最后输出 b 的值:{}' .format( b ) ) 函数中 b 赋值后的值:[1, 2, 3, 4, 5, 1000] 最后输出 b 的值:[1, 2, 3, 4, 5, 1000] ``` + + diff --git a/Article/python6/5.md b/Article/PythonBasis/python6/5.md similarity index 84% rename from Article/python6/5.md rename to Article/PythonBasis/python6/5.md index 34982e9f..4da7b8ab 100644 --- a/Article/python6/5.md +++ b/Article/PythonBasis/python6/5.md @@ -1,6 +1,8 @@ # 五、匿名函数 # -有没有想过定义一个很短的回调函数,但又不想用 `def` 的形式去写一个那么长的函数,那么有没有快捷方式呢?答案是有的。 +有没有想过定义一个很短的回调函数,但又不想用 `def` 的形式去写一个那么长的函数,那么有没有快捷方式呢? + +答案是有的。 python 使用 lambda 来创建匿名函数,也就是不再使用 def 语句这样标准的形式定义一个函数。 @@ -57,4 +59,5 @@ print( sum2( 1 ) ) 10001 ``` -这主要在于 lambda 表达式中的 num2 是一个自由变量,在运行时绑定值,而不是定义时就绑定,这跟函数的默认值参数定义是不同的。所以建议还是遇到这种情况还是使用第一种解法。 \ No newline at end of file +**这主要在于 lambda 表达式中的 num2 是一个自由变量,在运行时绑定值,而不是定义时就绑定,这跟函数的默认值参数定义是不同的。所以建议还是遇到这种情况还是使用第一种解法。** + diff --git a/Article/PythonBasis/python6/Preface.md b/Article/PythonBasis/python6/Preface.md new file mode 100644 index 00000000..8b6f2210 --- /dev/null +++ b/Article/PythonBasis/python6/Preface.md @@ -0,0 +1,13 @@ +# 前言 # + +函数这个章节内容有点多,对于新手,也有些不好理解。建议各位多看几篇,多敲几次代码。 + +最后这是我的个人微信号,大家可以添加一下,交个朋友,一起讨论。 + +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-07-070041.jpg) + +# 目录 # + +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-07-%E5%87%BD%E6%95%B0.png) + + diff --git a/Article/python7/1.md b/Article/PythonBasis/python7/1.md similarity index 91% rename from Article/python7/1.md rename to Article/PythonBasis/python7/1.md index b9f9df2c..61bbff4b 100644 --- a/Article/python7/1.md +++ b/Article/PythonBasis/python7/1.md @@ -4,7 +4,9 @@ 比如在 Java 中,我们通过 List 集合的下标来遍历 List 集合中的元素,在 Python 中,给定一个 list 或 tuple,我们可以通过 for 循环来遍历这个 list 或 tuple ,这种遍历就是迭代。 -可是,Python 的 `for` 循环抽象程度要高于 Java 的 `for` 循环的,为什么这么说呢?因为 Python 的 `for` 循环不仅可以用在 list 或tuple 上,还可以作用在其他可迭代对象上。也就是说,只要是可迭代的对象,无论有没有下标,都是可以迭代的。 +可是,Python 的 `for` 循环抽象程度要高于 Java 的 `for` 循环的,为什么这么说呢?因为 Python 的 `for` 循环不仅可以用在 list 或tuple 上,还可以作用在其他可迭代对象上。 + +也就是说,只要是可迭代的对象,无论有没有下标,都是可以迭代的。 比如: @@ -59,3 +61,5 @@ name age sex 2 b 3 c ``` + + diff --git a/Article/python7/2.md b/Article/PythonBasis/python7/2.md similarity index 100% rename from Article/python7/2.md rename to Article/PythonBasis/python7/2.md diff --git a/Article/python7/3.md b/Article/PythonBasis/python7/3.md similarity index 84% rename from Article/python7/3.md rename to Article/PythonBasis/python7/3.md index 126edbcd..177ba14d 100644 --- a/Article/python7/3.md +++ b/Article/PythonBasis/python7/3.md @@ -1,4 +1,4 @@ -# 三、lsit 生成式(列表生成式) # +# 三、list 生成式(列表生成式) # ## 1、创建 list 的方式 ## @@ -18,9 +18,13 @@ print(list1) [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] ``` -这个其实在之前也有提到过:比如有个例子,打印九九乘法表,用这个方法其实就几句代码就可以了,具体可以看之前的这个章节:[条件语句和循环语句综合实例](https://www.readwithu.com/python5/Example.html) +这个其实在之前也有提到过,打印九九乘法表,用这个方法其实就几句代码就可以了,具体可以看之前的这个章节:[条件语句和循环语句综合实例](../python5/Example.md) -但是,如果用到 list 生成式,可以一句代码就生成九九乘法表了。具体看代码: +但是,如果用到 list 生成式,可以一句代码就生成九九乘法表了。 + +你没听错,就是一句代码。 + +具体实现: ```python print('\n'.join([' '.join ('%dx%d=%2d' % (x,y,x*y) for x in range(1,y+1)) for y in range(1,10)])) @@ -44,7 +48,7 @@ print('\n'.join([' '.join ('%dx%d=%2d' % (x,y,x*y) for x in range(1,y+1)) for y ## 2、list 生成式的创建 ## -首先,lsit 生成式的语法为: +首先,list 生成式的语法为: ```python [expr for iter_var in iterable] @@ -61,8 +65,8 @@ print('\n'.join([' '.join ('%dx%d=%2d' % (x,y,x*y) for x in range(1,y+1)) for y ```python # -*- coding: UTF-8 -*- -lsit1=[x * x for x in range(1, 11)] -print(lsit1) +list1=[x * x for x in range(1, 11)] +print(list1) ``` 输出的结果: @@ -75,8 +79,8 @@ print(lsit1) ```python # -*- coding: UTF-8 -*- -lsit1= [x * x for x in range(1, 11) if x % 2 == 0] -print(lsit1) +list1= [x * x for x in range(1, 11) if x % 2 == 0] +print(list1) ``` 输出的结果: @@ -91,8 +95,8 @@ print(lsit1) ```python # -*- coding: UTF-8 -*- -lsit1= [(x+1,y+1) for x in range(3) for y in range(5)] -print(lsit1) +list1= [(x+1,y+1) for x in range(3) for y in range(5)] +print(list1) ``` 输出的结果: @@ -102,3 +106,5 @@ print(lsit1) ``` 其实知道了 list 生成式是怎样组合的,就不难理解这个东西了。因为 list 生成式只是把之前学习的知识点进行了组合,换成了一种更简洁的写法而已。 + + diff --git a/Article/python7/4.md b/Article/PythonBasis/python7/4.md similarity index 70% rename from Article/python7/4.md rename to Article/PythonBasis/python7/4.md index 684c0e96..fe95fe1e 100644 --- a/Article/python7/4.md +++ b/Article/PythonBasis/python7/4.md @@ -2,15 +2,21 @@ ## 1、为什么需要生成器 ## -通过上面的学习,可以知道列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含 1000 万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。 +通过上面的学习,可以知道列表生成式,我们可以直接创建一个列表。 -所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的 list,从而节省大量的空间。在 Python 中,这种一边循环一边计算的机制,称为生成器:generator。 +但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含 1000 万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。 + +**所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?** + +这样就不必创建完整的 list,从而节省大量的空间。 + +**在 Python 中,这种一边循环一边计算的机制,称为生成器:generator。** 在 Python 中,使用了 yield 的函数被称为生成器(generator)。 跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。 -在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回yield的值。并在下一次执行 next()方法时从当前位置继续运行。 +在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值。并在下一次执行 next()方法时从当前位置继续运行。 那么如何创建一个生成器呢? @@ -31,7 +37,11 @@ print(gen) at 0x0000000002734A40> ``` -创建 List 和 generator 的区别仅在于最外层的 `[]` 和 `()` 。但是生成器并不真正创建数字列表, 而是返回一个生成器,这个生成器在每次计算出一个条目后,把这个条目“产生” ( yield ) 出来。 生成器表达式使用了“惰性计算” ( lazy evaluation,也有翻译为“延迟求值”,我以为这种按需调用 call by need 的方式翻译为惰性更好一些),只有在检索时才被赋值( evaluated ),所以在列表比较长的情况下使用内存上更有效。 +创建 List 和 generator 的区别仅在于最外层的 `[]` 和 `()` 。 + +但是生成器并不真正创建数字列表, 而是返回一个生成器,这个生成器在每次计算出一个条目后,把这个条目“产生” ( yield ) 出来。 + +生成器表达式使用了“惰性计算” ( lazy evaluation,也有翻译为“延迟求值”,我以为这种按需调用 call by need 的方式翻译为惰性更好一些),只有在检索时才被赋值( evaluated ),所以在列表比较长的情况下使用内存上更有效。 那么竟然知道了如何创建一个生成器,那么怎么查看里面的元素呢? @@ -55,7 +65,11 @@ for num in gen : 上面也提到,创建生成器最简单最简单的方法就是把一个列表生成式的 `[]` 改成 `()`。为啥突然来个以函数的形式来创建呢? -其实生成器也是一种迭代器,但是你只能对其迭代一次。这是因为它们并没有把所有的值存在内存中,而是在运行时生成值。你通过遍历来使用它们,要么用一个“for”循环,要么将它们传递给任意可以进行迭代的函数和结构。而且实际运用中,大多数的生成器都是通过函数来实现的。那么我们该如何通过函数来创建呢? +其实生成器也是一种迭代器,但是你只能对其迭代一次。 + +这是因为它们并没有把所有的值存在内存中,而是在运行时生成值。你通过遍历来使用它们,要么用一个“for”循环,要么将它们传递给任意可以进行迭代的函数和结构。 + +而且实际运用中,大多数的生成器都是通过函数来实现的。那么我们该如何通过函数来创建呢? 先不急,来看下这个例子: @@ -119,9 +133,9 @@ for x in fibon(1000000): 运行的效果: -![计算斐波那契数列的生成器](http://upload-images.jianshu.io/upload_images/2136918-304e50af22b787ce?imageMogr2/auto-orient/strip) +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-07-%E8%AE%A1%E7%AE%97%E6%96%90%E6%B3%A2%E9%82%A3%E5%A5%91%E6%95%B0%E5%88%97%E7%9A%84%E7%94%9F%E6%88%90%E5%99%A8.gif) -你看,运行一个这么打的参数,也不会说有卡死的状态,因为这种方式不会使用太大的资源。这里,最难理解的就是 generator 和函数的执行流程不一样。函数是顺序执行,遇到 return 语句或者最后一行函数语句就返回。而变成 generator 的函数,在每次调用 next() 的时候执行,遇到 yield语句返回,再次执行时从上次返回的 yield 语句处继续执行。 +你看,运行一个这么大的参数,也不会说有卡死的状态,因为这种方式不会使用太大的资源。这里,最难理解的就是 generator 和函数的执行流程不一样。函数是顺序执行,遇到 return 语句或者最后一行函数语句就返回。而变成 generator 的函数,在每次调用 next() 的时候执行,遇到 yield语句返回,再次执行时从上次返回的 yield 语句处继续执行。 比如这个例子: @@ -189,3 +203,5 @@ for t in triangles( 10 ): # 直接修改函数名即可运行 [1, 8, 28, 56, 70, 56, 28, 8, 1] [1, 9, 36, 84, 126, 126, 84, 36, 9, 1] ``` + + diff --git a/Article/python7/5.md b/Article/PythonBasis/python7/5.md similarity index 100% rename from Article/python7/5.md rename to Article/PythonBasis/python7/5.md diff --git a/Article/PythonBasis/python7/Preface.md b/Article/PythonBasis/python7/Preface.md new file mode 100644 index 00000000..1646e388 --- /dev/null +++ b/Article/PythonBasis/python7/Preface.md @@ -0,0 +1,11 @@ +# 前言 # + +这篇内容挺多的,而且比内容不好理解。或许新手看完后,还会一脸懵逼,不过这是正常的,如果你看完后,是迷糊的,那么建议你继续学习后面的内容,等学完,再回来看几次。 + +注:这也是我第二次修改内容没有改过的章节。 + +# 目录 # + +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-07-%E8%BF%AD%E4%BB%A3%E5%99%A8%E5%92%8C%E7%94%9F%E6%88%90%E5%99%A8.png) + + diff --git a/Article/python9/1.md b/Article/PythonBasis/python8/1.md similarity index 54% rename from Article/python9/1.md rename to Article/PythonBasis/python8/1.md index e40cb10d..13fd9e0d 100644 --- a/Article/python9/1.md +++ b/Article/PythonBasis/python8/1.md @@ -1,11 +1,23 @@ # 一、面向对象的概念 # -Python 是一门面向对象的语言, 面向对象是一种抽象,抽象是指用分类的眼光去看世界的一种方法。 用 JAVA 的编程思想来说就是:万事万物皆对象。也就是说在面向对象中,把构成问题事务分解成各个对象。 -面向对象有三大特性,封装、继承和多态。 ## 1、面向对象的两个基本概念 ## +编程语言中,一般有两种编程思维,面向过程和面向对象。 + +面向过程,看重的是解决问题的过程。 + +这好比我们解决日常生活问题差不多,分析解决问题的步骤,然后一步一步的解决。 + +而面向对象是一种抽象,抽象是指用分类的眼光去看世界的一种方法。 + +Python 就是一门面向对象的语言, + +如果你学过 Java ,就知道 Java 的编程思想就是:万事万物皆对象。Python 也不例外,在解决实际问题的过程中,可以把构成问题事务分解成各个对象。 + +面向对象都有两个基本的概念,分别是类和对象。 + * **类** 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。 @@ -15,8 +27,13 @@ Python 是一门面向对象的语言, 面向对象是一种抽象,抽象是 通过类定义的数据结构实例 + + + ## 2、面向对象的三大特性 ## +面向对象的编程语言,也有三大特性,继承,多态和封装性。 + * **继承** 即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。 @@ -30,3 +47,8 @@ Python 是一门面向对象的语言, 面向对象是一种抽象,抽象是 * **封装性** “封装”就是将抽象得到的数据和行为(或功能)相结合,形成一个有机的整体(即类);封装的目的是增强安全性和简化编程,使用者不必了解具体的实现细节,而只是要通过外部接口,一特定的访问权限来使用类的成员。 + + +**如果你是初次接触面向对象的编程语言,看到这里还一脸懵逼,不要紧,这是正常的。下面我们会通过大量的例子逐步了解 Python 的面向对象的知识。** + + diff --git a/Article/PythonBasis/python8/2.md b/Article/PythonBasis/python8/2.md new file mode 100644 index 00000000..67917711 --- /dev/null +++ b/Article/PythonBasis/python8/2.md @@ -0,0 +1,83 @@ +# 二、类的定义和调用 # + + + +## 1、怎么理解类? ## + +类是什么? + +个人认为理解类,最简单的方式就是:类是一个变量和函数的集合。 + +可以看下下面的这张图。 + +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2020-03-09-014706.jpg) + +这张图很好的诠释了类,就是把变量和函数包装在一起。 + +当然我们包装也不是毫无目的的包装,我们会把同性质的包装在一个类里,这样就方便我们重复使用。 + +所以学到现在,你会发现很多编程的设计,都是为了我们能偷懒,重复使用。 + + + + + + +## 2、怎么定义类 ## + +知道了类是什么样子的,我们接下来就要学习怎么去定义类了。 + +类定义语法格式如下: + +```python +class ClassName(): + + . + . + . + +``` + +可以看到,我们是用 `class` 语句来自定义一个类的,其实这就好比我们是用 `def` 语句来定义一个函数一样。 + +竟然说类是变量和方法的集合包,那么我们来创建一个类。 + +```python +class ClassA(): + var1 = 100 + var2 = 0.01 + var3 = '两点水' + + def fun1(): + print('我是 fun1') + + def fun2(): + print('我是 fun1') + + def fun3(): + print('我是 fun1') +``` + +你看,上面我们就定义了一个类,类名叫做 `ClassA` , 类里面的变量我们称之为属性,那么就是这个类里面有 3 个属性,分别是 `var1` , `var2` 和 `var3` 。除此之外,类里面还有 3 个类方法 `fun1()` , `fun2()` 和 `fun3()` 。 + + + + + +## 3、怎么调用类属性和类方法 ## + + +我们定义了类之后,那么我们怎么调用类里面的属性和方法呢? + +直接看下图: + +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2020-03-09-014728.jpg) + +这里就不文字解释了(注:做图也不容易啊,只有写过技术文章才知道,这系列文章,多耗时) + +好了,知道怎么调用之后,我们尝试一下: + + +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2020-03-09-014742.jpg) + + diff --git a/Article/PythonBasis/python8/3.md b/Article/PythonBasis/python8/3.md new file mode 100644 index 00000000..82147949 --- /dev/null +++ b/Article/PythonBasis/python8/3.md @@ -0,0 +1,57 @@ +# 三、类方法 # + + +## 1、类方法如何调用类属性 ## + +通过上面我们已经会定义类了,那么这里讲一下在同一个类里,类方法如何调用类属性的。 + +直接看个例子吧: + + +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-08-110451.png) + +注意看,在类方法上面多了个 `@classmethod` ,这是干嘛用的呢? + +这是用于声明下面的函数是类函数。其实从名字就很好理解了。 + +class 就是类,method 就是方法。 + +那是不是一定需要注明这个呢? + +答案是是的。 + +如果你没使用,是会报错的。 + + +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-08-110822.png) + +如果没有声明是类方法,方法参数中就没有 `cls` , 就没法通过 `cls` 获取到类属性。 + +因此类方法,想要调用类属性,需要以下步骤: + +* 在方法上面,用 `@classmethod` 声明该方法是类方法。只有声明了是类方法,才能使用类属性 +* 类方法想要使用类属性,在第一个参数中,需要写上 `cls` , cls 是 class 的缩写,其实意思就是把这个类作为参数,传给自己,这样就可以使用类属性了。 +* 类属性的使用方式就是 `cls.变量名` + + +记住喔,无论是 `@classmethod` 还是 `cls` ,都是不能省去的。 + +省了都会报错。 + + + + + +## 2、类方法传参 ## + +上面我们学习了类方法如何调用类属性,那么类方法如何传参呢? + +其实很简单,跟普通的函数一样,直接增加参数就好了。 + +这个就直接上例子了: + +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-08-113458.png) + + + + diff --git a/Article/PythonBasis/python8/4.md b/Article/PythonBasis/python8/4.md new file mode 100644 index 00000000..2dea4f4b --- /dev/null +++ b/Article/PythonBasis/python8/4.md @@ -0,0 +1,32 @@ +# 四、修改和增加类属性 # + + +## 1、从内部增加和修改类属性 ## + +来,我们先来温习一下类的结构。 + +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-08-034102.png) + +看着这个结构,提一个问题,如何修改类属性,也就是类里面的变量? + +从类结构来看,我们可以猜测,从类方法来修改,也就是从类内部来修改和增加类属性。 + +看下具体的实例: + +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-08-120146.png) + +这里还是强调一下,例子还是要自己多写,不要只看,自己运行, 看效果。多想。 + + + + +## 2、从外部增加和修改类属性 ## + +我们刚刚看了通过类方法来修改类的属性,这时我们看下从外部如何修改和增加类属性。 + +例子如下: + +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-08-121135.png) + + + diff --git a/Article/PythonBasis/python8/5.md b/Article/PythonBasis/python8/5.md new file mode 100644 index 00000000..1f92bcf0 --- /dev/null +++ b/Article/PythonBasis/python8/5.md @@ -0,0 +1,171 @@ +# 五、类和对象 # + + + + +## 1、类和对象之间的关系 ## + +这部分内容主要讲类和对象,我们先来说说类和对象之间的关系。 + +**类是对象的模板** + +我们得先有了类,才能制作出对象。 + +类就相对于工厂里面的模具,对象就是根据模具制造出来的产品。 + +**从模具变成产品的过程,我们就称为类的实例化。** + +**类实例化之后,就变成对象了。也就是相当于例子中的产品。** + + + + + +## 2、类的实例化 ## + +这里强调一下,类的实例化和直接使用类的格式是不一样的。 + +之前我们就学过,直接使用类格式是这样的: + +```python +class ClassA(): + var1 = '两点水' + + @classmethod + def fun1(cls): + print('var1 值为:' + cls.var1) + + +ClassA.fun1() +``` + +而类的实例化是怎样的呢? + +是这样的,可以仔细对比一下,类的实例化和直接使用类的格式有什么不同? + +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-09-025401.png) + + +主要的不同点有: + +* 类方法里面没有了 `@classmethod` 声明了,不用声明他是类方法 +* 类方法里面的参数 `cls` 改为 `self` +* 类的使用,变成了先通过 `实例名 = 类()` 的方式实例化对象,为类创建一个实例,然后再使用 `实例名.函数()` 的方式调用对应的方法 ,使用 `实例名.变量名` 的方法调用类的属性 + + +这里说明一下,类方法的参数为什么 `cls` 改为 `self` ? + +其实这并不是说一定要写这个,你改为什么字母,什么名字都可以。 + +不妨试一下: + +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-09-032030.png) + +你看,把 `self` 改为 `aaaaaaaa` 还是可以一样运行的。 + +只不过使用 `cls` 和 `self` 是我们的编程习惯,这也是我们的编程规范。 + +因为 cls 是 class 的缩写,代表这类 , 而 self 代表这对象的意思。 + +所以啊,这里我们实例化对象的时候,就使用 self 。 + +**而且 self 是所有类方法位于首位、默认的特殊参数。** + +除此之外,在这里,还要强调一个概念,当你把类实例化之后,里面的属性和方法,就不叫类属性和类方法了,改为叫实例属性和实例方法,也可以叫对象属性和对象方法。 + +为什么要这样强调呢? + +**因为一个类是可以创造出多个实例对象出来的。** + +你看下面的例子: + +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-09-034453.png) + +我不仅能用这个类创建 a 对象,还能创建 b 对象 + + + + + +## 3、实例属性和类属性 ## + +一个类可以实例化多个对象出来。 + +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-09-040408.png) + +根据这个图,我们探究一下实例对象的属性和类属性之间有什么关系呢? + +**先提出第一个问题,如果类属性改变了,实例属性会不会跟着改变呢?** + +还是跟以前一样,提出了问题,我们直接用程序来验证就好。 + +看程序: + + +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-09-061015.png) + + +从程序运行的结果来看,**类属性改变了,实例属性会跟着改变。** + +这很好理解,因为我们的实例对象就是根据类来复制出来的,类属性改变了,实例对象的属性也会跟着改变。 + +**那么相反,如果实例属性改变了,类属性会改变吗?** + +答案当然是不能啦。因为每个实例都是单独的个体,不能影响到类的。 + +具体我们做下实验: + + +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-09-062437.png) + +可以看到,**不管实例对象怎么修改属性值,对类的属性还是没有影响的。** + + + + +## 4、实例方法和类方法 ## + +那这里跟上面一样,还是提出同样的问题。 + +**如果类方法改变了,实例方法会不会跟着改变呢?** + +看下下面的例子: + +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-09-063242.png) + +这里建议我的例子,各位都要仔细看一下,自己重新敲一遍。相信为什么要这么做,这么证明。 + +还是那句话多想,多敲。 + +回归正题,从运行的结果来看,类方法改变了,实例方法也是会跟着改变的。 + +在这个例子中,我们需要改变类方法,就用到了**类的重写**。 + +我们使用了 `类.原始函数 = 新函数` 就完了类的重写了。 + +要注意的是,这里的赋值是在替换方法,并不是调用函数。所以是不能加上括号的,也就是 `类.原始函数() = 新函数()` 这个写法是不对的。 + + +**那么如果实例方法改变了,类方法会改变吗?** + +如果这个问题我们需要验证的话,是不是要重写实例的方法,然后观察结果,看看类方法有没有改变,这样就能得出结果了。 + + +可是我们是不能重写实例方法。 + +你看,会直接报错。 + +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-09-064303.png) + + + + + + + + + + + + + diff --git a/Article/PythonBasis/python8/6.md b/Article/PythonBasis/python8/6.md new file mode 100644 index 00000000..71152336 --- /dev/null +++ b/Article/PythonBasis/python8/6.md @@ -0,0 +1,146 @@ +# 六、初始化函数 # + + + +## 1、什么是初始化函数 ## + +初始化函数的意思是,当你创建一个实例的时候,这个函数就会被调用。 + +比如: + +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-09-071102.png) + +当代码在执行 `a = ClassA()` 的语句时,就自动调用了 `__init__(self)` 函数。 + +**而这个 `__init__(self)` 函数就是初始化函数,也叫构造函数。** + +初始化函数的写法是固定的格式:中间是 `init`,意思是初始化,然后前后都要有【两个下划线】,然后 `__init__()` 的括号中,第一个参数一定要写上 `self`,不然会报错。 + +构造函数(初始化函数)格式如下: + +```python +def __init__(self,[...): +``` + + +初始化函数一样可以传递参数的,例如: + +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-09-073421.png) + + + + +## 2、析构函数 ## + +竟然一个在创建的时候,会调用构造函数,那么理所当然,这个当一个类销毁的时候,就会调用析构函数。 + +析构函数语法如下: + +```python +def __del__(self,[...): +``` + +看下具体的示例: + + +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-09-084417.png) + + + +## 3、Python 定义类的历史遗留问题 ## + +Python 在版本的迭代中,有一个关于类的历史遗留问题,就是新式类和旧式类的问题,具体先看以下的代码: + +```python +#!/usr/bin/env python +# -*- coding: UTF-8 -*- + +# 旧式类 +class OldClass: + pass + +# 新式类 +class NewClass(object): + pass + +``` + +可以看到,这里使用了两者中不同的方式定义类,可以看到最大的不同就是,新式类继承了`object` 类,在 Python2 中,我们定义类的时候最好定义新式类,当然在 Python3 中不存在这个问题了,因为 Python3 中所有类都是新式类。 + +那么新式类和旧式类有什么区别呢? + +运行下下面的那段代码: + +```python +#!/usr/bin/env python +# -*- coding: UTF-8 -*- + +# 旧式类 +class OldClass: + def __init__(self, account, name): + self.account = account + self.name = name + + +# 新式类 +class NewClass(object): + def __init__(self, account, name): + self.account = account + self.name = name + + +if __name__ == '__main__': + old_class = OldClass(111111, 'OldClass') + print(old_class) + print(type(old_class)) + print(dir(old_class)) + print('\n') + new_class = NewClass(222222, 'NewClass') + print(new_class) + print(type(new_class)) + print(dir(new_class)) + +``` + +这是 python 2.7 运行的结果: + +``` +/Users/twowater/dev/python/test/venv/bin/python /Users/twowater/dev/python/test/com/twowater/test.py +<__main__.OldClass instance at 0x109a50560> + +['__doc__', '__init__', '__module__', 'account', 'name'] + + +<__main__.NewClass object at 0x109a4b150> + +['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'account', 'name'] + +Process finished with exit code 0 + +``` + +这是 Python 3.6 运行的结果: + +``` +/usr/local/bin/python3.6 /Users/twowater/dev/python/test/com/twowater/test.py +<__main__.OldClass object at 0x1038ba630> + +['__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__', 'account', 'name'] + + +<__main__.NewClass object at 0x103e3c9e8> + +['__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__', 'account', 'name'] + +Process finished with exit code 0 + +``` + + +仔细观察输出的结果,对比一下,就能观察出来,注意喔,Pyhton3 中输出的结果是一模一样的,因为Python3 中没有新式类旧式类的问题。 + + + + + + diff --git a/Article/python9/5.md b/Article/PythonBasis/python8/7.md similarity index 82% rename from Article/python9/5.md rename to Article/PythonBasis/python8/7.md index d85ab90d..0e95adad 100644 --- a/Article/python9/5.md +++ b/Article/PythonBasis/python8/7.md @@ -1,7 +1,16 @@ -# 五、类的继承 # +# 七、类的继承 # ## 1、定义类的继承 ## +说到继承,你一定会联想到继承你老爸的家产之类的。 + +类的继承也是一样。 + +比如有一个旧类,是可以算平均数的。然后这时候有一个新类,也要用到算平均数,那么这时候我们就可以使用继承的方式。新类继承旧类,这样子新类也就有这个功能了。 + +通常情况下,我们叫旧类为父类,新类为子类。 + + 首先我们来看下类的继承的基本语法: ```python @@ -13,7 +22,7 @@ class ClassName(BaseClassName): ``` -在定义类的时候,可以在括号里写继承的类,一开始也提到过,如果不用继承类的时候,也要写继承 object 类,因为在 Python 中 object 类是一切类的父类。 +在定义类的时候,可以在括号里写继承的类,如果不用继承类的时候,也要写继承 object 类,因为在 Python 中 object 类是一切类的父类。 当然上面的是单继承,Python 也是支持多继承的,具体的语法如下: @@ -112,12 +121,12 @@ if __name__ == '__main__': 最后打印的结果: -![Python 类的继承](http://upload-images.jianshu.io/upload_images/2136918-aa2701fc5913a8a6?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-09-Python%20%E7%B1%BB%E7%9A%84%E7%BB%A7%E6%89%BF.png) 这里就是重写了父类的构造函数。 -## 3、子类的类型判断 ## +## 4、子类的类型判断 ## 对于 class 的继承关系来说,有些时候我们需要判断 class 的类型,该怎么办呢? @@ -168,3 +177,5 @@ False ``` 可以看到 `isinstance()` 不仅可以告诉我们,一个对象是否是某种类型,也可以用于基本类型的判断。 + + diff --git a/Article/python9/6.md b/Article/PythonBasis/python8/8.md similarity index 92% rename from Article/python9/6.md rename to Article/PythonBasis/python8/8.md index da1b03d4..7a2c9cbb 100644 --- a/Article/python9/6.md +++ b/Article/PythonBasis/python8/8.md @@ -1,4 +1,4 @@ -# 六、类的多态 # +# 八、类的多态 # 多态的概念其实不难理解,它是指对不同类型的变量进行相同的操作,它会根据对象(或类)类型的不同而表现出不同的行为。 @@ -11,7 +11,9 @@ 'ab' ``` -可以看到,我们对两个整数进行 + 操作,会返回它们的和,对两个字符进行相同的 + 操作,会返回拼接后的字符串。也就是说,不同类型的对象对同一消息会作出不同的响应。 +可以看到,我们对两个整数进行 + 操作,会返回它们的和,对两个字符进行相同的 + 操作,会返回拼接后的字符串。 + +也就是说,不同类型的对象对同一消息会作出不同的响应。 看下面的实例,来了解多态: @@ -64,4 +66,5 @@ Hello ! 尊敬的用户:水水水 -最后,本章的所有代码都可以在 [https://github.com/TwoWater/Python](https://github.com/TwoWater/Python) 上面找到,文章的内容和源文件都放在上面。同步更新到 Gitbooks。 \ No newline at end of file +最后,本章的所有代码都可以在 [https://github.com/TwoWater/Python](https://github.com/TwoWater/Python) 上面找到,文章的内容和源文件都放在上面。同步更新到 Gitbooks。 + diff --git a/Article/python9/4.md b/Article/PythonBasis/python8/9.md similarity index 62% rename from Article/python9/4.md rename to Article/PythonBasis/python8/9.md index 6514b268..68d56fb6 100644 --- a/Article/python9/4.md +++ b/Article/PythonBasis/python8/9.md @@ -1,6 +1,62 @@ -# 四、类的方法 # +# 九、类的访问控制 # -## 1、类专有的方法 ## + +## 1、类属性的访问控制 ## + +在 Java 中,有 public (公共)属性 和 private (私有)属性,这可以对属性进行访问控制。 + +那么在 Python 中有没有属性的访问控制呢? + +一般情况下,我们会使用 `__private_attrs` 两个下划线开头,声明该属性为私有,不能在类地外部被使用或直接访问。在类内部的方法中使用时 `self.__private_attrs`。 + +为什么只能说一般情况下呢? + +因为实际上, Python 中是没有提供私有属性等功能的。 + +但是 Python 对属性的访问控制是靠程序员自觉的。为什么这么说呢? + +看看下面的示例: + +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-09-Python%20%E5%B1%9E%E6%80%A7%E8%AE%BF%E9%97%AE%E6%8E%A7%E5%88%B6.png) + +仔细看图片,为什么说双下划线不是真正的私有属性呢?我们看下下面的例子,用下面的例子来验证: + +```python + +#!/usr/bin/env python +# -*- coding: UTF-8 -*- + +class UserInfo(object): + def __init__(self, name, age, account): + self.name = name + self._age = age + self.__account = account + + def get_account(self): + return self.__account + + +if __name__ == '__main__': + userInfo = UserInfo('两点水', 23, 347073565); + # 打印所有属性 + print(dir(userInfo)) + # 打印构造函数中的属性 + print(userInfo.__dict__) + print(userInfo.get_account()) + # 用于验证双下划线是否是真正的私有属性 + print(userInfo._UserInfo__account) + + +``` + +输出的结果如下图: + +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-09-Python%E5%8F%8C%E4%B8%8B%E5%88%92%E7%BA%BF%E5%B1%9E%E6%80%A7.png) + + + + +## 2、类专有的方法 ## 一个类创建的时候,就会包含一些方法,主要有以下方法: @@ -32,7 +88,9 @@ * `setattr(obj, attr, value)`:设定该属性/方法的值,类似于 obj.attr=value; * `dir(obj)`:可以获取相应对象的所有属性和方法名的列表: -## 2、方法的访问控制 ## + + +## 3、方法的访问控制 ## 其实我们也可以把方法看成是类的属性的,那么方法的访问控制也是跟属性是一样的,也是没有实质上的私有方法。一切都是靠程序员自觉遵守 Python 的编程规范。 @@ -54,53 +112,7 @@ class User(object): ``` -## 3、方法的装饰器 ## - -* **@classmethod** -调用的时候直接使用类名类调用,而不是某个对象 -* **@property** -可以像访问属性一样调用方法 - -具体的使用看下实例: - -```python -#!/usr/bin/env python -# -*- coding: UTF-8 -*- - -class UserInfo(object): - lv = 5 - - def __init__(self, name, age, account): - self.name = name - self._age = age - self.__account = account - - def get_account(self): - return self.__account - - @classmethod - def get_name(cls): - return cls.lv - - @property - def get_age(self): - return self._age - - -if __name__ == '__main__': - userInfo = UserInfo('两点水', 23, 347073565); - # 打印所有属性 - print(dir(userInfo)) - # 打印构造函数中的属性 - print(userInfo.__dict__) - # 直接使用类名类调用,而不是某个对象 - print(UserInfo.lv) - # 像访问属性一样调用方法(注意看get_age是没有括号的) - print(userInfo.get_age) -``` -运行的结果: -![Python 方法的装饰器](http://upload-images.jianshu.io/upload_images/2136918-63dc478a8b2f965f?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) diff --git a/Article/python8/Preface.md b/Article/PythonBasis/python8/Preface.md similarity index 72% rename from Article/python8/Preface.md rename to Article/PythonBasis/python8/Preface.md index abd89936..a0abeb00 100644 --- a/Article/python8/Preface.md +++ b/Article/PythonBasis/python8/Preface.md @@ -1,7 +1,30 @@ # 前言 # + 之前的文章都是使用[Sublime Text](http://www.sublimetext.com/)来编写 Python 的,主要是为了更好的熟悉和了解 Python ,可是开发效率不高,也不方便,从这章开始,改为使用 Pycharm 了,在之前的篇节[集成开发环境(IDE): PyCharm](https://www.readwithu.com/python1/IDE.html)中介绍了 PyCharm ,如果如要激活软件可以通过授权服务器来激活,具体看这个网址。[JetBrains激活(http://www.imsxm.com/jetbrains-license-server.html)](http://www.imsxm.com/jetbrains-license-server.html)当然你也可以尝试破解, [Pycharm2017.1.1破解方式](http://blog.csdn.net/zyfortirude/article/details/70800681),不过对于软件的升级不方便。 + +这篇内容非常的重要,也是我用了很多时间写的。基本上把以前写的东西都重新改了一遍。里面的代码都是我一个一个的敲的,图片也是我一个一个制作的。 + + + + # 目录 # -![草根学Python(八) 模块与包](http://upload-images.jianshu.io/upload_images/2136918-4434f73dc82c0101?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) +![面向对象](media/%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1.png) + + + + + + + + + + + + + + + + diff --git a/Article/PythonBasis/python9/1.md b/Article/PythonBasis/python9/1.md new file mode 100644 index 00000000..70c912a6 --- /dev/null +++ b/Article/PythonBasis/python9/1.md @@ -0,0 +1,50 @@ +# 一、Python 模块简介 # + +在开发过程中,随着程序代码越写越多,在一个文件里代码就会越来越长,越来越不容易维护。 + +后面我们学习了函数,知道函数是实现一项或多项功能的一段程序,这样就更方便我们重复使用代码。 + +紧接着,我们有学了类,类可以封装方法和变量(属性)。这样就更方便我们维护代码了。 + +我们之前学过,类的结构是这样的: + +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-08-034102.png) + +而我们要学的模块是这样的: + + +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-10-175017.png) + +在模块中,我们不但可以直接存放变量,还能存放函数,还能存放类。 + +不知道你们还有没有印象,我们封装函数用的是 `def` , 封装类用的是 `class` 。 + +而我们封装模块,是不需要任何语句的。 + +**在 Python 中,一个 .py 文件就称之为一个模块(Module)。** + +可以看下我之前写的例子,在 pychrome 上 ,这样一个 test.py 文件就是一个模块。 + +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-14-070013.png) + +其实模块就是函数功能的扩展。为什么这么说呢? + +那是因为模块其实就是实现一项或多项功能的程序块。 + +通过上面的定义,不难发现,函数和模块都是用来实现功能的,只是模块的范围比函数广,在模块中,可以有多个函数。 + +然有了函数,那为啥那需要模块? + +最大的好处是大大提高了代码的可维护性。 + +其次,编写代码不必从零开始。当一个模块编写完毕,就可以被其他地方引用。我们在编写程序的时候,也经常引用其他模块,包括 Python 内置的模块和来自第三方的模块。 + +使用模块还可以避免函数名和变量名冲突。相同名字的函数和变量完全可以分别存在不同的模块中,因此,我们自己在编写模块时,不必考虑名字会与其他模块冲突。但是也要注意,尽量不要与内置函数名字冲突。 + +Python 本身就内置了很多非常有用的模块,只要安装完毕,这些模块就可以立刻使用。我们可以尝试找下这些模块,比如我的 Python 安装目录是默认的安装目录,在 C:\Users\Administrator\AppData\Local\Programs\Python\Python36 ,然后找到 Lib 目录,就可以发现里面全部都是模块,没错,这些 `.py` 文件就是模块了。 + +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-14-python36bin%E7%9B%AE%E5%BD%95.png) + +其实模块可以分为标准库模块和自定义模块,而刚刚我们看到的 Lib 目录下的都是标准库模块。 + + diff --git a/Article/python8/2.md b/Article/PythonBasis/python9/2.md similarity index 85% rename from Article/python8/2.md rename to Article/PythonBasis/python9/2.md index 1dafbc97..abf1c87b 100644 --- a/Article/python8/2.md +++ b/Article/PythonBasis/python9/2.md @@ -73,16 +73,24 @@ from modname import name1[, name2[, ... nameN]] `import` 导入 sys 模块,然后使用 version 属性 -![from···import和 import的区别1](http://upload-images.jianshu.io/upload_images/2136918-499dd531d4ce3d72?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-14-from%C2%B7%C2%B7%C2%B7import%E5%92%8C%20import%E7%9A%84%E5%8C%BA%E5%88%AB1.png) `from···import` 直接导入 version 属性 -![from···import和 import的区别2](http://upload-images.jianshu.io/upload_images/2136918-eea99fc170ed5a07?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) +![from···import和 import的区别2](media/from%C2%B7%C2%B7%C2%B7import%E5%92%8C%20import%E7%9A%84%E5%8C%BA%E5%88%AB2-2.png) + + ## 3、from ··· import * ## -通过上面的学习,我们知道了 `from sys import version` 可以直接导入 version 属性。但是如果我们想使用其他的属性呢?比如使用 sys 模块中的 `executable` ,难道又要写多一句 `from sys import executable` ,两个还好,如果三个,四个呢?难道要一直这样写下去? +通过上面的学习,我们知道了 `from sys import version` 可以直接导入 version 属性。 + +但是如果我们想使用其他的属性呢? + +比如使用 sys 模块中的 `executable` ,难道又要写多一句 `from sys import executable` ,两个还好,如果三个,四个呢? + +难道要一直这样写下去? 这时候就需要 `from ··· import *` 语句了,这个语句可以把某个模块中的所有方法属性都导入。比如: @@ -105,3 +113,5 @@ C:\Users\Administrator\AppData\Local\Programs\Python\Python36\python.exe ``` 注意:这提供了一个简单的方法来导入一个模块中的所有方法属性。然而这种声明不该被过多地使用。 + + diff --git a/Article/python8/3.md b/Article/PythonBasis/python9/3.md similarity index 85% rename from Article/python8/3.md rename to Article/PythonBasis/python9/3.md index 16505fdb..48947d50 100644 --- a/Article/python8/3.md +++ b/Article/PythonBasis/python9/3.md @@ -14,10 +14,12 @@ 首先创建了模块 lname ,然后判断一下是否是主模块,如果是主模块就输出 `main` 不是,就输出 `not main` ,首先直接运行该模块,由于该模块是直接使用,而没有被人调用,所以是主模块,因此输出了 `main` ,具体看下图: -![name属性区分模块1](http://upload-images.jianshu.io/upload_images/2136918-d892d81a71cda9d6?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-14-name%E5%B1%9E%E6%80%A7%E5%8C%BA%E5%88%86%E6%A8%A1%E5%9D%971.png) 然后又创建一个 user_lname 模块,里面只是简单的导入了 lname 模块,然后执行,输出的结果是 `not main` ,因为 lname 模块被该模块调用了,所以不是主模块,输出结果如图: -![name属性区分模块2](http://upload-images.jianshu.io/upload_images/2136918-9137cb874588dded?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-14-name%E5%B1%9E%E6%80%A7%E5%8C%BA%E5%88%86%E6%A8%A1%E5%9D%972.png) + + diff --git a/Article/python8/4.md b/Article/PythonBasis/python9/4.md similarity index 51% rename from Article/python8/4.md rename to Article/PythonBasis/python9/4.md index d90bc947..a98e5376 100644 --- a/Article/python8/4.md +++ b/Article/PythonBasis/python9/4.md @@ -1,11 +1,21 @@ # 四、包 # -包,其实在上面的一些例子中,都创建了不同的包名了,具体可以仔细观察。在一开始模块的简介中提到,使用模块可以避免函数名和变量名冲突。相同名字的函数和变量完全可以分别存在不同的模块中,因此,我们自己在编写模块时,不必考虑名字会与其他模块冲突。但是也要注意,尽量不要与内置函数名字冲突。但是这里也有个问题,如果不同的人编写的模块名相同怎么办?为了避免模块名冲突,Python 又引入了按目录来组织模块的方法,称为包(Package)。 +包,其实在上面的一些例子中,都创建了不同的包名了,具体可以仔细观察。 + +在一开始模块的简介中提到,使用模块可以避免函数名和变量名冲突。 + +相同名字的函数和变量完全可以分别存在不同的模块中,因此,我们自己在编写模块时,不必考虑名字会与其他模块冲突。但是也要注意,尽量不要与内置函数名字冲突。 + +但是这里也有个问题,如果不同的人编写的模块名相同怎么办? + +为了避免模块名冲突,Python 又引入了按目录来组织模块的方法,称为包(Package)。 比如最开始的例子,就引入了包,这样子做就算有相同的模块名,也不会造成重复,因为包名不同,其实也就是路径不同。如下图,引入了包名后, lname.py 其实变成了 com.Learn.module.nameattributes.lname -![Python 包](http://upload-images.jianshu.io/upload_images/2136918-7f92a0da0bc609d5?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-14-Python%20%E5%8C%85.png) 仔细观察的人,基本会发现,每一个包目录下面都会有一个 `__init__.py` 的文件,为什么呢? 因为这个文件是必须的,否则,Python 就把这个目录当成普通目录,而不是一个包 。 `__init__.py` 可以是空文件,也可以有Python代码,因为 `__init__.py` 本身就是一个模块,而它对应的模块名就是它的包名。 + + diff --git a/Article/python8/5.md b/Article/PythonBasis/python9/5.md similarity index 65% rename from Article/python8/5.md rename to Article/PythonBasis/python9/5.md index 30085574..93cc20e9 100644 --- a/Article/python8/5.md +++ b/Article/PythonBasis/python9/5.md @@ -1,10 +1,14 @@ # 五、作用域 # -学习过 Java 的同学都知道,Java 的类里面可以给方法和属性定义公共的( public )或者是私有的 ( private ),这样做主要是为了我们希望有些函数和属性能给别人使用或者只能内部使用。 通过学习 Python 中的模块,其实和 Java 中的类相似,那么我们怎么实现在一个模块中,有的函数和变量给别人使用,有的函数和变量仅仅在模块内部使用呢? +学习过 Java 的同学都知道,Java 的类里面可以给方法和属性定义公共的( public )或者是私有的 ( private ),这样做主要是为了我们希望有些函数和属性能给别人使用或者只能内部使用。 -在 Python 中,是通过 `_` 前缀来实现的。正常的函数和变量名是公开的(public),可以被直接引用,比如:abc,ni12,PI等;类似`__xxx__`这样的变量是特殊变量,可以被直接引用,但是有特殊用途,比如上面的 `__name__` 就是特殊变量,还有 `__author__` 也是特殊变量,用来标明作者。注意,我们自己的变量一般不要用这种变量名;类似 `_xxx` 和 `__xxx` 这样的函数或变量就是非公开的(private),不应该被直接引用,比如 `_abc` ,`__abc` 等; + 通过学习 Python 中的模块,其实和 Java 中的类相似,那么我们怎么实现在一个模块中,有的函数和变量给别人使用,有的函数和变量仅仅在模块内部使用呢? -注意,这里是说不应该,而不是不能。因为 Python 种并没有一种方法可以完全限制访问 private 函数或变量,但是,从编程习惯上不应该引用 private 函数或变量。 +在 Python 中,是通过 `_` 前缀来实现的。正常的函数和变量名是公开的(public),可以被直接引用,比如:abc,ni12,PI等;类似`__xxx__`这样的变量是特殊变量,可以被直接引用,但是有特殊用途,比如上面的 `__name__` 就是特殊变量,还有 `__author__` 也是特殊变量,用来标明作者。 + +注意,我们自己的变量一般不要用这种变量名;类似 `_xxx` 和 `__xxx` 这样的函数或变量就是非公开的(private),不应该被直接引用,比如 `_abc` ,`__abc` 等; + +**这里是说不应该,而不是不能。因为 Python 种并没有一种方法可以完全限制访问 private 函数或变量,但是,从编程习惯上不应该引用 private 函数或变量。** 比如: @@ -48,4 +52,6 @@ DiamondVIP2 ------------------------ -最后扯淡,欢迎加我微信:`androidwed`,进入微信Python讨论群,一起学习讨论。现在微信群只有50几个人. +最后扯淡,欢迎加我微信:`thinktoday2019`, 进入微信 Python 讨论群。 + + diff --git a/Article/PythonBasis/python9/Preface.md b/Article/PythonBasis/python9/Preface.md new file mode 100644 index 00000000..ba6b2563 --- /dev/null +++ b/Article/PythonBasis/python9/Preface.md @@ -0,0 +1,9 @@ +# 前言 # + +学习到这里,可以说 Python 基础学习基本接近尾声了。 + +# 目录 # + +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-14-%E6%A8%A1%E5%9D%97%E4%B8%8E%E5%8C%85.png) + + diff --git "a/Article/advanced/Python\345\256\236\347\216\260\346\224\266\345\217\221\351\202\256\344\273\266.md" "b/Article/advanced/Python\345\256\236\347\216\260\346\224\266\345\217\221\351\202\256\344\273\266.md" new file mode 100644 index 00000000..5945b1e1 --- /dev/null +++ "b/Article/advanced/Python\345\256\236\347\216\260\346\224\266\345\217\221\351\202\256\344\273\266.md" @@ -0,0 +1,66 @@ +在实际开发中,当你收到一个需求的时候,比如要做一个「收发邮件」的功能。 + +如果你完全没有印象,没有思路,可以直接 Google 搜索的。 + +因为我们不可能对每个知识点都了解,不了解不可耻,但要懂得怎么去找资料了解。 + +强调一下, + +用 Google 搜索。 + +用 Google 搜索。 + +用 Google 搜索。 + +恕我直言,百度搜索是真的辣鸡。 + +那我们怎么去找资料呢? + +首先我们可以直接 Google 「Python 收发邮件」,就可以得到这么一个结果。 + +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-15-065554.png) + +这种常用的需求,基本只要看前几个就能知道大概的思路了。 + +可以看到,用 Python 实现邮件的收发,主要用到 smtplib 和 email这两个模块。 + + +至于这些模块怎么用,直接看 [Python 官方文档](https://docs.python.org/3.7/library/smtplib.html?highlight=smtplib) + +![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-15-065957.png) + +真的,没有任何教程比官方文档资料还全。 + +不过我们可以总结一下这些内容。 + +**1、SMTP 发送邮件** + +Python 发送邮件主要步骤如下: + +* `import smtplib` + - 导入 `smtplib` 模块,主要用于构造传输服务的 +* `server = smtplib.SMTP()` + - SMTP 是 smtplib 模块中的一个类(class),实例化这个类,方便我们调用他里面的方法。 + - SMTP (Simple Mail Transfer Protocol)翻译过来是“简单邮件传输协议”的意思,SMTP 协议是由源服务器到目的地服务器传送邮件的一组规则。 +* `server.connect(host, port)` + - 连接(connect)指定的服务器 + - host 是指定连接的邮箱服务器,你可以指定服务器的域名。 + - port 服务器的端口号 + - 这些怎么找到,好比 qq 邮箱,在「设置」那里就有相关的开关和说明。 + - ![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-15-090427.png) + - 点相关的说明,你就能看到对应的服务器地址和端口号了 + - ![](http://twowaterimage.oss-cn-beijing.aliyuncs.com/2019-10-15-090619.png) +* `server.login(username, password)` + - 登录的账号密码 +* `server.sendmail(from_addr, to_addr, msg)` + - 发送邮件,发送邮件一般是谁发给了谁,发送了什么?总结为也就是三个参数,发送者,接受者,发送邮件的内容。 + - from_addr:邮件发送地址 + - to_addr:邮件收件人地址 + - msg : 发送邮件的内容,邮件内容需要用到 `email` 模块。通过 `email` 模块我们可以定义邮件的主题,收件人信息,发件人信息等等。 +* `server.quit()` + - 退出服务 + + 直接看下例子,给 QQ 邮箱发送一个邮件: + + + diff --git a/Article/codeSpecification/codeSpecification_first.md b/Article/codeSpecification/codeSpecification_first.md index 1c44091d..5f3faa6e 100644 --- a/Article/codeSpecification/codeSpecification_first.md +++ b/Article/codeSpecification/codeSpecification_first.md @@ -54,10 +54,6 @@ def main(): * 可以使用多个空行分隔多组相关的函数 * 函数中可以使用空行分隔出逻辑相关的代码 -### 2.5、编码 - -* 文件使用 UTF-8 编码 -* 文件头部加入`#-*-conding:utf-8-*-`标识 ## 3、import 语句 @@ -258,4 +254,4 @@ Optional plotz says to frobnicate the bizbaz first. """ """Oneline docstring""" -``` \ No newline at end of file +``` diff --git a/Article/python10/Preface.md b/Article/python10/Preface.md deleted file mode 100644 index 7c035ccb..00000000 --- a/Article/python10/Preface.md +++ /dev/null @@ -1,7 +0,0 @@ -# 前言 # - -距离上一篇已经三个多星期了,最近比较累,下班回到家,很早就休息了,所以更新的进度有点慢。 - -# 目录 # - -![草根学Python(十) Python 的 Magic Method](http://p1ceh5usj.bkt.clouddn.com/%E8%8D%89%E6%A0%B9%E5%AD%A6Python%EF%BC%88%E5%8D%81%EF%BC%89%20Python%20%E7%9A%84%20Magic%20Method.png) diff --git a/Article/python11/Preface.md b/Article/python11/Preface.md deleted file mode 100644 index b0b522b2..00000000 --- a/Article/python11/Preface.md +++ /dev/null @@ -1,9 +0,0 @@ -# 前言 # - -虽然没多少阅读,可是还是坚持写下去。对 Python 感兴趣的童鞋可以加入 Python 学习讨论微信群喔。可以先加我微信,然后拉进群。本人微信: - -![微信](http://img.blog.csdn.net/20170626191709373?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvVHdvX1dhdGVy/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) - -# 目录 # - -![草根学Python(十一) 枚举类](http://p1ceh5usj.bkt.clouddn.com/%E8%8D%89%E6%A0%B9%E5%AD%A6Python%EF%BC%88%E5%8D%81%E4%B8%80%EF%BC%89%20%E6%9E%9A%E4%B8%BE%E7%B1%BB.png) diff --git a/Article/python12/Preface.md b/Article/python12/Preface.md deleted file mode 100644 index 6a137ad5..00000000 --- a/Article/python12/Preface.md +++ /dev/null @@ -1,7 +0,0 @@ -# 前言 # - -第十二篇了,撸起袖子,就是干。 - -# 目录 # - -![草根学Python(十二)元类](http://p1ceh5usj.bkt.clouddn.com/%E8%8D%89%E6%A0%B9%E5%AD%A6Python%EF%BC%88%E5%8D%81%E4%BA%8C%EF%BC%89%20%E5%85%83%E7%B1%BB.png) diff --git a/Article/python13/Preface.md b/Article/python13/Preface.md deleted file mode 100644 index 33eaf357..00000000 --- a/Article/python13/Preface.md +++ /dev/null @@ -1,7 +0,0 @@ -# 前言 # - -拖了好久,不过还是得坚持。喜欢本文的话可以加下公众号【于你供读】。 - -# 目录 # - -![草根学Python(十三) 线程和进程](http://p1ceh5usj.bkt.clouddn.com/%E8%8D%89%E6%A0%B9%E5%AD%A6Python%EF%BC%88%E5%8D%81%E4%B8%89%EF%BC%89%20%E7%BA%BF%E7%A8%8B%E5%92%8C%E8%BF%9B%E7%A8%8B.png) diff --git a/Article/python14/Preface.md b/Article/python14/Preface.md deleted file mode 100644 index 1a380ff5..00000000 --- a/Article/python14/Preface.md +++ /dev/null @@ -1,5 +0,0 @@ -# 目录 # - -![草根学Python(十四) 一步一步了解正则表达式](https://raw.githubusercontent.com/TwoWater/Python/master/Article/python14/%E8%8D%89%E6%A0%B9%E5%AD%A6Python%EF%BC%88%E5%8D%81%E5%9B%9B%EF%BC%89%20%E4%B8%80%E6%AD%A5%E4%B8%80%E6%AD%A5%E4%BA%86%E8%A7%A3%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F.png) - - diff --git a/Article/python6/1.md b/Article/python6/1.md deleted file mode 100644 index 4c3c0757..00000000 --- a/Article/python6/1.md +++ /dev/null @@ -1,42 +0,0 @@ -# 一、Python 自定义函数的基本步骤 # - -函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。 - -自定义函数,基本有以下规则步骤: - -* 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号() -* 任何传入参数和自变量必须放在圆括号中间。圆括号之间可以用于定义参数 -* 函数的第一行语句可以选择性地使用文档字符串(用于存放函数说明) -* 函数内容以冒号起始,并且缩进 -* return [表达式] 结束函数,选择性地返回一个值给调用方。不带表达式的 return 相当于返回 None。 - -语法示例: - -```python -def functionname( parameters ): - "函数_文档字符串" - function_suite - return [expression] -``` - -实例: - -1. def 定义一个函数,给定一个函数名 sum -2. 声明两个参数 num1 和 num2 -3. 函数的第一行语句进行函数说明:两数之和 -4. 最终 return 语句结束函数,并返回两数之和 - -```python -def sum(num1,num2): - "两数之和" - return num1+num2 - -# 调用函数 -print(sum(5,6)) -``` - -输出结果: - -```python -11 -``` \ No newline at end of file diff --git a/Article/python6/Preface.md b/Article/python6/Preface.md deleted file mode 100644 index f05ffefa..00000000 --- a/Article/python6/Preface.md +++ /dev/null @@ -1,7 +0,0 @@ -# 前言 # - -前天创了个 Python 微信讨论群,以为没人进的,哈哈,想不到还真有小伙伴进群学习讨论。如果想进群,可以加我微信: androidwed ,拉进群,就不贴微信群二维码了,一是会失效,二影响文章。 - -# 目录 # - -![草根学Python(六) 函数](http://upload-images.jianshu.io/upload_images/2136918-be9226fe109027f3?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) diff --git a/Article/python7/Preface.md b/Article/python7/Preface.md deleted file mode 100644 index 22583dc6..00000000 --- a/Article/python7/Preface.md +++ /dev/null @@ -1,7 +0,0 @@ -# 前言 # - -这篇博客写了很久,其实写每一篇博客用的时间还是挺长的,不够这有利于自己的学习,也想分享一下。之前也说了创建了一个微信群,Python 学习讨论群,现在只有 40 个左右的小伙伴,如果有兴趣加入学习讨论的话,可以加我微信:`androidwed`,拉你进群。想看回之前的文章,也可以通过 [Gitbook](https://www.gitbook.com/book/twowater/python/details) 查看,欢迎提出问题和点下 star,及时查看更新。 - -# 目录 # - -![草根学Python(七) 迭代器和生成器](http://upload-images.jianshu.io/upload_images/2136918-b350c0e98ca47183?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) diff --git a/Article/python8/1.md b/Article/python8/1.md deleted file mode 100644 index c193d42d..00000000 --- a/Article/python8/1.md +++ /dev/null @@ -1,21 +0,0 @@ -# 一、Python 模块简介 # - -在开发过程中,随着程序代码越写越多,在一个文件里代码就会越来越长,越来越不容易维护。 - -为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,这样,每个文件包含的代码就相对较少,很多编程语言都采用这种组织代码的方式。在 Python 中,一个 .py 文件就称之为一个模块(Module)。 - -之前我们学习过函数,知道函数是实现一项或多项功能的一段程序 。其实模块就是函数功能的扩展。为什么这么说呢?那是因为模块其实就是实现一项或多项功能的程序块。 - -通过上面的定义,不难发现,函数和模块都是用来实现功能的,只是模块的范围比函数广,在模块中,可以有多个函数。 - -既然了解了什么是模块了,那么为什么需要模块呢?既然有了函数,那为啥那需要模块? - -最大的好处是大大提高了代码的可维护性。其次,编写代码不必从零开始。当一个模块编写完毕,就可以被其他地方引用。我们在编写程序的时候,也经常引用其他模块,包括 Python 内置的模块和来自第三方的模块。 - -使用模块还可以避免函数名和变量名冲突。相同名字的函数和变量完全可以分别存在不同的模块中,因此,我们自己在编写模块时,不必考虑名字会与其他模块冲突。但是也要注意,尽量不要与内置函数名字冲突。 - -Python 本身就内置了很多非常有用的模块,只要安装完毕,这些模块就可以立刻使用。我们可以尝试找下这些模块,比如我的 Python 安装目录是默认的安装目录,在 C:\Users\Administrator\AppData\Local\Programs\Python\Python36 ,然后找到 Lib 目录,就可以发现里面全部都是模块,没错,这些 `.py` 文件就是模块了。 - -![python36bin目录](http://upload-images.jianshu.io/upload_images/2136918-5ecc6493206da1ec?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -其实模块可以分为标准库模块和自定义模块,而刚刚我们看到的 Lib 目录下的都是标准库模块。 diff --git a/Article/python9/2.md b/Article/python9/2.md deleted file mode 100644 index 6e7606c6..00000000 --- a/Article/python9/2.md +++ /dev/null @@ -1,117 +0,0 @@ -# 二、类 # - -## 1、定义类 ## - -类定义语法格式如下: - -```python -class ClassName: - - . - . - . - -``` - -一个类也是由属性和方法组成的,有些时候我们定义类的时候需要设置类的属性,因此这就需要构造函 - -类的构造函数如下: - -```python -def __init__(self,[...): -``` - -类定义了 __init__() 方法的话,类的实例化操作会自动调用 __init__() 方法。 - -那么如构造函数相对应的是析构函数,理所当然,一个类创建的时候我们可以用过构造函数设置属性,那么当一个类销毁的时候,就会调用析构函数。 - -析构函数语法如下: - -```python -def __del__(self,[...): -``` - -仔细观察的童鞋都会发现,类的方法与普通的函数有一个特别的区别,它们必须有一个额外的第一个参数名称, 按照惯例它的名称是 self。 - -那么这个 self 代表什么呢? - -我们可以看下实例,通过实例来找出答案: - -```python -#!/usr/bin/env python3 -# -*- coding: UTF-8 -*- - -class Test: - def prt(self): - print(self) - print(self.__class__) - -t = Test() -t.prt() -``` - -观察输出的结果: - -![Python self](http://upload-images.jianshu.io/upload_images/2136918-66d29b081ad5510b?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -从执行结果可以很明显的看出,self 代表的是类的实例,输出的是当前对象的地址,而 `self.__class__` 则指向类。 - -当然 self 不是 python 关键字,也就是说我们把他换成其他的字符也是可以正常执行的。只不过我们习惯使用 self - -## 2、Python 定义类的历史遗留问题 ## - -Python 在版本的迭代中,有一个关于类的历史遗留问题,就是新式类和旧式类的问题,具体先看以下的代码: - -```python -#!/usr/bin/env python -# -*- coding: UTF-8 -*- - -# 旧式类 -class OldClass: - pass - -# 新式类 -class NewClass(object): - pass - -``` - -可以看到,这里使用了两者中不同的方式定义类,可以看到最大的不同就是,新式类继承了`object` 类,在 Python2 中,我们定义类的时候最好定义新式类,当然在 Python3 中不存在这个问题了,因为 Python3 中所有类都是新式类。 - -那么新式类和旧式类有什么区别呢? - -运行下下面的那段代码: - -```python -#!/usr/bin/env python -# -*- coding: UTF-8 -*- - -# 旧式类 -class OldClass: - def __init__(self, account, name): - self.account = account; - self.name = name; - - -# 新式类 -class NewClass(object): - def __init__(self, account, name): - self.account = account; - self.name = name; - - -if __name__ == '__main__': - old_class = OldClass(111111, 'OldClass') - print(old_class) - print(type(old_class)) - print(dir(old_class)) - print('\n') - new_class=NewClass(222222,'NewClass') - print(new_class) - print(type(new_class)) - print(dir(new_class)) - -``` - - -仔细观察输出的结果,对比一下,就能观察出来,注意喔,Pyhton3 中输出的结果是一模一样的,因为Python3 中没有新式类旧式类的问题。 diff --git a/Article/python9/3.md b/Article/python9/3.md deleted file mode 100644 index 34a593e8..00000000 --- a/Article/python9/3.md +++ /dev/null @@ -1,64 +0,0 @@ -# 三、类的属性 # - -## 1、直接在类中定义属性 ## - -定义类的属性,当然最简单最直接的就是在类中定义,例如: - -```python -class UserInfo(object): - name='两点水' -``` - -## 2、在构造函数中定义属性 ## - -故名思议,就是在构造对象的时候,对属性进行定义。 - -```python -class UserInfo(object): - def __init__(self,name): - self.name=name -``` - -## 3、属性的访问控制 ## - -在 Java 中,有 public (公共)属性 和 private (私有)属性,这可以对属性进行访问控制。那么在 Python 中有没有属性的访问控制呢? - -一般情况下,我们会使用 `__private_attrs` 两个下划线开头,声明该属性为私有,不能在类地外部被使用或直接访问。在类内部的方法中使用时 `self.__private_attrs`。 - -为什么只能说一般情况下呢?因为实际上, Python 中是没有提供私有属性等功能的。但是 Python 对属性的访问控制是靠程序员自觉的。为什么这么说呢?看看下面的示例: - -![Python 属性访问控制](http://upload-images.jianshu.io/upload_images/2136918-4ac2643aa5b0fa37?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -仔细看图片,为什么说双下划线不是真正的私有属性呢?我们看下下面的例子,用下面的例子来验证: - -```python - -#!/usr/bin/env python -# -*- coding: UTF-8 -*- - -class UserInfo(object): - def __init__(self, name, age, account): - self.name = name - self._age = age - self.__account = account - - def get_account(self): - return self.__account - - -if __name__ == '__main__': - userInfo = UserInfo('两点水', 23, 347073565); - # 打印所有属性 - print(dir(userInfo)) - # 打印构造函数中的属性 - print(userInfo.__dict__) - print(userInfo.get_account()) - # 用于验证双下划线是否是真正的私有属性 - print(userInfo._UserInfo__account) - - -``` - -输出的结果如下图: - -![Python 属性访问控制](http://upload-images.jianshu.io/upload_images/2136918-de89d4dc5f5f9f77?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) diff --git a/Article/python9/Preface.md b/Article/python9/Preface.md deleted file mode 100644 index cc15f62c..00000000 --- a/Article/python9/Preface.md +++ /dev/null @@ -1,10 +0,0 @@ -# 前言 # - -这篇写的很纠结,不过还是写完了。弄了个很逊的公众号,如果对本文有兴趣,可以关注下公众号喔,会持续更新。 - - -![公众号](http://img.blog.csdn.net/20170730171715934?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvVHdvX1dhdGVy/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) - -# 目录 # - -![草根学Python(九)面向对象](http://upload-images.jianshu.io/upload_images/2136918-eecf427fdbd1688c?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) diff --git a/README.md b/README.md index 78f39ad6..6053629b 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ IT 行业相对于一般传统行业,发展更新速度更快,一旦停止 自学 Python ,也是一样,不要一开始因为头脑发热就不停地收藏各种资料网站,购买各种书籍,下载了大量的教学视频,过了几天,学习的热情开始褪去,再过几个星期,终于完成了学习课程 —— 《从入门到放弃》。所以,学习 Python 需要一步一个脚印,踏踏实实地学。 + # FQ 在讲 Python 如何入门之前,个人建议最好每个人都有自己的 FQ 工具,多使用 Google 搜索,多去看一下墙外的世界,多看 Github 上的开源项目。 @@ -11,6 +12,7 @@ IT 行业相对于一般传统行业,发展更新速度更快,一旦停止 至于如何 FQ ,这里提供一下我用过的工具:[FQ工具集](/Res/FQ.md) + # Python 学习资源集 相信很多人学习某门编程语言的时候,都会找各种学习资料。说句实话,资料太多,反而没用,根据自己的学习习惯,个人能力选择一门资源坚持学就好了。 @@ -19,6 +21,11 @@ IT 行业相对于一般传统行业,发展更新速度更快,一旦停止 * [Python 博客网站资源](/Res/Python博客网站资源.md) +还有一些有趣的网站: + +* [一个可以看执行过程的网站](http://www.pythontutor.com/visualize.html#mode=edit) + + # Python 入门 @@ -57,74 +64,89 @@ IT 行业相对于一般传统行业,发展更新速度更快,一旦停止 - [条件语句](/Article/PythonBasis/python5/If.md) - [循环语句](/Article/PythonBasis/python5/Cycle.md) - [条件语句和循环语句综合实例](/Article/PythonBasis/python5/Example.md) -* [函数](/Article/python6/Preface.md) - - [Python 自定义函数的基本步骤](/Article/python6/1.md) - - [函数传值问题](/Article/python6/2.md) - - [函数返回值](/Article/python6/3.md) - - [函数的参数](/Article/python6/4.md) - - [匿名函数](/Article/python6/5.md) -* [迭代器和生成器](/Article/python7/Preface.md) - - [迭代](/Article/python7/1.md) - - [Python 迭代器](/Article/python7/2.md) - - [lsit 生成式(列表生成式)](/Article/python7/3.md) - - [生成器](/Article/python7/4.md) - - [迭代器和生成器综合例子](/Article/python7/5.md) -* [模块与包](/Article/python8/Preface.md) - - [Python 模块简介](/Article/python8/1.md) - - [模块的使用](/Article/python8/2.md) - - [主模块和非主模块](/Article/python8/3.md) - - [包](/Article/python8/4.md) - - [作用域](/Article/python8/5.md) -* [面向对象](/Article/python9/Preface.md) - - [面向对象的概念](/Article/python9/1.md) - - [类](/Article/python9/2.md) - - [类的属性](/Article/python9/3.md) - - [类的方法](/Article/python9/4.md) - - [类的继承](/Article/python9/5.md) - - [类的多态](/Article/python9/6.md) -* [Python 的 Magic Method](/Article/python10/Preface.md) - - [Python 的 Magic Method](/Article/python10/1.md) - - [构造(`__new__`)和初始化(`__init__`)](/Article/python10/2.md) - - [属性的访问控制](/Article/python10/3.md) - - [对象的描述器](/Article/python10/4.md) - - [自定义容器(Container)](/Article/python10/5.md) - - [运算符相关的魔术方法](/Article/python10/6.md) -* [枚举类](/Article/python11/Preface.md) - - [枚举类的使用](/Article/python11/1.md) - - [Enum 的源码](/Article/python11/2.md) - - [自定义类型的枚举](/Article/python11/3.md) - - [枚举的比较](/Article/python11/4.md) -* [元类](/Article/python12/Preface.md) - - [Python 中类也是对象](/Article/python12/1.md) - - [使用 `type()` 动态创建类](/Article/python12/2.md) - - [什么是元类](/Article/python12/3.md) - - [自定义元类](/Article/python12/4.md) - - [使用元类](/Article/python12/5.md) -* [线程与进程](/Article/python13/Preface.md) - - [线程与进程](/Article/python13/1.md) - - [多线程编程](/Article/python13/2.md) - - [进程](/Article/python13/3.md) -* [一步一步了解正则表达式](/Article/python14/Preface.md) - - [初识 Python 正则表达式](/Article/python14/1.md) - - [字符集](/Article/python14/2.md) - - [数量词](/Article/python14/3.md) - - [边界匹配符和组](/Article/python14/4.md) - - [re.sub](/Article/python14/5.md) - - [re.match 和 re.search](/Article/python14/6.md) -* [闭包](/Article/python15/1.md) -* [装饰器](/Article/python16/1.md) +* [函数](/Article/PythonBasis/python6/Preface.md) + - [Python 自定义函数的基本步骤](/Article/PythonBasis/python6/1.md) + - [函数返回值](/Article/PythonBasis/python6/2.md) + - [函数的参数](/Article/PythonBasis/python6/3.md) + - [函数传值问题](/Article/PythonBasis/python6/4.md) + - [匿名函数](/Article/PythonBasis/python6/5.md) +* [迭代器和生成器](/Article/PythonBasis/python7/Preface.md) + - [迭代](/Article/PythonBasis/python7/1.md) + - [Python 迭代器](/Article/PythonBasis/python7/2.md) + - [list 生成式(列表生成式)](/Article/PythonBasis/python7/3.md) + - [生成器](/Article/PythonBasis/python7/4.md) + - [迭代器和生成器综合例子](/Article/PythonBasis/python7/5.md) +* [面向对象](/Article/PythonBasis/python8/Preface.md) + - [面向对象的概念](/Article/PythonBasis/python8/1.md) + - [类的定义和调用](/Article/PythonBasis/python8/2.md) + - [类方法](/Article/PythonBasis/python8/3.md) + - [修改和增加类属性](/Article/PythonBasis/python8/4.md) + - [类和对象](/Article/PythonBasis/python8/5.md) + - [初始化函数](/Article/PythonBasis/python8/6.md) + - [类的继承](/Article/PythonBasis/python8/7.md) + - [类的多态](/Article/PythonBasis/python8/8.md) + - [类的访问控制](/Article/PythonBasis/python8/9.md) +* [模块与包](/Article/PythonBasis/python9/Preface.md) + - [Python 模块简介](/Article/PythonBasis/python9/1.md) + - [模块的使用](/Article/PythonBasis/python9/2.md) + - [主模块和非主模块](/Article/PythonBasis/python9/3.md) + - [包](/Article/PythonBasis/python9/4.md) + - [作用域](/Article/PythonBasis/python9/5.md) +* [Python 的 Magic Method](/Article/PythonBasis/python10/Preface.md) + - [Python 的 Magic Method](/Article/PythonBasis/python10/1.md) + - [构造(`__new__`)和初始化(`__init__`)](/Article/PythonBasis/python10/2.md) + - [属性的访问控制](/Article/PythonBasis/python10/3.md) + - [对象的描述器](/Article/PythonBasis/python10/4.md) + - [自定义容器(Container)](/Article/PythonBasis/python10/5.md) + - [运算符相关的魔术方法](/Article/PythonBasis/python10/6.md) +* [枚举类](/Article/python11/PythonBasis/Preface.md) + - [枚举类的使用](/Article/PythonBasis/python11/1.md) + - [Enum 的源码](/Article/PythonBasis/python11/2.md) + - [自定义类型的枚举](/Article/PythonBasis/python11/3.md) + - [枚举的比较](/Article/PythonBasis/python11/4.md) +* [元类](/Article/PythonBasis/python12/Preface.md) + - [Python 中类也是对象](/Article/PythonBasis/python12/1.md) + - [使用 `type()` 动态创建类](/Article/PythonBasis/python12/2.md) + - [什么是元类](/Article/PythonBasis/python12/3.md) + - [自定义元类](/Article/PythonBasis/python12/4.md) + - [使用元类](/Article/PythonBasis/python12/5.md) +* [线程与进程](/Article/PythonBasis/python13/Preface.md) + - [线程与进程](/Article/PythonBasis/python13/1.md) + - [多线程编程](/Article/PythonBasis/python13/2.md) + - [进程](/Article/PythonBasis/python13/3.md) +* [一步一步了解正则表达式](/Article/PythonBasis/python14/Preface.md) + - [初识 Python 正则表达式](/Article/PythonBasis/python14/1.md) + - [字符集](/Article/PythonBasis/python14/2.md) + - [数量词](/Article/PythonBasis/python14/3.md) + - [边界匹配符和组](/Article/PythonBasis/python14/4.md) + - [re.sub](/Article/PythonBasis/python14/5.md) + - [re.match 和 re.search](/Article/PythonBasis/python14/6.md) +* [闭包](/Article/PythonBasis/python15/1.md) +* [装饰器](/Article/PythonBasis/python16/1.md) + + # 知识点补漏 * [Python 关键字 yield](/Article/supplement/Python关键字yield.md) + # Python 进阶 * [使用Python虚拟环境](/Article/advanced/使用Python虚拟环境.md) * [Mac中使用virtualenv和virtualenvwrapper](/Article/advanced/Mac中使用virtualenv和virtualenvwrapper.md) + + +# HTML 和 CSS 入门 + + +# JavaScript 入门 + + + # Django Python 下有许多款不同的 Web 框架。Django 是重量级选手中最有代表性的一位。许多成功的网站和 APP 都基于 Django。 @@ -134,12 +156,14 @@ Python 下有许多款不同的 Web 框架。Django 是重量级选手中最有 * [一个完整的初学者指南Django-part1](/Article/django/一个完整的初学者指南Django-part1.md) * [一个完整的初学者指南Django-part2](/Article/django/一个完整的初学者指南Django-part2.md) -后面经一个朋友说,这个教程已经有人在翻译了,因此我也不翻译了,不过感觉我的翻译还是挺好的,因为不是直译的,是通过了解后,用自己的语言再次表达出来。 -这里有上面这个教程翻译计划的 [Github](https://github.com/wzhbingo/django-beginners-guide) 以及 [博客](https://www.cloudcrossing.xyz/post/20/),觉得哪个看得舒服,就选哪个进行学习。 +持续更新.... +可以关注我的公众号,实时了解更新情况。 + + + -持续更新.... diff --git a/Res/FQ.md b/Res/FQ.md index 6076951a..24cb613a 100644 --- a/Res/FQ.md +++ b/Res/FQ.md @@ -22,6 +22,7 @@ 当然,最好的还是自己能搭建 ss/ssr 服务器,这里有个适合初学者的教程。 - 传送门:[教程地址](https://github.com/getlantern/forum/issues/5620) + 传送门:[教程地址](../Res/自己搭建ss:ssr服务器.md) + diff --git "a/Res/\350\207\252\345\267\261\346\220\255\345\273\272ss:ssr\346\234\215\345\212\241\345\231\250.md" "b/Res/\350\207\252\345\267\261\346\220\255\345\273\272ss:ssr\346\234\215\345\212\241\345\231\250.md" new file mode 100644 index 00000000..efb5e017 --- /dev/null +++ "b/Res/\350\207\252\345\267\261\346\220\255\345\273\272ss:ssr\346\234\215\345\212\241\345\231\250.md" @@ -0,0 +1,293 @@ +# 客户端下载 + +第一次电脑系统使用SSR/SS客户端时,需要安装NET Framework 4.0,不然无法正常使用,[微软官网下载](https://www.microsoft.com/zh-cn/download/details.aspx?id=17718)。 + +NET Framework 4.0是SSR/SS的运行库,没有这个SSR/SS客户端无法正常运行。有的电脑系统可能会自带NET Framework 4.0。 + +* Windows SSR客户端 [下载地址](https://github.com/shadowsocksr-backup/shadowsocksr-csharp/releases) [备用下载地址](https://nofile.io/f/6Jm7WJCyOVv/ShadowsocksR-4.7.0-win.7z) + +* MAC SSR客户端 [下载地址](https://github.com/shadowsocksr-backup/ShadowsocksX-NG/releases) [备用下载地址](https://nofile.io/f/jgMWFwCBonU#ab0d3c3b6ac54482) + +* Linux客户端一键安装配置 [使用脚本](https://github.com/the0demiurge/CharlesScripts/blob/master/charles/bin/ssr) (使用方法见注释) 或者采用图形界面的[linux ssr客户端](https://github.com/erguotou520/electron-ssr/releases) + +* 安卓 SSR客户端 [下载地址](https://github.com/shadowsocksr-backup/shadowsocksr-android/releases) [备用下载地址](https://nofile.io/f/rvTJoj0h5GC/shadowsocksr-release.apk) + +* 苹果手机SSR客户端:Potatso Lite、Potatso、shadowrocket都可以作为SSR客户端,但这些软件目前已经在国内的app商店下架,可以用美区的appid账号来下载。但是,如果你配置的SSR账号兼容SS客户端,或者协议选择origin且混淆选择plain,那么你可以选择苹果SS客户端软件(即协议和混淆可以不填),APP商店里面有很多,比如:openwingy、superwingy、bestwingy、wingy+、greatwingy等。 + +**有了客户端后我们需要自己搭建服务器创建ss/ssr账号才能翻墙。提供ss/ssr免费账号 有需求的人可以使用。** + +# 搭建教程 + +### 为什么不怕被封ip?因为vultr可以随时删除和创建服务器,新服务器就是新的ip,所以不怕被封ip。 + + +**教程很简单,整个教程分三步:** + +第一步:购买VPS服务器 + +第二步:一键部署VPS服务器 + +第三步:一键加速VPS服务器 (谷歌BBR加速,推荐) + +* * * + +**第一步:购买VPS服务器** + +VPS服务器需要选择国外的,首选国际知名的vultr,速度不错、稳定且性价比高,按小时计费,能够随时开通和删除服务器,新服务器即是新ip。 + +vultr注册地址: [http://www.vultr.com/?ref=7048874](http://www.vultr.com/?ref=7048874) (全球15个服务器位置可选,KVM框架,最低2.5美元/月) + +[![img](https://camo.githubusercontent.com/e5b4fc7834baffafe9883ac40cc7f296e62f9741/68747470733a2f2f7777772e76756c74722e636f6d2f6d656469612f62616e6e65725f322e706e67)](https://www.vultr.com/?ref=7048874) + +虽然是英文界面,但是现在的浏览器都有网页翻译功能,鼠标点击右键,选择网页翻译即可翻译成中文。 + +注册并邮件激活账号,充值后即可购买服务器。充值方式是paypal(首选)或支付宝,使用paypal有银行卡(包括信用卡)即可。paypal注册地址:[https://www.paypal.com](https://www.paypal.com/) (paypal是国际知名的第三方支付服务商,注册一下账号,绑定银行卡即可购买国外商品) + +2.5美元/月的服务器配置信息:单核 512M内存 20G SSD硬盘 带宽峰值100M 500G流量/月 + +5美元/月的服务器配置信息: 单核 1G内存 25G SSD硬盘 带宽峰值100M 1000G流量/月 + +10美元/月的服务器配置信息: 单核 2G内存 40G SSD硬盘 带宽峰值100M 2000G流量/月 + +20美元/月的服务器配置信息: 2cpu 4G内存 60G SSD硬盘 带宽峰值100M 3000G流量/月 + +40美元/月的服务器配置信息: 4cpu 8G内存 100G SSD硬盘 带宽峰值100M 4000G流量/月 + +**vultr实际上是折算成小时来计费的,比如服务器是5美元1个月,那么每小时收费为5/30/24=0.0069美元 会自动从账号中扣费,只要保证账号有钱即可。如果你部署的服务器实测后速度不理想,你可以把它删掉(destroy),重新换个地区的服务器来部署,方便且实用。因为新的服务器就是新的ip,所以当ip被墙时这个方法很有用。当ip被墙时,为了保证新开的服务器ip和原先的ip不一样,先开新服务器,开好后再删除旧服务器即可。** + +计费从你开通服务器开始算的,不管你有没有使用,即使服务器处于关机状态仍然会计费,如果你没有开通服务器就不算。比如你今天早上开通了服务器,但你有事情,晚上才部署,那么这段时间是会计费的。同理,如果你早上删掉服务器,第二天才开通新的服务器,那么这段时间是不会计费的。在账号的Billing选项里可以看到账户余额。 + +温馨提醒:同样的服务器位置,不同的宽带类型和地区所搭建的账号的翻墙速度会不同,这与中国电信、中国联通、中国移动国际出口带宽和线路不同有关,所以以实测为准。可以先选定一个服务器位置来按照教程进行搭建,熟悉搭建方法,当账号搭建完成并进行了bbr加速后,测试下速度自己是否满意,如果满意那就用这个服务器位置的服务器。如果速度不太满意,就一次性开几台不同的服务器位置的服务器,然后按照同样的方法来进行搭建并测试,选择最优的,之后把其它的服务器删掉,按小时计费测试成本可以忽略。 + +如图: + +[![img](https://raw.githubusercontent.com/Alvin9999/pac2/master/pp100.png)](https://raw.githubusercontent.com/Alvin9999/pac2/master/pp100.png) + +[![img](https://raw.githubusercontent.com/Alvin9999/pac2/master/pp101.png)](https://raw.githubusercontent.com/Alvin9999/pac2/master/pp101.png) + +**vps服务器系统推荐选择CentOS 6.X64位的系统(系统版本不要选centos7!centos7默认的防火墙会阻止ssr的正常连接!)。完成购买后,找到系统的密码记下来,部署服务器时需要用到。** + +如图: +[![img](https://raw.githubusercontent.com/Alvin9999/crp_up/master/pac%E6%95%99%E7%A8%8B01.png)](https://raw.githubusercontent.com/Alvin9999/crp_up/master/pac%E6%95%99%E7%A8%8B01.png) + +[![img](https://raw.githubusercontent.com/Alvin9999/crp_up/master/pac%E6%95%99%E7%A8%8B02.png)](https://raw.githubusercontent.com/Alvin9999/crp_up/master/pac%E6%95%99%E7%A8%8B02.png) + +[![img](https://raw.githubusercontent.com/Alvin9999/crp_up/master/pac%E6%95%99%E7%A8%8B04.png)](https://raw.githubusercontent.com/Alvin9999/crp_up/master/pac%E6%95%99%E7%A8%8B04.png) + +**不要选centos7系统!点击图中的CentOS几个字,会弹出centos6,然后选中centos6!entos7默认的防火墙可能会干扰ssr的正常连接!** + +> 接下来这一步是开启vps的ipv6 ip,选填项。如果你的电脑系统可以用ipv6,那么可以勾选此项。大多数用户没有这个需求,但有一些用户可能会用到,所以补充了这部分内容。 + +[![img](https://raw.githubusercontent.com/Alvin9999/PAC/master/ss/ssripv6-01.png)](https://raw.githubusercontent.com/Alvin9999/PAC/master/ss/ssripv6-01.png) + +[![img](https://raw.githubusercontent.com/Alvin9999/crp_up/master/pac%E6%95%99%E7%A8%8B05.png)](https://raw.githubusercontent.com/Alvin9999/crp_up/master/pac%E6%95%99%E7%A8%8B05.png) + +[![img](https://raw.githubusercontent.com/Alvin9999/crp_up/master/pac%E6%95%99%E7%A8%8B06.png)](https://raw.githubusercontent.com/Alvin9999/crp_up/master/pac%E6%95%99%E7%A8%8B06.png) + +> 如果你开启了vps的ipv6,那么在后台的settings选项可以找到服务器的ipv6 ip。在部署SSR账号时,你用ipv6 ip就行。整个部署及使用过程中,记得把电脑系统开启ipv6喔。 + +[![img](https://raw.githubusercontent.com/Alvin9999/PAC/master/ss/ssripv6-02.png)](https://raw.githubusercontent.com/Alvin9999/PAC/master/ss/ssripv6-02.png) + +* * * + +**第二步:部署VPS服务器** + +购买服务器后,需要部署一下。因为你买的是虚拟东西,而且又远在国外,我们需要一个叫Xshell的软件来远程部署。Xshell windows版下载地址: + +[国外云盘1下载](http://45.32.141.248:8000/f/d91974d046/) + +[国外云盘2下载](https://nofile.io/f/eb5dUzYMQK4/Xshell_setup_wm.exe) 提取密码:666 + +[国外云盘3下载](https://www.adrive.com/public/NdK3Ez/Xshell_setup_wm.exe) 密码:123 + +如果你是苹果电脑操作系统,更简单,无需下载xshell,系统可以直接连接VPS。打开**终端**(Terminal),输入ssh root@ip 其中“ip”替换成你VPS的ip, 按回车键,然后复制粘贴密码,按回车键即可登录。粘贴密码时有可能不显示密码,但不影响, [参考设置方法](http://www.cnblogs.com/ghj1976/archive/2013/04/19/3030159.html) 如果不能用MAC自带的终端连接的话,直接网上搜“MAC连接SSH的软件”,有很多,然后通过软件来连接vps服务器就行,具体操作方式参考windows xshell。 + +* * * + +部署教程: + +下载xshell软件并安装后,打开软件 + +[![img](https://raw.githubusercontent.com/Alvin9999/PAC/master/xshell11.png)](https://raw.githubusercontent.com/Alvin9999/PAC/master/xshell11.png) + +选择文件,新建 + +[![img](https://raw.githubusercontent.com/Alvin9999/PAC/master/xshell12.png)](https://raw.githubusercontent.com/Alvin9999/PAC/master/xshell12.png) + +随便取个名字,然后把你的服务器ip填上 + +[![img](https://raw.githubusercontent.com/Alvin9999/PAC/master/xshell13.png)](https://raw.githubusercontent.com/Alvin9999/PAC/master/xshell13.png) + +连接国外ip即服务器时,软件会先后提醒你输入用户名和密码,用户名linux系统默认都是root,密码是购买服务器后的cent系统的密码。 + +**如果开好了服务器,发现xshell死活连不上,多半是开的服务器ip被墙了,遇到这种情况,把服务器删掉,重新开个新的服务器即可,可以是同地区的也可以选择其它地区。** + +[![img](https://raw.githubusercontent.com/Alvin9999/PAC/master/xshell14.png)](https://raw.githubusercontent.com/Alvin9999/PAC/master/xshell14.png) + +[![img](https://raw.githubusercontent.com/Alvin9999/PAC/master/ss/xshell2.png)](https://raw.githubusercontent.com/Alvin9999/PAC/master/ss/xshell2.png) + +连接成功后,会出现如上图所示,之后就可以复制粘贴代码部署了。 + +CentOS6/Debian6/Ubuntu14 ShadowsocksR一键部署管理脚本: + +* * * + +yum -y install wget + +wget -N –no-check-certificate [https://softs.fun/Bash/ssr.sh](https://softs.fun/Bash/ssr.sh) && chmod +x ssr.sh && bash ssr.sh + +备用脚本: + +yum -y install wget + +wget -N –no-check-certificate [https://raw.githubusercontent.com/ToyoDAdoubi/doubi/master/ssr.sh](https://raw.githubusercontent.com/ToyoDAdoubi/doubi/master/ssr.sh) && chmod +x ssr.sh && bash ssr.sh + +———————————————————代码分割线———————————————— + +复制上面的代码到VPS服务器里,按回车键,脚本会自动安装,以后只需要运行这个快捷命令就可以出现下图的界面进行设置,快捷管理命令为:bash ssr.sh + +[![img](https://raw.githubusercontent.com/Alvin9999/PAC/master/ss/8.png)](https://raw.githubusercontent.com/Alvin9999/PAC/master/ss/8.png) + +如上图出现管理界面后,**输入数字1来安装SSR服务端**。如果输入1后不能进入下一步,那么请退出xshell,重新连接vps服务器,然后输入快捷管理命令bash ssr.sh 再尝试。 + +[![img](https://raw.githubusercontent.com/Alvin9999/PAC/master/demo/31.png)](https://raw.githubusercontent.com/Alvin9999/PAC/master/demo/31.png) + +根据上图提示,依次输入自己想设置的**端口和密码** (**密码建议用复杂点的字母组合,端口号为1-65535之间的数字**),回车键用于确认 + +[![img](https://raw.githubusercontent.com/Alvin9999/PAC/master/demo/32.png)](https://raw.githubusercontent.com/Alvin9999/PAC/master/demo/32.png) + +如上图,选择想设置的**加密方式**,比如10,按回车键确认 + +接下来是选择**协议插件**,如下图: + +[![img](https://raw.githubusercontent.com/Alvin9999/PAC/master/ss/11.png)](https://raw.githubusercontent.com/Alvin9999/PAC/master/ss/11.png) + +[![img](https://raw.githubusercontent.com/Alvin9999/PAC/master/demo/41.PNG)](https://raw.githubusercontent.com/Alvin9999/PAC/master/demo/41.PNG) + +选择并确认后,会出现上图的界面,提示你是否选择兼容原版,这里的原版指的是SS客户端(SS客户端没有协议和混淆的选项),可以根据需求进行选择,演示选择y + +之后进行混淆插件的设置。 +**注意:有的地区需要把混淆设置成plain才好用。因为混淆不总是有效果,要看各地区的策略,有时候不混淆(plain)让其看起来像随机数据更好。(注意:tls 1.2_ticket_auth容易受到干扰!请选择除tls开头以外的其它混淆!!!)** + +[![img](https://raw.githubusercontent.com/Alvin9999/PAC/master/demo/33.png)](https://raw.githubusercontent.com/Alvin9999/PAC/master/demo/33.png) + +进行混淆插件的设置后,会依次提示你对设备数、单线程限速和端口总限速进行设置,默认值是不进行限制,个人使用的话,选择默认即可,即直接敲回车键。 + +[![img](https://raw.githubusercontent.com/Alvin9999/PAC/master/ss/14.png)](https://raw.githubusercontent.com/Alvin9999/PAC/master/ss/14.png) + +之后代码就正式自动部署了,到下图所示的位置,提示你下载文件,输入:y + +[![img](https://raw.githubusercontent.com/Alvin9999/PAC/master/ss/15.png)](https://raw.githubusercontent.com/Alvin9999/PAC/master/ss/15.png) + +耐心等待一会,出现下面的界面即部署完成: + +[![img](https://raw.githubusercontent.com/Alvin9999/PAC/master/ss/16.png)](https://raw.githubusercontent.com/Alvin9999/PAC/master/ss/16.png) + +[![img](https://raw.githubusercontent.com/Alvin9999/PAC/master/demo/34.png)](https://raw.githubusercontent.com/Alvin9999/PAC/master/demo/34.png) + +根据上图就可以看到自己设置的SSR账号信息,包括IP、端口、密码、加密方式、协议插件、混淆插件,这些信息需要填入你的SSR客户端。如果之后想修改账号信息,直接输入快捷管理命令:bash ssr.sh 进入管理界面,选择相应的数字来进行一键修改。例如: + +[![img](https://raw.githubusercontent.com/Alvin9999/PAC/master/ss/22.png)](https://raw.githubusercontent.com/Alvin9999/PAC/master/ss/22.png) + +[![img](https://raw.githubusercontent.com/Alvin9999/PAC/master/ss/23.png)](https://raw.githubusercontent.com/Alvin9999/PAC/master/ss/23.png) + +**脚本演示结束。** + +此脚本是开机自动启动,部署一次即可。最后可以重启服务器确保部署生效(一般情况不重启也可以)。重启需要在命令栏里输入reboot ,输入命令后稍微等待一会服务器就会自动重启,一般重启过程需要2~5分钟,重启过程中Xshell会自动断开连接,等VPS重启好后才可以用Xshell软件进行连接。如果部署过程中卡在某个位置超过10分钟,可以用xshell软件断开,然后重新连接你的ip,再复制代码进行部署。 + +* * * + +**第三步:一键加速VPS服务器** + +此加速教程为谷歌BBR加速,Vultr的服务器框架可以装BBR加速,加速后对速度的提升很明显,所以推荐部署加速脚本。该加速方法是开机自动启动,部署一次就可以了。 + +按照第二步的步骤,连接服务器ip,登录成功后,在命令栏里粘贴以下代码: + +【谷歌BBR加速教程】 + +yum -y install wget + +wget –no-check-certificate [https://github.com/teddysun/across/raw/master/bbr.sh](https://github.com/teddysun/across/raw/master/bbr.sh) + +chmod +x bbr.sh + +./bbr.sh + +把上面整个代码复制后粘贴进去,不动的时候按回车,然后耐心等待,最后重启vps服务器即可。 + +演示开始,如图: + +复制并粘贴代码后,按回车键确认 + +[![img](https://raw.githubusercontent.com/Alvin9999/PAC/master/ss/18.png)](https://raw.githubusercontent.com/Alvin9999/PAC/master/ss/18.png) + +如下图提示,按任意键继续部署 + +[![img](https://raw.githubusercontent.com/Alvin9999/PAC/master/ss/19.png)](https://raw.githubusercontent.com/Alvin9999/PAC/master/ss/19.png) + +[![img](https://raw.githubusercontent.com/Alvin9999/PAC/master/ss/20.png)](https://raw.githubusercontent.com/Alvin9999/PAC/master/ss/20.png) + +部署到上图这个位置的时候,等待3~6分钟 + +[![img](https://raw.githubusercontent.com/Alvin9999/PAC/master/ss/21.png)](https://raw.githubusercontent.com/Alvin9999/PAC/master/ss/21.png) + +最后输入y重启服务器,如果输入y提示command not found ,接着输入reboot来重启服务器,确保加速生效,bbr加速脚本是开机自动启动,装一次就可以了。 + +* * * + +购买vps服务器后,ip有了,通过部署,端口、密码、加密方式、协议和混淆也有了,最后将这些信息填入SSR客户端就可以翻墙啦。 + +**有了账号后,打开SSR客户端,填上信息,这里以windows版的SSR客户端为例子**: +[![img](https://raw.githubusercontent.com/Alvin9999/PAC/master/demo/42.PNG)](https://raw.githubusercontent.com/Alvin9999/PAC/master/demo/42.PNG) + +在对应的位置,填上服务器ip、服务器端口、密码、加密方式、协议和混淆,最后将浏览器的代理设置为(http)127.0.0.1和1080即可。账号的端口号就是你自己设置的,而要上网的浏览器的端口号是1080,固定的,谷歌浏览器可以通过 SwitchyOmega 插件来设置。 + +启动SSR客户端后,右键SSR客户端图标,选择第一个“系统代理模式”,里面有3个子选项,选择”全局模式“,之后就可以用浏览器设置好了的代理模式(http)127.0.0.1和1080翻墙,此模式下所有的网站都会走SSR代理。(适合新手) + +[![ssr9000](https://user-images.githubusercontent.com/12132898/32225069-cfe6195a-be7e-11e7-99e0-e2fa98f93b1f.png)](https://user-images.githubusercontent.com/12132898/32225069-cfe6195a-be7e-11e7-99e0-e2fa98f93b1f.png) + +* * * + +**常见问题参考解决方法**: + +1、用了一段时间发现ssr账号用不了了 + +首先ping一下自己的ip,看看能不能ping的通,ping不通那么就是ip被墙了,ip被墙时,xshell也会连接不上服务器,遇到这种情况重新部署一个新的服务器,新的服务器就是新的ip。关于怎么ping ip的方法,可以自行网上搜索,或者用xshell软件连接服务器来判断,连不上即是被墙了。vultr开通和删除服务器非常方便,新服务器即新ip,大多数vps服务商都没有这样的服务,一般的vps服务商可能会提供免费更换1次ip的服务。 + +2、刚搭建好的ssr账号,ip能ping通,但是还是用不了 + +首选排除杀毒软件的干扰,尤其是国产杀毒软件,比如360安全卫生、360杀毒软件、腾讯管家、金山卫生等。这些东西很容易干扰翻墙上网,如果你的电脑安装了这样的东西,建议至少翻墙时别用,最好卸载。其次,检查下SSR信息是否填写正确。浏览器的代理方式是否是ssr代理,即(HTTP)127.0.0.1 和1080。如果以上条件都排除,还是用不了,那么可以更换端口、加密方式、协议、混淆,或者更换服务器位置。另外,如果你的vps服务器配置的是SSR账号,即有协议和混淆且没有兼容原版(SS版),那么你必须使用SSSR客户端来使用账号,因为SS客户端没有填写协议和混淆的选项。 + +3、有的地区需要把混淆参数设置成plain才好用。因为混淆不总是有效果,要看各地区的策略,有时候不混淆(plain)让其看起来像随机数据更好。 + +4、电脑能用但手机用不了 + +如果你的手机用的是SS客户端,SS客户端没有填协议和混淆的地方,如果你部署的协议和混淆的时候没有选择兼容原版(SS版),因此手机是用不了的。这个时候你把协议弄成兼容原版、混淆也设置成兼容原版即可。或者直接将协议设置成origin,混淆设置成plain。 + +5、vps的服务器操作系统不要用的太高,太高可能会因为系统的防火墙问题导致搭建的SSR账号连不上,如果你用的centos系统,建议用centos6,不要用centos7。如果你前面不小心装了centos7系统,那么只能重装系统或者重新部署新的vps服务器。 + +6、vultr服务商提供的vps服务器是单向流量计算,有的vps服务商是双向流量计算,单向流量计算对于用户来说更实惠。因为我们是在vps服务器上部署SSR服务端后,再用SSR客户端翻墙,所以SSR服务端就相当于中转,比如我们看一个视频,必然会产生流量,假如消耗流量80M,那么VPS服务器会产生上传80M和下载80M流量,vultr服务商只计算单向的80M流量。如果是双向计算流量,那么会计算为160M流量。 + +7、如果你想把搭建的账号给多人使用,不用额外设置端口,因为一个账号就可以多人使用。一般10美元的服务器可以同时支持100人在线使用。 + +如果想实现支持每个用户(端口)不同的加密方式/协议/混淆等,并且管理流量使用,可以参考多用户配置脚本:wget -N –no-check-certificate [https://softs.fun/Bash/ssrmu.sh](https://softs.fun/Bash/ssrmu.sh) && chmod +x ssrmu.sh && bash ssrmu.sh 备用脚本:wget -N –no-check-certificate [https://raw.githubusercontent.com/ToyoDAdoubi/doubi/master/ssrmu.sh](https://raw.githubusercontent.com/ToyoDAdoubi/doubi/master/ssrmu.sh) && chmod +x ssrmu.sh && bash ssrmu.sh 安装后管理命令为:bash ssrmu.sh +注意:这个多用户配置脚本和教程内容的脚本无法共存!要想用这个脚本,把之前的脚本卸载,输入管理命令bash ssr.sh ,选择3,卸载ShadowsocksR即可卸载原脚本。 + +8、vultr服务器每月有流量限制,超过限制后服务器不会被停止运行,但是超出的流量会被额外收费。北美和西欧地区的服务器超出流量后,多出的部分收费为0.01美元/G。新加坡和日本东京(日本)为0.025美元/G,悉尼(澳大利亚)为0.05美元/G。把vultr服务器删掉,开通新的服务器,流量会从0开始重新计算。 + +9、vultr怎样才能申请退款呢? + +vultr和其他的国外商家一样,都是使用工单的形式与客服联系,如果需要退款,直接在后台点击support,选择open ticket新开一个工单,选择billing question财务问题,简单的在文本框输入你的退款理由。比如:Please refund all the balance in my account。工单提交以后一般很快就可以给你确认退款,若干个工作日后就会退回你的支付方式。(全额退款结束后,账号可能会被删除) + +如果英语水平不好,但是想和客服进行交流,可以用百度在线翻译,自动中文转英文和英文转中文。 + +10、路由器也可以配置ssr,关键的是路由器刷固件,华硕路由器刷梅林改版固件最简单,下载固件直接刷,梅林改版固件自带软件中心,然后再软件中心点离线安装就可以了(原版梅林不带软件中心 [下载](http://asuswrt.lostrealm.ca/download))。路由器刷merlin_8wan_firmware(八万)的固件就行[KoolShare固件下载](http://firmware.koolshare.cn/) +其他的路由器也可以刷梅林。有问题或者对路由器配置ssr感兴趣的,可以在这些网站上自学:[koolshare](http://koolshare.cn/forum.php) [华硕路由爱好者社区](http://www.52asus.com/forum.php) [NAP6](https://nap6.com/portal.php) + +* * * + +>转接自:https://github.com/getlantern/forum/issues/5620 +原出处也已经被删除了 + + + diff --git a/SUMMARY.md b/SUMMARY.md index d3ea42d8..501d1e0b 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -12,7 +12,7 @@ - [集成开发环境(IDE): PyCharm](/Article/PythonBasis/python1/IDE.md) * [基本数据类型和变量](/Article/PythonBasis/python2/Preface.md) - [Python 语法的简要说明](/Article/PythonBasis/python2/Grammar.md) - - [print() 函数](/Article/PythonBasis/python2/print.md) + - [print() 函数](/Article/PythonBasis/python2/print.md) - [Python 的基本数据类型](/Article/PythonBasis/python2/Type_of_data.md) - [字符串的编码问题](/Article/PythonBasis/python2/StringCoding.md) - [基本数据类型转换](/Article/PythonBasis/python2/Type_conversion.md) @@ -27,62 +27,65 @@ - [条件语句](/Article/PythonBasis/python5/If.md) - [循环语句](/Article/PythonBasis/python5/Cycle.md) - [条件语句和循环语句综合实例](/Article/PythonBasis/python5/Example.md) -* [函数](/Article/python6/Preface.md) - - [Python 自定义函数的基本步骤](/Article/python6/1.md) - - [函数传值问题](/Article/python6/2.md) - - [函数返回值](/Article/python6/3.md) - - [函数的参数](/Article/python6/4.md) - - [匿名函数](/Article/python6/5.md) -* [迭代器和生成器](/Article/python7/Preface.md) - - [迭代](/Article/python7/1.md) - - [Python 迭代器](/Article/python7/2.md) - - [lsit 生成式(列表生成式)](/Article/python7/3.md) - - [生成器](/Article/python7/4.md) - - [迭代器和生成器综合例子](/Article/python7/5.md) -* [模块与包](/Article/python8/Preface.md) - - [Python 模块简介](/Article/python8/1.md) - - [模块的使用](/Article/python8/2.md) - - [主模块和非主模块](/Article/python8/3.md) - - [包](/Article/python8/4.md) - - [作用域](/Article/python8/5.md) -* [面向对象](/Article/python9/Preface.md) - - [面向对象的概念](/Article/python9/1.md) - - [类](/Article/python9/2.md) - - [类的属性](/Article/python9/3.md) - - [类的方法](/Article/python9/4.md) - - [类的继承](/Article/python9/5.md) - - [类的多态](/Article/python9/6.md) -* [Python 的 Magic Method](/Article/python10/Preface.md) - - [Python 的 Magic Method](/Article/python10/1.md) - - [构造(`__new__`)和初始化(`__init__`)](/Article/python10/2.md) - - [属性的访问控制](/Article/python10/3.md) - - [对象的描述器](/Article/python10/4.md) - - [自定义容器(Container)](/Article/python10/5.md) - - [运算符相关的魔术方法](/Article/python10/6.md) -* [枚举类](/Article/python11/Preface.md) - - [枚举类的使用](/Article/python11/1.md) - - [Enum 的源码](/Article/python11/2.md) - - [自定义类型的枚举](/Article/python11/3.md) - - [枚举的比较](/Article/python11/4.md) -* [元类](/Article/python12/Preface.md) - - [Python 中类也是对象](/Article/python12/1.md) - - [使用 `type()` 动态创建类](/Article/python12/2.md) - - [什么是元类](/Article/python12/3.md) - - [自定义元类](/Article/python12/4.md) - - [使用元类](/Article/python12/5.md) -* [线程与进程](/Article/python13/Preface.md) - - [线程与进程](/Article/python13/1.md) - - [多线程编程](/Article/python13/2.md) - - [进程](/Article/python13/3.md) -* [一步一步了解正则表达式](/Article/python14/Preface.md) - - [初识 Python 正则表达式](/Article/python14/1.md) - - [字符集](/Article/python14/2.md) - - [数量词](/Article/python14/3.md) - - [边界匹配符和组](/Article/python14/4.md) - - [re.sub](/Article/python14/5.md) - - [re.match 和 re.search](/Article/python14/6.md) -* [闭包](/Article/python15/1.md) -* [装饰器](/Article/python16/1.md) +* [函数](/Article/PythonBasis/python6/Preface.md) + - [Python 自定义函数的基本步骤](/Article/PythonBasis/python6/1.md) + - [函数返回值](/Article/PythonBasis/python6/2.md) + - [函数的参数](/Article/PythonBasis/python6/3.md) + - [函数传值问题](/Article/PythonBasis/python6/4.md) + - [匿名函数](/Article/PythonBasis/python6/5.md) +* [迭代器和生成器](/Article/PythonBasis/python7/Preface.md) + - [迭代](/Article/PythonBasis/python7/1.md) + - [Python 迭代器](/Article/PythonBasis/python7/2.md) + - [lsit 生成式(列表生成式)](/Article/PythonBasis/python7/3.md) + - [生成器](/Article/PythonBasis/python7/4.md) + - [迭代器和生成器综合例子](/Article/PythonBasis/python7/5.md) +* [面向对象](/Article/PythonBasis/python8/Preface.md) + - [面向对象的概念](/Article/PythonBasis/python8/1.md) + - [类的定义和调用](/Article/PythonBasis/python8/2.md) + - [类方法](/Article/PythonBasis/python8/3.md) + - [修改和增加类属性](/Article/PythonBasis/python8/4.md) + - [类和对象](/Article/PythonBasis/python8/5.md) + - [初始化函数](/Article/PythonBasis/python8/6.md) + - [类的继承](/Article/PythonBasis/python8/7.md) + - [类的多态](/Article/PythonBasis/python8/8.md) + - [类的访问控制](/Article/PythonBasis/python8/9.md) +* [模块与包](/Article/PythonBasis/python9/Preface.md) + - [Python 模块简介](/Article/PythonBasis/python9/1.md) + - [模块的使用](/Article/PythonBasis/python9/2.md) + - [主模块和非主模块](/Article/PythonBasis/python9/3.md) + - [包](/Article/PythonBasis/python9/4.md) + - [作用域](/Article/PythonBasis/python9/5.md) +* [Python 的 Magic Method](/Article/PythonBasis/python10/Preface.md) + - [Python 的 Magic Method](/Article/PythonBasis/python10/1.md) + - [构造(`__new__`)和初始化(`__init__`)](/Article/PythonBasis/python10/2.md) + - [属性的访问控制](/Article/PythonBasis/python10/3.md) + - [对象的描述器](/Article/PythonBasis/python10/4.md) + - [自定义容器(Container)](/Article/PythonBasis/python10/5.md) + - [运算符相关的魔术方法](/Article/PythonBasis/python10/6.md) +* [枚举类](/Article/python11/PythonBasis/Preface.md) + - [枚举类的使用](/Article/PythonBasis/python11/1.md) + - [Enum 的源码](/Article/PythonBasis/python11/2.md) + - [自定义类型的枚举](/Article/PythonBasis/python11/3.md) + - [枚举的比较](/Article/PythonBasis/python11/4.md) +* [元类](/Article/PythonBasis/python12/Preface.md) + - [Python 中类也是对象](/Article/PythonBasis/python12/1.md) + - [使用 `type()` 动态创建类](/Article/PythonBasis/python12/2.md) + - [什么是元类](/Article/PythonBasis/python12/3.md) + - [自定义元类](/Article/PythonBasis/python12/4.md) + - [使用元类](/Article/PythonBasis/python12/5.md) +* [线程与进程](/Article/PythonBasis/python13/Preface.md) + - [线程与进程](/Article/PythonBasis/python13/1.md) + - [多线程编程](/Article/PythonBasis/python13/2.md) + - [进程](/Article/PythonBasis/python13/3.md) +* [一步一步了解正则表达式](/Article/PythonBasis/python14/Preface.md) + - [初识 Python 正则表达式](/Article/PythonBasis/python14/1.md) + - [字符集](/Article/PythonBasis/python14/2.md) + - [数量词](/Article/PythonBasis/python14/3.md) + - [边界匹配符和组](/Article/PythonBasis/python14/4.md) + - [re.sub](/Article/PythonBasis/python14/5.md) + - [re.match 和 re.search](/Article/PythonBasis/python14/6.md) +* [闭包](/Article/PythonBasis/python15/1.md) +* [装饰器](/Article/PythonBasis/python16/1.md) * [知识点补漏](README.md) - [Python 关键字 yield](/Article/supplement/Python关键字yield.md) * [**Python 进阶部分**](/Article/advanced/advanced.md)