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

类的定义以及类的基础

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

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

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335