5. 模块化编程

閱讀時間約 33 分鐘

HI, 大家好。我是茶桁。

上一节中我们学习了Python基本的流程控制,并且预告了这一节的内容,就是将要学习「模块化编程」。那什么是模块化编程呢?按照维基百科的说法:

模块化编程(英语:modular programming),是强调将计算机程序的功能分离成独立的、可相互改变的“模块)”(module)的软件设计技术,它使得每个模块都包含着执行预期功能的一个唯一方面(aspect)所必需的所有东西。

说的简单一点,就是把程序进行封装(函数封装、面向对象、文件...)

OK,话不多说,让我们开始吧。

函数

什么是函数?

函数的英文单词为function, 我们将其翻译过来,就是“函数,功能”。

其实,函数就是一个具有特定功能的代码块。

函数的作用

函数的目的是封装,将特定功能的代码块进行封装,其目的是提高代码的重用性,从而提高开发效率,并且降低了后期的维护成本。

函数的定义和使用

函数的定义其实非常简单,我们用代码来写一下:

# 定义函数[基本结构]
def 函数名([参数列表]):
当前行数的具体功能的代码
当前行数的具体功能的代码
...

当然,函数在写完之后并不会自动执行,只是把函数定义了而已。如果想要使用定义完成的函数,需要用语法来进行函数的调用。

那么函数该如何调用呢?如下:

函数名()

示例:

# 函数的定义格式
def love():
print('i')
print('love')
print('u')

# 函数的调用
love()

当前程序运行输出结果:

i
love
u

以上代码可以得到函数的第一个特征:函数定义后,不调用不执行。还记得咱们上节课强调的流程控制吗?代码最基本流程顺序是自上而下的,所以,这个时候我们如果调用放在上方,例如:

# 函数的调用
love()

# 函数的定义格式
def love():
print('i')
print('love')
print('u')

此时因为love()调用的时候函数还未被定义,所以会执行报错:

NameError: name 'love' is not defined
raw-image

所以我们需要注意:不能在函数定义前调用函数。

另外,我们需要注意,函数的调用不受次数的影响,比如,我们定义好函数后,这个时候在后面调用三次:

love()
love()
love()

那执行后的结果应该是连着打印了三次结果。

和变量一样,函数的命名也是要遵守命名规范的:

  • 字母数字下划线,不能以数字开头
  • 严格区分大小写,且不能使用关键字
  • 命名最好有意义,且不要使用中文

现在我们想想,在love()函数被定义后,我们再来定义一个同名的函数会怎么样?

我们尝试一下,在刚才定义好的函数下方重复写一个同名的函数:

# 函数的定义格式
def love():
print('i')
print('love')
print('u')

def love():
print('u')
print("don't")
print('love')
print('me')

# 函数的调用
love()

直接结果:

u
don't
love
me

那,我们得到了实验结果:同样的函数名被再次定义之后,冲突的函数会被覆盖。

所以,最后我们总结一下函数的特征及注意事项:

1. 函数定义后,不调用不执行
2. 不能在函数定义前调用函数
3. 函数的调用不受次数影响
4. 函数的命名要遵守命名规范
- 字母数字下划线,不能以数字开头
- 严格区分大小写,不能使用关键字
- 命名最好有意义,且不要使用中文
5. 函数名不要冲突,冲突后会被覆盖

函数的参数

在定义函数的时候,我们需要注意给函数的参数。可以在参数列表的位置进行定义,这个称为形参。如果一个函数有形参,那么在调用的时候必须传递参数(实参)。实参将值传递给实参的过程,本质上就是变量赋值操作。

函数参数概念及分类

带有参数的函数,该如何定义?

在定义函数时,在小括号内可以定义形参(形式上的参数)

def love(w):
print(f'i love {w}')

# 调用带有形参的函数时,需要传递参数(实参)
love('马户')

执行结果为:

i love 马户

在这整个函数中,小括号内的w就是形参,在调用的时候的马户就是实参,在调用过程中将值传给了形参w

那么,如果我在调用的时候没有传递实参,就会直接报错:

love()

TypeError: love() missing 1 required positional argument: 'w'

形参可以是多个,这就是定义带有多个参数的函数:

def love(m, n):
print(f'{m} love {n}')

love('i', 'u')

执行结果:

1
i love u

如果形参是多个的话,那么有多少个形参就必须传递几个实参。并且参数都是按照顺序进行传递的。

如果少传一个参数,则同样会被错。

那,能不能多传呢?也不行,如果多传了参数,一样会报错。

至此,我们可以做如下总结:

  • 函数参数:调用时需要传递的数据
  • 函数参数的大类分为形参和实参
    • 形参意思:函数定义时的参数
    • 实参意思:函数调用时的参数
  • 形实关系:函数调用时,形参和实参个数需要一一对应

函数中的参数类型

在确定了什么是形参和实参之后,我们来看看,这两种参数都有哪些类型。

函数参数在类型上,包括:

  • 普通参数
  • 默认参数
  • 收集参数
  • 命名关键字参数
  • 关键字参数收集

普通参数

先来说说普通参数,其实就是位置参数,也叫顺序参数,也是必须传递的参数。

def love(m, n):
print(f'{m} love {n}')

love('i', 'u')

这段代码中,m, n就是普通参数,必须传递。

默认参数

有些函数在定义的时候,行参上就已经定义了默认值,那么这种就叫做默认参数。

在调用函数的时候,默认参数是可以不传值的。当传值之后,默认值就会被改变:

def func(x, y=20):
print(x, y)

func(2)

这段代码中的行参y就是默认参数,我们在调用函数func()只写了一个实参,也就是只传了一个值给函数。这个时候执行结果为:

2 20

我们修改一下,传两个值进去看看结果:

def func(x, y=20):
print(x, y)

func(2, 100)

执行结果:

2 100

可以看到,本来我们定义的行参y的默认值被改变了。

在定义默认参数的时候需要注意,函数中的默认参数只能全部定义在普通参数的后面,否则在调用函数的时候就会报错,比如以下这些情况:

# 第1种错误情况
def func(x=100, y=200, z):
print(x, y, z)

func(100,200,300)

# 第2种错误情况
def func(x=100, y, z=200):
print(x, y, z)

func(100, 200, 300)

# 第3种错误情况
def func(x, y=100, z):
print(x, y, z)

func(300,200,50)

收集参数

收集参数就是专门收集在函数调用时传递的多余的实参,或者我们可以理解为,不确定需要传递多少个实参,直接用一个行参来接收。

比如,我们现在有个需求就是需要计算用户输入的数字总和,我们按前面那个函数的定义方式为:

def func(x, y z=100):
print(x+y+z)

func(20,30)

这个函数中,我们输入2个值或者3个值都可以,但是当我们只输入一个值或者三个以上的时候,程序就会报错了。

那么有没有什么办法,不管用户输入多少个数字,我们都可以进行相加计算呢?

def func(x="+", *args):
if x == '+':
print('加法运算', args)
else:
print('减法运算', args)

func("-", 2, 3, 4, 5, 6, 7, 8)

这段代码执行结果为:

减法运算 (2, 3, 4, 5, 6, 7, 8)

虽然中间的运算代码我没有写,但是大家可以看到,已经可以接受不固定的多个参数了。

这个*args就是我们的收集参数。

在定义函数的时候,如果需要收集参数,那么这个形参前面需要加一个*号,例如*args。这里需要注意一点,*args并不是固定写法,你可以随意定义一个,只要前面有*号就可以了。比如下面这样:

def func(x="+", *y):
if x == '+':
print('加法运算', y)
else:
print('减法运算', y)

func("-", 2, 3, 4, 5, 6, 7, 8)

一样可以执行并得到一样的结果,这个时候,我们的*y就是收集参数。

收集参数也有两类,一种是普通的收集参数:专门用于收集多余的普通参数,形成一个新的元组。

语法: 参数前面加*, 例如:*args

还有一种是关键字收集参数:用于专门收集多余关键字实参,形成一个新的字典:

语法:参数前面加**, 例如:**kwargs

现在我们已经理解了普通的收集参数,那么在学习关键字收集参数之前,我们先来学习一下命名关键字参数

命名关键字参数

命名关键字是放在*号后面的参数,调用的时候强制必须传入制定参数名才能进行调用。

def func(a, b, c=3, *args, name):
print(a, b, c, "\n", *args, "\n", name)

func(1, 2, 3, 4, 5, 6, 7, 8, name='茶桁')

这段代码执行结果:

1 2 3 
4 5 6 7 8
茶桁

我们特意在中间加了换行字符来清晰的辨别*argsname

如果在这段代码中我稍微变一下,在执行函数的时候,实参里不标明name可以吗?

def func(a, b, c=3, *args, name):
print(a, b, c, "\n", *args, "\n", name)

func(1, 2, 3, 4, 5, 6, 7, 8, '茶桁')

执行之后我们收到了报错:

TypeError: func() missing 1 required keyword-only argument: 'name'

这段报错明显告诉我们,确实了一个必须的关键字参数name

那为什么会出现这种报错呢?这是因为在关键字参数之前,我们使用了*args来进行收集参数,那么无论你写多少,这些值都会被*args接收变成元组,那么后面的name自然就无法接受到值了。

让我们再来做一个实验,给命名关键字参数加上一个默认值,那么我们就能明显的看出问题:

def func(a, b, c=3, *args, name='_茶桁'):
print(a, b, c, "\n", *args, "\n", name)

func(1, 2, 3, 4, 5, 6, 7, 8, '茶桁')

这段代码执行结果:

1 2 3 
4 5 6 7 8 茶桁
_茶桁

可以看到,name给了默认值之后不再出现报错,而我们的实参也并未传到name里,而是全部被*args接收了。最后打印出了name的默认值_茶桁

利用命名参数的这种定义参数名称接收值的特点,我们就可以打乱之前普通参数传值的顺序性,比如:

def func(x, y):
print(x, "\t", y)

func(2, 3)
func(y = 2, x = 3)

执行结果为:

2 	 3
3 2

还是最开始的普通参数的写法,但是最后执行函数的时候,我们给实参指定了名称,这样传参顺序就没那么重要了。

所以,我们总结一下:

  • 关键字参数定义在收集参数后面
  • 关键字参数必须通过形参的名字来进行传递

关键字参数收集

前面我们在讲收集参数的结尾处提到了关键字参数收集,形式为**kwargs

def func(a, b, c=3, *args, name, age,  **kwargs):
print(a, b, c)
print(args) # 普通收集参数,会把多余的参数收集为元组
print(name, age)
print(kwargs) # 关键字参数收集,会把多余的关键字参数收集为字典

func(1, 2, 4, 112, 123, 321, 541, 231, name="茶桁", age=18, sex='male', height=185, x='x', y='y')

执行结果:

1 2 4
(112, 123, 321, 541, 231)
茶桁 18
{'sex': 'male', 'height': 185, 'x': 'x', 'y': 'y'}

从执行结果上我们可以看到,在nameage之后的所有参数都被传递到了**kwargs里,然后作为字典打印了出来。

在声明这个函数和执行函数的时候需要注意,这些参数都是有顺序的,如果在执行函数的时候再多传一个非关键字参数,这个时候程序就会报错,如果是关键字参数,则照样会被**kwargs接收。

在我们介绍完这些参数之后,我们最后再说明一下:

  • 形参声明的位置顺序:普通参数 -> 默认参数 -> 收集参数 -> 命名关键字参数 -> 关键字收集参数
  • def func(a, b, c=1, *args, d, **kw) 这段声明中,a,b为普通参数,c是默认参数,args是收集参数,d是命名关键字参数,kw是关键字收集参数
  • 极少情况下会同时出现上面五种形参,一般情况下为:普通参数,收集参数,关键字收集参数
  • 所有参数的摆放问题:
    • 实参:普通实参在前,关键字参数在后
    • 形参:关键字收集参数一定在最后出现,收集参数推荐在普通参数之后使用。
    • 推荐顺序:普通形参、收集参数、关键字收集参数

函数的返回值

一个函数除了可以完成一定功能之外,还可以用来安需要返回一些内容。在函数中,使用return关键字来制定返回数据,可以返回任意类型的数据。

函数的返回值会把数据返回到调用的地方,可以使用变量进行接收,或者作其他处理。

函数可以分为两类:

  1. 执行过程函数:函数体内完成一定的功能即可,没有返回值
  2. 具有返回值的函数:函数体内完成一定的功能,并且返回一个结果到函数调用处。

比如:

def func(a, b):
print(f'{a} love {b}')

以上函数就是一个没有返回值的函数,这个函数只是为了完成打印这句话的功能。

那么有返回值的函数是什么样子?

如果需要在函数中制定返回内容,我们需要使用return关键字。

# 有返回值的函数
def func(a, b):
res = f'{a} love {b}'
# 可以在函数体内,使用return返回内容
return res

r = func('老鼠', '布丁')
print(r)

执行结果为:

老鼠 love 布丁

在这段代码中,我们在func()的函数体内最后利用关键字return返回了任意内容,并且使用变量r接收了这个返回值,最后讲r打印了出来。

在调用func()这个函数的时候,函数中的返回值会返回到函数调用处。

我们再来研究一下return这个关键字,我们在return的前后都加上一段打印代码,看看会发生什么。

def func(a, b):
res = f'{a} love {b}'
print('这是return前')
return res
print('这是return后')

r = func('老鼠','布丁')
print(r)

执行结果:

这是return
老鼠 love 布丁

看到结果我们可以清楚,return之后的的代码并未继续执行,也就是说,我们如果要在函数体内执行其他任务,必须放在return之前执行,否则根本不会执行。那么我们可以得出结论:return必须放在一个定义函数的最后面。

Tips: 其实,即便没有return关键字或者returen之后没有任何内容,也有返回值,只是返回的是None值。

None是一个特殊的数据,表示什么都没有。查询类型可以看到返回 <class ‘NoneType’>

变量的作用域

作用域就是当前起作用,可用的范围区域。也就是变量的有效范围。

变量按作用域可以分为:

  • 局部变量: 在函数内部可以使用的变量
  • 全局变量:在函数内外都可以使用的变量

局部变量

让我们尝试下,如果函数内定义的变量在函数外使用会如何:

def func():
a = 20

print(a)

执行结果:

NameError: name 'a' is not defined

被告知a并未被定义。

可以看到,函数内定义的变量,在函数外连获取都做不到。这种在函数内定义的这个变量a,就是局部变量,它在函数外不能使用。

再让我们来看看将变量定义在函数外会是怎样的一种情况:

num = 10
def func():
print(num)

func()

执行结果:

10

func函数内,我们获取到了变量num的值并打印。那说明,在函数内我们可以获取函数外部的变量。

我们继续在继续看:

num = 10
def func():
num += 20
print(num)

func()

执行后报错:

UnboundLocalError: local variable 'num' referenced before assignment

这样我们可以看到,变量num在函数内虽然可以使用,但是无法进行更改。

那在函数外定义的所有变量都是如此吗?再让我们试试看:

items = [1, 2, 3, 4, 5]
def func():
items[0] = 20
print(items)

func()

执行结果:

[20, 2, 3, 4, 5]

由此我们看出,并不是所有的变量都不可在函数内进行更改。

其实,变量是分为两种的:

  • 可变数据类型:在函数外定义的变量,在函数内可以使用并改变
  • 不可变数据类型:在函数外定义的变量,在函数内只可以访问而无法改变

可变数据类型有列表和字典,其他的都是不可变数据类型。

全局变量

之前我们介绍的都是局部变量,那怎样定义全局变量呢?

在函数内使用global直接定义的变量,就是全局变量,函数内外都可以直接使用。

在函数外定义的变量,在函数内使用global关键字进行声明,那么也是全局变量。

例如:

num = 20
def func():
global num
num += 10
print(num)

func()

这个时候我们可以得到执行结果:

30

那有小伙伴就问了,如果我在函数外直接使用global定义全局变量可以吗?让我们来试试看就知道了:

global num
num = 20
def func():
num += 10
print(num)

func()

执行之后得到报错:

UnboundLocalError: local variable 'num' referenced before assignment

这样我们就得到了结果:不可以。

在整个程序中,我们可以使用两个函数方法来获取数据:

globals()用来获取全局数据,locals()用来获取当前作用域的数据

讲到这里,我们再来多看一组代码:

# 函数的作用域
def outer():
print('this is outer func...')
def inner():
print('this is inner func...')

outer()
inner()

这段代码执行结果为:

this is outer func...

NameError: name 'inner' is not defined

正常执行了outer()内的打印,然后又报了一个错误,提示inner函数未定义。

说明,不只是变量有作用域,函数一样也有作用域。要想inner函数内的打印也起作用,我们需要在函数内就调用执行inner()

# 函数的作用域
def outer():
print('this is outer func...')
def inner():
print('this is inner func...')
inner() # 在函数内执行
outer()

这样,我们执行的结果就是:

this is outer func...
this is inner func...

如果我们在外层函数中定义一个局部变量,能在内层函数中使用吗?

# 函数的作用域
def outer():
a = 2
print('this is outer func...')
def inner():
a += 1
print('this is inner func...')
print(a)
inner()
outer()

执行之后得到报错:

UnboundLocalError: local variable 'a' referenced before assignment

说明并不可以。

nonlocal关键字

那么,到底有没有什么办法在内函数中使用上一层函数中的局部变量呢?答案是有办法。

在内函数中如果想要使用外层函数的变量,那么需要使用nonlocal关键字,可以引用上一层函数中定义的局部变量。

# 定义一个外层函数
def outer():
# 外函数的局部变量
num = 10
# 内函数, 局部函数, 在函数的内部定义的函数
def inner():
# nonlocal 关键字在局部函数中使用
nonlocal num # 可以引用上一层函数中定义的局部变量
num += 1
print(num)
inner()
outer()

执行后返回结果:

11

至此,我们通过使用nonlocal关键字,成功拿到了外层函数定义的变量num并使用。最后打印出使用的结果。

这里我们要注意,nonlocal虽然可以引用上一层函数中定义的局部变量,但是这并不代表提升为了全局变量。

既然我们有了global关键字可以提升变量为全局变量,为什么还需要一个nonlocal关键字呢?是不是有点多此一举?

这两者的功能上并不相同。global关键字修饰变量后标识该变量是全局变量,对该变量进行修改就是修改全局变量,而nonlocal关键字修饰变量后标识该变量是上一级函数中的局部变量,如果上一级函数中不存在该局部变量,nonlocal位置会发生错误(最上层的函数使用nonlocal修饰变量必定会报错)。

关于函数的文档

我们在一个未定义任何变量和函数的空白文档中打印一下全局数据:

print(globals())

执行结果:

{
'__name__': '__main__',
'__doc__': 'Automatically created module for IPython interactive environment',
'__package__': None,
'__loader__': None,
'__spec__': None,
'__builtin__': <module 'builtins' (built-in)>,
'__builtins__': <module 'builtins' (built-in)>,
'_ih': ['',
'print(globals())'],
'_oh': {},
'_dh': [PosixPath('/Users/xx/git/AI_Cheats/Python'),
PosixPath('/Users/xx/git/AI_Cheats/Python')],
'In': ['',
'print(globals())'],
'Out': {},
'get_ipython': <bound method InteractiveShell.get_ipython of <ipykernel.zmqshell.ZMQInteractiveShell object at 0x105be29e0>>,
'exit': <IPython.core.autocall.ZMQExitAutocall object at 0x105be3280>,
'quit': <IPython.core.autocall.ZMQExitAutocall object at 0x105be3280>,
'open': <function open at 0x10488e710>,
'_': '',
'__': '',
'___': '',
'__vsc_ipynb_file__': '/Users/xx/git/AI_Cheats/Python/globals.ipynb',
'_i': '',
'_ii': '',
'_iii': '',
'_i1': 'print(globals())'
}

我们来看这个打印出来的json

类似于__name__这种前后有__ __的数据,称之为“魔术变量”。我们并未定义,但是已经存在了。

如果脚本作为主程序,那么__name__值是__main__,如果是当作一个模块在另外一个脚本中引用去使用,那么值就是当前文件的命名。

__doc__当前脚本的文档说明,在当前脚本当中的第一个三引号注释就是当前脚本的说明文档。比如,我们在这个空白的文档中写一段三引号注释

"""
这里是整个文档的说明部分。
"""
def func():
pass

然后我们直接将doc打印出来查看:

print(__doc__)

可以看到输出内容:

这里是整个文档的说明部分。

这种文档其实不止适用于python文件,对于定义的函数依然适用。比如,我们执行定义了一个函数,并在函数内部用三引号进行注释:

def func():
"""
这里是让你写一写函数的文档说明的。
需要说明当前函数的作用,
如果当前函数还有形参,那么也需要对形参进行一一说明。
name: 这个是一个name参数,用于接收姓名
age: 这个参数是表示年龄
:return: 此处说明当前函数的返回值
"""
pass

这个时候,我们在下方执行:

print(func.__doc__)

可以看到我们在注释内定义的说明文档被打印出来了:

raw-image

这样,我们不仅可以在自己写函数的时候在上方清晰的写明当前函数的作用及参数,我们还可以使用此方法,查找其他人所写的函数的一些说明。

在我们平时写代码的时候,养成一个好习惯是非常有必要的。

总结一下:

  • print(__name__): 获取当前脚本的文件名
  • print(__doc__): 获取当前脚本的说明文档
  • print(func.__doc__): 获取当前函数的说明文档

练习:函数封装

我们上一讲中的练习中,我们打印了乘法表,矩形图形,还计算了12生肖。这里我们就将乘法表来封装成函数,实现我们上节课留的其中一道思考题:反向打印。

我们先将打印乘法表封装起来:

# 定义函数,打印九九乘法表
def multiply_table():
"""
当前函数的功能是打印出乘法表
"""
for x in range(1, 10):
for y in range(1, x+1):
print(f'{x}X{y}={x*y}', end=" ")
print()

这样,我们在其他地方执行multiply_table()函数的时候,就可以直接打印出乘法表。

现在让我们给这个函数多加一些功能:

# 定义函数,打印九九乘法表
def multiply_table(i=0):
"""
当前函数的功能是打印出乘法表
i=0; i 这个参数可以用来控制正向输出和方向输出,0的时候正向,1的时候反向,默认为0
"""
if i:
rs = range(9, 0, -1)
else:
rs = range(1, 10)

for x in rs:
for y in range(1, x+1):
print(f'{x}X{y}={x*y}', end=" ")
print()

我们执行函数的时候,输入1来试试看:

multiply_table(1)

输出结果:

9X1=9 9X2=18 9X3=27 9X4=36 9X5=45 9X6=54 9X7=63 9X8=72 9X9=81 
8X1=8 8X2=16 8X3=24 8X4=32 8X5=40 8X6=48 8X7=56 8X8=64
7X1=7 7X2=14 7X3=21 7X4=28 7X5=35 7X6=42 7X7=49
6X1=6 6X2=12 6X3=18 6X4=24 6X5=30 6X6=36
5X1=5 5X2=10 5X3=15 5X4=20 5X5=25
4X1=4 4X2=8 4X3=12 4X4=16
3X1=3 3X2=6 3X3=9
2X1=2 2X2=4
1X1=1

可以看到,我们的控制结果被成功打印出来。至此,这个有一些小功能的九九乘法表就封装完成了。

那么这一节课就不留思考题了,大家课后熟练掌握一下封装函数和变量的作用域,我们下节课来学习一些高阶函数, 好,下课。

9會員
62內容數
从基础开始,再到Python,然后是CV、BI、NLP等相关技术。从头到尾详细的教授一边人工智能。
留言0
查看全部
發表第一個留言支持創作者!
茶桁的沙龍 的其他內容
Hi,大家好。我是茶桁。 在前面几节课的基础之上,我们今天开始尝试在Python中控制流程。这中间,让我们来做一些实际的练习。 Python语句的分类 让我们先了解一下Python语句的分类。 在Python中,可分为单行代码和代码块/组, 顾名思义,单行代码就是一行的Python代码,而代
Python的系列课程是写给零基础的小白看的,如果基础比较好的小伙伴可以暂时先不关注,等待后续课程。 Hi, 大家好,我是茶桁。 之前的课程已经给大家讲解了Python相关特性和基本语法。那么这节课呢,我们尝试着从最简单的脚本来开始认识Python。 在开始这节课之前呢,我是默认大家已经安装好
千里之行始于足下。 大家好,我是茶桁,这里是我们《AI秘籍》的第一节,让我们先从Python来开始好好的打好基础。 第一堂课,我们先从最基础的Python特性开始,当然,还有一些基本语法。 上来就开始讲特性和语法,说明我们将会遗弃惯用的“环境搭建”等更基础的内容,那些内容网上已经很丰富了,一查
Hi,大家好。我是茶桁。 前两节我们学习了基本的Python特性和语法,并且认识了一些基本的Python脚本。今天,我们来学习一下Python的运算符,而我们选择的版本为Python3。 什么是运算符 为了能让我们的学习顺利进行下去,首先我们需要先弄明白:什么是运算符。 这里举一个简单的栗子
Hi,大家好。我时茶桁。 最近,我花了几天时间仔细思考了一下即将要开始写的专栏《AI秘籍》,再根据自己的能力大概规划了一下。目前大致已经理出了一些相关信息可以分享给大家。 专栏形式 本次专栏应该会以文章的形式先和大家见面,后续还会根据能力以原本的文章为准录制视频版本。 专栏平台 就如前一篇
Hi, 大家好,我是茶桁,这里为自己做个广告,目前打算开始写一整个系列《AI秘籍》。 这一段时间内我写过一个系列《零基础学习大语言模型》(目前还没写完)。 说实话,这个系列其实原出处并不是我,严谨的说来,有涉嫌擦边“洗稿”的嫌疑,所以最后放弃了收费的想法,仅仅对一些模型,资源以及计算结果进行了补
Hi,大家好。我是茶桁。 在前面几节课的基础之上,我们今天开始尝试在Python中控制流程。这中间,让我们来做一些实际的练习。 Python语句的分类 让我们先了解一下Python语句的分类。 在Python中,可分为单行代码和代码块/组, 顾名思义,单行代码就是一行的Python代码,而代
Python的系列课程是写给零基础的小白看的,如果基础比较好的小伙伴可以暂时先不关注,等待后续课程。 Hi, 大家好,我是茶桁。 之前的课程已经给大家讲解了Python相关特性和基本语法。那么这节课呢,我们尝试着从最简单的脚本来开始认识Python。 在开始这节课之前呢,我是默认大家已经安装好
千里之行始于足下。 大家好,我是茶桁,这里是我们《AI秘籍》的第一节,让我们先从Python来开始好好的打好基础。 第一堂课,我们先从最基础的Python特性开始,当然,还有一些基本语法。 上来就开始讲特性和语法,说明我们将会遗弃惯用的“环境搭建”等更基础的内容,那些内容网上已经很丰富了,一查
Hi,大家好。我是茶桁。 前两节我们学习了基本的Python特性和语法,并且认识了一些基本的Python脚本。今天,我们来学习一下Python的运算符,而我们选择的版本为Python3。 什么是运算符 为了能让我们的学习顺利进行下去,首先我们需要先弄明白:什么是运算符。 这里举一个简单的栗子
Hi,大家好。我时茶桁。 最近,我花了几天时间仔细思考了一下即将要开始写的专栏《AI秘籍》,再根据自己的能力大概规划了一下。目前大致已经理出了一些相关信息可以分享给大家。 专栏形式 本次专栏应该会以文章的形式先和大家见面,后续还会根据能力以原本的文章为准录制视频版本。 专栏平台 就如前一篇
Hi, 大家好,我是茶桁,这里为自己做个广告,目前打算开始写一整个系列《AI秘籍》。 这一段时间内我写过一个系列《零基础学习大语言模型》(目前还没写完)。 说实话,这个系列其实原出处并不是我,严谨的说来,有涉嫌擦边“洗稿”的嫌疑,所以最后放弃了收费的想法,仅仅对一些模型,资源以及计算结果进行了补
你可能也想看
Google News 追蹤
Thumbnail
這個秋,Chill 嗨嗨!穿搭美美去賞楓,裝備款款去露營⋯⋯你的秋天怎麼過?秋日 To Do List 等你分享! 秋季全站徵文,我們準備了五個創作主題,參賽還有機會獲得「火烤兩用鍋」,一起來看看如何參加吧~
Thumbnail
美國總統大選只剩下三天, 我們觀察一整週民調與金融市場的變化(包含賭局), 到本週五下午3:00前為止, 誰是美國總統幾乎大概可以猜到60-70%的機率, 本篇文章就是以大選結局為主軸來討論近期甚至到未來四年美股可能的改變
Thumbnail
Faker昨天真的太扯了,中國主播王多多點評的話更是精妙,分享給各位 王多多的點評 「Faker是我們的處境,他是LPL永遠繞不開的一個人和話題,所以我們特別渴望在決賽跟他相遇,去直面我們的處境。 我們曾經稱他為最高的山,最長的河,以為山海就是盡頭,可是Faker用他28歲的年齡...
Thumbnail
一, 简介 模块化开发系统最初见于俄罗斯人创立的Tibbo公司。 欧美设计的产品多是一个针对性设计,用于解决某个已知的问题,出厂后功能不能更改。比如说控制化工设备的控制器只能用于控制某一类化工设备,出厂后不能用于其它。这就导致了产品的功能针对性越来越强,越来越细分化,某一公司针对的领域越来越小。整个
Thumbnail
Craft 介绍 一款现代文档应用,相当于无 Database 功能的本地原生 Notion 文档。 优点 原生开发,拥有丝滑般的体验; 相当于无数据库版的 Notion; 易于上手; 简约优美; 支持社区插件; 数据自由。 缺点 Notion FlowUs 息流笔记 介绍 核心功能 特色功能
Thumbnail
随着 Notion 在笔记软件赛道的快速崛起,获得了很多用户的喜欢。然而,Notion 也存在部分缺点。对于中国大陆用户而言,使用 Notion 需要特殊网络。否则,有时候会登录很慢,或者分享/协作存在障碍。 那么,有什么解决办法呢? AnyType 介绍 优点 本地离线,没有网络也可以使用。
Thumbnail
<p>何其有幸。在沒有預期的路途裡,在茫茫人海的漂流中,能夠得到溫潤的回音。</p>
Thumbnail
<p>這些年在全球環境變遷的影響下,極端氣候發生的機率愈來愈高,一年之內有非常多次24小時之內溫差超過10度,甚至到15~20度的日子也不罕見。因此如何控制好自己血壓的變化,也成為當代人另一個身體保健的重點了。</p>
Thumbnail
<p>奇華夫婦倆正趴在窗口和對面的鄰居大聲喊話,然後他叫N和她男友來到窗邊喊回去,說如果他們這麼做的話,到時就給他們做伴郎伴娘。</p>
Thumbnail
<p>中國當然有其特殊性,歷史文化傳統悠久,國體龐大,國情複雜。因而任何新的轉變都異常困難與緩慢。但是,特殊性並不是拒絕改變的理由。憲政民主制度當然也會因國家而有所差異,但在憲政民主之外不應當有特殊性。</p>
Thumbnail
<p>只有性命和你休戚與共的專家,你才可以相信他,像開飛機的機師,或是和你一起在天空玩飛行傘的教練。投資理財上,不會有人和你是生命共同體。</p>
Thumbnail
<p>AI發展一日千里,憂慮與期待跳著糾纏的雙人舞。製程愈來愈數位化的當代流行音樂,影響所及,會變成什麼模樣呢?</p>
Thumbnail
<p>剛叮嚀我如果出事一通電話,他在軍中的父親一定會幫助我的他。</p>
Thumbnail
這個秋,Chill 嗨嗨!穿搭美美去賞楓,裝備款款去露營⋯⋯你的秋天怎麼過?秋日 To Do List 等你分享! 秋季全站徵文,我們準備了五個創作主題,參賽還有機會獲得「火烤兩用鍋」,一起來看看如何參加吧~
Thumbnail
美國總統大選只剩下三天, 我們觀察一整週民調與金融市場的變化(包含賭局), 到本週五下午3:00前為止, 誰是美國總統幾乎大概可以猜到60-70%的機率, 本篇文章就是以大選結局為主軸來討論近期甚至到未來四年美股可能的改變
Thumbnail
Faker昨天真的太扯了,中國主播王多多點評的話更是精妙,分享給各位 王多多的點評 「Faker是我們的處境,他是LPL永遠繞不開的一個人和話題,所以我們特別渴望在決賽跟他相遇,去直面我們的處境。 我們曾經稱他為最高的山,最長的河,以為山海就是盡頭,可是Faker用他28歲的年齡...
Thumbnail
一, 简介 模块化开发系统最初见于俄罗斯人创立的Tibbo公司。 欧美设计的产品多是一个针对性设计,用于解决某个已知的问题,出厂后功能不能更改。比如说控制化工设备的控制器只能用于控制某一类化工设备,出厂后不能用于其它。这就导致了产品的功能针对性越来越强,越来越细分化,某一公司针对的领域越来越小。整个
Thumbnail
Craft 介绍 一款现代文档应用,相当于无 Database 功能的本地原生 Notion 文档。 优点 原生开发,拥有丝滑般的体验; 相当于无数据库版的 Notion; 易于上手; 简约优美; 支持社区插件; 数据自由。 缺点 Notion FlowUs 息流笔记 介绍 核心功能 特色功能
Thumbnail
随着 Notion 在笔记软件赛道的快速崛起,获得了很多用户的喜欢。然而,Notion 也存在部分缺点。对于中国大陆用户而言,使用 Notion 需要特殊网络。否则,有时候会登录很慢,或者分享/协作存在障碍。 那么,有什么解决办法呢? AnyType 介绍 优点 本地离线,没有网络也可以使用。
Thumbnail
<p>何其有幸。在沒有預期的路途裡,在茫茫人海的漂流中,能夠得到溫潤的回音。</p>
Thumbnail
<p>這些年在全球環境變遷的影響下,極端氣候發生的機率愈來愈高,一年之內有非常多次24小時之內溫差超過10度,甚至到15~20度的日子也不罕見。因此如何控制好自己血壓的變化,也成為當代人另一個身體保健的重點了。</p>
Thumbnail
<p>奇華夫婦倆正趴在窗口和對面的鄰居大聲喊話,然後他叫N和她男友來到窗邊喊回去,說如果他們這麼做的話,到時就給他們做伴郎伴娘。</p>
Thumbnail
<p>中國當然有其特殊性,歷史文化傳統悠久,國體龐大,國情複雜。因而任何新的轉變都異常困難與緩慢。但是,特殊性並不是拒絕改變的理由。憲政民主制度當然也會因國家而有所差異,但在憲政民主之外不應當有特殊性。</p>
Thumbnail
<p>只有性命和你休戚與共的專家,你才可以相信他,像開飛機的機師,或是和你一起在天空玩飛行傘的教練。投資理財上,不會有人和你是生命共同體。</p>
Thumbnail
<p>AI發展一日千里,憂慮與期待跳著糾纏的雙人舞。製程愈來愈數位化的當代流行音樂,影響所及,會變成什麼模樣呢?</p>
Thumbnail
<p>剛叮嚀我如果出事一通電話,他在軍中的父親一定會幫助我的他。</p>