美文网首页
python (类与装饰器)的简明案例

python (类与装饰器)的简明案例

作者: 今天Martin学习了吗 | 来源:发表于2020-05-17 14:50 被阅读0次

    类的定义以及类的基础

    在写你的第一个类之前,你应该知道它的语法。我们以下面这种方式定义类:

    class nameoftheclass(parent_class):
        statement1
        statement2
        statement3
    
    类的继承

    当一个类继承另一个类时,它将继承父类的所有功能(如变量和方法)。这有助于重用代码。

    在下一个例子中我们首先创建一个叫做 Person 的类,然后创建两个派生类 StudentTeacher。当两个类都从 Person 类继承时,它们的类除了会有 Person 类的所有方法还会有自身用途的新方法和新变量。

    #!/usr/bin/env python3
    
    class Person(object):
        """
        返回具有给定名称的 Person 对象
        """
    
        def __init__(self, name):
            self.name = name
    
        def get_details(self):
            """
            返回包含人名的字符串
            """
            return self.name
    
    
    class Student(Person):
        """
        返回 Student 对象,采用 name, branch, year 3 个参数
        """
    
        def __init__(self, name, branch, year):
            Person.__init__(self, name)
            self.branch = branch
            self.year = year
    
        def get_details(self):
            """
            返回包含学生具体信息的字符串
            """
            return "{} studies {} and is in {} year.".format(self.name, self.branch, self.year)
    
    
    class Teacher(Person):
        """
        返回 Teacher 对象,采用字符串列表作为参数
        """
        def __init__(self, name, papers):
            Person.__init__(self, name)
            self.papers = papers
    
        def get_details(self):
            return "{} teaches {}".format(self.name, ','.join(self.papers))
    
    
    person1 = Person('Sachin')
    student1 = Student('Kushal', 'CSE', 2005)
    teacher1 = Teacher('Prashad', ['C', 'C++'])
    
    print(person1.get_details())
    print(student1.get_details())
    print(teacher1.get_details())
    

    在这个脚本中我们可以看到Student类和Teacher类对于父类Person__init__()方法的调用;还有对父类get_details()方法的重写

    当我们调用 student1teacher1get_details() 方法时,使用的是各自类(StudentTeacher)中定义的方法。

    多继承

    一个类可以继承自多个类,具有父类的所有变量和方法,语法如下:

    class MyClass(Parentclass1, Parentclass2,...):
        def __init__(self):
            Parentclass1.__init__(self)
            Parentclass2.__init__(self)
            ...
            ...
    
    删除对象

    在python中可以使用 del关键字删除对象

    >>> s = "I love you"
    >>> del s
    >>> s
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    NameError: name 's' is not defined           # 调用 对象 s 的时候发现对象 s 已经被删除了
    
    属性的读取方法

    与Java不同,python 在读取属性的时候不需要使用 getterssetters、python 的属性是可以直接调用和修改的

    >>> class Student(object):
    ...     def __init__(self,name):
    ...         self.name = name
    ...
    >>> std = Student("Kushal Das")
    >>> print(std.name)             # 可以通过 . 调取属性
    Kushal Das
    >>> std.name = "python"
    >>> print(std.name)
    python
    

    补充:python 装饰器

    简言之,python装饰器就是用于拓展原来函数功能的一种函数,这个函数的特殊之处在于它的返回值也是一个函数,也就是说 装饰器的运行效果是包裹函数,使用python装饰器的好处就是在不用更改原函数的代码前提下给函数增加新的功能。

    比如在记录一个函数执行的时间我们就可以这么做

    import time
    def func():
        startTime = time.time()
        # 原函数核心代码---开始
        print("hello")
        time.sleep(1)
        print("world")
        # 原函数核心代码---结束
        endTime = time.time()
        # 记录起始时间和结束时间,计算时间差|其中 time.time() 返回当前时间戳(单位ms)
        msecs = (endTime - startTime) * 1000
        print('time is %d ms'%msecs)     # 输出函数执行的时间
    func()
    

    在不更改原函数的情况下我们可以直接定义一个计时器函数,并在新定义的函数中调用原函数

    #避免直接侵入原函数修改,但是生效需要再次执行函数
    import time
    
    def deco(func):     # 自定义计时器函数
        startTime = time.time()
        func()
        endTime = time.time()
        msecs = (endTime - startTime)*1000
        print("time is %d ms" %msecs)
    
    
    def func():
        print("hello")
        time.sleep(1)
        print("world")
    
    if __name__ == '__main__':
        f = func
        deco(f)     # 只有把func()或者f()作为参数执行,新加入功能才会生效
        print("f.__name__ is",f.__name__)      # f的name就是func
    '''
    在使用 __name__ 的时候加入当前模块是系统模块,那么此时的模块名称就是__main__;通过 if 可以判断 __main__后面主函数的内容,假如是导入的模块,则这个模块名字就是导入文件的名字(不加后面的py)
    1. 如果模块是被导入,__name__的值为模块名字
    2. 如果模块是被直接执行,__name__的值为’__main__’
    '''
    

    利用装饰器可以更快的将主函数包裹在对应的函数内部执行(这样就不用每次在自定义的计时器函数中调用主函数了;这个计时器函数一旦被装饰器调用,可以适用于任何函数)

    import time
    
    def deco(func):
        def wapper():
            startTime = time.time()
            func()       # 调用主函数|包裹主函数的代码是为了统计主函数的执行时间
            endTime = time.time()
            msecs = (endTime - startTime) * 1000
            print("time is %d ms"%msecs)
        return wapper()
    
    # 在主函数上引用装饰器在调用主函数时会先调用装饰器函数(这个案例是在装饰器函数执行过程中执行主函数)
    @deco
    def func():
        print("hello")
        time.sleep(1)
        print("world")
    
    
    if __name__ == '__main__':
        f = func
        f       # 这里的 func 被实例化为 f 执行 f 就是执行 func
    

    这里的 deco 就相当于一个装饰器,它的参数是一个函数,然后也返回一个函数,其中作为装饰器函数参数的函数也就是被统计上执行时间的主函数func在装饰器函数的wrapper内执行(相当于函数被注入了计时器功能),仙子啊只要调用func,他就已经是功能更多的函数了

    装饰器就相当于是一个给函数诸如功能的符号,拓展原来的函数功能ing且不需要侵入函数内(修改主函数代码)也不需要重复执行函数

    案例:带有不定参数的装饰器

    #多个装饰器
    
    import time
    
    def deco01(func):     # 装饰器的参数要是函数
        def wrapper(*args, **kwargs):  
            print("this is deco01")
            startTime = time.time()
            func(*args, **kwargs)
            endTime = time.time()
            msecs = (endTime - startTime)*1000
            print("time is %d ms" %msecs)
            print("deco01 end here")
        return wrapper
    
    def deco02(func):
        def wrapper(*args, **kwargs):  # 函数可以带有不定参数
            print("this is deco02")
            func(*args, **kwargs)
    
            print("deco02 end here")
        return wrapper
    
    @deco01
    @deco02
    def func(a,b):
        print("hello,here is a func for add :")
        time.sleep(1)
        print("result is %d" %(a+b))
    
    
    
    if __name__ == '__main__':
        f = func
        f(3,4)
        
    
    

    从这个函数的执行结果可以看出:

    this is deco01
    this is deco02
    hello,here is a func for add :
    result is 7
    deco02 end here
    time is 1000 ms
    deco01 end here
    

    当函数使用多个装饰器的时候,正确的调用顺序时从最后一个装饰器开始,到第一个装饰器,直到函数本身执行完毕;

    import time
    
    
    def dec1(func):
        print("1111")
        def one():
            print("2222")
            func()
            print("3333")
        return one
    
    
    def dec2(func):
        print("aaaa")
        def two():
            print("bbbb")
            func()
            print("cccc")
        return two
    
    @dec1
    @dec2
    def demo():
        print("test  test")
    
    demo()
    # 函数的执行结果是:
    aaaa
    1111
    2222
    bbbb
    test  test
    cccc
    3333
    # 先执行 dec2的内容,再执行dec1的内容 最后执行 demo函数本身
    

    使用装饰器和类的思想写一个将美元转换成人民币的案例

    #!/usr/bin/env python3
    
    class Account(object):
        """
        __amt: 当前用户账户中的美元存量
        rate:美元与人民币兑换比率
        """
        def __init__(self,rate):
            self.__amt = 0
            self.rate = rate
    
        @property
        def amount(self):
            '''  这个方法返回当前用户的美元存量 通过这个方法修改这一条属性 '''
            return self.__amt
    
        @property
        def cny(self):
            """ 计算美元兑换成人民币的比率,通过这个方法计算出结果并返回给 cny """
            return self.__amt * self.rate
    
        @amount.setter
        def amount(self,value):
            if value < 0:
                print("Sorry , no negative amount in your account")
                return     #
            self.__amt = value
    
    if __name__ == '__main__':
        acc = Account(rate=6.6)
        acc.amount = 20
        print("Dollar Amount:",acc.amount)
        print("In CNY:",acc.cny)
        acc.amount = -100
        print("Dollar Amount:",acc.amount)
    
    

    案例中引用了 python自带的装饰器,装饰器的用法下期 会说(python 常见的装饰器)

    遇见的 BUG 和解决的方法

    在编程的过程中出现了以下 bug :

    ModuleNotFoundError: No module named 'pytest'

    解决的方法:不要使用test作为函数名称;否则python解释器会出现找不到 pytest 模块的错误

    TypeError: ‘NoneType’ object is not callable

    解决方法:在调用函数的时候(或者调用函数实例化的对象时)不要加()

    相关文章

      网友评论

          本文标题:python (类与装饰器)的简明案例

          本文链接:https://www.haomeiwen.com/subject/qehsohtx.html