Skip to content

Commit 8e719ca

Browse files
committed
更新了部分文档
1 parent 5e712ca commit 8e719ca

File tree

3 files changed

+81
-57
lines changed

3 files changed

+81
-57
lines changed

Day01-15/06.函数和模块的使用.md

Lines changed: 27 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
```Python
1414
"""
1515
输入M和N计算C(M,N)
16+
17+
Version: 0.1
18+
Author: 骆昊
1619
"""
1720

1821
m = int(input('m = '))
@@ -41,12 +44,7 @@ print(fm // fn // fmn)
4144

4245
```Python
4346
def factorial(num):
44-
"""
45-
求阶乘
46-
47-
:param num: 非负整数
48-
:return: num的阶乘
49-
"""
47+
"""求阶乘"""
5048
result = 1
5149
for n in range(1, num + 1):
5250
result *= n
@@ -59,31 +57,27 @@ n = int(input('n = '))
5957
print(factorial(m) // factorial(n) // factorial(m - n))
6058
```
6159

62-
> **说明:** Python的math模块中其实已经有一个factorial函数了,事实上要计算阶乘可以直接使用这个现成的函数而不用自己定义。下面例子中的某些函数其实Python中也是内置了,我们这里是为了讲解函数的定义和使用才把它们又实现了一遍,实际开发中不建议做这种低级的重复性的工作。
60+
> **说明:** Python的`math`模块中其实已经有一个`factoria`l函数了,事实上要计算阶乘可以直接使用这个现成的函数而不用自己定义。下面例子中的一些函数在Python中也都是现成的,我们这里是为了讲解函数的定义和使用才把它们又实现了一遍,实际开发中不建议做这种低级的重复性的工作。
6361
6462

6563
### 函数的参数
6664

67-
函数是绝大多数编程语言中都支持的一个代码的构建块,但是Python中的函数与其他语言中的函数还是有很多不太相同的地方,其中一个显著的区别就是Python对函数参数的处理。在Python中,函数的参数可以有默认值,也支持使用可变参数,所以Python并不需要像其他语言一样支持[函数的重载](https://zh.wikipedia.org/wiki/%E5%87%BD%E6%95%B0%E9%87%8D%E8%BD%BD),因为我们在定义一个函数的时候可以让它有多种不同的使用方式,下面是两个小例子。
65+
函数是绝大多数编程语言中都支持的一个代码的"构建块",但是Python中的函数与其他语言中的函数还是有很多不太相同的地方,其中一个显著的区别就是Python对函数参数的处理。在Python中,函数的参数可以有默认值,也支持使用可变参数,所以Python并不需要像其他语言一样支持[函数的重载](https://zh.wikipedia.org/wiki/%E5%87%BD%E6%95%B0%E9%87%8D%E8%BD%BD),因为我们在定义一个函数的时候可以让它有多种不同的使用方式,下面是两个小例子。
6866

6967
```Python
7068
from random import randint
7169

7270

7371
def roll_dice(n=2):
74-
"""
75-
摇色子
76-
77-
:param n: 色子的个数
78-
:return: n颗色子点数之和
79-
"""
72+
"""摇色子"""
8073
total = 0
8174
for _ in range(n):
8275
total += randint(1, 6)
8376
return total
8477

8578

8679
def add(a=0, b=0, c=0):
80+
"""三个数相加"""
8781
return a + b + c
8882

8983

@@ -105,14 +99,14 @@ print(add(c=50, a=100, b=200))
10599

106100
```Python
107101
# 在参数名前面的*表示args是一个可变参数
108-
# 即在调用add函数时可以传入0个或多个参数
109102
def add(*args):
110103
total = 0
111104
for val in args:
112105
total += val
113106
return total
114107

115108

109+
# 在调用add函数时可以传入0个或多个参数
116110
print(add())
117111
print(add(1))
118112
print(add(1, 2))
@@ -139,21 +133,21 @@ foo()
139133

140134
当然上面的这种情况我们很容易就能避免,但是如果项目是由多人协作进行团队开发的时候,团队中可能有多个程序员都定义了名为`foo`的函数,那么怎么解决这种命名冲突呢?答案其实很简单,Python中每个文件就代表了一个模块(module),我们在不同的模块中可以有同名的函数,在使用函数的时候我们通过`import`关键字导入指定的模块就可以区分到底要使用的是哪个模块中的`foo`函数,代码如下所示。
141135

142-
module1.py
136+
`module1.py`
143137

144138
```Python
145139
def foo():
146140
print('hello, world!')
147141
```
148142

149-
module2.py
143+
`module2.py`
150144

151145
```Python
152146
def foo():
153147
print('goodbye, world!')
154148
```
155149

156-
test.py
150+
`test.py`
157151

158152
```Python
159153
from module1 import foo
@@ -169,7 +163,7 @@ foo()
169163

170164
也可以按照如下所示的方式来区分到底要使用哪一个`foo`函数。
171165

172-
test.py
166+
`test.py`
173167

174168
```Python
175169
import module1 as m1
@@ -181,7 +175,7 @@ m2.foo()
181175

182176
但是如果将代码写成了下面的样子,那么程序中调用的是最后导入的那个`foo`,因为后导入的foo覆盖了之前导入的`foo`
183177

184-
test.py
178+
`test.py`
185179

186180
```Python
187181
from module1 import foo
@@ -191,7 +185,7 @@ from module2 import foo
191185
foo()
192186
```
193187

194-
test.py
188+
`test.py`
195189

196190
```Python
197191
from module2 import foo
@@ -201,9 +195,9 @@ from module1 import foo
201195
foo()
202196
```
203197

204-
需要说明的是,如果我们导入的模块除了定义函数之外还中有可以执行代码,那么Python解释器在导入这个模块时就会执行这些代码,事实上我们可能并不希望如此,因此如果我们在模块中编写了执行代码,最好是将这些执行代码放入如下所示的条件中,这样的话除非直接运行该模块,if条件下的这些代码是不会执行的,因为只有直接执行的模块的名字才是\_\_main\_\_
198+
需要说明的是,如果我们导入的模块除了定义函数之外还中有可以执行代码,那么Python解释器在导入这个模块时就会执行这些代码,事实上我们可能并不希望如此,因此如果我们在模块中编写了执行代码,最好是将这些执行代码放入如下所示的条件中,这样的话除非直接运行该模块,if条件下的这些代码是不会执行的,因为只有直接执行的模块的名字才是"\_\_main\_\_"
205199

206-
module3.py
200+
`module3.py`
207201

208202
```Python
209203
def foo():
@@ -223,7 +217,7 @@ if __name__ == '__main__':
223217
bar()
224218
```
225219

226-
test.py
220+
`test.py`
227221

228222
```Python
229223
import module3
@@ -239,13 +233,15 @@ import module3
239233

240234
```Python
241235
def gcd(x, y):
236+
"""求最大公约数"""
242237
(x, y) = (y, x) if x > y else (x, y)
243238
for factor in range(x, 0, -1):
244239
if x % factor == 0 and y % factor == 0:
245240
return factor
246241

247242

248243
def lcm(x, y):
244+
"""求最小公倍数"""
249245
return x * y // gcd(x, y)
250246
```
251247

@@ -255,6 +251,7 @@ def lcm(x, y):
255251

256252
```Python
257253
def is_palindrome(num):
254+
"""判断一个数是不是回文数"""
258255
temp = num
259256
total = 0
260257
while temp > 0:
@@ -269,6 +266,7 @@ def is_palindrome(num):
269266

270267
```Python
271268
def is_prime(num):
269+
"""判断一个数是不是素数"""
272270
for factor in range(2, num):
273271
if num % factor == 0:
274272
return False
@@ -286,15 +284,16 @@ if __name__ == '__main__':
286284
print('%d是回文素数' % num)
287285
```
288286

289-
通过上面的程序可以看出,当我们将代码中重复出现的和相对独立的功能抽取成函数后,我们可以组合使用这些函数来解决更为复杂的问题,这也是我们为什么要定义和使用函数的一个非常重要的原因。
287+
> **注意**通过上面的程序可以看出,当我们**将代码中重复出现的和相对独立的功能抽取成函数**后,我们可以**组合使用这些函数**来解决更为复杂的问题,这也是我们为什么要定义和使用函数的一个非常重要的原因。
290288
291289
最后,我们来讨论一下Python中有关变量作用域的问题。
292290

293291
```Python
294292
def foo():
295293
b = 'hello'
296294

297-
def bar(): # Python中可以在函数内部再定义函数
295+
# Python中可以在函数内部再定义函数
296+
def bar():
298297
c = True
299298
print(a)
300299
print(b)
@@ -310,7 +309,7 @@ if __name__ == '__main__':
310309
foo()
311310
```
312311

313-
上面的代码能够顺利的执行并且打印出100和“hello”,但我们注意到了,在`bar`函数的内部并没有定义`a`和`b`两个变量,那么`a`和`b`是从哪里来的。我们在上面代码的`if`分支中定义了一个变量`a`,这是一个全局变量(global variable),属于全局作用域,因为它没有定义在任何一个函数中。在上面的`foo`函数中我们定义了变量`b`,这是一个定义在函数中的局部变量(local variable),属于局部作用域,在`foo`函数的外部并不能访问到它;但对于`foo`函数内部的`bar`函数来说,变量`b`属于嵌套作用域,在`bar`函数中我们是可以访问到它的。`bar`函数中的变量`c`属于局部作用域,在`bar`函数之外是无法访问的。事实上,Python查找一个变量时会按照“局部作用域”、“嵌套作用域”、“全局作用域”和“内置作用域”的顺序进行搜索,前三者我们在上面的代码中已经看到了,所谓的“内置作用域”就是Python内置的那些隐含标识符`min`、`len`等都属于内置作用域
312+
上面的代码能够顺利的执行并且打印出100、hello和True,但我们注意到了,在`bar`函数的内部并没有定义`a`和`b`两个变量,那么`a`和`b`是从哪里来的。我们在上面代码的`if`分支中定义了一个变量`a`,这是一个全局变量(global variable),属于全局作用域,因为它没有定义在任何一个函数中。在上面的`foo`函数中我们定义了变量`b`,这是一个定义在函数中的局部变量(local variable),属于局部作用域,在`foo`函数的外部并不能访问到它;但对于`foo`函数内部的`bar`函数来说,变量`b`属于嵌套作用域,在`bar`函数中我们是可以访问到它的。`bar`函数中的变量`c`属于局部作用域,在`bar`函数之外是无法访问的。事实上,Python查找一个变量时会按照“局部作用域”、“嵌套作用域”、“全局作用域”和“内置作用域”的顺序进行搜索,前三者我们在上面的代码中已经看到了,所谓的“内置作用域”就是Python内置的那些标识符,我们之前用过的`input`、`print`、`int`等都属于内置作用域。
314313

315314
再看看下面这段代码,我们希望通过函数调用修改全局变量`a`的值,但实际上下面的代码是做不到的。
316315

@@ -343,7 +342,7 @@ if __name__ == '__main__':
343342

344343
我们可以使用`global`关键字来指示`foo`函数中的变量`a`来自于全局作用域,如果全局作用域中没有`a`,那么下面一行的代码就会定义变量`a`并将其置于全局作用域。同理,如果我们希望函数内部的函数能够修改嵌套作用域中的变量,可以使用`nonlocal`关键字来指示变量来自于嵌套作用域,请大家自行试验。
345344

346-
在实际开发中,我们应该尽量减少对全局变量的使用,因为全局变量的作用域和影响过于广泛,可能会发生意料之外的修改和使用,除此之外全局变量比局部变量拥有更长的生命周期,可能导致对象占用的内存长时间无法被[垃圾回收](https://zh.wikipedia.org/wiki/%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6_(%E8%A8%88%E7%AE%97%E6%A9%9F%E7%A7%91%E5%AD%B8))。事实上,减少对全局变量的使用,也是降低代码之间耦合度的一个重要举措,同时也是对[迪米特法则](https://zh.wikipedia.org/zh-hans/%E5%BE%97%E5%A2%A8%E5%BF%92%E8%80%B3%E5%AE%9A%E5%BE%8B)的践行。减少全局变量的使用就意味着我们应该尽量让变量的作用域在函数的内部,但是如果我们希望将一个局部变量的生命周期延长,使其在函数调用结束后依然可以访问,这时候就需要使用[闭包](https://zh.wikipedia.org/wiki/%E9%97%AD%E5%8C%85_(%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6)),这个我们在后续的内容中进行讲解。
345+
在实际开发中,我们应该尽量减少对全局变量的使用,因为全局变量的作用域和影响过于广泛,可能会发生意料之外的修改和使用,除此之外全局变量比局部变量拥有更长的生命周期,可能导致对象占用的内存长时间无法被[垃圾回收](https://zh.wikipedia.org/wiki/%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6_(%E8%A8%88%E7%AE%97%E6%A9%9F%E7%A7%91%E5%AD%B8))。事实上,减少对全局变量的使用,也是降低代码之间耦合度的一个重要举措,同时也是对[迪米特法则](https://zh.wikipedia.org/zh-hans/%E5%BE%97%E5%A2%A8%E5%BF%92%E8%80%B3%E5%AE%9A%E5%BE%8B)的践行。减少全局变量的使用就意味着我们应该尽量让变量的作用域在函数的内部,但是如果我们希望将一个局部变量的生命周期延长,使其在定义它的函数调用结束后依然可以使用它的值,这时候就需要使用[闭包](https://zh.wikipedia.org/wiki/%E9%97%AD%E5%8C%85_(%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6)),这个我们在后续的内容中进行讲解。
347346

348347
> **说明:** 很多人经常会将“闭包”和[“匿名函数”](https://zh.wikipedia.org/wiki/%E5%8C%BF%E5%90%8D%E5%87%BD%E6%95%B0)混为一谈,但实际上它们是不同的概念,如果想提前了解这个概念,推荐看看[维基百科](https://zh.wikipedia.org/wiki/)或者[知乎](https://www.zhihu.com/)上对这个概念的讨论。
349348

Day01-15/07.字符串和常用数据结构.md

Lines changed: 49 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
### 使用字符串
44

5-
第二次世界大战促使了现代电子计算机的诞生,最初的目的用计算机来快速的完成导弹弹道的计算,因此在计算机刚刚诞生的那个年代,计算机处理的信息基本上都是数值型的信息,而世界上的第一台电子计算机ENIAC每秒钟能够完成约5000次浮点运算。随着时间的推移,虽然数值运算仍然是计算机日常工作中最为重要的事情之一,但是今天的计算机更多的时间需要处理的数据可能都是以文本的方式存在的,如果我们希望通过Python程序操作本这些文本信息,就必须要先了解字符串类型以及与它相关的知识。
5+
第二次世界大战促使了现代电子计算机的诞生,最初计算机被应用于导弹弹道的计算,而在计算机诞生后的很多年时间里,计算机处理的信息基本上都是数值型的信息。世界上的第一台电子计算机叫ENIAC(电子数值积分计算机),诞生于美国的宾夕法尼亚大学,每秒钟能够完成约5000次浮点运算。随着时间的推移,虽然数值运算仍然是计算机日常工作中最为重要的事情之一,但是今天的计算机处理得更多的数据可能都是以文本的方式存在的,如果我们希望通过Python程序操作本这些文本信息,就必须要先了解字符串类型以及与它相关的知识。
66

77
所谓**字符串**,就是由零个或多个字符组成的有限序列,一般记为![$${\displaystyle s=a_{1}a_{2}\dots a_{n}(0\leq n \leq \infty)}$$](./res/formula_5.png)。在Python程序中,如果我们把单个或多个字符用单引号或者双引号包围起来,就可以表示一个字符串。
88

@@ -128,61 +128,80 @@ print(f'{a} * {b} = {a * b}')
128128

129129
### 使用列表
130130

131-
下面的代码演示了如何定义列表、使用下标访问列表元素以及添加和删除元素的操作。
131+
不知道大家是否注意到,刚才我们讲到的字符串类型(`str`)和之前我们讲到的数值类型(`int``float`)有一些区别。数值类型是标量类型,也就是说这种类型的对象没有可以访问的内部结构;而字符串类型是一种结构化的、非标量类型,所以才会有一系列的属性和方法。接下来我们要介绍的列表(`list`),也是一种结构化的、非标量类型,它是值的有序序列,每个值都可以通过索引进行标识,定义列表可以将列表的元素放在`[]`中,多个元素用`,`进行分隔,可以使用`for`循环对列表元素进行遍历,也可以使用`[]``[:]`运算符取出列表中的一个或多个元素。
132+
133+
下面的代码演示了如何定义列表、如何遍历列表以及列表的下标运算。
132134

133135
```Python
134136
list1 = [1, 3, 5, 7, 100]
135-
print(list1)
136-
list2 = ['hello'] * 5
137-
print(list2)
137+
print(list1) # [1, 3, 5, 7, 100]
138+
# 乘号表示列表元素的重复
139+
list2 = ['hello'] * 3
140+
print(list2) # ['hello', 'hello', 'hello']
138141
# 计算列表长度(元素个数)
139-
print(len(list1))
142+
print(len(list1)) # 5
140143
# 下标(索引)运算
141-
print(list1[0])
142-
print(list1[4])
144+
print(list1[0]) # 1
145+
print(list1[4]) # 100
143146
# print(list1[5]) # IndexError: list index out of range
144-
print(list1[-1])
145-
print(list1[-3])
147+
print(list1[-1]) # 100
148+
print(list1[-3]) # 5
146149
list1[2] = 300
147-
print(list1)
150+
print(list1) # [1, 3, 300, 7, 100]
151+
# 通过循环用下标遍历列表元素
152+
for index in range(len(list1)):
153+
print(list1[index])
154+
# 通过for循环遍历列表元素
155+
for elem in list1:
156+
print(elem)
157+
# 通过enumerate函数处理列表之后再遍历可以同时获得元素索引和值
158+
for index, elem in enumerate(list1):
159+
print(index, elem)
160+
```
161+
162+
下面的代码演示了如何向列表中添加元素以及如何从列表中移除元素。
163+
164+
```Python
165+
list1 = [1, 3, 5, 7, 100]
148166
# 添加元素
149167
list1.append(200)
150168
list1.insert(1, 400)
169+
# 合并两个列表
170+
# list1.extend([1000, 2000])
151171
list1 += [1000, 2000]
152-
print(list1)
153-
print(len(list1))
154-
# 删除元素
155-
list1.remove(3)
172+
print(list1) # [1, 400, 3, 5, 7, 100, 200, 1000, 2000]
173+
print(len(list1)) # 9
174+
# 先通过成员运算判断元素是否在列表中,如果存在就删除该元素
175+
if 3 in list1:
176+
list1.remove(3)
156177
if 1234 in list1:
157178
list1.remove(1234)
158-
del list1[0]
159-
print(list1)
179+
print(list1) # [1, 400, 5, 7, 100, 200, 1000, 2000]
180+
# 从指定的位置删除元素
181+
list1.pop(0)
182+
list1.pop(len(list1) - 1)
183+
print(list1) # [400, 5, 7, 100, 200, 1000]
160184
# 清空列表元素
161185
list1.clear()
162-
print(list1)
186+
print(list1) # []
163187
```
164188

165189
和字符串一样,列表也可以做切片操作,通过切片操作我们可以实现对列表的复制或者将列表中的一部分取出来创建出新的列表,代码如下所示。
166190

167191
```Python
168192
fruits = ['grape', 'apple', 'strawberry', 'waxberry']
169193
fruits += ['pitaya', 'pear', 'mango']
170-
# 循环遍历列表元素
171-
for fruit in fruits:
172-
print(fruit.title(), end=' ')
173-
print()
174194
# 列表切片
175195
fruits2 = fruits[1:4]
176-
print(fruits2)
177-
# fruit3 = fruits # 没有复制列表只创建了新的引用
196+
print(fruits2) # apple strawberry waxberry
178197
# 可以通过完整切片操作来复制列表
179198
fruits3 = fruits[:]
180-
print(fruits3)
199+
print(fruits3) # ['grape', 'apple', 'strawberry', 'waxberry', 'pitaya', 'pear', 'mango']
181200
fruits4 = fruits[-3:-1]
182-
print(fruits4)
201+
print(fruits4) # ['pitaya', 'pear']
183202
# 可以通过反向切片操作来获得倒转后的列表的拷贝
184203
fruits5 = fruits[::-1]
185-
print(fruits5)
204+
print(fruits5) # ['mango', 'pear', 'pitaya', 'waxberry', 'strawberry', 'apple', 'grape']
186205
```
187206

188207
下面的代码实现了对列表的排序操作。
@@ -204,6 +223,8 @@ list1.sort(reverse=True)
204223
print(list1)
205224
```
206225

226+
### 生成式和生成器
227+
207228
我们还可以使用列表的生成式语法来创建列表,代码如下所示。
208229

209230
```Python
@@ -255,7 +276,7 @@ if __name__ == '__main__':
255276

256277
### 使用元组
257278

258-
Python 的元组与列表类似,不同之处在于元组的元素不能修改,在前面的代码中我们已经不止一次使用过元组了。顾名思义,我们把多个元素组合到一起就形成了一个元组,所以它和列表一样可以保存多条数据。下面的代码演示了如何定义和使用元组。
279+
Python 中的元组与列表类似也是一种容器数据类型,可以用一个变量(对象)来存储多个数据,不同之处在于元组的元素不能修改,在前面的代码中我们已经不止一次使用过元组了。顾名思义,我们把多个元素组合到一起就形成了一个元组,所以它和列表一样可以保存多条数据。下面的代码演示了如何定义和使用元组。
259280

260281
```Python
261282
# 定义元组

Day91-100/100.Python面试题集.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,4 +221,8 @@
221221

222222
38. 说一下索引的原理和作用。
223223

224-
39. 是否使用过Nginx实现负载均衡?用过哪些负载均衡算法?
224+
39. 是否使用过Nginx实现负载均衡?用过哪些负载均衡算法?
225+
226+
40. 一个保存整数(int)的数组,除了一个元素出现过1次外,其他元素都出现过两次,请找出这个元素。
227+
228+
41. 有12个外观相同的篮球,其中1个的重要和其他11个的重量不同(有可能轻有可能重),现在有一个天平可以使用,怎样才能通过最少的称重次数找出这颗与众不同的球。

0 commit comments

Comments
 (0)