【Python】装饰器理解
以下文章转载自:点这里
关于装饰器相关的帖子记录在这里: 廖雪峰, thy专栏, stackflow
Python的函数是对象
简单的例子:
def shout(word="yes"):
return word.capitalize()+"!"
print shout()
# outputs : 'Yes!'
# 作为一个对象,你可以讲函数赋值给另一个对象
scream = shout
# 注意到这里我们并没有使用括号:我们不是调用函数,而是将函数'shout'赋给变量'scream'
# 这意味着,你可以通过'scream'调用'shout'
print scream()
# outputs : 'Yes!'
# 不仅如此,你可以删除老的名称'shout',但是通过'scream'依旧可以访问原有函数
del shout
try:
print shout()
except NameError, e:
print e
#outputs: "name 'shout' is not defined"
print scream()
# outputs: 'Yes!'
Python函数另一个有趣的特性是,函数可以被定义在另一个函数里面。
def talk():
# 你可以定义一个函数
def whisper(word="yes"):
return word.lower()+"..."
# ... 并且立刻调用
print whisper()
# 每次当你调用"talk", 都会定义"whisper"
# 并且在"talk"中被调用
talk()
# outputs:
# "yes..."
#但是在"talk"外部,函数"whisper"不存在!
try:
print whisper()
except NameError, e:
print e
#outputs : "name 'whisper' is not defined"*
函数引用
- 函数可以赋值给一个变量
- 函数可以定义在另一个函数内部
即,这也意味着一个函数可以返回另一个函数, 让我们来看另一段代码:
def getTalk(type="shout"):
# 定义函数
def shout(word="yes"):
return word.capitalize()+"!"
def whisper(word="yes") :
return word.lower()+"...";
# 返回函数
if type == "shout":
# 没有使用"()", 并不是要调用函数,而是要返回函数对象
return shout
else:
return whisper
# 如何使用?
# 将函数返回值赋值给一个变量
talk = getTalk()
# 我们可以打印下这个函数对象
print talk
#outputs : <function shout at 0xb7ea817c>
# 这个对象是函数的返回值
print talk()
#outputs : Yes!
# 不仅如此,你还可以直接使用之
print getTalk("whisper")()
#outputs : yes...
但是稍等,如果你可以返回一个函数,那么你也可以将函数作为参数传递
def doSomethingBefore(func):
print "I do something before then I call the function you gave me"
print func()
doSomethingBefore(scream)
#outputs:
#I do something before then I call the function you gave me
#Yes!
装饰器就是封装器,可以让你在被装饰函数之前或之后执行代码,而不必修改函数本身
手工装饰器
如何书写一个装饰器
# 装饰器是一个以另一个函数为参数的函数
def my_shiny_new_decorator(a_function_to_decorate):
# 在这里,装饰器定义一个函数: 包装器.
# 这个函数将原始函数进行包装,以达到在原始函数之前、之后执行代码的目的
def the_wrapper_around_the_original_function():
# 将你要在原始函数之前执行的代码放到这里
print "Before the function runs"
# 调用原始函数(需要带括号)
a_function_to_decorate()
# 将你要在原始函数之后执行的代码放到这里
print "After the function runs"
# 代码到这里,函数‘a_function_to_decorate’还没有被执行
# 我们将返回刚才创建的这个包装函数
# 这个函数包含原始函数及要执行的附加代码,并且可以被使用
return the_wrapper_around_the_original_function
# 创建一个函数
def a_stand_alone_function():
print "I am a stand alone function, don't you dare modify me"
a_stand_alone_function()
#outputs: I am a stand alone function, don't you dare modify me
# 好了,在这里你可以装饰这个函数,扩展其行为
# 将函数传递给装饰器,装饰器将动态地将其包装在任何你想执行的代码中,然后返回一个新的函数
a_stand_alone_function_decorated = my_shiny_new_decorator(a_stand_alone_function)
# 调用新函数,可以看到装饰器的效果
a_stand_alone_function_decorated()
#outputs:
#Before the function runs
#I am a stand alone function, don't you dare modify me
#After the function runs
到这里,或许你想每次调用a_stand_alone_function
都使用a_stand_alone_function_decorated
替代之 很简单,只需要将a_stand_alone_function
用my_shiny_new_decorator
装饰返回
a_stand_alone_function = my_shiny_new_decorator(a_stand_alone_function)
a_stand_alone_function()
#outputs:
#Before the function runs
#I am a stand alone function, don't you dare modify me
#After the function runs
# 这就是装饰器做的事情!
装饰器阐述
前面的例子,使用装饰器语法
@my_shiny_new_decorator
def another_stand_alone_function():
print "Leave me alone"
another_stand_alone_function()
#outputs:
#Before the function runs
#Leave me alone
#After the function runs
是的,就是这么简单. @decorator
是下面代码的简写
nother_stand_alone_function = my_shiny_new_decorator(another_stand_alone_function)
装饰器只是 装饰器模式的python实现
python
代码中还存在其他几个经典的设计模式,以方便开发,例如迭代器iterators
当然,你可以累加装饰器
def bread(func):
def wrapper():
print "</''''''\>"
func()
print "<\______/>"
return wrapper
def ingredients(func):
def wrapper():
print "#tomatoes#"
func()
print "~salad~"
return wrapper
def sandwich(food="--ham--"):
print food
sandwich()
#outputs: --ham--
#累加两个装饰器
sandwich = bread(ingredients(sandwich))
sandwich()
#outputs:
#</''''''\>
# #tomatoes#
# --ham--
# ~salad~
#<\______/>
使用python装饰器语法
@bread
@ingredients
def sandwich(food="--ham--"):
print food
sandwich()
#outputs:
#</''''''\>
# #tomatoes#
# --ham--
# ~salad~
#<\______/>
装饰器位置的顺序很重要
@ingredients
@bread
def strange_sandwich(food="--ham--"):
print food
strange_sandwich()
#outputs:
##tomatoes#
#</''''\>
# --ham--
#<\______/>
# ~salad~'
最后回答问题
# bold装饰器
def makebold(fn):
def wrapper():
# 在前后加入标签
return "<b>" + fn() + "</b>"
return wrapper
# italic装饰器
def makeitalic(fn):
def wrapper():
# 加入标签
return "<i>" + fn() + "</i>"
return wrapper
@makebold
@makeitalic
def say():
return "hello"
print say()
#outputs: <b><i>hello</i></b>
# 等价的代码
def say():
return "hello"
say = makebold(makeitalic(say))
print say()
#outputs: <b><i>hello</i></b>
装饰器高级的用法
向装饰器函数传递参数
# 这不是黑魔法,你只需要让包装传递参数:
def a_decorator_passing_arguments(function_to_decorate):
def a_wrapper_accepting_arguments(arg1, arg2):
print "I got args! Look:", arg1, arg2
function_to_decorate(arg1, arg2)
return a_wrapper_accepting_arguments
# 当你调用装饰器返回的函数,实际上是调用包装函数,所以给包装函数传递参数即可将参数传给装饰器函数
@a_decorator_passing_arguments
def print_full_name(first_name, last_name):
print "My name is", first_name, last_name
print_full_name("Peter", "Venkman")
# outputs:
#I got args! Look: Peter Venkman
#My name is Peter Venkman
装饰方法
Python
中对象的方法和函数是一样的,除了对象的方法首个参数是指向当前对象的引用(self)
。这意味着你可以用同样的方法构建一个装饰器,只是必须考虑self
def method_friendly_decorator(method_to_decorate):
def wrapper(self, lie):
lie = lie - 3 # very friendly, decrease age even more :-)
return method_to_decorate(self, lie)
return wrapper
class Lucy(object):
def __init__(self):
self.age = 32
@method_friendly_decorator
def sayYourAge(self, lie):
print "I am %s, what did you think?" % (self.age + lie)
l = Lucy()
l.sayYourAge(-3)
#outputs: I am 26, what did you think?
当然,你可以构造一个更加通用的装饰器,可以作用在任何函数或对象方法上,而不必关系其参数 使用: *args, **kwargs
def a_decorator_passing_arbitrary_arguments(function_to_decorate):
# 包装函数可以接受任何参数
def a_wrapper_accepting_arbitrary_arguments(*args, **kwargs):
print "Do I have args?:"
print args
print kwargs
# 然后你可以解开参数, *args,**kwargs
# 如果你对此不是很熟悉,可以参考 http://www.saltycrane.com/blog/2008/01/how-to-use-args-and-kwargs-in-python/
function_to_decorate(*args, **kwargs)
return a_wrapper_accepting_arbitrary_arguments
@a_decorator_passing_arbitrary_arguments
def function_with_no_argument():
print "Python is cool, no argument here."
function_with_no_argument()
#outputs
#Do I have args?:
#()
#{}
#Python is cool, no argument here.
@a_decorator_passing_arbitrary_arguments
def function_with_arguments(a, b, c):
print a, b, c
function_with_arguments(1,2,3)
#outputs
#Do I have args?:
#(1, 2, 3)
#{}
#1 2 3
@a_decorator_passing_arbitrary_arguments
def function_with_named_arguments(a, b, c, platypus="Why not ?"):
print "Do %s, %s and %s like platypus? %s" %\
(a, b, c, platypus)
function_with_named_arguments("Bill", "Linus", "Steve", platypus="Indeed!")
#outputs
#Do I have args ? :
#('Bill', 'Linus', 'Steve')
#{'platypus': 'Indeed!'}
#Do Bill, Linus and Steve like platypus? Indeed!
class Mary(object):
def __init__(self):
self.age = 31
@a_decorator_passing_arbitrary_arguments
def sayYourAge(self, lie=-3): # You can now add a default value
print "I am %s, what did you think ?" % (self.age + lie)
m = Mary()
m.sayYourAge()
#outputs
# Do I have args?:
#(<__main__.Mary object at 0xb7d303ac>,)
#{}
#I am 28, what did you think?
向装饰器传递参数
装饰器必须使用函数作为参数,所以这看起来会有些复杂,你不能直接传递参数给装饰器本身
在开始处理这个问题前,看一点提醒
# 装饰器是普通的方法
def my_decorator(func):
print "I am a ordinary function"
def wrapper():
print "I am function returned by the decorator"
func()
return wrapper
# 所以,你可以不通过@调用它
def lazy_function():
print "zzzzzzzz"
decorated_function = my_decorator(lazy_function)
#outputs: I am a ordinary function
# It outputs "I am a ordinary function", because that's just what you do:
# 调用一个函数,没有什么特别
@my_decorator
def lazy_function():
print "zzzzzzzz"
#outputs: I am a ordinary function
上面两个形式本质上是相同的, "my_decorator" 被调用.所以当你使用"@my_decorator",告诉python一个函数被变量"my_decorator"标记 这十分重要,因为你提供的标签直接指向装饰器...或者不是,继续
# 声明一个用于创建装饰器的函数
def decorator_maker():
print "I make decorators! I am executed only once: "+\
"when you make me create a decorator."
def my_decorator(func):
print "I am a decorator! I am executed only when you decorate a function."
def wrapped():
print ("I am the wrapper around the decorated function. "
"I am called when you call the decorated function. "
"As the wrapper, I return the RESULT of the decorated function.")
return func()
print "As the decorator, I return the wrapped function."
return wrapped
print "As a decorator maker, I return a decorator"
return my_decorator
# Let's create a decorator. It's just a new function after all.
# 创建一个装饰器,本质上只是一个函数
new_decorator = decorator_maker()
#outputs:
#I make decorators! I am executed only once: when you make me create a decorator.
#As a decorator maker, I return a decorator
# 使用装饰器装饰函数
def decorated_function():
print "I am the decorated function."
decorated_function = new_decorator(decorated_function)
#outputs:
#I am a decorator! I am executed only when you decorate a function.
#As the decorator, I return the wrapped function
# 调用被装饰函数
decorated_function()
#outputs:
#I am the wrapper around the decorated function. I am called when you call the decorated function.
#As the wrapper, I return the RESULT of the decorated function.
#I am the decorated function.
我们跳过中间变量,做同样的事情
def decorated_function():
print "I am the decorated function."
decorated_function = decorator_maker()(decorated_function)
#outputs:
#I make decorators! I am executed only once: when you make me create a decorator.
#As a decorator maker, I return a decorator
#I am a decorator! I am executed only when you decorate a function.
#As the decorator, I return the wrapped function.
# 最后:
decorated_function()
#outputs:
#I am the wrapper around the decorated function. I am called when you call the decorated function.
#As the wrapper, I return the RESULT of the decorated function.
#I am the decorated function.
使用装饰器语法,更简短
@decorator_maker()
def decorated_function():
print "I am the decorated function."
#outputs:
#I make decorators! I am executed only once: when you make me create a decorator.
#As a decorator maker, I return a decorator
#I am a decorator! I am executed only when you decorate a function.
#As the decorator, I return the wrapped function.
#最终:
decorated_function()
#outputs:
#I am the wrapper around the decorated function. I am called when you call the decorated function.
#As the wrapper, I return the RESULT of the decorated function.
#I am the decorated function.
到这里,我们使用@调用一个函数
回到问题,向装饰器本身传递参数,如果我们可以通过函数去创建装饰器,那么我们可以传递参数给这个函数,对么?
def decorator_maker_with_arguments(decorator_arg1, decorator_arg2):
print "I make decorators! And I accept arguments:", decorator_arg1, decorator_arg2
def my_decorator(func):
# 这里能传递参数的能力,是闭包的特性
# 更多闭包的内容,参考 http://stackoverflow.com/questions/13857/can-you-explain-closures-as-they-relate-to-python
print "I am the decorator. Somehow you passed me arguments:", decorator_arg1, decorator_arg2
# 不要搞混了装饰器参数和函数参数
def wrapped(function_arg1, function_arg2) :
print ("I am the wrapper around the decorated function.\n"
"I can access all the variables\n"
"\t- from the decorator: {0} {1}\n"
"\t- from the function call: {2} {3}\n"
"Then I can pass them to the decorated function"
.format(decorator_arg1, decorator_arg2,
function_arg1, function_arg2))
return func(function_arg1, function_arg2)
return wrapped
return my_decorator
@decorator_maker_with_arguments("Leonard", "Sheldon")
def decorated_function_with_arguments(function_arg1, function_arg2):
print ("I am the decorated function and only knows about my arguments: {0}"
" {1}".format(function_arg1, function_arg2))
decorated_function_with_arguments("Rajesh", "Howard")
#outputs:
#I make decorators! And I accept arguments: Leonard Sheldon
#I am the decorator. Somehow you passed me arguments: Leonard Sheldon
#I am the wrapper around the decorated function.
#I can access all the variables
# - from the decorator: Leonard Sheldon
# - from the function call: Rajesh Howard
#Then I can pass them to the decorated function
#I am the decorated function and only knows about my arguments: Rajesh Howard
好了,that's it.
参数可以设置为变量
c1 = "Penny"
c2 = "Leslie"
@decorator_maker_with_arguments("Leonard", c1)
def decorated_function_with_arguments(function_arg1, function_arg2):
print ("I am the decorated function and only knows about my arguments:"
" {0} {1}".format(function_arg1, function_arg2))
decorated_function_with_arguments(c2, "Howard")
#outputs:
#I make decorators! And I accept arguments: Leonard Penny
#I am the decorator. Somehow you passed me arguments: Leonard Penny
#I am the wrapper around the decorated function.
#I can access all the variables
# - from the decorator: Leonard Penny
# - from the function call: Leslie Howard
#Then I can pass them to the decorated function
#I am the decorated function and only knows about my arguments: Leslie Howard
你可以看到,你可以使用像其它函数一样使用这个方法向装饰器传递参数.如果你愿意你甚至可以使用 arg *kwargs.
但是记住,装饰器仅在Python代码导入时被调用一次,之后你不能动态地改变参数.当你使用"import x"
,函数已经被装饰,所以你不能改变什么
练习:一个装饰装饰器的装饰器
作为奖励,我将展示创建可以处理任何参数的装饰器代码片段. 毕竟,为了接收参数,必须使用另一个函数来创建装饰器
让我们来给装饰器写一个装饰器:
# 装饰 装饰器 的装饰器 (好绕.....)
def decorator_with_args(decorator_to_enhance):
"""
这个函数将作为装饰器使用
它必须装饰另一个函数
它将允许任何接收任意数量参数的装饰器
方便你每次查询如何实现
"""
# 同样的技巧传递参数
def decorator_maker(*args, **kwargs):
# 创建一个只接收函数的装饰器
# 但是这里保存了从创建者传递过来的的参数
def decorator_wrapper(func):
# 我们返回原始装饰器的结果
# 这是一个普通的函数,返回值是另一个函数
# 陷阱:装饰器必须有这个特殊的签名,否则不会生效
return decorator_to_enhance(func, *args, **kwargs)
return decorator_wrapper
return decorator_maker
使用:
# 你创建这个函数是作为一个装饰器,但是给它附加了一个装饰器
# 别忘了,函数签名是: "decorator(func, *args, **kwargs)"
@decorator_with_args
def decorated_decorator(func, *args, **kwargs):
def wrapper(function_arg1, function_arg2):
print "Decorated with", args, kwargs
return func(function_arg1, function_arg2)
return wrapper
# 然后,使用这个装饰器(your brand new decorated decorator)
@decorated_decorator(42, 404, 1024)
def decorated_function(function_arg1, function_arg2):
print "Hello", function_arg1, function_arg2
decorated_function("Universe and", "everything")
#outputs:
#Decorated with (42, 404, 1024) {}
#Hello Universe and everything
# Whoooot!
我知道,到现在你一定会有这种感觉,就像你听一个人说“在理解递归之前,你必须首先了解递归”,但是现在,掌握这儿你有没有觉得很棒?
装饰器使用最佳实践
- 这是Python2.4的新特性,所以确保你的代码在2.4及之上的版本运行
- 装饰器降低了函数调用的性能,记住这点
- You can not un-decorate a function. There are hacks to create
decorators that can be removed but nobody uses them. So once a
function is decorated, it's done. For all the code. - 装饰器包装函数,所以很难debug
Python2.5
解决了最后一个问题,它提供functools
模块,包含functools.wraps.
这个函数会将被装饰函数的名称,模块,文档字符串拷贝给封装函数,有趣的是,functools.wraps
是一个装饰器。
# 调试,打印函数的名字
def foo():
print "foo"
print foo.__name__
#outputs: foo
# 但当你使用装饰器,这一切变得混乱
def bar(func):
def wrapper():
print "bar"
return func()
return wrapper
@bar
def foo():
print "foo"
print foo.__name__
#outputs: wrapper
# "functools" 可以改变这点
import functools
def bar(func):
# 我们所说的 "wrapper", 封装 "func"
@functools.wraps(func)
def wrapper():
print "bar"
return func()
return wrapper
@bar
def foo():
print "foo"
# 得到的是原始的名称, 而不是封装器的名称
print foo.__name__
#outputs: foo
装饰器为何那么有用
现在的问题是,我们用装饰器来坐什么?看起来很酷很强大,但是如果有实践的例子会更好.好了,有1000种可能。经典的用法是,在函数的外部,扩展一个函数的行为(你不需要改变这个函数),或者,为了调试的目的(我们不修改的原因是这是临时的),你可以使用装饰器扩展一些函数,而不用在这些函数中书写相同的函数实现一样的功能
def benchmark(func):
"""
装饰器打印一个函数的执行时间
"""
import time
def wrapper(*args, **kwargs):
t = time.clock()
res = func(*args, **kwargs)
print func.__name__, time.clock()-t
return res
return wrapper
def logging(func):
"""
装饰器记录函数日志
"""
def wrapper(*args, **kwargs):
res = func(*args, **kwargs)
print func.__name__, args, kwargs
return res
return wrapper
def counter(func):
"""
记录并打印一个函数的执行次数
"""
def wrapper(*args, **kwargs):
wrapper.count = wrapper.count + 1
res = func(*args, **kwargs)
print "{0} has been used: {1}x".format(func.__name__, wrapper.count)
return res
wrapper.count = 0
return wrapper
@counter
@benchmark
@logging
def reverse_string(string):
return str(reversed(string))
print reverse_string("Able was I ere I saw Elba")
print reverse_string("A man, a plan, a canoe, pasta, heros, rajahs, a coloratura, maps, snipe, percale, macaroni, a gag, a banana bag, a tan, a tag, a banana bag again (or a camel), a crepe, pins, Spam, a rut, a Rolo, cash, a jar, sore hats, a peon, a canal: Panama!")
#outputs:
#reverse_string ('Able was I ere I saw Elba',) {}
#wrapper 0.0
#wrapper has been used: 1x
#ablE was I ere I saw elbA
#reverse_string ('A man, a plan, a canoe, pasta, heros, rajahs, a coloratura, maps, snipe, percale, macaroni, a gag, a banana bag, a tan, a tag, a banana bag again (or a camel), a crepe, pins, Spam, a rut, a Rolo, cash, a jar, sore hats, a peon, a canal: Panama!',) {}
#wrapper 0.0
#wrapper has been used: 2x
#!amanaP :lanac a ,noep a ,stah eros ,raj a ,hsac ,oloR a ,tur a ,mapS ,snip ,eperc a ,)lemac a ro( niaga gab ananab a ,gat a ,nat a ,gab ananab a ,gag a ,inoracam ,elacrep ,epins ,spam ,arutaroloc a ,shajar ,soreh ,atsap ,eonac a ,nalp a ,nam A
装饰器意味着,你可以用正确的方法实现几乎所有的事情,而不必重写他们
@counter
@benchmark
@logging
def get_random_futurama_quote():
import httplib
conn = httplib.HTTPConnection("slashdot.org:80")
conn.request("HEAD", "/index.html")
for key, value in conn.getresponse().getheaders():
if key.startswith("x-b") or key.startswith("x-f"):
return value
return "No, I'm ... doesn't!"
print get_random_futurama_quote()
print get_random_futurama_quote()
#outputs:
#get_random_futurama_quote () {}
#wrapper 0.02
#wrapper has been used: 1x
#The laws of science be a harsh mistress.
#get_random_futurama_quote () {}
#wrapper 0.01
#wrapper has been used: 2x
#Curse you, merciful Poseidon!
Python
本身提供了一些装饰器:property
,staticmethod
,等等,
【Python】装饰器理解的更多相关文章
- python装饰器理解
1.装饰器的作用 在不修改被装饰对象的源代码以及调用方式的前提下为被装饰对象添加新功能 原则: 1.不修改被装饰对象的源代码2.不修改被装饰对象的调用方式 目标: 为被装饰对象添加新功能 2.装饰器的 ...
- python 装饰器理解
简介 装饰器可以在不修改原有代码的基础上添加新的功能,可以将重复重用的代码抽取出来,进一步解耦,方便维护,一般适用于插入日志.性能测试.事务处理.缓存等 装饰器的前提 闭包 一般来说,当一个函数嵌套另 ...
- 关于python装饰器(Decorators)最底层理解的一句话
一个decorator只是一个带有一个函数作为参数并返回一个替换函数的闭包. http://www.xxx.com/html/2016/pythonhexinbiancheng_0718/1044.h ...
- 如何理解Python装饰器
如何理解Python装饰器?很多学员对此都有疑问,那么上海尚学堂python培训这篇文章就给予答复. 一.预备知识 首先要理解装饰器,首先要先理解在 Python 中很重要的一个概念就是:“函数是 F ...
- 转发对python装饰器的理解
[Python] 对 Python 装饰器的理解的一些心得分享出来给大家参考 原文 http://blog.csdn.net/sxw3718401/article/details/3951958 ...
- 理解 Python 装饰器看这一篇就够了
讲 Python 装饰器前,我想先举个例子,虽有点污,但跟装饰器这个话题很贴切. 每个人都有的内裤主要功能是用来遮羞,但是到了冬天它没法为我们防风御寒,咋办?我们想到的一个办法就是把内裤改造一下,让它 ...
- python 装饰器的理解以及类装饰器
python装饰器的作用就是在不改变原有函数结构的情况下给该函数增加一个新功能,就是不入侵到原来函数里面修改代码给其增加一个新功能 先看代码 def out(fn): def inner(*args, ...
- Python装饰器的通俗理解
转载:http://blog.csdn.net/u013471155 在学习Python的过程中,我相信有很多人和我一样,对Python的装饰器一直觉得很困惑,我也是困惑了好久,并通过思考和查阅才能略 ...
- (一)Python装饰器的通俗理解
在学习Python的过程中,我相信有很多人和我一样,对Python的装饰器一直觉得很困惑,我也是困惑了好久,并通过思考和查阅才能略有领悟,我希望以下的内容会对你有帮助,我也努力通过通俗的方式使得对Py ...
随机推荐
- (C++) Assertion failed: !"Bad error code", file VMem.c, line 715
(C++) Assertion failed: !"Bad error code", file VMem.c, line 715 Misc error. myInterface F ...
- 在Windows上安装Elasticsearch 5.x
在Windows上安装Elasticsearch 5.x 自己想学习Elasticsearch,但是又不懂Linux,按照同事给的Linux安装教程,也是搞不明白,于是想先在Windows上安装一下入 ...
- web性能深入探究 eventloop 与浏览器渲染的时序问题 #
https://github.com/jin5354/404forest/issues/61
- iOS开发之HelloKit代码片段
完整代码托管:https://github.com/1042710553/HelloKit.git /************************/plist/****************** ...
- TCP/IP原理简述
TCP/IP与OSI TCP/IP工作在第4层,在TCP/IP协议簇中,有两个不同的传输协议:TCP(传输控制协议)和UDP(用户数据报协议),它们分别承载不同的应用.TCP协议提供可靠的服务,UDP ...
- 比较字符串CompareTo的用法及注意
CompareTo用法 static void Main(string[] args) { string str = "1"; ...
- Visual Studio 2010生成解决方案时,导致C盘空间越来越小
为了从根本上解决问题,还是去掉智能跟踪选项吧,方案: VS2010-->工具-->选项-->IntelliTrance-->将“启用IntelliTrace”勾选去掉--> ...
- wget指定目录下载以及其它的使用方式
转自 http://java-er.com/blog/wget-useage-x/ 有时候我们需要wget一个文件下载到指定的目录下,或者重命名成指定的名字 wget -r -p -np -k -P ...
- js 自定义事件观察者模式(发布/订阅)
/* * 示例: * Event.create("namespace1").listen('click', function(a){ * console.log(a); * }); ...
- 初入spring boot(七 )Spring Data JPA
Spring Data JPA通过提供基于JPA的Repository极大地减少JPA作为数据访问方案的代码量. 1.定义数据访问层 使用Spring Data JPA建立数据访问层十分简单,只需定义 ...