码迷,mamicode.com
首页 > 编程语言 > 详细

python基础(3):函数对象、函数嵌套、名称空间与作用域、装饰器

时间:2018-09-02 01:58:59      阅读:255      评论:0      收藏:0      [点我收藏+]

标签:退出   any   rand   用户   dex   程序   python基础   type   round   

  1. 函数对象

  2. 函数嵌套

  3. 名称空间与作用域

  4. 闭包函数

  5. 装饰器

  6. 练习

一 函数对象

#1 可以被引用
def max(x, y):
    return x if x > y else y
func = max
print(func(1, 2))

#2 可以当作参数传递
def max(x, y):
    return x if x > y else y
def max_1(x, func):
    return func(x, 1)
print(max_1(2, max))

#3 返回值可以是函数

#4 可以当作容器类型的元素
def foo():
    print(foo)

def bar():
    print(bar)

dic={
    foo:foo,
    bar:bar,
}
while True:
    choice=input(>>: ).strip()
    if choice in dic:
        dic[choice]()

 

二 函数嵌套

def foo():
    def bar():
        print(from bar)
    bar()

foo()
bar() #报错

 

三 名称空间与作用域

#名称空间:存放名字的地方,(x=1,1存放于内存中,名称空间正是存放名字x与1绑定关系的地方)
#三种名称空间:局部名称空间--->全局名称空间--->内置名称空间

内置名称空间在 Python 解释器启动时就创建了,直到 Python 解释器退出时内置名称空间才失效。这使得我们可以在程序的任何位置使用内置名称空间内的名称,例如,
id()print()等函数。 
全局命名空间,每个模块加载执行时创建的,记录了模块中定义的变量,包括模块中定义的函数、类、其他导入的模块、模块级的变量与常量。
python自带的内建命名空间,任何模块均可以访问,放着内置的函数和异常。
#1、作用域即范围
        - 全局范围(内置名称空间与全局名称空间属于该范围):全局存活,全局有效
      - 局部范围(局部名称空间属于该范围):临时存活,局部有效
#2、作用域关系是在函数定义阶段就已经固定的,与函数的调用位置无关,如下
x=1
def f1():
    def f2():
        print(x)
    return f2
x=100
def f3(func):
    x=2
    func()
x=10000
f3(f1())

#3、查看作用域:globals(),locals()


LEGB 代表名字查找顺序: locals -> enclosing function -> globals -> __builtins__
locals 是函数内的名字空间,包括局部变量和形参
enclosing 外部嵌套函数的名字空间(闭包中常见)
globals 全局变量,函数定义所在模块的名字空间
builtins 内置模块的名字空间

 

四 闭包函数

它是怎么产生的及用来解决什么问题呢。给出字面的定义先:闭包是由函数及其相关的引用环境组合而成的实体(即:闭包=函数+引用环境)

def counter():
    n = 0

    def incr():
        nonlocal n
        x = n
        n += 1
        return x

    return incr


c = counter()
print(c())
print(c())
print(c.__closure__[0].cell_contents)  # 查看闭包的元素

用途:延迟计算

from urllib.request import urlopen

def index(url):
    def get():
        return urlopen(url).read()

    return get

baidu = index(http://www.baidu.com)
print(baidu().decode(utf-8))

 

五 装饰器

装饰器就是闭包函数的一种应用场景,用于拓展原来函数功能的一种函数

强调装饰器的原则:1 不修改被装饰对象的源代码  2 不修改被装饰对象的调用方式

装饰器的目标:在遵循1和2的前提下,为被装饰对象添加上新功能

装饰器函数以目标函数名为参数,且必须返回一个函数调用目标函数参数执行

 

import time

def deco1(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        print(deco1 start)
        func(*args, **kwargs)
        print(deco1 end)
        end_time = time.time()
        print(end_time - start_time)
    return wrapper

def deco2(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        print(deco2 start)
        func(*args, **kwargs)
        print(deco2 end)
        end_time = time.time()
        print(end_time - start_time)
    return wrapper

@deco1
@deco2
def fun(x, y):
    time.sleep(2)
    print(x + y)

fun(1, 2)

 

装饰器函数的参数为被装饰函数。装饰后执行被装饰函数相当于执行装饰器函数返回的函数,即例子中的wrapper

 

六 练习

# 编写函数,函数执行的时间是随机的
import random
import time
def func1():
    t = random.random()
    print(sleeping time =, t)
    print(sleeping starts)
    time.sleep(t)
    print(sleeping ends)
func1()
# 编写装饰器,为函数加上统计时间的功能
import random
import time

def deco(func):
    def wrapper(*args, **kwargs):
        stime = time.time()
        func(*args, **kwargs)
        etime = time.time()
        print(deco time:, (etime - stime))
    return wrapper

@deco
def func():
    t = random.random()
    print(sleeping time =, t)
    print(sleeping starts)
    time.sleep(t)
    print(sleeping ends)

func()

 

# 编写装饰器,为多个函数加上认证功能,要求登录成功一次,在超时时间内无需重复登录,超过了超时时间,则必须重新登录
# db.txt内容:{‘user‘: ‘zsy‘, ‘passwd‘: ‘123‘}
db = db.txt

def auth(authtype=file):
    user_status = {user: None, passwd: None}
    def origin_auth(func):
        def wrapper(*args, **kwargs):
            if authtype == file:
                if user_status[user] != None or user_status[passwd] != None:
                    func(*args, **kwargs)
                else:
                    dict = eval(open(db, r, encoding=utf-8).read())
                    user_name = input(Name: )
                    user_passwd = input(Passwd: )
                    if user_name == dict[user] and user_passwd == dict[passwd]:
                        user_status[user] = user_name
                        user_status[passwd] = user_passwd
                        print(登录成功)
                        func(*args, **kwargs)
                    else:
                        print(用户名或密码错误)
            elif authtype == sql:
                print(暂无sql库)
            else:
                print(错误的authtyoe)
        return wrapper
    return origin_auth

origin_auth = auth()
@origin_auth
def func():
    print(func)

func()

@origin_auth
def func2():
    print(func2)

func2()

 

# 编写装饰器,实现缓存网页内容的功能:
具体:实现下载的页面存放于文件中,如果文件内有值(文件大小不为0),就优先从文件中读取网页内容,否则,就去下载,然后存到文件中

import os, requests, hashlib
engine_conf = {
    file: {dirname: db},
    sql: {
        host: 127.0.0.1,
        port: 3306,
        user: root,
        password: 123},
    redis: {
        host: 127.0.0.1,
        port: 6379,
        user: root,
        password: 123}
}

db = db.txt

def make_cache(engine = file):
    if engine not in engine_conf:
        raise TypeError(engine +  not in engine_conf)
    user_status = {user: None, passwd: None}
    def deco(func):
        if user_status[user] == None or user_status[passwd] == None:
            user_info = eval(open(db, r).read())
            user_name = input(User: )
            user_passwd = input(Passwd: )
            if user_name != user_info[user] or hashlib.md5(user_passwd.encode(utf-8)).hexdigest() != user_info[passwd]:
                print(用户名或密码错误)
                exit()
            else:
                user_status[user] = user_name
                user_status[passwd] = user_passwd
        def wrapper(url):
            if engine == file:
                filename = hashlib.md5(url.encode(utf-8)).hexdigest()
                filepath = os.path.join(engine_conf[file][dirname], filename)
                if os.path.exists(filepath):
                    print(已爬取该网页)
                else:
                    content = func(url)
                    if content == None:
                        print(爬取内容为空)
                    else:
                        with open(filepath, w, encoding=utf-8) as f:
                            f.write(content)
            elif engine == sql:
                pass
            elif engine == redis:
                pass
        return wrapper
    return deco

@make_cache()
def get_html_text(url, *args, **kwargs):
    try:
        response = requests.get(url)
        response.encoding = response.apparent_encoding
        response.raise_for_status()
        return response.text
    except:
        return None


get_html_text(http://www.baidu.com)

 

 

 

python基础(3):函数对象、函数嵌套、名称空间与作用域、装饰器

标签:退出   any   rand   用户   dex   程序   python基础   type   round   

原文地址:https://www.cnblogs.com/zhangshuyuan/p/9571592.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!