• python高级编程——入门语法(二)


    闭包

      概念:外函数outer定义一个变量a,又定义一个内函数inner,而这个内函数inner访问了外函数outer的变量a,如果需要改变外函数outer的变量a的值,则需要声明 nonlocal a,之后才可以修改。由于外函数outer执行完,返回的值是内函数inner的函数变量名,在一般情况下,外函数里面的变量a就会被释放掉,而这种情况,内函数inner还是可以直接使用,即延长了变量名a的作用域(或者叫声明周期),我们成这个函数叫闭包函数,简称闭包

    # 求任意直线的x对应y的值
    def lines(a, b):
        def get_y(x):
            # 使用了外函数的变量b
            nonlocal b
            b = b+1
            return a*x+b
        return get_y
    
    # 先确定一条直线
    y = lines(2,3)
    print(y(1))

    装饰器

      概念:就是给原有的代码增加一点新的功能,在了解完装饰器之后,你会发现装饰器是引用了闭包函数的知识,装饰器的三大要求(原则):

        1、不能修改被装饰的函数的源代码

        2、不能修改被装饰的函数的调用方式

        3、满足1、2的情况下给程序增添新的功能

      装饰器一步一步过程:

        1、假设源代码有两个函数:

    # 函数1:求和
    def func_test01(a, b):
        print("func_test01 is running")
        return a + b
    
    
    # 函数2:简单运算
    def func_test02(a, b, c, d):
        print("func_test02 is running")
        return (a+b)*c//d
    
    print(func_test01(2, 4))     #func_test01 is running      6
    print(func_test02(2, 3, 7, 4))    # func_test02 is running      8

        2、现在需要给这两个函数增加一样的新功能:先睡眠2秒,在执行函数,并打印耗时。但是这两个函数的形参变量不一样,我们可以借助可变参数来实现

    import time
    # 函数1:求和
    def func_test01(a, b):
        print("func_test01 is running")
        return a + b
    
    
    # 函数2:简单运算
    def func_test02(a, b, c, d):
        print("func_test02 is running")
        return (a+b)*c//d
    
    # 定义一个新函数,传参为需要新增功能的函数名称,在闭包函数实现主要添加的新功能
    def wrapper_inner(func):
        def wrapper(*args, **kwargs):
            start_time = time.time()
            time.sleep(2)
            res = func(*args, **kwargs)
            end_time = time.time()
            print("耗时:", end_time-start_time)
            return res
        return wrapper
    func_test01 = wrapper_inner(func_test01)
    func_test02 = wrapper_inner(func_test02)
    
    
    # 原函数未改变,两者的调用方式也没有改变
    print(func_test01(2, 4))
    print(func_test02(2, 3, 7, 4))

        3、上面已经差不多实现了装饰器了,但是上述代码是添加了新的调用方式,以至于原有的调用方式没有改变,为此我们可以简化上述代码,将新的调用方式删除,在原有的函数上方添加@wrapper_inner即可,这样下来装饰器函数基本上已经完整了。

          @wrapper_inner 等价于 func_test01 = wrapper_inner(func_test01)

          @wrapper_inner 等价于 func_test01 = wrapper_inner(func_test01)

          @wrapper_inner默认是将被装饰的函数名称传递给装饰函数的形参func变量

    import time
    # 函数1:求和
    @wrapper_inner
    def func_test01(a, b):
        print("func_test01 is running")
        return a+b
    
    # 函数2: 简单运算
    @wrapper_inner
    def func_test02(a, b, c, d):
        print("func_test02 is running")
        return (a+b)*c//d
    
    # 定义一个新函数,传参为需要新增功能的函数名称,在闭包函数实现主要添加的新功能
    def wrapper_inner(func):
        def wrapper(*args, **kwargs):
            start_time = time.time()
            time.sleep(2)
            res = func(*args, **kwargs)
            end_time = time.time()
            print("耗时:", end_time-start_time)
            return res
        return wrapper
    
    
    
    # 原函数未改变,两者的调用方式也没有改变
    print(func_test01(2, 4))
    print(func_test02(2, 3, 7, 4))

        4、补添一个新的功能,给装饰器函数传递一个参数,在这里博主只是给函数做一个标记,验证是哪个被装饰函数执行

    import time
    
    # 函数1:求和
    @wrapper_outer(parameter="func_test01")
    def func_test01(a, b):
        print("这是个求和函数,返回值是两者之和")
        return a + b
    
    
    # 函数2:简单运算
    @wrapper_outer(parameter="func_test02")
    def func_test02(a, b, c, d):
        print("这是个简单运算函数,返回值是运算之后的整数值")
        return (a+b)*c//d
    
    
    # 装饰器函数传递被装饰函数的名称,作为标记,并打印
    def wrapper_outer(parameter):
        # 定义一个新函数,传参为需要新增功能的函数名称,在闭包函数实现主要添加的新功能
        def wrapper_inner(func):
            def wrapper(*args, **kwargs):
                # 分开执行,可以任意增添被装饰函数的的功能
                # 这样做是可以让被装饰函数新增不一样的功能
                if parameter == "func_test01":
                    start_time = time.time()
                    time.sleep(2)
                    res = func(*args, **kwargs)
                    end_time = time.time()
                    print("被装饰的函数", parameter,"	耗时:", end_time-start_time)
                    return res
                elif parameter == "func_test02":
                    start_time = time.time()
                    time.sleep(1)
                    res = func(*args, **kwargs)
                    time.sleep(1)
                    end_time = time.time()
                    print("被装饰的函数", parameter,"	耗时:", end_time-start_time)
                    return res
            return wrapper
        return wrapper_inner
    
    
    
    
    
    # 原函数未改变,两者的调用方式也没有改变
    print(func_test01(2, 4))
    print(func_test02(2, 3, 7, 4))

    私有化

      在python中也有类似于Java中私有变量和保护变量,虽然python中没有这种概念,但是作用还是和Java一样(可能说错了,没学过多少Java)。

        在python中"私有变量"的声明双下划线__xxx,这个变量在类作用域外,什么对象都不能访问,在类作用域内可以访问和修改。如果在类外访问或者修改,则需要在类内另外定义方法

        "保护变量"的声明是单下滑线_xxx,这个变量只能在当前模块访问和修改,但是可以导入到另外一个模块使用,导入的方式:import xxx(模块名)

        "魔法方法"的声明是以双下划线开头和结尾的__xxx__,这是python提供的特殊方法,有些时候我们可以自定义原有的"魔法方法"

    class People(object):
        def __init__(self, name, gender, age):
            self.name = name
            self._gender = gender
            self.__age = age
        def get_age(self):
            return self.__age
        def set_age(self, age):
            self.__age = age
        def show(self):
            print("名字:", self.name, "	性别:", self._gender, "	年龄", self.__age)
        
    
    if __name__ == "__main__":
        people = People("aaa", "female", 22)
        people._gender = "male"
        print(people._gender)   # male
        people.set_age(25)     # 年龄转换25
        print(people.get_age())  # 25
        # 查看结果
        people.show()
        # 类外不能访问私有变量
        # print(people.__age)    # error
        # print(People.__age)    # error

    property

      上述代码中的”私有变量“只能靠调用方法进行访问和修改,为了让私有变量的访问和修改的方式和普通的对象的属性一样,property就起到了重要的作用。property有两种方式处理私有变量

      1、先在类内定义两个方法,然后用property(访问变量的方法,设置变量的方法),顺序不能颠倒,将其赋值给一个变量名,这个变量是在类外进行访问和修改的

    class People(object):
        def __init__(self, name, gender, age):
            self.name = name
            self._gender = gender
            self.__age = age
        # 先定义好私有变量的访问和设置方法    
        def get_age(self):
            return self.__age
        def set_age(self, age):
            self.__age = age
        # 变量名就是类外访问的变量名,通过下面方式进行设置即可
        age = property(get_age, set_age)
        def show(self):
            print("名字:", self.name, "	性别:", self._gender, "	年龄", self.__age)
        
    
    if __name__ == "__main__":
        people = People("aaa", "female", 22)
        people._gender = "male"
        print(people._gender)   # male
        people.age = 25     # 年龄转换25
        print(people.age)  # 25
        # 查看结果
        people.show()

      2、使用装饰器简化: @property、@x.setter、@x.deleter(这个一般用不到,这里不做介绍),这里很关键,x(变量名)和被装饰的方法名一定要相同,这个变量名是可以在类外进行访问和修改的

    class People(object):
        def __init__(self, name, gender, age):
            self.name = name
            self._gender = gender
            self.__age = age
        # @property 装饰的是返回私有变量的值  
        @property
        def age(self):
            return self.__age
        # 变量名.setter,这个变量名是类外进行访问和修改的
        @age.setter
        def age(self, age):
            self.__age = age
    
        def show(self):
            print("名字:", self.name, "	性别:", self._gender, "	年龄", self.__age)
        
    
    if __name__ == "__main__":
        people = People("aaa", "female", 22)
        people._gender = "male"
        print(people._gender)   # male
        people.age = 25     # 年龄转换25
        print(people.age)  # 25
        # 查看结果
        people.show()

    reload

      概念:重新加载模块:即原先导入的模块没有改变,但是在之后,导入的模块改变了,那么就要重新载入

    # 假设自己写的模块mymodel
    import mymodel
    
    # 之后mymodel代码程序或者功能改变了,在运行的过程中需要重新导入
    mymodel.reload
  • 相关阅读:
    Maven3路程(五)用Maven创建Hibernate项目
    Eclipse中通过Hibernate Tools插件实现从数据库逆向生成Hibernate带注解的实体类
    Maven3路程(三)用Maven创建第一个web项目(1)
    jquery下载所有版本(实时更新)
    Oracle读取Blob数据-通过hibernate
    使用以下代码可以插入BLOB类型的图片或pdf文档到Oracle数据库中:
    Intellij IDEA系列 --GIT的初步使用
    java.lang.OutOfMemoryError GC overhead limit exceeded原因分析及解决方案
    idea如何安装使用jetty runner
    IntelliJ IDEA下SVN的配置及使用说明
  • 原文地址:https://www.cnblogs.com/aitiknowledge/p/11453548.html
Copyright © 2020-2023  润新知