可调用对象

callable()  # 可调用的(对象加括号可以执行特定的功能,如:类和函数)

可调用对象即将自身传入 callable 函数(  callable(对象)  )返回结果为  True  的对象

x = 1
print(callable(x))
# False
# x() # 会报错,TypeError: 'int' object is not callable,说明 变量x 不是可调用对象
def func():
pass
print(callable(func))
# True # 说明 函数 func 是可调用对象

闭包函数

闭:# 函数内部的函数(全局看不到)

包: # 内部函数引用了外部函数作用域的名字

一个简单的闭包函数案例(无参版)

x = 111
def outter():
x = 100
def inner():
print(x) # 找到的是局部的变量 x
return inner
# 没有调用,所以没有返回值(函数都没执行)
x = 120
res = outter()
res()
# 100 # 并没有受到全局 x 变化的影响 ---> 上一篇博客命名空间的查找顺序知识点 def func():
x = 666
res()
func()
# 100 # 并没有受到func空间中 变量x 变化的影响

闭包函数的优点: # 无论在什么地方调用,目标函数(inner) 用的都是外部包围函数outter 中的变量值,不会受全局中变量变化的影响   ---> 可以方便调用函数,一次传参,多次使用

  有参版案例

def outter(x, y):  # x = 传过来的参数x, y = 传过来的参数y
# x = 1
# y = 40
def my_max():
if x > y:
return x
return y
return my_max res1 = outter(1, 40) # res就是my_max函数的内存地址
print(res1())
print(res1())
#
#
res2 = outter(90, 200)
print(res2())
print(res2())
#
#
print(res1())
#

获取百度首页数据长度(模块知识先不用理解)

  普通写法

import requests  # 需先安装这个模块 (命令行输入:pip3 install requests,安装)
# 第一个直接给函数传参
url1 = 'https://www.baidu.com'
url2 = '...'
def my_get(url):
response = requests.get(url)
if response.status_code == 200:
print(len(response.text)) my_get(url1)
my_get(url1)
my_get('https://www.baidu.com')
my_get('https://www.baidu.com')
#
#
#
#

  闭包传参写法(一次传参即可,避免多次传参)

import requests
def outter(url):
# url = 'https://www.jd.com'
def my_get():
response = requests.get(url)
if response.status_code == 200:
print(len(response.text))
return my_get
my_jd = outter('https://www.jd.com') # 一次传参
my_jd() # 无需传参即可使用
my_jd()
my_baidu = outter('https://www.baidu.com')
my_baidu()
my_baidu()
my_jd()
#
#
#
#
#

  tips: 上面两种写法其实也对应的是给函数传参的两种形式 , # 直接给该函数传参 , # 通过闭包间接达到传参的效果

  ** 闭包传参就是给要接收参数的函数外层再套一层函数,给外层的函数传参,然后通过函数定义的命名空间查找顺序原理,让该函数获取到外层函数接收到的参数,间接传参,下文的有参数版装饰器用到的就是这个原理

装饰器

初衷(由来):想要在不改变函数源代码且不改变函数调用方式的情况下给函数添加新功能

开放封闭原则: # 对扩展开放,对修改封闭

首先要申明一点: 装饰器真的不难,真的不难,你只要跟着我理解一遍,以后就都不是问题了(忘了你就再看一遍嘛) ,装饰器只是闭包函数的一种扩展应用。

装饰器的推导过程

现有一个需求,给现有的shopping 功能扩展一下,自动判断其是否已经登录,未登录先登录(不改源码与调用方式)

def shopping():
print("我要开始购物啦!")
pass

不让改源码又不让改调用方式,那咋整呢?(反正我想了半天是想不出来)

那就一起来头脑风暴一下

  先抛开调用方式,我们可以在它调用前后加上自己的逻辑代码,然后封装成函数,通过调用这个函数实现添加功能的目的

def check_login():
if is_login:
shopping()
else:
login() # 调用login 函数,登录,登陆结束后会接着执行shopping 函数
shopping()

  如果尝试运用昨天的知识点,函数名可以被当做变量一样赋值传递呢?就是说我把 shopping = check_login ,那是不是说我再 shopping() 执行的就是 check_login() 方法了呢?

is_login = False

def shopping():
print("我要开始购物啦!")
pass def check_login():
global is_login
if is_login:
shopping()
else:
print("登录成功了") # 调用login 函数,登录,登陆结束后会接着执行shopping 函数
is_login = True # 这里写的是 = 赋值操作,局部命名空间会新创建一个变量is_login 而我们要用的是全局的,所以在上方要加上 global is_login
shopping() shopping = check_login
shopping()

代码

  一运行就发现编译器报错了,这样一写原来 check_login() 里面的 shopping 函数 也被替换掉了, shopping  加括号执行其实是 check_login 函数加括号执行,它会无限调用自身,然后。。。。

  那我可不可以利用 # 名称空间查找顺序在函数定义阶段就已经固定了 的特性,再利用 # 函数名可被当做函数的参数被传递 的特性把 函数名 shopping 作为参数传入进去,然后shopping()的时候调用的是传进去的shopping函数呢?

is_login = False

def shopping():
print("我要开始购物啦!")
pass def check_login(shopping):
global is_login
if is_login:
shopping()
else:
print("登录成功了") # 调用login 函数,登录,登陆结束后会接着执行shopping 函数
is_login = True # 这里写的是 = 赋值操作,局部命名空间会新创建一个变量is_login 而我们要用的是全局的,所以在上方要加上 global is_login
shopping() shopping = check_login(shopping)
shopping()
# 登录成功了
# 我要开始购物啦!
# Traceback (most recent call last):
# File "E:/PyCharm 2019.1.3/ProjectFile/day010/day011/博客代码整理草稿.py", line 20, in <module>
# shopping()
# TypeError: 'NoneType' object is not callable # tips: 上面的那个报错位置可能会在前两个输出的前面,但这不重要

代码

  一运行发现还是报错了,但好像又有点样子了,一经排查,原来在 shopping = check_login(shopping) 的时候就完成了我们的扩展功能。。。报错的是下面那句 shopping() ,前面那句执行了 check_login 函数 ,而 check_login 函数 没有返回值,那么 shopping 变量 接收到的其实是 None ,再执行 shopping() 这就是那个报错的原因了

  那我可不可以利用 # 函数在定义阶段只会检查语法,不会执行内部代码 和 # 函数名可以被当做函数的返回值的特性 的特性把 check_login 函数 里面的代码再给它封装一个函数然后返回这个函数名呢?再利用 # 函数名加括号可以调用函数 的特点,要用的时候再给接收的变量加上括号不就可以调用了吗?

is_login = False

def shopping():
print("我要开始购物啦!")
pass def check_login(shopping):
def inner():
global is_login
if is_login:
shopping()
else:
print("登录成功了") # 调用login 函数,登录,登陆结束后会接着执行shopping 函数
is_login = True # 这里写的是 = 赋值操作,局部命名空间会新创建一个变量is_login 而我们要用的是全局的,所以在上方要加上 global is_login
shopping()
return inner shopping = check_login(shopping)
shopping()
# 登录成功了
# 我要开始购物啦!

代码

  经过上述那么一波猛如虎的操作,发现,耶?我好像达到了要求,既没有改变原函数,也没有改变它的调用方式???

  那...我要给现有的 pay 功能也同样扩展一下呢?再...?再写一遍?我不!作为一个有追求的程序员,我觉得我的代码还可以抢救一下(不然你让我再给其他功能也同样加上这个登录验证...?那如果有几十个...?想想还是花点脑子写个通用的吧,最起码后面用起来可以省时省事呀,以后也可以模仿着写)

def pay():
print("我要结账啦!")
pass

  既然现在要给 pay 函数 也扩展登录验证,那我上面的写法里面肯定就不能直接是 shopping() 了,那我再利用一下 # 函数名可以被当做函数的参数被传递 的特性,把.....?等等,函数定义时的形参好像相当于是一个变量我好像直接把上面的 shopping = check_login(shopping) 改成 pay = check_login(pay) 然后 pay() 不就搞定了?一试还真的是这样....

  不过啊,这里的shopping 和 pay 函数好像都是没有参数也没有返回值的,那...?要被扩展的函数有参数,或者有返回值呢?那函数的参数又有好几个呢?总不可能每个函数的参数个数都一样吧?这该如何是好?

  要可以有返回值,那我调用完被扩展的函数用一个变量接收它的返回值不就行了,再return 出来,哎... 这个简单

  那可以有任意个参数呢?emmm? 等等,任意个参数,这好像和可变长参数的应用场景差不多啊,我可以用 # * 接收多余的位置参数, ** 接收多余的关键字参数  ,嘿,这就不管你来几个参数我都可以接收了,那我再通过前面学的打散机制,用 # * 打散容器对象,拆成若干个位置参数, ** 打散字典对象,拆成若干个关键字参数  ,不就完成了参数的传递了?

  哎,作为一个处女座, check_login 函数 里面接收到的函数名和被执行的函数名怎么能还是shopping 呢?改一下改一下,规范点。

is_login = False

def pay():
print("我要结账啦!")
pass def say_hi(username):
return 'hello, {}'.format(username) def hello_world():
print('Hello world!') def check_login(func): # 被扩展的函数总不能都叫shopping 吧?取个func 统一代表被扩展的函数吧
# 肯定是调用被扩展函数的时候才根据情况传参数的嘛,所以这里check_login和inner 的参数就得这么写
def inner(*args, **kwargs): # 利用可变长参数接收不定个数的参数(可变长参数的标准写法哦)
global is_login
if is_login:
res = func(*args, **kwargs) # 再利用* ** 的打散机制,将inner 接收到的参数打散
# 用一个变量 res 来接收被扩展函数的返回值
else:
print("登录成功了")
is_login = True
res = func(*args, **kwargs)
return res # 再把这个被扩展函数的返回值返回回去
return inner # 返回给外界一个函数名,这样外界就可以拿到这个函数名加括号直接调用了 # 登录成功了 pay = check_login(pay)
print(pay())
# 我要结账啦! say_hi = check_login(say_hi)
print(say_hi('jason'))
# hello, jason hello_world = check_login(hello_world)
hello_world()
# Hello world!

代码

  哇塞,完美啊,既可以给有参数的函数调用,又可以给没参数的函数调用,既可以给有返回值的函数调用,又可以给没有返回值的函数调用!NB(到这里,一个简单的装饰器就算是写好了)

  但是啊,这个 hello_world = check_login(hello_world) 好像有点多余啊...我不想每次都要写这么一句,哎,python提供的装饰器语法糖了解一下

is_login = False

def check_login(func):  # 被扩展的函数总不能都叫shopping 吧?取个func 统一代表被扩展的函数吧
# 肯定是调用被扩展函数的时候才根据情况传参数的嘛,所以这里check_login和inner 的参数就得这么写
def inner(*args, **kwargs): # 利用可变长参数接收不定个数的参数(可变长参数的标准写法哦)
global is_login
if is_login:
res = func(*args, **kwargs) # 再利用* ** 的打散机制,将inner 接收到的参数打散
# 用一个变量 res 来接收被扩展函数的返回值
else:
print("登录成功了")
is_login = True
res = func(*args, **kwargs)
return res # 再把这个被扩展函数的返回值返回回去
return inner # 返回给外界一个函数名,这样外界就可以拿到这个函数名加括号直接调用了 @check_login # 等价于 say_hi = check_login(say_hi)
def say_hi(username):
return 'hello, {}'.format(username) @check_login
def hello_world():
print('Hello world!')
# say_hi = check_login(say_hi)
print(say_hi('jason'))
# 登录成功了
# hello, jason # hello_world = check_login(hello_world)
hello_world()
# Hello world!

装饰器语法糖代码

   到了这里,插播一小段装饰器语法糖啊,各位观众姥爷不介意吧?咱们装饰器语法糖之后再见

装饰器语法糖

工作原理: # 装饰器语法糖会自动将下面的可调用对象的名字(函数)当做参数直接传入 @后所跟函数名并自动调用

注意点: # 装饰器语法糖在书写的时候应该与被装饰对象紧紧挨着,中间不能有空行 --> 也就意味着被扩展(装饰)函数要写在装饰器函数的后面,不然装饰器还没定义,你用啥嘞?

  案例的话上面的代码就是咯,多多用装饰的语法糖可以让代码的可读性更强哦

装饰器推导过程后续

好,下面我们接着上面的话题继续扯。

  这个时候我打印一下 hello_world,我天?怎么是inner ?那我要看下 hello_world 的注释呢?打印一下,耶?也是inner 的,那咋整咧?装饰器修复技术了解一下?

is_login = False

def check_login(func):
# inner的注释(不给inner函数写函数注释的时候,help(inner) 返回的是这句话,当然这里的inner并没有返回给外界,在全局是获取不到的)
def inner(*args, **kwargs):
'''
inner的函数注释
:param args: 任意个数的位置参数会被组成一个元组接收
:param kwargs: 任意个数的关键字参数会被组成一个元组接收
:return: 被装饰的函数返回值是什么,这里的返回值就是什么
'''
global is_login
if is_login:
res = func(*args, **kwargs) # 再利用* ** 的打散机制,将inner 接收到的参数打散
# 用一个变量 res 来接收被扩展函数的返回值
else:
print("登录成功了")
is_login = True
res = func(*args, **kwargs)
return res # 再把这个被扩展函数的返回值返回回去
return inner # 返回给外界一个函数名,这样外界就可以拿到这个函数名加括号直接调用了 @check_login # 等价于 say_hi = check_login(say_hi)
def say_hi(username):
return 'hello, {}'.format(username) @check_login
def hello_world():
print('Hello world!') print(hello_world)
# <function check_login.<locals>.inner at 0x000002651E63BAE8>
print(help(hello_world))
# Help on function inner in module __main__:
#
# inner(*args, **kwargs)
# inner的函数注释
# :param args: 任意个数的位置参数会被组成一个元组接收
# :param kwargs: 任意个数的关键字参数会被组成一个元组接收
# :return: 被装饰的函数返回值是什么,这里的返回值就是什么
#
# None

修复前

from functools import wraps
is_login = False def check_login(func):
# inner的注释(不给inner函数写函数注释的时候,help(inner) 返回的是这句话,当然这里的inner并没有返回给外界,在全局是获取不到的)
@wraps(func) # 不要忘了导最上面的包,这个语法糖一定要在最内层函数的上一行,然后要指定参数(被装饰方法)
def inner(*args, **kwargs):
'''
inner的函数注释
:param args: 任意个数的位置参数会被组成一个元组接收
:param kwargs: 任意个数的关键字参数会被组成一个元组接收
:return: 被装饰的函数返回值是什么,这里的返回值就是什么
'''
global is_login
if is_login:
res = func(*args, **kwargs) # 再利用* ** 的打散机制,将inner 接收到的参数打散
# 用一个变量 res 来接收被扩展函数的返回值
else:
print("登录成功了")
is_login = True
res = func(*args, **kwargs)
return res # 再把这个被扩展函数的返回值返回回去
return inner # 返回给外界一个函数名,这样外界就可以拿到这个函数名加括号直接调用了 @check_login # 等价于 say_hi = check_login(say_hi)
def say_hi(username):
return 'hello, {}'.format(username) @check_login
# 测试注释,如果 不写hello_world函数的注释的话,返回的还是inner 函数上方的那行注释(在inner 函数有些函数注释的情况下),这一句注释并不会返回
def hello_world():
'''
hello_world 函数的注释
:return: 木得返回值
'''
print('Hello world!') print(hello_world)
# <function hello_world at 0x000001EAA7A50378>
print(help(hello_world))
# Help on function hello_world in module __main__:
#
# hello_world()
# hello_world 函数的注释
# :return: 木得返回值
#
# None

修复后

  这一对比,简直就是本质的区别啊

  为了将上面花了半天心思推导出来的成果广泛应用,那咱们提炼一个简单的装饰器模板吧?

不带参数的装饰器模板

from functools import wraps  # 要用到 wraps 装饰器修复技术,就不要忘了导入这个包

def outter(func):  # 这个outter 函数的名字最好取实际用途的名字,比如统计函数运行时间,就可以改成statistical_execution_time
@wraps(func) # 加上这句让被装饰函数再被 print(函数名) 的时候可以打印出他自己的内存地址, print(help(函数名)) 的时候可以打印出他自己的注释
def inner(*args, **kwargs): # 这个inner 函数的名字就无所谓啦,没有太大的意义,或者你可以根据你的理解给他取个名字
# 这里写被装饰函数执行前的操作
res = func(*args, **kwargs)
# 这里写被装饰函数执行后的操做
return res # 这里不要忘了return 被装饰函数的返回值
return inner # 注意,这里的inner 不能加括号 # 最后一把,在要被他装饰的函数定义位置的上一行加上这个语法糖 --> @outter

简单装饰器模板

  咳,编不下去了,这里在扩展一下带参数的装饰器,分析了一下,装饰内部的 inner 函数 参数是可变长度参数,你可以选择在 *args 前面加个位置参数,传入参数,但那就意味着你调用被装饰函数的时候,要多传一个参数,也就意味着调用方式变了,他不再是装饰器了。

  那我给最外层的函数多加一个参数呢?

from functools import wraps  # 要用到 wraps 装饰器修复技术,就不要忘了导入这个包

def outter(x,func):
@wraps(func)
def inner(*args, **kwargs):
# 这里写被装饰函数执行前的操作
res = func(*args, **kwargs)
# 这里写被装饰函数执行后的操做
return res # 这里不要忘了return 被装饰函数的返回值
return inner # 注意,这里的inner 不能加括号 # @outter(1, hello) # 会报错,因为程序执行到这里 hello 函数还没有定义
def hello():
print("hello") hello = outter(1, hello) # 这样写可读性不太好,当然是能用语法糖就语法糖啦
hello()
# hello

给装饰器传参(请勿模仿)

  好像也可以哈? 不过就不能用语法糖了,还是不爽,不能直接传参,那就试试通过闭包传参再套一层呗

带参数的装饰器模板

from functools import wraps  # 要用到 wraps 装饰器修复技术,就不要忘了导入这个包

def outs(x):  # 其实这里已经可以随便你指定多少个参数了(inner 函数里面可以获取到用了,这里只演示可以传)
def outter(func):
@wraps(func)
def inner(*args, **kwargs):
# 这里写被装饰函数执行前的操作
res = func(*args, **kwargs)
# 这里写被装饰函数执行后的操做
return res # 这里不要忘了return 被装饰函数的返回值
return inner # 注意,这里的inner 不能加括号
return outter # 这里这个return 函数名 也不要忘了,记住一点,函数名后面千万不要加括号!函数名后面千万不要加括号!函数名后面千万不要加括号! # 至此,带参数版的装饰器差不多就写好了,outs函数里的 x 根据情况换成需要的参数(如果你不需要参数,那你写简单版的不好吗?) @outs(1) # 这里的outs 要加括号!直接执行 outs 函数,然后返回 outter函数内存地址,传入hello 函数名(对象),装饰
# --> outs() -> hello = outter(hello)
def hello():
print("hello") # 上面装饰器语法糖的写法等同于:
# outter = outs(1)
# hello = outter(hello)
hello()
# hello

带参数的装饰器模板

  emmm,到这里就差不多了,完事儿,收工。

  咳,申明一点啊,装饰器可不是我推导出来的,写上面那一长串的知识点呢,主要是为了真正了解装饰器,并且复习一下前面的知识点嘛

  下面通过一个案例加深一下对装饰器的理解(多层装饰器)

def outter1(func1):
print('语法糖加载outter1') def wrapper1(*args, **kwargs):
print('被装饰函数函数名加括号调用,执行到了wrapper1')
res1 = func1(*args, **kwargs)
return res1 return wrapper1 def outter2(func2):
print('语法糖加载outter2') def wrapper2(*args, **kwargs):
print('被装饰函数函数名加括号调用,执行到了wrapper2')
res2 = func2(*args, **kwargs)
return res2 return wrapper2 def outter3(func3):
print('语法糖加载outter3') def wrapper3(*args, **kwargs):
print('被装饰函数函数名加括号调用,执行到了wrapper3')
res3 = func3(*args, **kwargs)
return res3 return wrapper3 @outter1 # index = outter1(wapper2) # 完成装饰
@outter2 # wrapper2 = outter2(wrapper3)
@outter3 # wrapper3 = outter3(最原始的index函数内存地址)
# 语法糖加载outter3 # 只要用语法糖装饰到函数上就会返回
# 语法糖加载outter2
# 语法糖加载outter1
def index():
print('from index') index()
# 被装饰函数函数名加括号调用,执行到了wrapper1
# 被装饰函数函数名加括号调用,执行到了wrapper2
# 被装饰函数函数名加括号调用,执行到了wrapper3
# from index

装饰器巩固案例

  从上面的案例中也可以总结出: # 多个装饰器装饰函数时顺序是从下往上的,执行顺序是从上往下的

  怎么样,不难吧?理解了再看一遍,你会发现好简单啊

精简注释的模板(纯净模板)

# 最简单版装饰器
from functools import wraps def outter(func):
@wraps(func)
def inner(*args, **kwargs):
# 这里写被装饰函数执行前的操作
res = func(*args, **kwargs)
# 这里写被装饰函数执行后的操做
return res
return inner # 使用
@outter
def hello():
print("hello") hello()
# hello # 带参数版的装饰器
from functools import wraps def outs(params):
def outter(func):
@wraps(func)
def inner(*args, **kwargs):
# 这里写被装饰函数执行前的操作
res = func(*args, **kwargs)
# 这里写被装饰函数执行后的操做
print(params) # 这里是想说,可以用到传进来的参数
return res
return inner
return outter # 使用
@outs(1)
def hello():
print("hello") hello()
# hello
#

python函数闭包-装饰器-03的更多相关文章

  1. Python函数06/装饰器

    Python函数06/装饰器 目录 Python函数06/装饰器 内容大纲 1.装饰器 1.1 开放封闭原则 1.2 装饰器 2.今日练习 内容大纲 1.装饰器 1.装饰器 1.1 开放封闭原则 扩展 ...

  2. python函数、装饰器、迭代器、生成器

    目录: 函数补充进阶 函数对象 函数的嵌套 名称空间与作用域 闭包函数 函数之装饰器 函数之迭代器 函数之生成器 内置函数 一.函数补充进阶 1.函数对象:  函数是第一类对象,即函数可以当作数据传递 ...

  3. python高级-闭包-装饰器

    闭包内容: 匿名函数:能够完成简单的功能,传递这个函数的引用,只有功能 普通函数:能够完成复杂的功能,传递这个函数的引用,只有功能 闭包:能够完成较为复杂的功能,传递这个闭包中的函数以及数据,因此传递 ...

  4. python——函数之装饰器

    1 问题 实际生活中,我们很难一次性就把一个函数代码写得完美无缺.当我们需要对以前的函数添加新功能时,我们应该怎么做? 2 问题解决思路 (1)可以直接修改原来的函数,在函数内直接修改.当我们对多个函 ...

  5. Python 函数之装饰器

    1.函数 #### 第一波 #### def foo(): print 'foo' foo #表示是函数 foo() #表示执行foo函数 #### 第二波 #### def foo(): print ...

  6. Python函数的装饰器修复技术(@wraps)

    @wraps 函数的装饰器修复技术,可使被装饰的函数在增加了新功能的前提下,不改变原函数名称,还继续使用原函数的注释内容: 方便了上下文环境中不去更改原来使用的函数地方的函数名: 使用方法: from ...

  7. Python函数的装饰器修复技术(@wraps)

    @wraps 函数的装饰器修复技术,可使被装饰的函数在增加了新功能的前提下,不改变原函数名称,还继续使用原函数的注释内容: 方便了上下文环境中不去更改原来使用的函数地方的函数名: 使用方法 from ...

  8. Python函数加工厂-装饰器

    引言: 函数和装饰器好比程序界的加工厂: 1.函数一般可用来加工一种或者多种数据类型的数据:字符串.数字.列表.字典等 举一个简单例子:已知半径求面积 def s(r): s = 3.14 * r * ...

  9. Python函数的装饰器

    函数的装饰器. 1. 装饰器 开闭原则: 对功能的扩展开放 对代码的修改是封闭 通用装饰器语法: def wrapper(fn): def inner(*args, **kwargs): # 聚合 & ...

随机推荐

  1. Qt的槽可以使用默认参数

    引用自:http://www.ibm.com/developerworks/cn/linux/guitoolkit/qt/signal-slot/ 的一篇经典文章,是关于Qt的信号和槽的分析的.看年份 ...

  2. hive -e和hive -f的区别(转)

    大家都知道,hive -f 后面指定的是一个文件,然后文件里面直接写sql,就可以运行hive的sql,hive -e 后面是直接用双引号拼接hivesql,然后就可以执行命令. 但是,有这么一个东西 ...

  3. C语言实现常用查找算法——二分查找

    #include<stdio.h> void insert_sort(int a[],int n); int binary_search(int a[],int x,int n); voi ...

  4. MyBatis 源码分析

    MyBatis 运行过程 传统的 JDBC 编程查询数据库的代码和过程总结. 加载驱动. 创建连接,Connection 对象. 根据 Connection 创建 Statement 或者 Prepa ...

  5. Storm 学习之路(二)—— Storm核心概念详解

    一.Storm核心概念 1.1 Topologies(拓扑) 一个完整的Storm流处理程序被称为Storm topology(拓扑).它是一个是由Spouts 和Bolts通过Stream连接起来的 ...

  6. java源码解析之String类(一)

    String是我们接触最多的类,无论是学习中还是工作中,基本每天都会和字符串打交道,从字符串本身的各种拼接.切片.变形,再到和其他基本数据类型的转换,几乎无时无刻都在使用它,今天就让我们揭开Strin ...

  7. Linux命令之nohup (转)

    nohup 详解   阅读目录 nohup 案例 nohup和&的区别 参考链接 正文 回到顶部 nohup nohup 命令运行由 Command参数和任何相关的 Arg参数指定的命令,忽略 ...

  8. jQuery中ajax-$.getJSON,$.getScript

    jQuery提供了两个特定异步加载的方法$.getJSON()方法和$.getScript()方法 $.getJSON()来加载特定的json文件 $.getScript()来加载特定的javascr ...

  9. linuxprobe培训第1节课笔记2019年7月5日

    报了老刘的RHCE培训,这是老刘上课笔记简略版. 老刘在课上介绍了开源共享精神和大胡子(Richard M. Stallman—GNU创始人).linux发展史(Linus Benedict Torv ...

  10. Altium Designer设计PCB--如何增大电源地的线宽

    笑话: 看见楼下老大爷在下棋,我看了一会儿,跟大爷说:大爷,你che没了. 大爷一脸不屑:小朋友,那叫ju. 然后我静静地在那看了两个小时. 对完棋,大爷起身要走. 我说:大爷,我刚才说的不是你的棋, ...