美文网首页
python 高级编程

python 高级编程

作者: TENG书 | 来源:发表于2017-06-06 20:16 被阅读0次

    1.1==,is的使用

    ·is是比较两个引用是否指向了同一个对象(引用比较)。

    ·==是比较两个对象是否相等。

    1.2深拷贝、浅拷贝

    1.2.1浅拷贝

    浅拷贝是对于一个对象的顶层拷贝

    通俗的理解是:拷贝了引用,并没有拷贝内容

    1.2.2深拷贝

    copy.deepcopy

    1.2.3拷贝的其他方式

    浅拷贝对不可变类型和可变类型的copy不同

    In [88]: a = [11,22,33]

    In [89]: b = copy.copy(a)

    In [90]: id(a)

    Out[90]:59275144

    In [91]: id(b)

    Out[91]:59525600

    In [92]: a.append(44)

    In [93]: a

    Out[93]: [11,22,33,44]

    In [94]: b

    Out[94]: [11,22,33]

    In [95]:

    In [95]:

    In [95]: a = (11,22,33)

    In [96]: b = copy.copy(a)

    In [97]: id(a)

    Out[97]:58890680

    In [98]: id(b)

    Out[98]:58890680

    ·分片表达式可以赋值一个序列

    a ="abc"

    b = a[:]

    ·字典的copy方法可以拷贝一个字典

    d = dict(name="zhangsan", age=27)

    co = d.copy()

    ·有些内置函数可以生成拷贝(list)

    a = list(range(10))

    b = list(a)

    ·copy模块中的copy函数

    importcopy

    a = (1,2,3)

    b = copy.copy(a)

    1.3属性property

    面试题:

    1、你对面向对象的理解

    2、面向对象的特征是什么

    3、对封装的理解?

    封装,类本身就是一个封装,封装了属性和方法。方法也是封装,对一些业务逻辑的封装。私有也是封装,将一些方法和属性私有化,对外提供可访问的接口。

    4、对继承的理解

    将共性的内容放在父类中,子类只需要关注自己特有的内容,共性的继承过来就行了。

    这样简化开发,符合逻辑习惯,利于扩展。

    5、多态的理解

    多态,一个对象在不同的情况下显示不同的形态。在python中因为是弱类型语言,对类型没有限定,所有python中不完全支持多态,但是多态的思想呢,python也是能体现的。

    1.3.1私有属性添加getter和setter方法

    classMoney(object):

    def__init__(self):

    self.__money =0

    defgetMoney(self):

    returnself.__money

    defsetMoney(self, value):

    ifisinstance(value, int):

    self.__money = value

    else:

    print("error:不是整型数字")

    1.3.2使用property升级getter和setter方法

    classMoney(object):

    def__init__(self):

    self.__money =0

    defgetMoney(self):

    returnself.__money

    defsetMoney(self, value):

    ifisinstance(value, int):

    self.__money = value

    else:

    print("error:不是整型数字")

    money = property(getMoney, setMoney)

    运行结果:

    In [1]:fromget_setimportMoney

    In [2]:

    In [2]: a = Money()

    In [3]:

    In [3]: a.money

    Out[3]:0

    In [4]: a.money =100

    In [5]: a.money

    Out[5]:100

    In [6]: a.getMoney()

    Out[6]:100

    1.3.3使用property取代getter和setter方法

    @property成为属性函数,可以对属性赋值时做必要的检查,并保证代码的清晰短小,主要有2个作用

    ·将方法转换为只读

    ·重新实现一个属性的设置和读取方法,可做边界判定

    classMoney(object):

    def__init__(self):

    self.__money =0

    @property

    defmoney(self):

    returnself.__money

    @money.setter

    defmoney(self, value):

    ifisinstance(value, int):

    self.__money = value

    else:

    print("error:不是整型数字")

    运行结果

    In [3]: a = Money()

    In [4]:

    In [4]:

    In [4]: a.money

    Out[4]:0

    In [5]: a.money =100

    In [6]: a.money

    Out[6]:100

    1.4生成器

    1.4.1什么是生成器

    通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。

    1.4.2创建生成器方法1

    要创建一个生成器,有很多种方法。第一种方法很简单,只要把一个列表生成式的[ ]改成( )

    In [15]: L = [ x*2forxinrange(5)]

    In [16]: L

    Out[16]: [0,2,4,6,8]

    In [17]: G = ( x*2forxinrange(5))

    In [18]: G

    Out[18]: at0x7f626c132db0>

    In [19]:

    创建L和G的区别仅在于最外层的[ ]和( ),L是一个列表,而G是一个生成器。我们可以直接打印出L的每一个元素,但我们怎么打印出G的每一个元素呢?如果要一个一个打印出来,可以通过next()函数获得生成器的下一个返回值:

    In [19]: next(G)

    Out[19]: 0

    In [20]: next(G)

    Out[20]: 2

    In [21]: next(G)

    Out[21]: 4

    In [22]: next(G)

    Out[22]: 6

    In [23]: next(G)

    Out[23]: 8

    In [24]: next(G)

    ---------------------------------------------------------------------------

    StopIteration                             Traceback (most recent call last)

    in ()

    ----> 1 next(G)

    StopIteration:

    In [25]:

    In [26]: G = ( x*2forxinrange(5))

    In [27]:forxinG:

    ....:     print(x)

    ....:

    0

    2

    4

    6

    8

    In [28]:

    生成器保存的是算法,每次调用next(G),就计算出G的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的异常。当然,这种不断调用next()实在是太变态了,正确的方法是使用for循环,因为生成器也是可迭代对象。所以,我们创建了一个生成器后,基本上永远不会调用next(),而是通过for循环来迭代它,并且不需要关心StopIteration异常。

    1.4.3创建生成器方法2

    generator非常强大。如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现。

    比如,著名的斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到:

    1, 1, 2, 3, 5, 8, 13, 21, 34, ...

    斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易:

    In [28]:deffib(times):

    ....:     n =0

    ....:     a,b =0,1

    ....:whilen

    ....:         print(b)

    ....:         a,b = b,a+b

    ....:         n+=1

    ....:return'done'

    ....:

    In [29]: fib(5)

    1

    1

    2

    3

    5

    Out[29]:'done'

    仔细观察,可以看出,fib函数实际上是定义了斐波拉契数列的推算规则,可以从第一个元素开始,推算出后续任意的元素,这种逻辑其实非常类似generator。

    也就是说,上面的函数和generator仅一步之遥。要把fib函数变成generator,只需要把print(b)改为yield b就可以了:

    In [30]: def fib(times):

    ....:     n = 0

    ....:     a,b = 0,1

    ....:     while n

    ....:         yield b

    ....:         a,b = b,a+b

    ....:         n+=1

    ....:     return 'done'

    ....:

    In [31]: F = fib(5)

    In [32]: next(F)

    Out[32]: 1

    In [33]: next(F)

    Out[33]: 1

    In [34]: next(F)

    Out[34]: 2

    In [35]: next(F)

    Out[35]: 3

    In [36]: next(F)

    Out[36]: 5

    In [37]: next(F)

    ---------------------------------------------------------------------------

    StopIteration                             Traceback (most recent call last)

    in ()

    ----> 1 next(F)

    StopIteration: done

    在上面fib的例子,我们在循环过程中不断调用yield,就会不断中断。当然要给循环设置一个条件来退出循环,不然就会产生一个无限数列出来。同样的,把函数改成generator后,我们基本上从来不会用next()来获取下一个返回值,而是直接使用for循环来迭代:

    In [38]:forninfib(5):

    ....:     print(n)

    ....:

    1

    1

    2

    3

    5

    In [39]:

    但是用for循环调用generator时,发现拿不到generator的return语句的返回值。如果想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIteration的value中:

    In [39]: g = fib(5)

    In [40]:whileTrue:

    ....:try:

    ....:         x = next(g)

    ....:         print("value:%d"%x)

    ....:exceptStopIterationase:

    ....:         print("生成器返回值:%s"%e.value)

    ....:break

    ....:

    value:1

    value:1

    value:2

    value:3

    value:5

    生成器返回值:done

    In [41]:

    1.4.4send

    例子:执行到yield时,gen函数作用暂时保存,返回i的值;temp接收下次c.send("python"),send发送过来的值,c.next()等价c.send(None)

    In [10]:defgen():

    ....:     i =0

    ....:whilei<5:

    ....:         temp =yieldi

    ....:         print(temp)

    ....:         i+=1

    ....:

    使用next函数

    In [11]: f = gen()

    In [12]: next(f)

    Out[12]: 0

    In [13]: next(f)

    None

    Out[13]: 1

    In [14]: next(f)

    None

    Out[14]: 2

    In [15]: next(f)

    None

    Out[15]: 3

    In [16]: next(f)

    None

    Out[16]: 4

    In [17]: next(f)

    None

    ---------------------------------------------------------------------------

    StopIteration                             Traceback (most recent call last)

    in ()

    ----> 1 next(f)

    StopIteration:

    使用__next__()方法

    In [18]: f = gen()

    In [19]: f.__next__()

    Out[19]: 0

    In [20]: f.__next__()

    None

    Out[20]: 1

    In [21]: f.__next__()

    None

    Out[21]: 2

    In [22]: f.__next__()

    None

    Out[22]: 3

    In [23]: f.__next__()

    None

    Out[23]: 4

    In [24]: f.__next__()

    None

    ---------------------------------------------------------------------------

    StopIteration                             Traceback (most recent call last)

    in ()

    ----> 1 f.__next__()

    StopIteration:

    使用send

    In [43]: f = gen()

    In [44]: f.__next__()

    Out[44]:0

    In [45]: f.send('haha')

    haha

    Out[45]:1

    In [46]: f.__next__()

    None

    Out[46]:2

    In [47]: f.send('haha')

    haha

    Out[47]:3

    In [48]:

    1.4.5实现多任务

    模拟多任务实现方式之一:协程

    def test1():

    while True:

    print("--1--")

    yield None

    def test2():

    while True:

    print("--2--")

    yield None

    t1 = test1()

    t2 = test2()

    while True:

    t1.__next__()

    t2.__next__()

    总结

    生成器是这样一个函数,它记住上一次返回时在函数体中的位置。对生成器函数的第二次(或第n次)调用跳转至该函数中间,而上次调用的所有局部变量都保持不变。

    生成器不仅“记住”了它数据状态;生成器还“记住”了它在流控制构造(在命令式编程中,这种构造不只是数据值)中的位置。

    生成器的特点:

    1.节约内存

    2.迭代到下一次的调用时,所使用的参数都是第一次所保留下的,即是说,在整个所有函数调用的参数都是第一次所调用时保留的,而不是新创建的

    1.5迭代器

    迭代是访问集合元素的一种方式。迭代器是一个可以记住遍历的位置的对象。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。

    1.5.1可迭代对象

    以直接作用于for循环的数据类型有以下几种:

    一类是集合数据类型,如list、tuple、dict、set、str等;

    一类是generator,包括生成器和带yield的generator function。

    这些可以直接作用于for循环的对象统称为可迭代对象:Iterable。

    1.5.2判断是否可以迭代

    可以使用isinstance()判断一个对象是否是Iterable对象:

    In [50]:fromcollectionsimportIterable

    In [51]: isinstance([], Iterable)

    Out[51]:True

    In [52]: isinstance({}, Iterable)

    Out[52]:True

    In [53]: isinstance('abc', Iterable)

    Out[53]:True

    In [54]: isinstance((xforxinrange(10)), Iterable)

    Out[54]:True

    In [55]: isinstance(100, Iterable)

    Out[55]:False

    而生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了。

    1.5.3迭代器

    可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。

    可以使用isinstance()判断一个对象是否是Iterator对象:

    In [56]:fromcollectionsimportIterator

    In [57]: isinstance((xforxinrange(10)), Iterator)

    Out[57]:True

    In [58]: isinstance([], Iterator)

    Out[58]:False

    In [59]: isinstance({}, Iterator)

    Out[59]:False

    In [60]: isinstance('abc', Iterator)

    Out[60]:False

    In [61]: isinstance(100, Iterator)

    Out[61]:False

    1.5.4iter()函数

    生成器都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator。

    把list、dict、str等Iterable变成Iterator可以使用iter()函数:

    In [62]: isinstance(iter([]), Iterator)

    Out[62]:True

    In [63]: isinstance(iter('abc'), Iterator)

    Out[63]:True

    总结

    ·凡是可作用于for循环的对象都是Iterable类型;

    ·凡是可作用于next()函数的对象都是Iterator类型

    ·集合数据类型如list、dict、str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。

    ·目的是在使用集合的时候,减少占用的内存。

    1.6闭包

    1.61.1.1什么是闭包.1函数引用

    deftest1():

    print("--- in test1 func----")

    #调用函数

    test1()

    #引用函数

    ret = test1

    print(id(ret))

    print(id(test1))

    #通过引用调用函数

    ret()

    运行结果:

    ---intest1 func----

    140212571149040

    140212571149040

    ---intest1 func----

    1.6.2 什么是闭包

    定义一个函数

    deftest(number):

    #在函数内部再定义一个函数,并且这个函数用到了外边函数的变量,那么将这个函数以及用到的一些变量称之为闭包

    deftest_in(number_in):

    print("in test_in函数, number_in is %d"%number_in)

    returnnumber+number_in

    #其实这里返回的就是闭包的结果

    returntest_in

    #给test函数赋值,这个20就是给参数number

    ret = test(20)

    #注意这里的100其实给参数number_in

    print(ret(100))

    #注意这里的200其实给参数number_in

    print(ret(200))

    运行结果:

    intest_in函数, number_inis100

    120

    intest_in函数, number_inis200

    220

    1.6.3看一个闭包的实际例子:

    defline_conf(a, b):

    defline(x):

    returna*x + b

    returnline

    line1 = line_conf(1,1)

    line2 = line_conf(4,5)

    print(line1(5))

    print(line2(5))

    这个例子中,函数line与变量a,b构成闭包。在创建闭包的时候,我们通过line_conf的参数a,b说明了这两个变量的取值,这样,我们就确定了函数的最终形式(y = x + 1和y = 4x + 5)。我们只需要变换参数a,b,就可以获得不同的直线表达函数。由此,我们可以看到,闭包也具有提高代码可复用性的作用。

    如果没有闭包,我们需要每次创建直线函数的时候同时说明a,b,x。这样,我们就需要更多的参数传递,也减少了代码的可移植性。

    闭包思考:

    1.闭包似优化了变量,原来需要类对象完成的工作,闭包也可以完成

    2.由于闭包引用了外部函数的局部变量,则外部函数的局部变量没有及时释放,消耗内存

    1.7.装饰器

    装饰器是程序开发中经常会用到的一个功能,用好了装饰器,开发效率如虎添翼,所以这也是Python面试中必问的问题,但对于好多初次接触这个知识的人来讲,这个功能有点绕,自学时直接绕过去了,然后面试问到了就挂了,因为装饰器是程序开发的基础知识,这个都不会,别跟人家说你会Python,看了下面的文章,保证你学会装饰器。

    1.7.1装饰器理解

    1、先明白这段代码

    ####第一波####

    deffoo():

    print('foo')

    foo#表示是函数

    foo()#表示执行foo函数

    ####第二波####

    deffoo():

    print('foo')

    foo =lambdax: x +1

    foo()#执行下面的lambda表达式,而不再是原来的foo函数,因为foo这个名字被重新指向了另外一个匿名函数

    2、需求来了

    初创公司有N个业务部门,1个基础平台部门,基础平台负责提供底层的功能,如:数据库操作、redis调用、监控API等功能。业务部门使用基础功能时,只需调用基础平台提供的功能即可。如下:

    ###############基础平台提供的功能如下###############

    deff1():

    print('f1')

    deff2():

    print('f2')

    deff3():

    print('f3')

    deff4():

    print('f4')

    ###############业务部门A调用基础平台提供的功能###############

    f1()

    f2()

    f3()

    f4()

    ###############业务部门B调用基础平台提供的功能###############

    f1()

    f2()

    f3()

    f4()

    目前公司有条不紊的进行着,但是,以前基础平台的开发人员在写代码时候没有关注验证相关的问题,即:基础平台的提供的功能可以被任何人使用。现在需要对基础平台的所有功能进行重构,为平台提供的所有功能添加验证机制,即:执行功能前,先进行验证。

    老大把工作交给Low B,他是这么做的:

    跟每个业务部门交涉,每个业务部门自己写代码,调用基础平台的功能之前先验证。诶,这样一来基础平台就不需要做任何修改了。太棒了,有充足的时间泡妹子...

    当天Low B被开除了…

    老大把工作交给Low BB,他是这么做的:

    ###############基础平台提供的功能如下###############

    deff1():

    #验证1

    #验证2

    #验证3

    print('f1')

    deff2():

    #验证1

    #验证2

    #验证3

    print('f2')

    deff3():

    #验证1

    #验证2

    #验证3

    print('f3')

    deff4():

    #验证1

    #验证2

    #验证3

    print('f4')

    ###############业务部门不变###############

    ###业务部门A调用基础平台提供的功能###

    f1()

    f2()

    f3()

    f4()

    ###业务部门B调用基础平台提供的功能###

    f1()

    f2()

    f3()

    f4()

    过了一周Low BB被开除了…

    老大把工作交给Low BBB,他是这么做的:

    只对基础平台的代码进行重构,其他业务部门无需做任何修改

    ###############基础平台提供的功能如下###############

    defcheck_login():

    #验证1

    #验证2

    #验证3

    pass

    deff1():

    check_login()

    print('f1')

    deff2():

    check_login()

    print('f2')

    deff3():

    check_login()

    print('f3')

    deff4():

    check_login()

    print('f4')

    老大看了下Low BBB的实现,嘴角漏出了一丝的欣慰的笑,语重心长的跟Low BBB聊了个天:

    老大说:

    写代码要遵循开放封闭原则,虽然在这个原则是用的面向对象开发,但是也适用于函数式编程,简单来说,它规定已经实现的功能代码不允许被修改,但可以被扩展,即:

    ·封闭:已实现的功能代码块

    ·开放:对扩展开发

    如果将开放封闭原则应用在上述需求中,那么就不允许在函数f1、f2、f3、f4的内部进行修改代码,老板就给了Low BBB一个实现方案:

    defw1(func):

    definner():

    #验证1

    #验证2

    #验证3

    func()

    returninner

    @w1

    deff1():

    print('f1')

    @w1

    deff2():

    print('f2')

    @w1

    deff3():

    print('f3')

    @w1

    deff4():

    print('f4')

    对于上述代码,也是仅仅对基础平台的代码进行修改,就可以实现在其他人调用函数f1 f2 f3 f4之前都进行【验证】操作,并且其他业务部门无需做任何操作。

    Low BBB心惊胆战的问了下,这段代码的内部执行原理是什么呢?

    老大正要生气,突然Low BBB的手机掉到地上,恰巧屏保就是Low BBB的女友照片,老大一看一紧一抖,喜笑颜开,决定和Low BBB交个好朋友。

    详细的开始讲解了:

    单独以f1为例:

    defw1(func):

    definner():

    #验证1

    #验证2

    #验证3

    func()

    returninner

    @w1

    deff1():

    print('f1')

    python解释器就会从上到下解释代码,步骤如下:

    1.def w1(func): ==>将w1函数加载到内存

    2.@w1

    没错,从表面上看解释器仅仅会解释这两句代码,因为函数在没有被调用之前其内部代码不会被执行。

    从表面上看解释器着实会执行这两句,但是@w1这一句代码里却有大文章,@函数名 是python的一种语法糖。

    上例@w1内部会执行一下操作:

    执行w1函数

    执行w1函数 ,并将@w1下面的函数作为w1函数的参数,即:@w1等价于w1(f1)所以,内部就会去执行:

    definner():

    #验证1

    #验证2

    #验证3

    f1()# func是参数,此时func等于f1

    returninner#返回的inner,inner代表的是函数,非执行函数,其实就是将原来的f1函数塞进另外一个函数中

    w1的返回值

    将执行完的w1函数返回值 赋值 给@w1下面的函数的函数名f1即将w1的返回值再重新赋值给f1,即:

    新f1 =definner():

    #验证1

    #验证2

    #验证3

    原来f1()

    returninner

    所以,以后业务部门想要执行f1函数时,就会执行 新f1函数,在新f1函数内部先执行验证,再执行原来的f1函数,然后将原来f1函数的返回值返回给了业务调用者。

    如此一来,即执行了验证的功能,又执行了原来f1函数的内容,并将原f1函数返回值 返回给业务调用着

    Low BBB你明白了吗?要是没明白的话,我晚上去你家帮你解决吧!!!

    1.1.2多个装饰器

    #定义函数:完成包裹数据

    defmakeBold(fn):

    defwrapped():

    return""+ fn() +""

    returnwrapped

    #定义函数:完成包裹数据

    defmakeItalic(fn):

    defwrapped():

    return""+ fn() +""

    returnwrapped

    @makeBold

    deftest1():

    return"hello world-1"

    @makeItalic

    deftest2():

    return"hello world-2"

    @makeBold

    @makeItalic

    deftest3():

    return"hello world-3"

    print(test1()))

    print(test2()))

    print(test3()))

    运行结果:

    hello world-1

    hello world-2

    hello world-3

    1.7.3装饰器(decorator)功能

    1.引入日志

    2.函数执行时间统计

    3.执行函数前预备处理

    4.执行函数后清理功能

    5.权限校验等场景

    6.缓存

    1.7.4装饰器示例

    1.7.4.1例1:无参数的函数

    fromtimeimportctime, sleep

    deftimefun(func):

    defwrappedfunc():

    print("%s called at %s"%(func.__name__, ctime()))

    func()

    returnwrappedfunc

    @timefun

    deffoo():

    print("I am foo")

    foo()

    sleep(2)

    foo()

    上面代码理解装饰器执行行为可理解成

    foo = timefun(foo)

    #foo先作为参数赋值给func后,foo接收指向timefun返回的wrappedfunc

    foo()

    #调用foo(),即等价调用wrappedfunc()

    #内部函数wrappedfunc被引用,所以外部函数的func变量(自由变量)并没有释放

    #func里保存的是原foo函数对象

    1.7.2例2:被装饰的函数有参数

    fromtimeimportctime, sleep

    deftimefun(func):

    defwrappedfunc(a, b):

    print("%s called at %s"%(func.__name__, ctime()))

    print(a, b)

    func(a, b)

    returnwrappedfunc

    @timefun

    deffoo(a, b):

    print(a+b)

    foo(3,5)

    sleep(2)

    foo(2,4)

    1.7.3例3:被装饰的函数有不定长参数

    fromtimeimportctime, sleep

    deftimefun(func):

    defwrappedfunc(*args, **kwargs):

    print("%s called at %s"%(func.__name__, ctime()))

    func(*args, **kwargs)

    returnwrappedfunc

    @timefun

    deffoo(a, b, c):

    print(a+b+c)

    foo(3,5,7)

    sleep(2)

    foo(2,4,9)

    1.7.4例4:装饰器中的return

    fromtimeimportctime, sleep

    deftimefun(func):

    defwrappedfunc():

    print("%s called at %s"%(func.__name__, ctime()))

    func()

    returnwrappedfunc

    @timefun

    deffoo():

    print("I am foo")

    @timefun

    defgetInfo():

    return'----hahah---'

    foo()

    sleep(2)

    foo()

    print(getInfo())

    执行结果:

    foo called at Fri Nov421:55:352016

    I am foo

    foo called at Fri Nov421:55:372016

    I am foo

    getInfo called at Fri Nov421:55:372016

    None

    如果修改装饰器为return func(),则运行结果:

    foo called at Fri Nov421:55:572016

    I am foo

    foo called at Fri Nov421:55:592016

    I am foo

    getInfo called at Fri Nov421:55:592016

    ----hahah---

    总结:

    ·一般情况下为了让装饰器更通用,可以有return

    1.7.5例5:装饰器带参数,在原有装饰器的基础上,设置外部变量

    #decorator2.py

    fromtimeimportctime, sleep

    deftimefun_arg(pre="hello"):

    deftimefun(func):

    defwrappedfunc():

    print("%s called at %s %s"%(func.__name__, ctime(), pre))

    returnfunc()

    returnwrappedfunc

    returntimefun

    @timefun_arg("wangcai")

    deffoo():

    print("I am foo")

    @timefun_arg("python")

    deftoo():

    print("I am too")

    foo()

    sleep(2)

    foo()

    too()

    sleep(2)

    too()

    可以理解为

    foo()==timefun_arg("wangcai")(foo)()

    1.2python是动态语言

    1.2.1动态语言的定义

    动态编程语言是高级程序设计语言的一个类别,在计算机科学领域已被广泛应用。它是一类在运行时可以改变其结构的语言:例如新的函数、对象、甚至代码可以被引进,已有的函数可以被删除或是其他结构上的变化。动态语言目前非常具有活力。例如JavaScript便是一个动态语言,除此之外如PHP、Ruby、Python等也都属于动态语言,而C、C++等语言则不属于动态语言。----来自 维基百科

    1.2.2运行的过程中给对象绑定(添加)属性

    >>>classPerson(object):

    def__init__(self, name = None, age = None):

    self.name = name

    self.age = age

    >>>P = Person("小明","24")

    >>>

    在这里,我们定义了1个类Person,在这个类里,定义了两个初始属性name和age,但是人还有性别啊!如果这个类不是你写的是不是你会尝试访问性别这个属性呢?

    >>>P.sex ="male"

    >>>P.sex

    'male'

    >>>

    这时候就发现问题了,我们定义的类里面没有sex这个属性啊!怎么回事呢? 这就是动态语言的魅力和坑! 这里 实际上就是 动态给实例绑定属性!

    1.2.3运行的过程中给类绑定(添加)属性

    >>>P1 = Person("小丽","25")

    >>>P1.sex

    Traceback (most recent call last):

    File"", line1,in

    P1.sex

    AttributeError: Person instance has no attribute'sex'

    >>>

    我们尝试打印P1.sex,发现报错,P1没有sex这个属性!----给P这个实例绑定属性对P1这个实例不起作用! 那我们要给所有的Person的实例加上sex属性怎么办呢? 答案就是直接给Person绑定属性!

    >>>> Person.sex =None#给类Person添加一个属性

    >>>P1 = Person("小丽","25")

    >>>print(P1.sex)#如果P1这个实例对象中没有sex属性的话,那么就会访问它的类属性

    None#可以看到没有出现异常

    >>>

    1.2.4运行的过程中给类绑定(添加)方法

    我们直接给Person绑定sex这个属性,重新实例化P1后,P1就有sex这个属性了! 那么function呢?怎么绑定?

    >>>classPerson(object):

    def__init__(self, name = None, age = None):

    self.name = name

    self.age = age

    defeat(self):

    print("eat food")

    >>>defrun(self, speed):

    print("%s在移动,速度是%d km/h"%(self.name, speed))

    >>>P = Person("老王",24)

    >>>P.eat()

    eat food

    >>>

    >>>P.run()

    Traceback (most recent call last):

    File"", line1,in

    P.run()

    AttributeError: Person instance has no attribute'run'

    >>>

    >>>

    >>>importtypes

    >>>P.run = types.MethodType(run, P)

    >>>P.run(180)

    老王在移动,速度是180km/h

    既然给类添加方法,是使用类名.方法名= xxxx,那么给对象添加一个方法也是类似的对象.方法名= xxxx

    完整的代码如下:

    importtypes

    #定义了一个类

    classPerson(object):

    num =0

    def__init__(self, name = None, age = None):

    self.name = name

    self.age = age

    defeat(self):

    print("eat food")

    #定义一个实例方法

    defrun(self, speed):

    print("%s在移动,速度是%d km/h"%(self.name, speed))

    #定义一个类方法

    @classmethod

    deftestClass(cls):

    cls.num =100

    #定义一个静态方法

    @staticmethod

    deftestStatic():

    print("---static method----")

    #创建一个实例对象

    P = Person("老王",24)

    #调用在class中的方法

    P.eat()

    #给这个对象添加实例方法

    P.run = types.MethodType(run, P)

    #调用实例方法

    P.run(180)

    #给Person类绑定类方法

    Person.testClass = testClass

    #调用类方法

    print(Person.num)

    Person.testClass()

    print(Person.num)

    #给Person类绑定静态方法

    Person.testStatic = testStatic

    #调用静态方法

    Person.testStatic()

    1.2.5运行的过程中删除属性、方法

    删除的方法:

    1.del对象.属性名

    2.delattr(对象, "属性名")

    通过以上例子可以得出一个结论:相对于动态语言,静态语言具有严谨性!所以,玩动态语言的时候,小心动态的坑!

    那么怎么避免这种情况呢?请使用__slots__,

    1.2.6__slots__

    现在我们终于明白了,动态语言与静态语言的不同

    动态语言:可以在运行的过程中,修改代码

    静态语言:编译时已经确定好代码,运行过程中不能修改

    如果我们想要限制实例的属性怎么办?比如,只允许对Person实例添加name和age属性。

    为了达到限制的目的,Python允许在定义class的时候,定义一个特殊的__slots__变量,来限制该class实例能添加的属性:

    >>>classPerson(object):

    __slots__ = ("name","age")

    >>>P = Person()

    >>>P.name ="老王"

    >>>P.age =20

    >>>P.score =100

    Traceback (most recent call last):

    File"", line1,in

    AttributeError: Person instance has no attribute'score'

    >>>

    1.2.6.1注意:

    ·使用__slots__要注意,__slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的

    In [67]:classTest(Person):

    ...:pass

    ...:

    In [68]: t = Test()

    In [69]: t.score =100

    相关文章

      网友评论

          本文标题:python 高级编程

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