24. 装饰器语法与应用

閱讀時間約 28 分鐘
raw-image


Hi, 大家好。我是茶桁。

在最近几期的课程中,相信小伙伴们都频繁的看到一个词:「装饰器」, 那到底什么是装饰器,又有什么作用呢?我们这节课,就来好好的来了解一下。

装饰器定义

装饰器就是在不改变原有函数代码,且保持原函数调用方法不变的情况下,给原函数增加新的功能(或者给类增加属性和方法)。

核心思想:用一个函数(或者类)去装饰一个旧函数(或者类),造出一个新函数(或者新类)。

应用场景:引入日子,函数执行时间的统计,执行函数钱的准备工作,执行函数后的处理工作,权限校验,缓存等。

语法规则:在原有的函数上加上@符,装饰器会把下面的函数当作参数传递到装饰器中,@符又被称为「语法糖」。

装饰器原型

装饰器其实就是利用闭包,把函数当作参数传递,并在在函数内去调用传递进来的函数,并返回一个函数。

来,我们还是用代码来学习,先让我们定义一个普通函数:

 # 定义一个普通函数
 def old():
     print('我是一个普通的函数')
 ​
 old() # 作为普通函数直接调用
 ​
 ---
 我是一个普通的函数

现在让我们定义一个嵌套函数,分为外函数和内函数两部分:

 # 定义外函数,接受一个函数作为参数
 def outer(f):
     # 定义内函数, 并且在内函数中调用了外函数的参数
     def inner():
         print('我是外函数中的内函数1')
         f()
         print('我是外函数中的内函数2')
     return inner

这里面我们在内函数中打印了两句话,在两句话中间执行了一次外函数的参数(传递进来一个函数)。最后讲内函数作为参数返回。

然后我们讲刚才的普通函数old作为参数传进去,然后再用外函数返回的inner内函数重新赋值普通函数old,最后让我们再执行一遍old函数, 这个时候,因为old被重新赋值,其实等同于调用了inner函数。来,我们看看结果:

 old = outer(old) # outer返回了inner函数,赋值给了old
 old()
 ​
 ---
 我是外函数中的内函数1
 我是一个普通的函数
 我是外函数中的内函数2

是不是稍显繁杂?那让我们换个思路,现在我们已经先定义好了outerhe inter,两者关系不变。还是之前那些代码,那么我们如何利用装饰器来进行调用呢?

 # 装饰器用法
 @outer # 此处将outer作为了装饰器
 def old():
     print('我是一个普通的函数')

我们在定义old函数的时候,直接加上一个@语法糖,就将outer作为了装饰器。这个装饰器的作用就等同于old = outer(old)。那让我们打印看看结果:

 old()
 ​
 ---
 我是外函数中的内函数1
 我是一个普通的函数
 我是外函数中的内函数2

那我们现在完成了装饰器的用法,按照定义,我们在不改变old函数的代码,且保持了old函数调用方法不变的情况下,增加了新的方法outer

old函数经过outer装饰器进行了装饰,代码和调用方法不变,但是函数的功能发生了改变。

你是不是这个时候又有疑问了,那装饰器要用在什么地方呢?让我们来实现一个应用:

装饰器应用:统计函数的执行时间

在正式写代码之前,我还是习惯带着大家先思考一遍。我们需要统计函数的执行时间,那我们需要什么关键点?

  1. 开始时间,
  2. 结束时间
  3. 开始时间和结束时间之间,就是程序在运行的过程。

好的,让我们来开始写代码,先来一段简单的需要运行的程序,为了能顺利统计时间,我们给它设定两个东西,一个循环,一个停止运行时长。这样,我们不会因为程序运行过快而看不到结果:

 import time
 ​
 # 定义一个普通函数
 def func():
   for i in range(5):
     print(i, end=" ")
     time.sleep(1)

函数写完之后,让我们来执行一下看看:

 func()
 ​
 ---
 0 1 2 3 4
raw-image

没问题,确实是一秒打印一次。

现在,再来让我们完成要称为装饰器的统计函数:

 # 定义一个统计函数执行时间的装饰器
 def runtime(f):
     def inner():
         start = time.perf_counter()
         f()
         end = time.perf_counter() - start
         print(f'\n函数的调用执行时间为:{end}')
     return inner

在函数inner中,我们最终是打印了最终的时间end, 然后将整个inner函数返回。

那么,让我们来尝试执行一下看看吧:

 func = runtime(func)
 func()
 ​
 ---
 0 1 2 3 4
 函数的调用执行时间为:5.017943917075172

这样,我们就得到了func这个函数最后执行的时间,那现在的问题是,统计时间的函数是一个通用函数,我们很多函数中都需要用到它进行统计。但是我们总不能所有的函数都要用这种方法重新赋值之后再调用吧?

那我们就用装饰器来解决就好了:

 # 定义一个普通函数
 @runtime
 def func():
   for i in range(5):
     print(i, end=" ")
     time.sleep(1)
     
 func()
 ​
 ---
 0 1 2 3 4
 函数的调用执行时间为:5.017888417001814

当然,最终这种函数的调用执行时间并不会像现在这样打印到前台,而是会写进log变为日志存储起来,便于之后分析使用。

装饰器嵌套语法

在这一段代码中,我们来约个妹子,完成一场约会。从哪开始呢?就从找妹子要微信开始吧:

 def begin(f):
     def begin_inner():
         print('找妹子要微信,成功...')
         f()
         print('送妹子回家...')
     return begin_inner
     
 @begin
 def love():
     print('跟妹子畅谈人生和理想...')
 ​
 love()
 ​
 ---
 找妹子要微信,成功...
 跟妹子畅谈人生和理想...
 送妹子回家...

那这样,我们实现了一段最普通装饰器的定义。现在让我们在下面再定义一个装饰器函数,为什么呢?因为我渐渐不满足于只谈理想和人生了,要有点实际的行动了,顺便,我们写了一个列表,把和妹子要做的事情都列了个顺序,再来看看:

def begin(f):
def begin_inner():
print('找妹子要微信,成功... 1')
f()
print('送妹子回家... 5')
return begin_inner

def evolve(f):
def evolve_inner():
print('和妹子一起吃了个大餐.. 2')
f()
print('和妹子看了一场夜场电影... 4')
return evolve_inner

@evolve
@begin
def love():
print('跟妹子畅谈人生和理想... 3')

love()

---
和妹子一起吃了个大餐.. 2
找妹子要微信,成功... 1
跟妹子畅谈人生和理想... 3
送妹子回家... 5
和妹子看了一场夜场电影... 4

这个...顺序似乎不太对啊。让我们改变一下装饰器的顺序试试:

@begin
@evolve
def love():
print('跟妹子畅谈人生和理想... 3')

love()

---
找妹子要微信,成功... 1
和妹子一起吃了个大餐.. 2
跟妹子畅谈人生和理想... 3
和妹子看了一场夜场电影... 4
送妹子回家... 5

这回没错了,我们在最开始要妹子微信和最后送妹子回家中间,又进行了点什么。也算是有些进展了。那么,我们怎么去理解这个程序运行顺序呢?

  1. 先使用离得最近的begin装饰器,装饰love函数,返回了一个begin_inner函数
  2. 在使用上面的evolve, 装饰了上一次返回的begin_inner函数,又返回了一个evolve_inner函数。

在调用完成之后,就是需要顺序执行了,其执行的嵌套关系和顺序如下:

raw-image

那这,就是我们嵌套装饰器的用法。当然,这种嵌套装饰器的用法并不常见,可是一旦我们遇到了,要理解他的运行机制和顺序,避免不必要的麻烦。

装饰带有参数的函数

上一个部分,我们做了一个约会妹子的函数,并且使用装饰器进行了装饰。使的我们成功的按照进度依次执行了自己的计划。

但是问题来了,我们到目前为止约会了那么多妹子,都不知道谁是谁(海王体质),这可怎么办。这次,我们吸取教训,先要名字,既然之前的流程很成功,我们直接拿来使用就行了。但是繁杂的步骤我们都去掉,直奔主题:

# 带有参数的函数
def love(name):
print(f'跟{name}妹子在___畅谈人生...')

一个简单的函数,并且是一个填空题,你愿意待谁去哪里畅谈人生,随便。比如我,找「露思」去,去了哪里,恕不奉告了:

love('露思')

---
跟露思妹子在___畅谈人生...

可是即便如此,该有的流程还是不能丢,总不能凭空变出个妹子吧,还是得把必要的流程加上,原本定义的装饰器函数似乎不能使用了:

 # 定义装饰器
 def outer(f):
     def inner():
         print(f'找到妹子,成功的拿到了微信...')
         f()
         print(f'约妹子去看一场午夜电影...')
     return inner
 ​
 @outer
 def love(name):
     print(f'跟{name}妹子在___畅谈人生...')

流程上现在是没问题了,可是我们执行一下发现,报错了。

 love('露思')
 ​
 ---
 TypeError: outer..inner() takes 0 positional arguments but 1 was given

进行不下去了吧?那没办法,谁叫你之前和之后都把人家名字忘了呢,海王也得有点职业道德才行。既然我们在执行的时候有参数,那你整个过程中都得带上才行。不能玩着玩着忘记人家名字,对吧。让我们改进一下,既然我们已经知道,在使用装饰器装饰过后的love()执行实际上是执行装饰器inner, 那我们尝试给inner加上参数进行传递,还有很重要的,我们之前和之后,得把妹子名字记清楚才行,所以执行的时候也记得加上:

 # 定义装饰器
 def outer(f):
     def inner(var):
         print(f'找到{var}妹子,成功的拿到了微信...')
         f(var)
         print(f'约{var}妹子去看一场午夜电影...')
     return inner
 ​
 # 带有参数的函数
 @outer
 def love(name):
     print(f'跟{name}妹子在___畅谈人生...')
 ​
 love('露思')
 ​
 ---
 找到露思妹子,成功的拿到了微信...
 跟露思妹子在___畅谈人生...
 约露思妹子去看一场午夜电影...

嗯,这样一场和「露思」妹子之间完美的从认识到约会流程就完成了。我们总结一下:

如果装饰器带有参数的函数,需要在内函数中定义形参,并传递给调用的函数。因为调用原函数等于调用内函数。

装饰多参数的函数

上一个流程跑完之后呢,我觉得还是不太妥当。主要是其中有两个选择题,一个是谁,一个是去哪里。对吧。再说了,我也得跟妹子自我介绍一下,加强一点印象。

好,我们这次再多设置几个参数,让整个约会过程更完善一些,那我们从最初就要规划一下,需要的参数包括:我,妹子,地点,行为等等。还蛮多的。

# 装饰带有多参数的函数
def outer(f):
def inner(man,name,*args,**kwargs):
print(f'{man}要到了{name}妹子的微信...')
f(man, name, *args, **kwargs)
print('天色渐晚...')
return inner

# 定义多参数的函数
@outer
def love(man, name, *args, **kwargs):
print(f'{man}跟{name}畅谈人生...')
print(f'带{name}妹子去吃了很多美食:', args)
print(f'和{name}妹子看了夜场电影:', kwargs)

这样我们就定义好了,至于*args以及**kwargs是什么,可以翻看之前的教程。

让我们现在来执行一下:

love('茶桁','露思', '火锅', '海鲜', '饭后甜点', mov='封神第一部')

---
茶桁要到了露思妹子的微信...
茶桁跟露思畅谈人生...
带着露思妹子去吃了很多美食: ('火锅', '海鲜', '饭后甜点')
和露思妹子看了夜场电影: {'mov': '封神第一部'}
天色渐晚...

这样,多道选择题就被我们一一的化解了。相信「露思」妹子对我们的整体安排也是相当的满意了。

带有参数的装饰器

在我们平时使用Python各种第三方库的时候,不可避免的会遇到带有参数的装饰器。比如说,Django框架中的@login_required(redirect_field_name="my_redirect_field")

raw-image

这种带有参数的装饰器是干嘛的呢?还是拿我们之前的海王约会流程来举例。之前的流程是都没有什么问题,可是有没有发现,所有事情都是我们自己做主了,似乎妹子一直都没有反对过,也没有说自己想要什么。这是不是不太符合现实?

没错,我们也要给妹子装上一个会思考的大脑,也要学会做判断,好,让我们来实现一下:

既然我们这节是学习带有参数的装饰器,那么必然装饰器上是带参数的。呃,不要认为这句话是废话,我们看代码:

@put(var)
def love():
print('畅谈人生...')

就像这样,我们给装饰器加上了参数。

那么现在问题就来了,我们来看看我们之前写的装饰器函数:

def outer(f):
def inner():
pass
return inner

发现有什么问题了么?虽然我们的外层函数outer是有形参的,但是我们之前的过程中了解到,这个形参f是为了接收当前执行函数的。那还有什么其他地方接收非函数的普通参数嘛?

既然outer中很重要的作用,除了接收函数在内函数内执行,还有一个就是返回inner内函数,那么我们在不改变outer的基础之上,再加一个接收普通参数的函数不就行了。

def put(var):
def outer(f):
def inner1():
print('妹子给了你微信')
def inner2():
print('妹子给了你她闺蜜的微信')
def inner3():
print('妹子送了你一句感人肺腑的话:滚...')

# 装饰器壳的参数,可以用于在函数内去做流程控制。
if var == 1:
return inner1
elif var == 2:
return inner2
else:
return inner3
return outer

@put(2)
def love():
print('畅谈人生...')

定义完成之后,我们来执行一下看看:

love()

---
妹子给了你她闺蜜的微信

家人们谁懂啊,妹子真把我当海王了嘛?最后,我还是老老实实的接受了妹子的好意。

从整段代码中我们可以看出来,如果装饰器中有参数,需要有一个外壳函数来接收参数,传参之后就会进入到下一层函数中,并且传递当前对象。再然后才会再进入下一层中去。当然,我们在这里,利用传递的参数写了一段if判断,用于确定妹子的决定是什么。然后我们就返回哪个决定的函数。最后别忘记,在外壳函数中,我们还需要讲outer函数返回出去。此时虽然love函数是outer函数,但是在之前,put装饰器已经将参数传递给了外壳函数put(var)。在装饰器函数的争端代码中,我们都没有再执行过传进来的参数,也就是函数love(), 所以此段代码中love函数中的打印方法并未执行。

其执行步骤为:

put(var) => outer() => outer(love) => inner2()

用类装饰器装饰函数

之前我们所有的代码中,装饰器一直使用的都是函数装饰器。那我们能否用类来当装饰器装饰函数呢?

试试不就知道了。

# 类装饰器装饰函数
class Outer():
def __call__(self, func):
self.func = func
return self.inner

def inner(self, who):
print('拿到妹子的微信...')
self.func(who)
print('看一场午夜电影...')
@Outer()
def love(who):
print(f'{who}和妹子谈理想与人生...')

写完了,这下我们省略了那么多杂七杂八的流程,因为我发现,那么多流程下来,最终感动的人只有自己。妹子愿意,怎么都愿意,不愿意的,无论做多少都不愿意。

来,让我们跑一下程序试试:

 love('茶桁')
 ​
 ---
 拿到妹子的微信...
 茶桁和妹子谈理想与人生...
 看一场午夜电影...

没问题,正确的执行。那这个时候的love函数到底是什么呢?我们来打印出来看看:

 print(love)
 ​
 ---
 <bound method Outer.inner of <__main__.Outer object at 0x106646c80>>

可以看到,此时的love函数就是Outer类中的inner函数。那我们怎么理解整个代码呢?

我们在love函数上使用了装饰器Outer, 那么这个时候Outer就会实例化出来一个对象obj,然后这个@obj就等同于obj(love)

然后我们实例化对象进入Outer()内部,进入之后遇到了魔术方法__call__, 它会把该类的对象当作函数调用时自动触发。也就是obj()触发。

还记得类的实例化么?会传入一个参数,也就是实例化对象本身:obj。并且,第二个参数func用来接收了传递进来的函数love, 设置了self.func = func, 把传进来的函数作为对象的成员方法。最后返回了一个函数inner, 这个返回的函数是类中定义好的,于是作为实例化对象也将这个成员方法继承了下来,所以self.inner可以直接被返回出去。

这个定义好的inner接收了两个形参,一个是实例化对象本身,一个就是传递进来的函数love的参数who。然后,中间执行了一下魔术方法__call__内定义好的self.func(who),实际上也就是obj.love(who)

看着迷糊?这样,我写一个注释过的完整版本。

 # 类装饰器装饰函数
 class Outer():
 ​
     # 魔术方法:当把该类的对象当作函数调用时,自动触发obj()
     def __call__(self, func):
         # 把传进来的函数作为对象的成员方法
         self.func = func
         # 返回一个函数
         return self.inner
     
     # 在定义的需要返回的新方法中,去进行装饰和处理
     def inner(self, who):
         print('拿到妹子的微信...')
         self.func(who)
         print('看一场午夜电影...')
 '''
 Outer() 实例化对象 => obj
 @obj 就等于 obj(love)
 进入类后 => __call__(love)
 接收返回参数`inner()`
 '''
 @Outer()
 def love(who):
     print(f'{who}和妹子谈理想与人生...')
 ​
 # inner('茶桁')
 love('茶桁')
 # 此时的love就是属于`Outer`类这个对象中的inner方法
 print(love)

不知道这段注释代码加上刚才的解说,大家能否看懂?有没有发现,用类做装饰器比起函数装饰器反而更清晰一点?不需要写那么多外层函数和内层函数。

让我们继续...

类方法装饰函数

刚才我们将整个类都用作了一个装饰器,那我们思考一下,是不是我们还可以用类中的方法来做装饰器呢?

说干就干,直接上代码测试:

# 用类方法装饰函数
class Outer():
def newinner(f):
# 把传递进来的函数定义为类方法
Outer.func = f
# 同时返回一个新的类方法
return Outer.inner

def inner():
print('拿到妹子微信...')
Outer.func()
print('看一场午夜电影...')

'''
Outer.newinner(love)
接收返回参数:Outer.inner
'''

@Outer.newinner
def love():
print('和妹子谈谈人生喝喝茶...')
# love() 等于 Outer.inner()
love()

---
拿到妹子微信...
和妹子谈谈人生喝喝茶...
看一场午夜电影...

在经历了几场约会之后,我们的耐心也渐渐没了。连是谁都不管,也没耐心去谈理想了。喝点茶聊聊天就直奔主题了都是。

到目前为止以上所有形式的装饰器,包括「函数装饰器」、「类装饰器」、「类方法装饰器」,都有一个共同特点:都是在给函数去进行装饰,增加功能

那我们这个时候就不满足了,既然能装饰函数,那是否也能装饰类呢?

用装饰器装饰类

还真有一种装饰器是专门装饰类的,也就是在类的定义的前面使用@装饰器这种语法。和装饰函数并无什么区别,只是放在了类前面而已:

@装饰器
class Demo():
pass

装饰器给函数进行装饰,目的是不改变函数调用和代码的情况下给原函数增加新的功能。

装饰器给类进行装饰,目的是不改变类的定义和调用的情况下给类增加新的成员(属性或者方法)。

来,让我们具体的看看:

函数装饰器装饰类

 # 定义函数,接收一个类。返回修改后的类
 def expand(cls):
     def func2():
         print('我是在装饰器中追加的新方法,func2')
     cls.func2 = func2 # 把刚才定义的方法赋值给 类
     cls.name = '我是在装饰器中追加的新属性 name'
 ​
     # 返回时,把追加类新成员的类返回去
     return cls
 ​
 ​
 @expand   # expand(Demo) ==> cls ==> Demo
 class Demo():
     def func():
         print('我是Demo类中定义的func方法')
 ​
 Demo.func() # 此时在调用的Demo类是通过装饰器,更新过的Demo类
 Demo.func2()
 print(Demo.name)
 ​
 ---
 我是Demo类中定义的func方法
 我是在装饰器中追加的新方法,func2
 我是在装饰器中追加的新属性 name

这样,我们在原来的Demo这个类中,使用装饰器增加了一个成员方法func2,并且增加了一个成员属性name, 并最终返回到原始类中。从而扩展了这个原始类Demo中的方法和属性。

类装饰器装饰类

 # 使用类装饰器装饰类
 class expand():
     def __call__(self, cls):
         # 把接收的类,赋值给当前对象,作为一个属性
         self.cls = cls
         # 返回一个函数
         return self.newfunc
 ​
     def newfunc(self):
         self.cls.name = '我是在类装饰器中追加的新属性 name'
         self.cls.func2 = self.func2
         # 返回传递进来的类的实例化结果,obj
         return self.cls()
 ​
     def func2(self):
         print('我是在类装饰器中追加的新方法 func2')
 ​
 ​
 '''
 expand() ==> obj ==> @obj(Demo) ==> __call__(Demo) ==> newfunc
 '''
 @expand()
 class Demo():
     def func(self):
         print('我是Demo类中定义的func方法')
 ​
 obj = Demo()  # Demo() ==> newfunc() ==> obj
 obj.func()
 obj.func2()
 print(obj.name)

在之前那么多案例过后,相信大家这一段代码应该能看的出来吧。

那我这个地方要处一个思考题了,请问:此时的 obj这个对象,是哪个类的对象。Demo还是expand?

 print(obj)
 ​
 ---
 ???

这个问题的答案,我放在源码中了,大家要记得思考之后再去看答案。

那么,本节课的内容到这里也就结束了。

课程进行到这里,我们Python本身的所有内容就已经介绍完了。下节课开始,我们就要考试讲第三方库。

好,下课。

9會員
62內容數
从基础开始,再到Python,然后是CV、BI、NLP等相关技术。从头到尾详细的教授一边人工智能。
留言0
查看全部
發表第一個留言支持創作者!
茶桁的沙龍 的其他內容
Hi, 大家好,我是茶桁。 上一节课中,我们讲解了面向对象中的一些高阶应用,给大家介绍了一些魔术方法。并在最后,我们预告这节课内容会讲解描述符和设计模式。 好了,让我们开始吧。 描述符 这个玩意,怎么讲合适呢?这么说吧,当某一个类中,包含了三个魔术方法(__get__, __set__, _
之前的课程里面,我们简单的接触了面向对象编程,也和大家讲解了其思想,优缺点。相信上节课程结束之后,大家对面向对象都有了一定的理解。 那么我们这节课,就进入面向对象的一些高阶部分,让我们继续来学习一些魔术方法以及Python的内置成员,然后再来学习一下描述符与设计模式。
Hi,大家好。我是茶桁。 今天开始,我们要迈向Python的另外一个台阶了,那就是面向对象。 面向对象编程(Object Oriented Programming),简称为OOP,是一种以对象为中心的程序设计思想。 与之相对的,就是面向过程编程(Procedure Oriented Pro
Hi,大家好。我是茶桁。 在我们日常使用Python或者其他编程语言的时候,不可避免的都会出现报错和异常。那么,我们今天就来谈谈异常。 什么是异常? 异常异常,根据名字简单理解,那就是非正常,也就是没有达到预期目标。
Hi, 大家好。我是茶桁。 在我们之前的课程中,讲解了数据,函数,类,模块以及包。这些基本上已经构成了Python的全部了。 那么,我们在学习Python的包之后,有没有思考过,既然Python有内置模块,我们也可以自己写一些模块来使用,那一定有很多第三方写过相应的模块来供我们使用。那么,这
Hi, 大家好。我是茶桁。 这一段Python之旅怎么样?还算顺利吧? 之前我们都学习了些什么?有基本常识,流程,函数,不同类型的数据以及一些模块对吧?并且还做了一些练习来巩固所学过的内容。 那么今天,我们接着来学习模块。不过今天要学的模块和以往不太一样了,以前我们学习的都是Python内
Hi, 大家好,我是茶桁。 上一节课中,我们讲解了面向对象中的一些高阶应用,给大家介绍了一些魔术方法。并在最后,我们预告这节课内容会讲解描述符和设计模式。 好了,让我们开始吧。 描述符 这个玩意,怎么讲合适呢?这么说吧,当某一个类中,包含了三个魔术方法(__get__, __set__, _
之前的课程里面,我们简单的接触了面向对象编程,也和大家讲解了其思想,优缺点。相信上节课程结束之后,大家对面向对象都有了一定的理解。 那么我们这节课,就进入面向对象的一些高阶部分,让我们继续来学习一些魔术方法以及Python的内置成员,然后再来学习一下描述符与设计模式。
Hi,大家好。我是茶桁。 今天开始,我们要迈向Python的另外一个台阶了,那就是面向对象。 面向对象编程(Object Oriented Programming),简称为OOP,是一种以对象为中心的程序设计思想。 与之相对的,就是面向过程编程(Procedure Oriented Pro
Hi,大家好。我是茶桁。 在我们日常使用Python或者其他编程语言的时候,不可避免的都会出现报错和异常。那么,我们今天就来谈谈异常。 什么是异常? 异常异常,根据名字简单理解,那就是非正常,也就是没有达到预期目标。
Hi, 大家好。我是茶桁。 在我们之前的课程中,讲解了数据,函数,类,模块以及包。这些基本上已经构成了Python的全部了。 那么,我们在学习Python的包之后,有没有思考过,既然Python有内置模块,我们也可以自己写一些模块来使用,那一定有很多第三方写过相应的模块来供我们使用。那么,这
Hi, 大家好。我是茶桁。 这一段Python之旅怎么样?还算顺利吧? 之前我们都学习了些什么?有基本常识,流程,函数,不同类型的数据以及一些模块对吧?并且还做了一些练习来巩固所学过的内容。 那么今天,我们接着来学习模块。不过今天要学的模块和以往不太一样了,以前我们学习的都是Python内
你可能也想看
Google News 追蹤
Thumbnail
這個秋,Chill 嗨嗨!穿搭美美去賞楓,裝備款款去露營⋯⋯你的秋天怎麼過?秋日 To Do List 等你分享! 秋季全站徵文,我們準備了五個創作主題,參賽還有機會獲得「火烤兩用鍋」,一起來看看如何參加吧~
Thumbnail
美國總統大選只剩下三天, 我們觀察一整週民調與金融市場的變化(包含賭局), 到本週五下午3:00前為止, 誰是美國總統幾乎大概可以猜到60-70%的機率, 本篇文章就是以大選結局為主軸來討論近期甚至到未來四年美股可能的改變
Thumbnail
Faker昨天真的太扯了,中國主播王多多點評的話更是精妙,分享給各位 王多多的點評 「Faker是我們的處境,他是LPL永遠繞不開的一個人和話題,所以我們特別渴望在決賽跟他相遇,去直面我們的處境。 我們曾經稱他為最高的山,最長的河,以為山海就是盡頭,可是Faker用他28歲的年齡...
Thumbnail
如果離去 / 會記得有個人 / 曾經 / 勤勤懇懇 / 朝著他的夢想前進
Thumbnail
天亮還未開始 / 夜長沒有夢多 / 就把上進作廢 。 於是陷溺也能長出玫瑰
Thumbnail
窗外是雨 / 灰色是雨 / 寂寞是雨 / 心裡還是你 / 在哪
Thumbnail
《現代霊気ヒーリング協会-中文認定証樣式》 中心經過五年的時間,今日終於跟土居裕老師敲定「現代靈氣法」所有認證流程、講義及中文認定書的相關規定與默契,簡述相關堆定如下。 目前現代靈氣法的中文版講義共分成下面五本。 .基礎知識(Basic)本/500元 .初傳(Level 1)本/500元 .奧傳(L
Thumbnail
來世是假若 / 來世是可能 / 來世是不應該也不需要的問號 。 像世界從來也不真的需要我 / 曾經來過
Thumbnail
真愛過 就值得了分開 / 所以我離開你 / 或者你離開我 / 每一個決定都是正確的決定
Thumbnail
我知道很多人想只杯葛臨立會,而還是承認議會。但這終會矛盾的,如果你是追求民主,你的唯一結論就是否定香港的整個制度,因為這就是一個專制制度,一切選舉之類都只是為了配合專制而設的裝飾。而選舉是這些裝飾當中,最沒有用的部份,你去當差,你有權選擇拿槍射誰,你去當官,就有你職能的權力。
Thumbnail
浪漫是隨時擁有 / 在身邊 在心上 / 有在 / 就好了
Thumbnail
忘記了為什麼要開這間店 / 忘記了吃過了什麼 / 忘記了 / 原來我還記得
Thumbnail
不光是喜歡 / 不光是懷念 / 還有一點點 / 抱歉
Thumbnail
這個秋,Chill 嗨嗨!穿搭美美去賞楓,裝備款款去露營⋯⋯你的秋天怎麼過?秋日 To Do List 等你分享! 秋季全站徵文,我們準備了五個創作主題,參賽還有機會獲得「火烤兩用鍋」,一起來看看如何參加吧~
Thumbnail
美國總統大選只剩下三天, 我們觀察一整週民調與金融市場的變化(包含賭局), 到本週五下午3:00前為止, 誰是美國總統幾乎大概可以猜到60-70%的機率, 本篇文章就是以大選結局為主軸來討論近期甚至到未來四年美股可能的改變
Thumbnail
Faker昨天真的太扯了,中國主播王多多點評的話更是精妙,分享給各位 王多多的點評 「Faker是我們的處境,他是LPL永遠繞不開的一個人和話題,所以我們特別渴望在決賽跟他相遇,去直面我們的處境。 我們曾經稱他為最高的山,最長的河,以為山海就是盡頭,可是Faker用他28歲的年齡...
Thumbnail
如果離去 / 會記得有個人 / 曾經 / 勤勤懇懇 / 朝著他的夢想前進
Thumbnail
天亮還未開始 / 夜長沒有夢多 / 就把上進作廢 。 於是陷溺也能長出玫瑰
Thumbnail
窗外是雨 / 灰色是雨 / 寂寞是雨 / 心裡還是你 / 在哪
Thumbnail
《現代霊気ヒーリング協会-中文認定証樣式》 中心經過五年的時間,今日終於跟土居裕老師敲定「現代靈氣法」所有認證流程、講義及中文認定書的相關規定與默契,簡述相關堆定如下。 目前現代靈氣法的中文版講義共分成下面五本。 .基礎知識(Basic)本/500元 .初傳(Level 1)本/500元 .奧傳(L
Thumbnail
來世是假若 / 來世是可能 / 來世是不應該也不需要的問號 。 像世界從來也不真的需要我 / 曾經來過
Thumbnail
真愛過 就值得了分開 / 所以我離開你 / 或者你離開我 / 每一個決定都是正確的決定
Thumbnail
我知道很多人想只杯葛臨立會,而還是承認議會。但這終會矛盾的,如果你是追求民主,你的唯一結論就是否定香港的整個制度,因為這就是一個專制制度,一切選舉之類都只是為了配合專制而設的裝飾。而選舉是這些裝飾當中,最沒有用的部份,你去當差,你有權選擇拿槍射誰,你去當官,就有你職能的權力。
Thumbnail
浪漫是隨時擁有 / 在身邊 在心上 / 有在 / 就好了
Thumbnail
忘記了為什麼要開這間店 / 忘記了吃過了什麼 / 忘記了 / 原來我還記得
Thumbnail
不光是喜歡 / 不光是懷念 / 還有一點點 / 抱歉