mirror of https://github.com/TwoWater/Python
重新修订 6 - 8 章节
parent
54be4f5f6d
commit
95ad977818
|
@ -2,7 +2,7 @@
|
|||
|
||||
上一篇文章出现了个明显的知识点错误,不过感谢有个网友的提出,及时进行了修改。也希望各位多多包涵。
|
||||
|
||||
(2019年09月01日15:28:00) 在修改文章的时候,发现自己两年前写的像屎一样, 忍不住还在群里吐槽一番。
|
||||
>注:(2019年09月01日15:28:00) 在修改文章的时候,发现自己两年前写的像屎一样, 忍不住还在群里吐槽一番。
|
||||
|
||||

|
||||
|
||||
|
|
|
@ -1,12 +1,31 @@
|
|||
# 二、循环语句 #
|
||||
|
||||
一般编程语言都有循环语句,循环语句允许我们执行一个语句或语句组多次。
|
||||
|
||||
|
||||
## 1、什么是循环语句 ##
|
||||
|
||||
一般编程语言都有循环语句,为什么呢?
|
||||
|
||||
那就问一下自己,我们弄程序是为了干什么?
|
||||
|
||||
那肯定是为了方便我们工作,优化我们的工作效率啊。
|
||||
|
||||
而计算机和人类不同,计算机不怕苦也不怕累,也不需要休息,可以一直做。
|
||||
|
||||
你要知道,计算机最擅长就是做重复的事情。
|
||||
|
||||
所以这时候需要用到循环语句,循环语句允许我们执行一个语句或语句组多次。
|
||||
|
||||
循环语句的一般形式如下:
|
||||
|
||||

|
||||
|
||||
Python 提供了 for 循环和 while 循环,当然还有一些控制循环的语句:
|
||||
|
||||
在 Python 提供了 for 循环和 while 循环。
|
||||
|
||||
这里又有一个问题了,如果我想让他运行了一百次之后停止,那该怎么做呢?
|
||||
|
||||
这时候需要用到一些控制循环的语句:
|
||||
|
||||
|循环控制语句|描述|
|
||||
|------|------|
|
||||
|
@ -14,28 +33,210 @@ Python 提供了 for 循环和 while 循环,当然还有一些控制循环的
|
|||
|continue|在语句块执行过程中终止当前循环,跳出该次循环,执行下一次循环|
|
||||
|pass|pass 是空语句,是为了保持程序结构的完整性|
|
||||
|
||||
这些控制语句是为了让我们告诉程序什么时候停止,什么时候不运行这次循环。
|
||||
|
||||
## 1、While 循环语句 ##
|
||||
|
||||
|
||||
|
||||
## 2、 for 循环语句 ##
|
||||
|
||||
我们先来看下 for 循环语句。
|
||||
|
||||
它的流程图基本如下:
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
基本的语法格式:
|
||||
|
||||
```python
|
||||
for iterating_var in sequence:
|
||||
statements(s)
|
||||
```
|
||||
|
||||
那么我们根据他的基本语法格式,随便写个例子测试一下:
|
||||
|
||||
|
||||
```python
|
||||
count = 1
|
||||
sum = 0
|
||||
while (count <= 100):
|
||||
sum = sum + count
|
||||
count = count + 1
|
||||
print(sum)
|
||||
for letter in 'Hello 两点水':
|
||||
print(letter)
|
||||
```
|
||||
|
||||
输出的结果:
|
||||
输出的结果如下:
|
||||
|
||||
```txt
|
||||
H
|
||||
e
|
||||
l
|
||||
l
|
||||
o
|
||||
|
||||
两
|
||||
点
|
||||
水
|
||||
```
|
||||
|
||||
从打印结果来看,它就是把字符串 `Hello 两点水` 一个一个字符的打印出来。
|
||||
|
||||
那如果我们把字符串换为字典 dict 呢?
|
||||
|
||||

|
||||
|
||||
你会发现只打印了字典 dict 中的每一个 key 值。
|
||||
|
||||
很多时候,我都是建议大家学到一个新的知识点,都多去尝试。
|
||||
|
||||
你尝试一遍,自己观察出来的结论,好过别人说十遍。
|
||||
|
||||
如果你不知道怎么去试?
|
||||
|
||||
可以根据我们的例子举一反三,比如上面的 for 循环,试了字符串,字典,那我们之前学的基本数据类型还有什么呢?
|
||||
|
||||
不记得可以再返回去看看,可以把所有的基本类型都拿去尝试一下。
|
||||
|
||||
比如,你试了之后,会发现整数和浮点数是不可以直接放在 for 循环里面的。
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## 3、 range() 函数 ##
|
||||
|
||||
for 循环还常常和 range() 函数搭配使用的。
|
||||
|
||||
如果不知道 range() 函数 , 我们直接通过一段程序来理解。
|
||||
|
||||
```python
|
||||
for i in range(3):
|
||||
print(i)
|
||||
```
|
||||
|
||||
打印的结果为:
|
||||
|
||||
```
|
||||
0
|
||||
1
|
||||
2
|
||||
```
|
||||
|
||||
可见,打印了 0 到 3 。
|
||||
|
||||
使用 range(x) 函数,就可以生成一个从 0 到 x-1 的整数序列。
|
||||
|
||||
如果是 `range(a,b)` 函数,你可以生成了一个左闭右开的整数序列。
|
||||
|
||||
其实例子中的 `range(3)` 可以写成 `range(0,3)`, 结果是一样的。
|
||||
|
||||
其实使用 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 。
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## 4、While 循环语句 ##
|
||||
|
||||
While 循环和 for 循环的作用是一样的。
|
||||
|
||||
我们先来看看 While 循环语句的样子。
|
||||
|
||||

|
||||
|
||||
程序输出的结果是:
|
||||
|
||||
```txt
|
||||
5050
|
||||
```
|
||||
|
||||
当然 while 语句时还有另外两个重要的命令 continue,break 来跳过循环,continue 用于跳过该次循环,break 则是用于退出循环
|
||||
这个例子是计算 1 到 100 所有整数的和。
|
||||
|
||||
比如,上面的例子是计算 1 到 100 所有整数的和,当我们需要判断 sum 大于 1000 的时候,不在相加时,可以用到 break ,退出整个循环
|
||||
|
||||
|
||||
## 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
|
||||
while expression:
|
||||
while expression:
|
||||
statement(s)
|
||||
statement(s)
|
||||
```
|
||||
|
||||
除此之外,你也可以在循环体内嵌入其他的循环体,如在 while 循环中可以嵌入 for 循环, 反之,你可以在 for 循环中嵌入 while 循环
|
||||
|
||||
比如:
|
||||
|
||||
当我们需要判断 sum 大于 1000 的时候,不在相加时,可以用到 break ,退出整个循环。
|
||||
|
||||
```python
|
||||
count = 1
|
||||
|
@ -74,68 +275,7 @@ print(sum)
|
|||
2500
|
||||
```
|
||||
|
||||
在 Python 的 while 循环中,还可以使用 else 语句,while … else 在循环条件为 false 时执行 else 语句块
|
||||
|
||||
比如:
|
||||
|
||||
```python
|
||||
count = 0
|
||||
while count < 5:
|
||||
print (count)
|
||||
count = count + 1
|
||||
else:
|
||||
print (count)
|
||||
```
|
||||
|
||||
输出的结果:
|
||||
|
||||
```txt
|
||||
0
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
```
|
||||
|
||||
## 2、 for 循环语句 ##
|
||||
|
||||
for循环可以遍历任何序列的项目,如一个列表或者一个字符串
|
||||
|
||||
它的流程图基本如下:
|
||||
|
||||
|
||||

|
||||
|
||||
基本的语法格式:
|
||||
|
||||
```python
|
||||
for iterating_var in sequence:
|
||||
statements(s)
|
||||
```
|
||||
|
||||
实例:
|
||||
|
||||
```python
|
||||
for letter in 'Hello 两点水':
|
||||
print(letter)
|
||||
```
|
||||
|
||||
输出的结果如下:
|
||||
|
||||
```txt
|
||||
H
|
||||
e
|
||||
l
|
||||
l
|
||||
o
|
||||
|
||||
两
|
||||
点
|
||||
水
|
||||
```
|
||||
|
||||
有 while … else 语句,当然也有 for … else 语句啦,for 中的语句和普通的没有区别,else 中的语句会在循环正常执行完(即 for 不是通过 break 跳出而中断的)的情况下执行,while … else 也是一样。
|
||||
还有:
|
||||
|
||||
```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 … else` 语句。
|
||||
|
||||
具体的语法如下:
|
||||
其实 for 循环中的语句和普通的没有区别,else 中的语句会在循环正常执行完(即 for 不是通过 break 跳出而中断的)的情况下执行。
|
||||
|
||||
**for 循环嵌套语法**
|
||||
当然有 `for … else` ,也会有 `while … else` 。他们的意思都是一样的。
|
||||
|
||||
```python
|
||||
for iterating_var in sequence:
|
||||
for iterating_var in sequence:
|
||||
statements(s)
|
||||
statements(s)
|
||||
```
|
||||
|
||||
**while 循环嵌套语法**
|
||||
|
||||
```python
|
||||
while expression:
|
||||
while expression:
|
||||
statement(s)
|
||||
statement(s)
|
||||
```
|
||||
|
||||
除此之外,你也可以在循环体内嵌入其他的循环体,如在 while 循环中可以嵌入 for 循环, 反之,你可以在 for 循环中嵌入 while 循环
|
||||
|
|
|
@ -1,14 +1,19 @@
|
|||
# 一、条件语句 #
|
||||
|
||||
|
||||
## 1、什么是条件语句 ##
|
||||
|
||||
|
||||
Python 条件语句跟其他语言基本一致的,都是通过一条或多条语句的执行结果( True 或者 False )来决定执行的代码块。
|
||||
|
||||
Python 程序语言指定任何非 0 和非空(null)值为 True,0 或者 null为 False。
|
||||
Python 程序语言指定任何非 0 和非空(null)值为 True,0 或者 null 为 False。
|
||||
|
||||
执行的流程图如下:
|
||||
|
||||

|
||||
|
||||
## 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 语句多个判断条件的形式 ##
|
||||
输出的结果如下:
|
||||
|
||||

|
||||
|
||||
可见,把结果打印出来了。
|
||||
|
||||
那如果我们把 `num ` 改为空字符串呢?
|
||||
|
||||

|
||||
|
||||
很明显,空字符串是为 False 的,不符合条件语句,因此不会执行到 `print('Hello Python')` 这段代码。
|
||||
|
||||
还有再啰嗦一点,提醒一下,在条件判断代码中的冒号 `:` 后、下一行内容是一定要缩进的。不缩进是会报错的。
|
||||
|
||||

|
||||
|
||||
冒号和缩进是一种语法。它会帮助 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 嵌套来写。
|
||||
|
||||

|
||||
|
||||
当然这只是为了说明 if 条件语句是可以嵌套的。如果是这个需求,我个人还是不太建议这样使用 if 嵌套的,因为这样代码量多了,而且嵌套太多,也不方便阅读代码。
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,10 +1,16 @@
|
|||
# 前言 #
|
||||
|
||||
第一次建学习群,而且是 Python 的学习群,虽然之前深入学习和工作都是 Android 相关的,最近学起来 Python ,真的很好玩,所以创了个微信群,希望童鞋们进群学习讨论。也可以直接加我微`androidwed`拉进群。也欢迎大家在 [Gitbook](https://www.readwithu.com/) 中提出文章的不足。
|
||||
通常都听到别人说,计算机很牛逼,很聪明,其实计算机一点都不聪明,光是你要跟他沟通,都会气 shi 你,聪明的是在写程序的你。
|
||||
|
||||

|
||||
写程序就是跟计算机沟通,告诉它要做什么。
|
||||
|
||||
竟然是这样,那么肯定缺少不了一些沟通逻辑。比如你要告诉计算机在什么情况下做什么?或者在哪个时间点做什么?
|
||||
|
||||
这都需要用到逻辑判断。这一章节,主要就是说这个。
|
||||
|
||||
|
||||
# 目录 #
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
# 三、函数返回值 #
|
||||
# 二、函数返回值 #
|
||||
|
||||
通过上面的学习,可以知道通过 return [表达式] 语句用于退出函数,选择性地向调用方返回一个表达式。不带参数值的 return 语句返回 None。
|
||||
通过上面的学习,可以知道通过 return [表达式] 语句用于退出函数,选择性地向调用方返回一个表达式。
|
||||
|
||||
**不带参数值的 return 语句返回 None。**
|
||||
|
||||
具体示例:
|
||||
|
||||
|
@ -51,4 +53,16 @@ print (tuple1)
|
|||
(2.0, 1)
|
||||
```
|
||||
|
||||
认真观察就可以发现,尽管从第一个输出值来看,返回了多个值,实际上是先创建了一个元组然后返回的。回忆一下,元组是可以直接用逗号来创建的,观察例子中的 ruturn ,可以发现实际上我们使用的是逗号来生成一个元组。
|
||||
认真观察就可以发现,尽管从第一个输出值来看,返回了多个值,实际上是先创建了一个元组然后返回的。
|
||||
|
||||
回忆一下,元组是可以直接用逗号来创建的,观察例子中的 ruturn ,可以发现实际上我们使用的是逗号来生成一个元组。
|
||||
|
||||
Python 语言中的函数返回值可以是多个,而其他语言都不行,这是Python 相比其他语言的简便和灵活之处。
|
||||
|
||||
**Python 一次接受多个返回值的数据类型就是元组。**
|
||||
|
||||
不知道此刻你还记不记得元组的相关知识,如果不记得,建议现在立刻写几个例子回忆一下,比如如何获取元组的第一个元素出来。
|
||||
|
||||
|
||||
|
||||
|
|
@ -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` 类的实例,但是这些实例没什么实际用处,因为它并没有任何有用的方法, 也没有任何实例数据(因为它没有任何的实例字典,你甚至都不能设置任何属性值)。 你唯一能做的就是测试同一性。也正好利用这个特性,来判断是否有值输入。
|
||||
|
||||
在 Python 中,可以通过参数名来给函数传递参数,而不用关心参数列表定义时的顺序,这被称之为关键字参数。使用关键参数有两个优势 :
|
||||
|
||||
一、由于我们不必担心参数的顺序,使用函数变得更加简单了。
|
||||
|
||||
二、假设其他参数都有默认值,我们可以只给我们想要的那些参数赋值
|
||||
|
||||
## 3、关键字参数(位置参数) ##
|
||||
|
||||
一般情况下,我们需要给函数传参的时候,是要按顺序来的,如果不对应顺序,就会传错值。
|
||||
|
||||
不过在 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` 参数更好且强制关键字参数在一些更高级场合同样也很有用。
|
|
@ -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]
|
||||
```
|
||||
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
# 五、匿名函数 #
|
||||
|
||||
有没有想过定义一个很短的回调函数,但又不想用 `def` 的形式去写一个那么长的函数,那么有没有快捷方式呢?答案是有的。
|
||||
有没有想过定义一个很短的回调函数,但又不想用 `def` 的形式去写一个那么长的函数,那么有没有快捷方式呢?
|
||||
|
||||
答案是有的。
|
||||
|
||||
python 使用 lambda 来创建匿名函数,也就是不再使用 def 语句这样标准的形式定义一个函数。
|
||||
|
||||
|
@ -57,4 +59,5 @@ print( sum2( 1 ) )
|
|||
10001
|
||||
```
|
||||
|
||||
这主要在于 lambda 表达式中的 num2 是一个自由变量,在运行时绑定值,而不是定义时就绑定,这跟函数的默认值参数定义是不同的。所以建议还是遇到这种情况还是使用第一种解法。
|
||||
**这主要在于 lambda 表达式中的 num2 是一个自由变量,在运行时绑定值,而不是定义时就绑定,这跟函数的默认值参数定义是不同的。所以建议还是遇到这种情况还是使用第一种解法。**
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
# 前言 #
|
||||
|
||||
函数这个章节内容有点多,对于新手,也有些不好理解。建议各位多看几篇,多敲几次代码。
|
||||
|
||||
最后这是我的个人微信号,大家可以添加一下,交个朋友,一起讨论。
|
||||
|
||||

|
||||
|
||||
# 目录 #
|
||||
|
||||

|
||||
|
||||
|
|
@ -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
|
||||
```
|
||||
|
||||
|
|
@ -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)]))
|
||||
|
@ -102,3 +106,5 @@ print(lsit1)
|
|||
```
|
||||
|
||||
其实知道了 list 生成式是怎样组合的,就不难理解这个东西了。因为 list 生成式只是把之前学习的知识点进行了组合,换成了一种更简洁的写法而已。
|
||||
|
||||
|
|
@ -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)
|
|||
<generator object <genexpr> 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):
|
|||
|
||||
运行的效果:
|
||||
|
||||

|
||||

|
||||
|
||||
你看,运行一个这么打的参数,也不会说有卡死的状态,因为这种方式不会使用太大的资源。这里,最难理解的就是 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]
|
||||
```
|
||||
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
# 前言 #
|
||||
|
||||
这篇内容挺多的,而且比内容不好理解。或许新手看完后,还会一脸懵逼,不过这是正常的,如果你看完后,是迷糊的,那么建议你继续学习后面的内容,等学完,再回来看几次。
|
||||
|
||||
注:这也是我第二次修改内容没有改过的章节。
|
||||
|
||||
# 目录 #
|
||||
|
||||

|
||||
|
||||
|
|
@ -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 的面向对象的知识。**
|
||||
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
# 二、类的定义和调用 #
|
||||
|
||||
|
||||
|
||||
## 1、怎么理解类? ##
|
||||
|
||||
类是什么?
|
||||
|
||||
个人认为理解类,最简单的方式就是:类是一个变量和函数的集合。
|
||||
|
||||
可以看下下面的这张图。
|
||||
|
||||

|
||||
|
||||
这张图很好的诠释了类,就是把变量和函数包装在一起。
|
||||
|
||||
当然我们包装也不是毫无目的的包装,我们会把同性质的包装在一个类里,这样就方便我们重复使用。
|
||||
|
||||
所以学到现在,你会发现很多编程的设计,都是为了我们能偷懒,重复使用。
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## 2、怎么定义类 ##
|
||||
|
||||
知道了类是什么样子的,我们接下来就要学习怎么去定义类了。
|
||||
|
||||
类定义语法格式如下:
|
||||
|
||||
```python
|
||||
class ClassName():
|
||||
<statement-1>
|
||||
.
|
||||
.
|
||||
.
|
||||
<statement-N>
|
||||
```
|
||||
|
||||
可以看到,我们是用 `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、怎么调用类属性和类方法 ##
|
||||
|
||||
|
||||
我们定义了类之后,那么我们怎么调用类里面的属性和方法呢?
|
||||
|
||||
直接看下图:
|
||||
|
||||

|
||||
|
||||
这里就不文字解释了(注:做图也不容易啊,只有写过技术文章才知道,这系列文章,多耗时)
|
||||
|
||||
好了,知道怎么调用之后,我们尝试一下:
|
||||
|
||||
|
||||

|
||||
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
# 三、类方法 #
|
||||
|
||||
|
||||
## 1、类方法如何调用类属性 ##
|
||||
|
||||
通过上面我们已经会定义类了,那么这里讲一下在同一个类里,类方法如何调用类属性的。
|
||||
|
||||
直接看个例子吧:
|
||||
|
||||
|
||||

|
||||
|
||||
注意看,在类方法上面多了个 `@classmethod` ,这是干嘛用的呢?
|
||||
|
||||
这是用于声明下面的函数是类函数。其实从名字就很好理解了。
|
||||
|
||||
class 就是类,method 就是方法。
|
||||
|
||||
那是不是一定需要注明这个呢?
|
||||
|
||||
答案是是的。
|
||||
|
||||
如果你没使用,是会报错的。
|
||||
|
||||
|
||||

|
||||
|
||||
如果没有声明是类方法,方法参数中就没有 `cls` , 就没法通过 `cls` 获取到类属性。
|
||||
|
||||
因此类方法,想要调用类属性,需要以下步骤:
|
||||
|
||||
* 在方法上面,用 `@classmethon` 声明该方法是类方法。只有声明了是类方法,才能使用类属性
|
||||
* 类方法想要使用类属性,在第一个参数中,需要写上 `cls` , cls 是 class 的缩写,其实意思就是把这个类作为参数,传给自己,这样就可以使用类属性了。
|
||||
* 类属性的使用方式就是 `cls.变量名`
|
||||
|
||||
|
||||
记住喔,无论是 `@classmethon` 还是 `cls` ,都是不能省去的。
|
||||
|
||||
省了都会报错。
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## 2、类方法传参 ##
|
||||
|
||||
上面我们学习了类方法如何调用类属性,那么类方法如何传参呢?
|
||||
|
||||
其实很简单,跟普通的函数一样,直接增加参数就好了。
|
||||
|
||||
这个就直接上例子了:
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
# 四、修改和增加类属性 #
|
||||
|
||||
|
||||
## 1、从内部增加和修改类属性 ##
|
||||
|
||||
来,我们先来温习一下类的结构。
|
||||
|
||||

|
||||
|
||||
看着这个结构,提一个问题,如何修改类属性,也就是类里面的变量?
|
||||
|
||||
从类结构来看,我们可以猜测,从类方法来修改,也就是从类内部来修改和增加类属性。
|
||||
|
||||
看下具体的实例:
|
||||
|
||||

|
||||
|
||||
这里还是强调一下,例子还是要自己多写,不要只看,自己运行, 看效果。多想。
|
||||
|
||||
|
||||
|
||||
|
||||
## 2、从外部增加和修改类属性 ##
|
||||
|
||||
我们刚刚看了通过类方法来修改类的属性,这时我们看下从外部如何修改和增加类属性。
|
||||
|
||||
例子如下:
|
||||
|
||||

|
||||
|
||||
|
||||
|
|
@ -0,0 +1,171 @@
|
|||
# 五、类和对象 #
|
||||
|
||||
|
||||
|
||||
|
||||
## 1、类和对象之间的关系 ##
|
||||
|
||||
这部分内容主要讲类和对象,我们先来说说类和对象之间的关系。
|
||||
|
||||
**类是对象的模板**
|
||||
|
||||
我们得先有了类,才能制作出对象。
|
||||
|
||||
类就相对于工厂里面的模具,对象就是根据模具制造出来的产品。
|
||||
|
||||
**从模具变成产品的过程,我们就称为类的实例化。**
|
||||
|
||||
**类实例化之后,就变成对象了。也就是相当于例子中的产品。**
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## 2、类的实例化 ##
|
||||
|
||||
这里强调一下,类的实例化和直接使用类的格式是不一样的。
|
||||
|
||||
之前我们就学过,直接使用类格式是这样的:
|
||||
|
||||
```python
|
||||
class ClassA():
|
||||
var1 = '两点水'
|
||||
|
||||
@classmethod
|
||||
def fun1(cls):
|
||||
print('var1 值为:' + cls.var1)
|
||||
|
||||
|
||||
ClassA.fun1()
|
||||
```
|
||||
|
||||
而类的实例化是怎样的呢?
|
||||
|
||||
是这样的,可以仔细对比一下,类的实例化和直接使用类的格式有什么不同?
|
||||
|
||||

|
||||
|
||||
|
||||
主要的不同点有:
|
||||
|
||||
* 类方法里面没有了 `@classmethod` 声明了,不用声明他是类方法
|
||||
* 类方法里面的参数 `cls` 改为 `self`
|
||||
* 类的使用,变成了先通过 `实例名 = 类()` 的方式实例化对象,为类创建一个实例,然后再使用 `实例名.函数()` 的方式调用对应的方法 ,使用 `实例名.变量名` 的方法调用类的属性
|
||||
|
||||
|
||||
这里说明一下,类方法的参数为什么 `cls` 改为 `self` ?
|
||||
|
||||
其实这并不是说一定要写这个,你改为什么字母,什么名字都可以。
|
||||
|
||||
不妨试一下:
|
||||
|
||||

|
||||
|
||||
你看,把 `self` 改为 `aaaaaaaa` 还是可以一样运行的。
|
||||
|
||||
只不过使用 `cls` 和 `self` 是我们的编程习惯,这也是我们的编程规范。
|
||||
|
||||
因为 cls 是 class 的缩写,代表这类 , 而 self 代表这对象的意思。
|
||||
|
||||
所以啊,这里我们实例化对象的时候,就使用 self 。
|
||||
|
||||
**而且 self 是所有类方法位于首位、默认的特殊参数。**
|
||||
|
||||
除此之外,在这里,还要强调一个概念,当你把类实例化之后,里面的属性和方法,就不叫类属性和类方法了,改为叫实例属性和实例方法,也可以叫对象属性和对象方法。
|
||||
|
||||
为什么要这样强调呢?
|
||||
|
||||
**因为一个类是可以创造出多个实例对象出来的。**
|
||||
|
||||
你看下面的例子:
|
||||
|
||||

|
||||
|
||||
我不仅能用这个类创建 a 对象,还能创建 b 对象
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## 3、实例属性和类属性 ##
|
||||
|
||||
一个类可以实例化多个对象出来。
|
||||
|
||||

|
||||
|
||||
根据这个图,我们探究一下实例对象的属性和类属性之间有什么关系呢?
|
||||
|
||||
**先提出第一个问题,如果类属性改变了,实例属性会不会跟着改变呢?**
|
||||
|
||||
还是跟以前一样,提出了问题,我们直接用程序来验证就好。
|
||||
|
||||
看程序:
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
从程序运行的结果来看,**类属性改变了,实例属性会跟着改变。**
|
||||
|
||||
这很好理解,因为我们的实例对象就是根据类来复制出来的,类属性改变了,实例对象的属性也会跟着改变。
|
||||
|
||||
**那么相反,如果实例属性改变了,类属性会改变吗?**
|
||||
|
||||
答案当然是不能啦。因为每个实例都是单独的个体,不能影响到类的。
|
||||
|
||||
具体我们做下实验:
|
||||
|
||||
|
||||

|
||||
|
||||
可以看到,**不管实例对象怎么修改属性值,对类的属性还是没有影响的。**
|
||||
|
||||
|
||||
|
||||
|
||||
## 4、实例方法和类方法 ##
|
||||
|
||||
那这里跟上面一样,还是提出同样的问题。
|
||||
|
||||
**如果类方法改变了,实例方法会不会跟着改变呢?**
|
||||
|
||||
看下下面的例子:
|
||||
|
||||

|
||||
|
||||
这里建议我的例子,各位都要仔细看一下,自己重新敲一遍。相信为什么要这么做,这么证明。
|
||||
|
||||
还是那句话多想,多敲。
|
||||
|
||||
回归正题,从运行的结果来看,类方法改变了,实例方法也是会跟着改变的。
|
||||
|
||||
在这个例子中,我们需要改变类方法,就用到了**类的重写**。
|
||||
|
||||
我们使用了 `类.原始函数 = 新函数` 就完了类的重写了。
|
||||
|
||||
要注意的是,这里的赋值是在替换方法,并不是调用函数。所以是不能加上括号的,也就是 `类.原始函数() = 新函数()` 这个写法是不对的。
|
||||
|
||||
|
||||
**那么如果实例方法改变了,类方法会改变吗?**
|
||||
|
||||
如果这个问题我们需要验证的话,是不是要重写实例的方法,然后观察结果,看看类方法有没有改变,这样就能得出结果了。
|
||||
|
||||
|
||||
可是我们是不能重写实例方法。
|
||||
|
||||
你看,会直接报错。
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
# 六、初始化函数 #
|
||||
|
||||
|
||||
|
||||
## 1、什么是初始化函数 ##
|
||||
|
||||
初始化函数的意思是,当你创建一个实例的时候,这个函数就会被调用。
|
||||
|
||||
比如:
|
||||
|
||||

|
||||
|
||||
当代码在执行 `a = ClassA()` 的语句时,就自动调用了 `__init__(self)` 函数。
|
||||
|
||||
**而这个 `__init__(self)` 函数就是初始化函数,也叫构造函数。**
|
||||
|
||||
初始化函数的写法是固定的格式:中间是 `init`,意思是初始化,然后前后都要有【两个下划线】,然后 `__init__()` 的括号中,第一个参数一定要写上 `self`,不然会报错。
|
||||
|
||||
构造函数(初始化函数)格式如下:
|
||||
|
||||
```python
|
||||
def __init__(self,[...):
|
||||
```
|
||||
|
||||
|
||||
初始化函数一样可以传递参数的,例如:
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
|
||||
## 2、析构函数 ##
|
||||
|
||||
竟然一个在创建的时候,会调用构造函数,那么理所当然,这个当一个类销毁的时候,就会调用析构函数。
|
||||
|
||||
析构函数语法如下:
|
||||
|
||||
```python
|
||||
def __del__(self,[...):
|
||||
```
|
||||
|
||||
看下具体的示例:
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
## 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>
|
||||
<type 'instance'>
|
||||
['__doc__', '__init__', '__module__', 'account', 'name']
|
||||
|
||||
|
||||
<__main__.NewClass object at 0x109a4b150>
|
||||
<class '__main__.NewClass'>
|
||||
['__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 '__main__.OldClass'>
|
||||
['__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 '__main__.NewClass'>
|
||||
['__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 中没有新式类旧式类的问题。
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,7 +1,16 @@
|
|||
# 五、类的继承 #
|
||||
# 七、类的继承 #
|
||||
|
||||
## 1、定义类的继承 ##
|
||||
|
||||
说到继承,你一定会联想到继承你老爸的家产之类的。
|
||||
|
||||
类的继承也是一样。
|
||||
|
||||
比如有一个旧类,是可以算平均数的。然后这时候有一个新类,也要用到算平均数,那么这时候我们就可以使用继承的方式。新类继承旧类,这样子新类也就有这个功能了。
|
||||
|
||||
通常情况下,我们叫旧类为父类,新类为子类。
|
||||
|
||||
|
||||
首先我们来看下类的继承的基本语法:
|
||||
|
||||
```python
|
||||
|
@ -13,7 +22,7 @@ class ClassName(BaseClassName):
|
|||
<statement-N>
|
||||
```
|
||||
|
||||
在定义类的时候,可以在括号里写继承的类,一开始也提到过,如果不用继承类的时候,也要写继承 object 类,因为在 Python 中 object 类是一切类的父类。
|
||||
在定义类的时候,可以在括号里写继承的类,如果不用继承类的时候,也要写继承 object 类,因为在 Python 中 object 类是一切类的父类。
|
||||
|
||||
当然上面的是单继承,Python 也是支持多继承的,具体的语法如下:
|
||||
|
||||
|
@ -112,12 +121,12 @@ if __name__ == '__main__':
|
|||
|
||||
最后打印的结果:
|
||||
|
||||

|
||||

|
||||
|
||||
这里就是重写了父类的构造函数。
|
||||
|
||||
|
||||
## 3、子类的类型判断 ##
|
||||
## 4、子类的类型判断 ##
|
||||
|
||||
对于 class 的继承关系来说,有些时候我们需要判断 class 的类型,该怎么办呢?
|
||||
|
||||
|
@ -168,3 +177,5 @@ False
|
|||
```
|
||||
|
||||
可以看到 `isinstance()` 不仅可以告诉我们,一个对象是否是某种类型,也可以用于基本类型的判断。
|
||||
|
||||
|
|
@ -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。
|
||||
最后,本章的所有代码都可以在 [https://github.com/TwoWater/Python](https://github.com/TwoWater/Python) 上面找到,文章的内容和源文件都放在上面。同步更新到 Gitbooks。
|
||||
|
|
@ -1,6 +1,62 @@
|
|||
# 四、类的方法 #
|
||||
# 九、类的访问控制 #
|
||||
|
||||
## 1、类专有的方法 ##
|
||||
|
||||
## 1、类属性的访问控制 ##
|
||||
|
||||
在 Java 中,有 public (公共)属性 和 private (私有)属性,这可以对属性进行访问控制。
|
||||
|
||||
那么在 Python 中有没有属性的访问控制呢?
|
||||
|
||||
一般情况下,我们会使用 `__private_attrs` 两个下划线开头,声明该属性为私有,不能在类地外部被使用或直接访问。在类内部的方法中使用时 `self.__private_attrs`。
|
||||
|
||||
为什么只能说一般情况下呢?
|
||||
|
||||
因为实际上, Python 中是没有提供私有属性等功能的。
|
||||
|
||||
但是 Python 对属性的访问控制是靠程序员自觉的。为什么这么说呢?
|
||||
|
||||
看看下面的示例:
|
||||
|
||||

|
||||
|
||||
仔细看图片,为什么说双下划线不是真正的私有属性呢?我们看下下面的例子,用下面的例子来验证:
|
||||
|
||||
```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)
|
||||
|
||||
|
||||
```
|
||||
|
||||
输出的结果如下图:
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
|
||||
## 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)
|
||||
```
|
||||
|
||||
运行的结果:
|
||||
|
||||

|
|
@ -0,0 +1,26 @@
|
|||
# 前言 #
|
||||
|
||||
这篇内容非常的重要,也是我用了很多时间写的。基本上把以前写的东西都重新改了一遍。里面的代码都是我一个一个的敲的,图片也是我一个一个制作的。
|
||||
|
||||
|
||||
|
||||
|
||||
# 目录 #
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 66 KiB |
|
@ -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
|
||||
```
|
|
@ -1,7 +0,0 @@
|
|||
# 前言 #
|
||||
|
||||
前天创了个 Python 微信讨论群,以为没人进的,哈哈,想不到还真有小伙伴进群学习讨论。如果想进群,可以加我微信: androidwed ,拉进群,就不贴微信群二维码了,一是会失效,二影响文章。
|
||||
|
||||
# 目录 #
|
||||
|
||||

|
|
@ -1,7 +0,0 @@
|
|||
# 前言 #
|
||||
|
||||
这篇博客写了很久,其实写每一篇博客用的时间还是挺长的,不够这有利于自己的学习,也想分享一下。之前也说了创建了一个微信群,Python 学习讨论群,现在只有 40 个左右的小伙伴,如果有兴趣加入学习讨论的话,可以加我微信:`androidwed`,拉你进群。想看回之前的文章,也可以通过 [Gitbook](https://www.gitbook.com/book/twowater/python/details) 查看,欢迎提出问题和点下 star,及时查看更新。
|
||||
|
||||
# 目录 #
|
||||
|
||||

|
|
@ -1,117 +0,0 @@
|
|||
# 二、类 #
|
||||
|
||||
## 1、定义类 ##
|
||||
|
||||
类定义语法格式如下:
|
||||
|
||||
```python
|
||||
class ClassName:
|
||||
<statement-1>
|
||||
.
|
||||
.
|
||||
.
|
||||
<statement-N>
|
||||
```
|
||||
|
||||
一个类也是由属性和方法组成的,有些时候我们定义类的时候需要设置类的属性,因此这就需要构造函
|
||||
|
||||
类的构造函数如下:
|
||||
|
||||
```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()
|
||||
```
|
||||
|
||||
观察输出的结果:
|
||||
|
||||

|
||||
|
||||
从执行结果可以很明显的看出,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 中没有新式类旧式类的问题。
|
|
@ -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
|
||||
|
||||
#!/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)
|
||||
|
||||
|
||||
```
|
||||
|
||||
输出的结果如下图:
|
||||
|
||||

|
|
@ -1,10 +0,0 @@
|
|||
# 前言 #
|
||||
|
||||
这篇写的很纠结,不过还是写完了。弄了个很逊的公众号,如果对本文有兴趣,可以关注下公众号喔,会持续更新。
|
||||
|
||||
|
||||

|
||||
|
||||
# 目录 #
|
||||
|
||||

|
62
README.md
62
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,31 +64,34 @@ 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)
|
||||
* [函数](/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/python10/Preface.md)
|
||||
- [Python 的 Magic Method](/Article/python10/1.md)
|
||||
- [构造(`__new__`)和初始化(`__init__`)](/Article/python10/2.md)
|
||||
|
@ -115,10 +125,12 @@ IT 行业相对于一般传统行业,发展更新速度更快,一旦停止
|
|||
* [装饰器](/Article/python16/1.md)
|
||||
|
||||
|
||||
|
||||
# 知识点补漏
|
||||
* [Python 关键字 yield](/Article/supplement/Python关键字yield.md)
|
||||
|
||||
|
||||
|
||||
# Python 进阶
|
||||
|
||||
* [使用Python虚拟环境](/Article/advanced/使用Python虚拟环境.md)
|
||||
|
|
Loading…
Reference in New Issue