[python 进阶] 第7章 函数装饰器和闭包

文章目录

    • 7.1 装饰器基础知识
    • 7.2 Python何时执行装饰器
    • 7.3 使用装饰器改进“策略”
    • 7.4 变量作用域(global)
    • 备注 -比较字节码(暂略)
    • 7.5 闭包
    • 7.6 nonlocal声明
    • global和nonlocal的区别
    • 7.7 实现一个简单的装饰器
    • 7.8 标准库中的装饰器
      • 7.8.1 使用functools.lru_cache做备忘
      • 补充 @functools.lru_cache()可以配置参数
      • 7.8.2 单分派泛函数( @functools.singledispatch)
    • 7.9 叠放装饰器
    • 7.10 参数化装饰器
      • 7.10.1 一个参数化的注册装饰器
      • 7.10.2 参数化clock装饰器

函数装饰器用于在源码中“标记”函数,以某种方式增强函数的行为。这是一项强大的功能,但是若想掌握,必须理解闭包。
nonlocal 是新近出现的保留关键字,在 Python 3.0 中引入。
除了在装饰器中有用处之外,闭包还是 回调式异步编程函数式编程风格的基础。
本章的最终目标是解释清楚函数装饰器的工作原理,包括最简单的 注册装饰器和较复杂的 参数化装饰器。但是,在实现这一目标之前,我们要讨论下述话题:

  • Python 如何计算装饰器句法
  • Python 如何判断变量是不是局部的
  • 闭包存在的原因和工作原理
  • nonlocal 能解决什么问题
    掌握这些基础知识后,我们可以进一步探讨装饰器:
  • 实现行为良好的装饰器
  • 标准库中有用的装饰器
  • 实现一个参数化装饰器

7.1 装饰器基础知识

装饰器是可调用的对象,其参数是另一个函数(被装饰的函数)。 装饰器可能会处理被装饰的函数,然后把它返回,或者将其替换成另一个函数或可调用对象。
假如有个名为 decorate 的装饰器:

@decorate
def target():
print('running target()')

上述代码的效果与下述写法一样:

def target():
print('running target()')
target = decorate(target)

两种写法的最终结果一样:上述两个代码片段执行完毕后得到的 target 不一定是原来那
个 target 函数,而是 decorate(target) 返回的函数。

为了确认被装饰的函数会被替换,请看示例 7-1 中的控制台会话。
示例 7-1 装饰器通常把函数替换成另一个函数

>>> def deco(func):
... def inner():
... print('running inner()')
... return inner 
...
>>> @deco
... def target(): 
... print('running target()')
...
>>> target() 
running inner()
>>> target 
<function deco.<locals>.inner at 0x10063b598>

严格来说,装饰器只是语法糖。如前所示,装饰器可以像常规的可调用对象那样调用,其
参数是另一个函数。有时,这样做更方便,尤其是做元编程(在运行时改变程序的行
为)时。
综上,装饰器的一大特性是,能把被装饰的函数替换成其他函数。第二个特性是,装饰器
在加载模块时立即执行。

7.2 Python何时执行装饰器

装饰器的一个关键特性是,它们在被装饰的函数定义之后立即运行。这通常是在导入时
(即 Python 加载模块时)

registry = []
def register(func):print('running register(%s)' % func)registry.append(func)return func
@register
def f1():print('running f1()')
@register
def f2():print('running f2()')
def f3():print('running f3()')
def main():print('running main()')print('registry ->', registry)  # 发现registry这个数组并不是空f1()f2()f3()
if __name__=='__main__':main()

输出后是什么样子呢?

running register(<function f1 at 0x7ff079e400d0>)
running register(<function f2 at 0x7ff06c9e37b8>)
running main()
registry -> [<function f1 at 0x7ff079e400d0>, <function f2 at 0x7ff06c9e37b8>]
running f1()
running f2()
running f3()

注意:在调用f1()和f2()时,输出的是 runnint f1()和running f2()。
上面的例子主要是强调:函数装饰器在导入模块时立即执行,而被装饰的函数只在明确调用时运行。这突出了 Python 程序员所说的导入时和运行时之间的区别。
考虑到装饰器在真实代码中的常用方式,示例 7-2 有两个不寻常的地方。装饰器函数与被装饰的函数在同一个模块中定义。实际情况是,装饰器通常在一个模块中定义,然后应用到其他模块中的函数上。
register 装饰器返回的函数与通过参数传入的相同。实际上,大多数装饰器会在内部定义一个函数,然后将其返回。

虽然上示例中的 register 装饰器原封不动地返回被装饰的函数,但是这种技术并非没有用处。很多 Python Web 框架使用这样的装饰器把函数添加到某种中央注册处,例如把URL模式映射到生成 HTTP 响应的函数上的注册处。这种注册装饰器可能会也可能不会修改被装饰的函数。

7.3 使用装饰器改进“策略”

使用注册装饰器可以改进之前的第六章中的电商促销折扣示例。
回顾一下,示例 6-6 的主要问题是,定义体中有函数的名称,但是 best_promo 用来判断哪个折扣幅度最大的 promos 列表中也有函数名称。这种重复是个问题,因为新增策略函数后可能会忘记把它添加到 promos 列表中,导致 best_promo 忽略新策略,而且不报错,为系统引入了不易察觉的缺陷。以下这个例子使用注册装饰器解决了这个问题。

  • promos 列表中的值使用 promotion 装饰器

      from collections import namedtupleCustomer = namedtuple('Customer', 'name fidelity')class LineItem:def __init__(self, product, quantity, price):self.product = productself.quantity = quantityself.price = pricedef total(self):return self.price * self.quantitypromos =[]def promotion(promo_func):promos.append(promo_func)return promo_func@promotiondef fidelity(order):"""为积分为1000或者以上的顾客提供5%折扣"""return order.total() * 0.05 if order.customer.fidelity >= 1000 else 0@promotiondef bulk_item(order):"""单个商品为20个或者以上时提供10%折扣"""discount = 0for item in order.cart:if item.quantity >= 20:discount += item.total() * 0.01return discount@promotiondef large_order(order):"""订单中的不同商品达到10个以上时提供7%折扣"""distinct_items = {item.product for item in order.cart}if len(distinct_items) >= 10:return order.total() * 0.07return 0def best_promo(order):"""选择可用的最佳折扣"""return max(promo(order) for promo in promos)class Order: #上下文def __init__(self, customer, cart, promotion=None):self.customer = customerself.cart = list(cart)self.promotion = promotiondef total(self):if not hasattr(self, '__total'):self.__total = sum(item.total() for item in self.cart)return self.__totaldef due(self):if self.promotion is None:discount = 0else:discount = self.promotion(self)return self.total() - discountdef __repr__(self):fmt = '<Order total: {:.2f} due: {:.2f}>'return fmt.format(self.total(), self.due())if __name__ == '__main__':joe = Customer('John Doe', 0)ann = Customer('Ann Smith', 1000)cart = [LineItem('banana', 4, 0.5),LineItem('apple', 10, 1.5),LineItem('watermellon', 5, 5.0)]print(Order(joe, cart, fidelity))   # <Order total: 42.00 due: 42.00>print(Order(ann, cart, fidelity))   #<Order total: 42.00 due: 39.90>
    

与 6.1 节给出的方案相比,这个方案有几个优点。

  • 促销策略函数无需使用特殊的名称(即不用以 _promo 结尾)。
  • @promotion 装饰器突出了被装饰的函数的作用,还便于临时禁用某个促销策略:只需把装饰器注释掉。
  • 促销折扣策略可以在其他模块中定义,在系统中的任何地方都行,只要使用@promotion 装饰即可。

不过,多数装饰器会修改被装饰的函数。通常,它们会定义一个内部函数,然后将其返
回,替换被装饰的函数。使用内部函数的代码几乎都要靠闭包才能正确运作。

7.4 变量作用域(global)

在示例 7-4 中,我们定义并测试了一个函数,它读取两个变量的值:一个是局部变量 a,
是函数的参数;另一个是变量 b,这个函数没有定义它。

示例 7-4 一个函数,读取一个局部变量和一个全局变量

>>> def f1(a):
... print(a)
... print(b)
...
>>> f1(3)
3
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in f1
NameError: global name 'b' is not defined

出现错误并不奇怪。 在示例 7-4 中,如果先给全局变量 b 赋值,然后再调用 f,那就不
会出错。

示例 7-5 b 是局部变量,因为在函数的定义体中给它赋值了

>>> b = 6
>>> def f2(a):
... print(a)
... print(b)
... b = 9
...
>>> f2(3)
3
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in f2
UnboundLocalError: local variable 'b' referenced before assignment

注意,首先输出了 3,这表明 print(a) 语句执行了。但是第二个语句 print(b) 执行不了。一开始我很吃惊,我觉得会打印 6,因为有个全局变量 b,而且是在 print(b) 之后为局部变量 b 赋值的。
可事实是,Python 编译函数的定义体时,它判断 b 是局部变量,因为在函数中给它赋值了。生成的字节码证实了这种判断,Python 会尝试从本地环境获取 b。后面调用 f2(3)时, f2 的定义体会获取并打印局部变量 a 的值,但是尝试获取局部变量 b 的值时,发现b 没有绑定值。
这不是缺陷,而是设计选择:Python 不要求声明变量,但是假定在函数定义体中赋值的变量是局部变量。这比 JavaScript 的行为好多了,JavaScript 也不要求声明变量,但是如果忘记把变量声明为局部变量(使用 var),可能会在不知情的情况下获取全局变量。
如果在函数中赋值时想让解释器把 b 当成全局变量,要使用 global 声明:

>>> b = 6
>>> def f3(a):
... global b
... print(a)
... print(b)
... b = 9
...
>>> f3(3)
3
6
>>> b
9
>>> f3(3)
3
9
>>> b = 30
>>> b
30
>>>

了解 Python 的变量作用域之后,下一节可以讨论闭包了。如果好奇示例 7-4 和示例 7-5 中的两个函数生成的字节码有什么区别,可以下面的备注:

备注 -比较字节码(暂略)

7.5 闭包

在博客圈,人们有时会把闭包和匿名函数弄混。这是有历史原因的:在函数内部定义函数不常见,直到开始使用匿名函数才会这样做。而且,只有涉及嵌套函数时才有闭包问题。
因此,很多人是同时知道这两个概念的。
其实,闭包指延伸了作用域的函数,其中包含函数定义体中引用、但是不在定义体中定义的非全局变量。函数是不是匿名的没有关系,关键是它能访问定义体之外定义的非全局变量。
这个概念难以掌握,最好通过示例理解。
假如有个名为 avg 的函数,它的作用是计算不断增加的系列值的均值;例如,整个历史中某个商品的平均收盘价。每天都会增加新价格,因此平均值要考虑至目前为止所有的价格。

示例 7-8 average_oo.py:计算移动平均值

class Averager():def __init__(self):self.series=[]def __call__(self, new_value):self.series.append(new_value)total = sum(self.series)return total/len(self.series)
avg=Averager()
print(avg(10)) #10.0
print(avg(11)) #10.5
print(avg(12)) #11.0

Averager 的实例是可调用对象

示例 7-9 是函数式实现,使用高阶函数 make_averager。

示例 7-9 average.py:计算移动平均值的高阶函数

def make_averager():series = []def averager(new_value):series.append(new_value)total = sum(series)return total/len(series)
return averager

调用 make_averager 时,返回一个 averager 函数对象。每次调用 averager 时,它会
把参数添加到系列值中,然后计算当前平均值,如示例 7-10 所示。
示例 7-10 测试示例 7-9

>>> avg = make_averager()
>>> avg(10)
10.0
>>> avg(11)
10.5
>>> avg(12)
11.0

注意,这两个示例有共通之处:调用 Averager() 或 make_averager() 得到一个可调用对象 avg,它会更新历史值,然后计算当前均值。在示例 7-8 中,avg 是 Averager 的实例;在示例 7-9 中是内部函数 averager。不管怎样,我们都只需调用 avg(n),把 n 放入系列值中,然后重新计算均值。
Averager 类的实例 avg 在哪里存储历史值很明显:self.series 实例属性。但是第二个示例中的 avg 函数在哪里寻找 series 呢?
注意,series 是 make_averager 函数的局部变量,因为那个函数的定义体中初始化了series:series = []。可是,调用 avg(10) 时,make_averager 函数已经返回了,而它的本地作用域也一去不复返了。
在 averager 函数中,series 是自由变量(free variable)。这是一个技术术语,指未在本地作用域中绑定的变量。

在这里插入图片描述
averager 的闭包延伸到那个函数的作用域之外,包含自由变量 series 的绑定。
综上,闭包是一种函数,它会保留定义函数时存在的自由变量的绑定,这样调用函数时,虽然定义作用域不可用了,但是仍能使用那些绑定。
注意,只有嵌套在其他函数中的函数才可能需要处理不在全局作用域中的外部变量。

7.6 nonlocal声明

前面实现 make_averager 函数的方法效率不高。在示例 7-9 中,我们把所有值存储在历史数列中,然后在每次调用 averager 时使用 sum 求和。更好的实现方式是,只存储目前的总值和元素个数,然后使用这两个数计算均值。
示例 7-13 中的实现有缺陷,只是为了阐明观点。你能看出缺陷在哪儿吗?

示例 7-13 计算移动平均值的高阶函数,不保存所有历史值,但有缺陷
def make_averager():
count = 0
total = 0def averager(new_value):count += 1total += new_valuereturn total / count
return averager

Python 3 引入了 nonlocal 声明。它的作用是把变量标记为自由变量,即使在函数中为变量赋予新值了,也会变成自由变量。如果为 nonlocal 声明的变量赋予新值,闭包中保存的绑定会更新。

示例 7-14 计算移动平均值,不保存所有历史(使用 nonlocal 修正)
def make_averager():
count = 0
total = 0def averager(new_value):nonlocal count, totalcount += 1total += new_valuereturn total / count
return averager

global和nonlocal的区别

global 表示将变量声明为全局变量
nonlocal 表示将变量声明为外层变量(外层函数的局部变量,而且不能是全局变量)。

    1. global关键字用来在函数或其他局部作用域中使用全局变量。但是如果不修改全局变量也可以不使用global关键字。
    1. 声明全局变量,如果在局部要对全局变量修改,需要在局部也要先声明该全局变量。

         gcount = 0def global_test():global gcountgcount +=1print (gcount)global_test()
      
  • 3.在局部如果不声明全局变量,并且不修改全局变量。则可以正常使用全局变量:

      			gcount = 0def global_test():print(gcount)global_test()
    
    1. nonlocal关键字用来在函数或其他作用域中使用外层(非全局)变量

         def make_counter(): count = 0 def counter(): nonlocal count count += 1 return count return counter def make_counter_test(): mc = make_counter() print(mc())print(mc())print(mc())make_counter_test()
      

7.7 实现一个简单的装饰器

定义了一个装饰器,它会在每次调用被装饰的函数时计时,然后把经过的时间、传入的参数和调用的结果打印出来。
import time

def clock(func):def clocked(*args):t0=time.perf_counter()result = func(*args)elapsed = time.perf_counter()name = func.__name__arg_str = ','.join(repr(arg) for arg in args)print('[%0.8fs] %s(%s)-> %r' % (elapsed, name, arg_str, result))return resultreturn clocked@clock
def snooze(seconds):time.sleep(seconds)
@clock
def factorial(n):return 1 if n < 2 else n*factorial(n-1)
if __name__ == '__main__':print('*' * 40, 'Calling snooze(.123)')snooze(.123)print('*' * 40, 'Calling factorial(6)')print('6! =', factorial(6))

这是装饰器的典型行为:把被装饰的函数替换成新函数,二者接受相同的参数,而且(通常)返回被装饰的函数本该返回的值,同时还会做些额外操作。

将上述例子改进一下:

7.8 标准库中的装饰器

Python 内置了三个用于装饰方法的函数:property、classmethod 和
staticmethod。另一个常见的装饰器是 functools.wraps,它的作用是协助构建行为良好的装饰器。我
们在示例 7-17 中用过。标准库中最值得关注的两个装饰器是 lru_cache 和全新的
singledispatch(Python 3.4 新增)。这两个装饰器都在 functools 模块中定义。

7.8.1 使用functools.lru_cache做备忘

示例 7-18 生成第 n 个斐波纳契数,递归方式非常

import timedef clock(func):def clocked(*args):print(*args)t0 = time.perf_counter()result = func(*args)elapsed = time.perf_counter()name = func.__name__arg_str = ','.join(repr(arg) for arg in args)print('[%0.8fs] %s(%s)-> %r' % (elapsed, name, arg_str, result))return resultreturn clocked@clock
def fibonacci(n):return n if n < 2 else fibonacci(n-2)+fibonacci(n-1)if __name__ == '__main__':print(fibonacci(6))

示例 7-19 使用缓存实现,速度

import time
import functools
def clock(func):def clocked(*args):print(*args)t0 = time.perf_counter()result = func(*args)elapsed = time.perf_counter()name = func.__name__arg_str = ','.join(repr(arg) for arg in args)print('[%0.8fs] %s(%s)-> %r' % (elapsed, name, arg_str, result))return resultreturn clocked@functools.lru_cache() #注意,必须像常规函数那样调用 lru_cache。这一行中有一对括号:@functools.lru_cache()。这么做的原因是,lru_cache 可以接受配置参数
@clock
def fibonacci(n):return n if n < 2 else fibonacci(n-2)+fibonacci(n-1)if __name__ == '__main__':print(fibonacci(6))

补充 @functools.lru_cache()可以配置参数

7.8.2 单分派泛函数( @functools.singledispatch)

7.9 叠放装饰器

示例 7-19 演示了叠放装饰器的方式:@lru_cache 应用到 @clock 装饰 fibonacci 得到的结果上。在示例 7-21 中,模块中最后一个函数应用了两个 @htmlize.register 装饰器。
把 @d1 和 @d2 两个装饰器按顺序应用到 f 函数上,作用相当于 f = d1(d2(f))。
也就是说,下述代码:

@d1
@d2
def f():print('f')

等同于:

def f():print('f')f = d1(d2(f))

除了叠放装饰器之外,本章还用到了几个接受参数的装饰器,

7.10 参数化装饰器

解析源码中的装饰器时,Python 把被装饰的函数作为第一个参数传给装饰器函数。那怎么让装饰器接受其他参数呢?答案是:创建一个装饰器工厂函数,把参数传给它,返回一个装饰器,然后再把它应用到要装饰的函数上。

registry = []
def register(func):print('running register(%s)' % func)registry.append(func)return func
@register
def f1():print('running f1()')
print('running main')
print('registry ->',registry)
f1()

7.10.1 一个参数化的注册装饰器

为了便于启用或禁用 register 执行的函数注册功能,我们为它提供一个可选的 active参数,设为 False 时,不注册被装饰的函数。实现方式参见下面这个例子。从概念上看,这个新的 register 函数不是装饰器,而是装饰器工厂函数。调用它会返回真正的装饰器,这才是应用到目标函数上的装饰器。

registry = []
def register(active=True):def decorate(func):print('running register(active=%s)->decorate(%s)'%(active, func))if active:registry.add(func)else:registry.discard(func)return func #decorate 是装饰器,必须返回一个函数return decorate # register 是装饰器工厂函数,因此返回 decorate
@register(active=True)
def f1():print('running f1()')
@register() #即使不传入参数,register 也必须作为函数调用(@register()),即要返回真正的装饰器 decorate。
def f2():print('running f2()')
def f3():print('running f3()')

如果不使用 @ 句法,那就要像常规函数那样使用 register;若想把 f 添加到 registry中,则装饰 f 函数的句法是 register()(f);不想添加(或把它删除)的话,句法是register(active=False)(f)。

参数化装饰器的原理相当复杂,我们刚刚讨论的那个比大多数都简单。参数化装饰器通常会把被装饰的函数替换掉,而且结构上需要多一层嵌套。

7.10.2 参数化clock装饰器

本节再次探讨 clock 装饰器,为它添加一个功能:让用户传入一个格式字符串,控制被装饰函数的输出。
import time
DEFAULT_FMT=’[{elapsed:0.8f}s] {name}({args})-> {result}’

def clock(fmt=DEFAULT_FMT):def decorate(func):def clocked(*_args):t0 = time.time()_result= func(*_args)elapsed=time.time-t0name = func._name__args = ','.join(repr(arg) for arg in _args)result = repr(_result)print(fmt.format(**locals()))return _resultreturn clockedreturn decorate
if __name__ == '__main__':@clockdef snooze(seconds):time.sleep(seconds)for i in range(3):snooze(.123)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/273795.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

自制“低奢内”CSS3登入表单,包含JS验证,请别嫌弃哦。

要求 必备知识 基本了解CSS语法,初步了解CSS3语法知识。和JS/JQuery基本语法。 开发环境 Adobe Dreamweaver CS6 演示地址 演示地址 预览截图(抬抬你的鼠标就可以看到演示地址哦): 制作步骤: 一, html结构 <div id"home"><form id"login" class…

class里面只能写以下5种

转载于:https://www.cnblogs.com/phplearnings/p/3650849.html

【排序】算法(python实现)

文章目录python 排序算法1 插入排序1.1 直接插入排序算法思想1.2 希尔排序算法思想2. 选择排序2.1 简单选择排序2.2 堆排序参考python 排序算法 1 插入排序 1.1 直接插入排序 算法思想 直接插入排序的核心思想就是&#xff1a;将数组中的所有元素依次跟前面已经排好的元素相…

OpenSSL漏洞补救办法详解(转)

CVE-2014-0160漏洞背景 2014年4月7日OpenSSL发布了安全公告&#xff0c;在OpenSSL1.0.1版本中存在严重漏洞(CVE-2014-0160)。OpenSSL Heartbleed模块存在一个BUG&#xff0c;问题存在于ssl/dl_both.c文件中的心跳部分&#xff0c;当攻击者构造一个特殊的数据包&#xff0c;满足…

SharePoint 自定义WebPart之间的连接

1、创建SharePoint解决方案&#xff0c;添加两个WebPart分别用来发送和接收&#xff1b; 2、发送值的WebPart需要继承自IWebPartField(当然&#xff0c;根据需要还可以选择IWebPartField,IWebPartParameters,IWebPartRow,IWebPartTable&#xff0c;具体参见msdn)&#xff0c;原…

[python 进阶] 9. 符合Python风格的对象

文章目录9.1 对象表示形式9.2 再谈向量类9.3 备选构造方法9.4 classmethod与staticmethod9.5 格式化显示9.6 可散列的Vector2d什么是可散列的数据类型9.6 可散列的Vector9.7 Python的私有属性和“受保护的”属性9.8 使用 __slots__ 类属性节省空间本章包含以下话题&#xff1a;…

android软件获取系统签名

有时候有的功能必须要有系统签名才能使用&#xff0c;例如调用系统自带的Surface.screenShot方法时&#xff0c;就必须在androidManifest.xml里声明android:sharedUserId"android.uid.system" 但是这个时候在编译生成的apk很有可能无法安装的情况 并且报这个错误&…

Python3中的可变与不可变类型

在描述变量是否是可变类型时&#xff0c;可变与否实际上说的是对变量进行“修改”时变量的内存地址是否会发生变化&#xff0c;而非值是否可变。在Python中&#xff0c;对不可变的变量进行“修改”实际上是重新赋值&#xff0c;对可变的变量进行修改才是真正的修改&#xff0c;…

python中带*(单星号)的变量和**(双星号)的变量

一、*args的使用方法 *args 用来将参数打包成tuple给函数体调用二、**kwargs的使用方法 **kwargs 打包关键字参数成dict给函数体调用注意点&#xff1a;参数arg、*args、**kwargs三个参数的位置必须是一定的。必须是(arg,*args,**kwargs)这个顺序&#xff0c;否则程序会报错。单…

百度知道回答的依赖注入

oC 或者 DI 或者 ...一大堆的缩写词不管是面向对象&#xff0c;还是面向过程&#xff0c;都需要分成许多的块&#xff0c;然后由这些部件协同工作完成任务 要协同工作就会产生依赖&#xff0c;一个方法调用另一个方法&#xff0c;一个对象包含另一个对象 如果对象A包含对象B的话…

Django model中的 class Meta 详解

参考 (1) https://www.cnblogs.com/tongchengbin/p/7670927.html

C\C++ 获取当前路径

C\C 获取当前路径 获取当前工作目录是使用函数&#xff1a;getcwd。cwd指的是“current working directory”&#xff0c;这样就好记忆了。 函数说明&#xff1a; 函数原型&#xff1a;char* getcwd(char* buffer, int len); 参数&#xff1a;buffer是指将当前工作…

[python进阶]11接口:从协议到抽象基类

本章讨论的话题是接口&#xff1a;从鸭子类型的代表特征动态协议&#xff0c;到使接口更明确、能验证实现是否符合规定的抽象基类&#xff08;Abstract Base Class&#xff0c;ABC&#xff09;。 首先&#xff0c;本章说明抽象基类的常见用途&#xff1a;实现接口时作为**超类(…

ie11浏览器不能显示最新修改的程序,调试出现代码逻辑错误却依旧执行

1、问题&#xff1a;ie11浏览器不能显示最新修改的程序&#xff0c;调试也不能&#xff0c;出现代码逻辑错误却依旧执行 2、百度解决方案&#xff1a;http://blog.163.com/wang_hj138126/blog/static/1408001062012631508444/ FireFox每次访问页面时检查最新版本 2012-07-31 …

C# 基础备忘录

1. decimal 类型调用ToString()方法后没把末尾的0去掉的解决办法: 例子&#xff1a;decimal? money Convert.ToDecimal(10.8950);string moneyStrmoney.Value.ToString(); 结果在同一台机子&#xff0c;两个项目里面会出现两个不同的结果。结果一&#xff1a;moneyStr"1…

[python进阶]12.继承的优缺点

本章探讨继承和子类化&#xff0c;重点是说明对 Python 而言尤为重要的两个细节&#xff1a; 子类化内置类型的缺点多重继承和方法解析顺序 12.1 子类化内置类型很 12.2 多重继承和方法解析

Android中用GridView实现九宫格的两种方法(转)

Android中用GridView实现九宫格的两种方法http://blog.csdn.net/shakespeare001/article/details/7768455 1.传统办法&#xff1a;实现一个继承BaseAdapter的 ImageAdapter package com.test; import android.app.Activity; import android.content.Context; import andro…

django框架中的模型

文章目录关联关系Many-to-one relationshipsMany-to-many relationshipsdjango学习——model中的get和filter方法的区别模型模型是您的数据唯一而且准确的信息来源。它包含您正在储存的数据的重要字段和行为。一般来说&#xff0c;每一个模型都映射一个数据库表。基础&#xff…

虚拟主机TOMCAT配置

在tomcat中添加虚拟主机&#xff1a;   编辑"tomcat\conf\server.xml"&#xff0c;在"<Engine></Engine>"元素中新加子元素"<Host></Host>"&#xff0c;如下&#xff1a;  </Host>     <Host name&quo…