VII Python(4)基础知识(函数、yield、decorator、类与面向对象)

 

python函数:

函数是为了代码最大程度的重用和最小化代码冗余而提供的基本程序结构;

函数是一种设计工具,它能让程序员将复杂的系统分解为可管理的部件;

函数用于将相关功能打包并参数化;

python提供很多内置函数,在python中可创建四种函数:全局函数(直接定义在模块中);局部函数(嵌套于其它函数中);lambda匿名函数(表达式,灵活性强);方法(定义在类中的函数,与特定的数据类型关联的函数,并且只能与数据类型关联一起使用);

 

语法:

def functionName(parameters):

         suite

注:

def是一个可执行语句,因此可出现在任何能够使用语句的地方,甚至可嵌套于其它语句;

def创建了一个对象并将其赋值给一个变量名(函数名);

def运行之后,可在程序中通过函数名附加小括号进行调用;

return用于返回结果对象,可选,无return语句的函数自动返回None对象;返回多个值时,彼此间互相用逗号分隔,且组合为tuple形式返回一个对象;

函数作用域:python创建、改变、查找变量名都是在名称空间中进行;在代码中,变量名被赋值的位置,决定了其能被访问到的范围;函数定义了本地作用域,而模块定义了全局作用域;每个模块都是一个全局作用域,因此全局作用域的范围仅限于单个程序文件;每次对函数的调用,都会创建一个新的本地作用域,函数中赋值的变量除非声明为全局变量,否则均为本地变量;所有的变量名都可归纳为本地、全局、内置的(内置的由__builtin__模块提供));

 

变量名解析:LEGB原则(localenclosing function localsglobalbuiltin),首先是本地,之后是函数内,接着是全局,最后是内置(本地-->函数内-->全局-->内置)

wKiom1dhCi7zYMtAAAFAX55GjU8946.jpg

举例:

[root@localhost ~]# vim func_var.py

----------------------scirpt start----------------------

#!/usr/bin/python2.7

#filename:func_var.py

x=6

z='global'

def f1():

       x='from f1'

       y=8

       print x,z

       def f2():

                x='from f2'

                print x,y,z

       f2()

f1()

------------------------script end--------------------

[root@localhost ~]# chmod 755 func_var.py

[root@localhost ~]# ./func_var.py   #f2函数调用时,x本地中有则用本地,y本地没有则用上一级f1中定义的,z本地没有上一级f1也没有则用全局的;f1函数调用时,x本地有则用本地,z本地没有用上一级即全局的)

from f1 global

from f2 8 global

 

 

python的闭包lexical closure(函数的闭合、工厂函数):

变量定义在外层函数中,由内层函数引用,外层函数return返回了内层函数,再次调用内层函数可直接使用外层函数的变量,实现了记忆的效果;

嵌套的函数,f1中嵌套f2,最后f1的返回值为f2这个函数,内层函数f2可记忆调用过的外层函数f1的变量,f1f2提供运行环境;

举例1

In [19]: def f1():

  ....:     x=8

  ....:     def f2():

  ....:         y='hello'

  ....:         print x,y

  ....:     return f2

  ....:

In [20]: a1=f1()

In [21]: type(a1)

Out[21]: function

In [22]: a1()

8 hello

举例2

In [23]: def startPos(m,n):

  ....:     def newPos(x,y):

  ....:         print 'the oldposition is (%d,%d),and the new position (%d,%d)' % (m,n,m+x,n+y)

  ....:     return newPos

  ....:

In [24]: action=startPos(10,10)

In [25]: action(1,2)

the old position is (10,10),and the newposition (11,12)

In [26]: action(-1,3)

the old position is (10,10),and the newposition (9,13)

 

 

注:数字、字符均是不可变对象,不影响函数外部的变量;函数的多态性(不同的对象即不同的数据结构);列表是可变对象,不要在函数中有修改可变对象的语句,若要在函数中修改某对象,在调用函数时使用切片,否则会影响原对象中的数据

举例1

In [1]: def f1(x):

  ...:     print x

  ...:    

In [2]: print f1(4)

4

None

In [3]: print f1('abc')

abc

None

举例2

In [4]: def f2(x,y):

  ...:     print x+y

  ...:    

In [5]: f2(3,4)

7

In [6]: f2('hello',' world')

hello world

举例3

In [7]: m=7;n=8

In [8]: def f3(x,y):

  ...:     x-=1

  ...:     print x,y

  ...:    

In [9]: f3(m,n)

6 8

举例4

In [10]: l1=[1,2,3]

In [11]: def f4(x):

  ....:     x.pop()

  ....:     print x

  ....:    

In [12]: f4(l1)  #(注意调用函数时不要这样用,要使用切片方式f4(l1[:])

[1, 2]

In [13]: l2=[4,5,6]

In [14]: f4(l2[:])

[4, 5]

In [15]: print l2

[4, 5, 6]

In [16]: print l1

[1, 2]

 

 

参数传递:

参数匹配模型,默认情况下,参数通过其位置进行传递,从左至右,这意味着必须精确的传递和函数头部一样多的参数,但也可通过关键字参数、默认参数、参数容器等改变这种机制;

位置参数(调用函数时依次从左至右);

关键字参数(调用函数时使用name=value的语法,通过参数名进行匹配);

默认参数(定义函数时使用name=value,直接给变量一个值,从而在调用函数时传入的值可以少于参数个数);

def f(x=1,y,z=9):

         printx,y,z

可变参数(定义函数时使用一个*星号或两个星号开头的参数,可用于收集任意多基于位置和关键字的参数;定义函数时一个星号开头会在调用函数时将多余的位置参数返回成tuple,收集位置参数;定义函数时两个星号开头在调用函数时将多余的关键字参数返回dict,收集关键字参数);

def f(*x):

         printx

def f(**x):

         printx

可变参数解包(调用函数时使用一个*星号或两个星号开头的参数,可用于将参数集合打散,从而传递任意多基于位置或关键字的参数;调用函数时使用一个星号开头,解包tuplelist,如f(m,n,o);调用函数时使用两个星号开头,解包dict,如f(m=1,n=2,o=3));

注:

定义函数时使用***是整合,调用函数时使用***是分解,函数的灵活性体现在定义和调用时都使用***

调用函数时若混用位置参数和关键字的参数,要先位置参数再关键字参数;

调用函数时若混用无默认值和有默认值的参数,无默认值的参数要放在前面;

调用函数时若混用位置参数和可变参数,位置参数在前,可变参数在后;

调用函数时若滥用位置参数、默认参数、可变参数,先位置参数再默认参数最后可变参数;

调用函数时若混用可变参数,一个星号开头的参数要在前,两个星号开头的参数要在后;

 

举例:

In [17]: l1=['mon','tue','wed']

In [18]: x,y,z=l1   #(变量的分解赋值)

In [19]: print x,y,z

mon tue wed

In [20]: def f(x,y,z):

  ....:     print x,y,z

  ....:    

In [21]: f(*l1)   #(调用函数时使用可变参数解包)

mon tue wed

In [22]: def f(x,*y,**z):

  ....:     print x

  ....:     print y

  ....:     print z

  ....:    

In [23]: m=1

In [24]: l1=[2,3,4]

In [25]: d1={'key5':5,'key6':6,'key7':7}

In [26]: f(m,*l1,**d1)

1

(2, 3, 4)

{'key7': 7, 'key6': 6, 'key5': 5}

In [28]:f(m,2,3,4,key5='v5',key6='v6',key7='v7')  #2,3,4*y收集的位置参数,key5='v5',key6='v6',key7='v7'**z收集的关键字参数)

1

(2, 3, 4)

{'key7': 'v7', 'key6': 'v6', 'key5': 'v5'}

 

 

lambda匿名函数:

语法:

lambda args: expression

注:

args为以逗号分隔的参数列表,expression用到args中各参数的表达式;

lambda语句定义的代码必须是合法的表达式,不能出现多条件语句和其它非表达式语句(for,while等),但可使用if的三元表达式;

lambda的首要用途是指定短小的回调函数;

lambda将返回一个函数而不是将函数赋值给某变量名;

lambda是一个表达式而非语句(def定义的是语句),lambda是一个单个表达式而不是一个代码块;

def语句创建的函数将赋值给某变量名,而lambda表达式则直接返回函数,lambda也支持使用默认参数;

举例1

In [1]: f=lambda x,y:x+y

In [2]: f(1,2)   #(调用)

Out[2]: 3

同以下def定义的函数

In [3]: del f

In [4]: def f(x,y):

  ...:     return x+y

  ...:

In [5]: f(1,2)   #(调用)

Out[5]: 3

举例2

In [6]: del f

In [7]: f=(lambda x,y,z=10:x+y+z)

In [8]: f(1,2)

Out[8]: 13

举例3

In [10]: lam1=[(lambda x:x**2),(lambday:y**3)]

In [11]: for i in lam1:

  ....:     print i(2)

  ....:    

4

8

 

 

python函数式编程(泛函编程,是一种编程范型):

泛函编程(将一个函数作为参数传递给另一个函数);

函数式编程将电脑运算视为数学上的函数计算,且避免状态及可变数据;

函数式编程语言最重要的基础是lambda演算,而且lambda演算的函数可接受函数当作输入和输出;

python支持有限的函数式编程;

filter(function or None,sequence)(过滤器,调用一个布尔函数(二元函数,TrueFalsefunc来迭代遍历每个seq中的元素,返回一个使func返回值为True的元素的序列(tuple,list,string),filter返回的是一个序列);

map(function,sequence[,sequence])(映射器,将函数作用于给定序列中的每个元素,返回值为一个列表,如果functionNonefunction表现为一个身份函数,返回一个含有每个序列中元素集合的n个元组的列表,map返回的是由元组组成的列表);

reduce(function,sequence[,initial])(折叠,将二元函数作用于序列中的元素,每次携带一对(先前的结果及下一个序列元素),连续地将现有的结果和下一个值作用在获得的随后结果上,最后减少序列为一个单一的返回值value,如果初始值initial给定,第一个比较会是initial和第一个序列元素而不是序列的头两个元素,reduce返回的是一个value);

 

fileter()过滤器,为已知的序列中的每个元素调用给定的布尔函数,调用过程中返回值为非零的元素将被添加至一个列表中,举例:

In [1]: l1=[1,2,3,4,5,6]

In [2]: def f1(x):

  ...:     if x>3:

  ...:         return True

  ...:     else:

  ...:         return False

  ...:    

In [3]: filter(f1,l1)

Out[3]: [4, 5, 6]

 

map()映射器,将函数调用映射到每个序列的对应元素上,并返回一个含有所有返回值的列表,举例:

举例一:

In [4]: l1=[1,2,3,4,5,6,7]

In [5]: l2=['m','t','w','t','f','s','s']

In [6]: map(None,l1,l2)   #(将两个列表相同位置的元素组成tuple,最后成为以tuple为元素的列表,None表示不作计算)

Out[6]: [(1, 'm'), (2, 't'), (3, 'w'), (4,'t'), (5, 'f'), (6, 's'), (7, 's')]

举例二:

In [7]: def f2(x):

  ...:     return x*2

  ...:

In [8]: map(f2,l1)

Out[8]: [2, 4, 6, 8, 10, 12, 14]

In [9]: map(f2,l2)

Out[9]: ['mm', 'tt', 'ww', 'tt', 'ff', 'ss','ss']

In [10]: print l1

[1, 2, 3, 4, 5, 6, 7]

In [11]: print l2

['m', 't', 'w', 't', 'f', 's', 's']

举例三:

In [12]: def f3(x,y):

  ....:     return x*2,y*2

  ....:

In [13]: map(f3,l1,l2)

Out[13]:

[(2, 'mm'),

 (4,'tt'),

 (6,'ww'),

 (8,'tt'),

 (10,'ff'),

 (12,'ss'),

 (14,'ss')]

举例四:

In [6]: map(lambda x:x*2,[5,4,3,2,1])

Out[6]: [10, 8, 6, 4, 2]

 

reduce()折叠,举例一:

In [14]: l1=[1,2,3,4,5,6,7,8,9,10]

In [15]: def f4(x,y):

  ....:     return x+y

  ....:

In [16]: reduce(f4,l1)

Out[16]: 55

In [17]: reduce(f4,l1,10)

Out[17]: 65

举例二:

In [31]: reduce(lambda x,y:x*y,[5,4,3,2,1])   #(使用折叠的方式求阶乘)

Out[31]: 120

 

 

yeildgenerator

yield能生成一个生成器对象;

举例(generator:

In [1]: for i in (j**2 for j inrange(1,11)):

  ...:     print i,

  ...:    

1 4 9 16 25 36 49 64 81 100

In [2]: list(i**2 for i in range(1,11))   #(将生成器表达式转为列表)

Out[2]: [1, 4, 9, 16, 25, 36, 49, 64, 81,100]

举例(函数中使用yield会返回一个生成器对象):

In [4]: def genNum(x):

  ...:     y=0

  ...:     while y<=x:

  ...:         yield y

  ...:         y+=1

  ...:        

In [5]: g1=genNum(5)

In [6]: type(g1)

Out[6]: generator

In [7]: g1.next()

Out[7]: 0

In [8]: g1.next()

Out[8]: 1

In [9]: g1.next()

Out[9]: 2

In [10]: g1.next()

Out[10]: 3

举例(函数中使用yield):

In [11]: def genNum(n):

  ....:     i=1

  ....:     while i<=n:

  ....:         yield i**2

  ....:         i+=1

  ....:        

In [12]: g1=genNum(3)

In [13]: for i in g1:   #(生成器本身可迭代)

  ....:     print i

  ....:    

1

4

9

 

 

decorator装饰器:

装饰器本身是个函数,能将其它函数的功能增强,实现函数代码在不同环境中重用,增强被装饰函数的功能;

被用于有切面需求的场景,如(插入日志、性能测试、事务处理等),装饰器是解决这些问题绝佳的设计;

装饰器一般接受一个一个函数对象作为参数,以对其进行增强;

举例一:

In [14]: def deco(func):

  ....:     def wrapper():

  ....:         print 'please saysomething:hehe'

  ....:         func()

  ....:         print 'xiao xiao'

  ....:     return wrapper

  ....: @deco

  ....: def show():

  ....:     print 'i am from mars'

  ....:    

In [15]: show()

please say something:hehe

i am from mars

xiao xiao

举例二:

In [16]: def decorator(func):

  ....:     def wrapper(x):

  ....:         print 'please saysomething:xiang'

  ....:         func(x)

  ....:         print 'no zuo nodie'

  ....:     return wrapper

  ....: @decorator

  ....: def show(x):

  ....:     print x

  ....:    

In [17]: show('hello,xiang')

please say something:xiang

hello,xiang

no zuo no die

 

 

递归函数:

函数执行中调用自身,一定要有退出条件(边界条件),否则无限递归;

边界条件、递归前进段、递归返回段;

举例(阶乘):

In [18]: def factorial(n):

  ....:     if n<=1:

  ....:         return 1

  ....:     else:

  ....:         returnn*factorial(n-1)

  ....:    

In [19]: factorial(10)  

Out[19]: 3628800

In [20]: factorial(3)   #(即factorial(3)=3*factorial(2)=3*2*factorial(1)=3*2*1=6

Out[20]: 6

 

 

练习:

举例一(将/etc/passwd文件中的每一行都分隔为一个列表):

In [9]: for i in f1.readlines():

  ...:     l1.append(i)

  ...:    

In [10]: print l1

['root:x:0:0:root:/root:/bin/bash\n','bin:x:1:1:bin:/bin:/sbin/nologin\n','daemon:x:2:2:daemon:/sbin:/sbin/nologin\n','adm:x:3:4:adm:/var/adm:/sbin/nologin\n',……]

举例二(将目录与文件组合在一起;将一个列表中的两元素按linuxOS的路径分隔符连在一起):

In [8]: s1='/etc/open***/'

In [9]: s2='server.conf'

In [10]: s1+s2

Out[10]: '/etc/open***/server.conf'

In [21]: s1='/etc/open***'

In [22]: s2='server.conf'

In [23]: s1+os.sep+s2

Out[23]: '/etc/open***/server.conf'

In [15]: import os

In [16]: os.sep

Out[16]: '/'

In [17]: l1=['/etc/open***','client.conf']

In [18]: ''.join(l1)   #(此种方式是按空字符连接,不符合要求)

Out[18]: '/etc/open***client.conf'

In [19]: '/'.join(l1)

Out[19]: '/etc/open***/client.conf'

In [20]: os.sep.join(l1)

Out[20]: '/etc/open***/client.conf'

 

 

函数的设计规范:

耦合性(尽可能通过参数接受输入,通过return产生输出以保证函数的独立性;尽量减少使用全局变量进行函数间通信;不要在函数中修改可变类型的参数,这样不易于排错;避免直接改变定义在另一个模块中的变量);

聚合性(每个函数都应该有一个单一的、统一的目标,功能越简单越好;每个函数的功能都应相对简单);

函数执行环境(函数可通过多种方法获得输入,产生输出):

wKioL1dhC7Tz7uqeAAA-HrJ5Xz4581.jpg

 

 

python类与面向对象:

面向对象编程oop,程序=指令+数据;

两种范型:代码可以选择以指令为核心或以数据为核心进行编写;以指令为核心,围绕“正在发生什么”,是面向过程编程,程序具有一系列线性步骤,主体思想是代码作用于数据,;以数据为核心,围绕“将影响谁”进行编写,oop围绕数据及为数据严格定义的接口来组织程序,用数据控制对代码的访问;

所有编程语言的最终目的都是提供一种抽象方法,在机器模型(解空间或方案空间)与实际解决的问题模型(问题空间)之间,程序员必须建立一种联系;

面向过程(程序=算法+数据结构);

面向对象(将问题空间中的元素及它们在解空间中的表示物抽象为对象,并允许通过问题来描述问题而不是方案;

可以把对象(实例)想象成一种新型变量,它保存着数据,但可以对自身的数据进行操作;例如l1=[1,2,3]l1是列表list这一类型的实例化,实例不仅是数据还有方法,或叫支持的操作(数据支持的访问接口),这些数据所支持的操作是程序员事先定义好的;

类型由状态集合(数据)和转换这些状态的操作集合组成;

 

类抽象:

类,定义了被多个同一类型对象共享的结构和行为(数据和代码);

类的数据和代码,即类的成员;

数据(成员变量或实例变量);

成员方法(简称方法,用于定义如何使用成员变量,因此一个类的行为和接口是通过方法来定义的);

方法和变量(私有(内部使用);公共(外部可见));

 

python中所有的东西都是对象;

程序是一大堆对象的组合(通过消息传递,各对象知道自己该做什么;消息,即调用请求,它调用的是从属于目标对象的一个方法);

每个对象都有自己的存储空间,并可容纳其它对象;通过封装现有对象,可制作成新型对象;

每个对象都属于某一类型;类型也即类;对象是类的实例;类的一个重要特性为“能发什么样的消息给它”;

同一个类的所有对象都能接收相同的消息(相同的消息即方法,所支持的操作);

 

对象的接口:

定义一个类后,可根据需要实例化出多个对象;

如何利用对象完成真正有用的工作?必须有一种方法能向对象发出请求,令其做一些事情;每个对象仅能接受特定的请求;能向对象发送的请求由其“接口”进行定义;对象的类型(类)则规定了它的接口形式;

例如:light灯(类型名),接口(on(),off(),bright(),dim()

 

类(将同一种具体物事的共同特性抽象出来的表现);

状态(数据),类属性(变量);

转换这些状态的操作(方法),函数(操作变量引用的数据的代码);

方法是类的组成部分,是在类中定义的,数据和属性也在类中定义,数据本身是在类被实例化后给赋值的;

类定义的有数据结构和方法,方法能对数据结构中的变量作操作;

 

类间关系:

依赖(uses-a,一个类的方法操纵另一个类的对象);

聚合(has-a,将A的对象包含B的对象);

继承(is-a,描述特殊与一般关系);

 

面向对象编程的原则(封装、继承、多态):

封装Encapsulation(隐藏实现方案细节,将代码及其处理的数据绑定在一起的一种编程机制,用于保证程序和数据不受外部干扰且不会被误用);

继承Inheritance(一个对象获得另一个对象属性的过程,用于实现按层分类的概念,一个深度继承的子类继承了类层次中它的每个祖先的所有属性;超类、基类、父类;子类、派生类);

wKioL1dhC8aRxULhAAA-Nh1VSpo030.jpg

注:爬树方式两种(先上到根上走再向右找;先在同级的右侧找逐级上升直到根)

多态Polymorphism(允许一个接口被多个通用的类动作使用的特性,具体使用哪个动作与应用场合相关;一个接口多个方法;用于为一组相关的动作设计一个通用的接口,以降低程序复杂性);

 

类和实例:

类是一种数据结构,可用于创建实例;一般情况下,类封装了数据和可用于该数据的方法;

python类是一个可调用对象(像使用函数一样),即类对象;

python2.2之后,类是一种自定义类型,而实例则是声明某个自定义类型的变量;

实例初始化,通过调用类来创建实例,如instance=className(args...),类在实例化时可使用__init____del__两个特殊的方法;

class ClassName()(生成className引用的类对象,类中的代码不会真正执行,只有在实例化时类中代码才真正执行,类中的方法也不会执行,只有对实例调用相应的方法时才执行);

 

In [27]: l1=[1,2,3]

In [28]: type(list)

Out[28]: type

In [29]: type(l1)

Out[29]: list

In [30]: type(tuple)

Out[30]: type

In [31]: type(dict)

Out[31]: type

In [32]: type(int)

Out[32]: type

In [33]: type(float)

Out[33]: type

 

创建类,语法:

class ClassName(bases):

         'classdocuments string'

         class_suite

注:

定义类时,类名中每个单词的首字母均大写;定义函数时,首个单词的首字母小写后面的单词首字母均大写;这只是惯例,不遵循也可;

超类是一个或多个用于继承的父类的集合;

类体可以包含(声明语句,类成员定义,数据属性、方法);

如果不存在继承关系bases可以不提供;

类文档可选;

class语句类似def是可执行代码,直到运行class语句后类才会存在;

class语句内,任何赋值的语句都会创建类属性;

每个实例对象都会继承类的属性并获得自己的名称空间;

 

class语句的一般形式:

class ClassName(bases):  

         data=value   #(定义类属性,类数据属性)

         defmethod(self,...):   #(定义方法属性)

                   self.member=value   #(定义实例属性,在类方法中对传给特殊参数self进行赋值会创建实例属性;类属性是所有实例共享的,此处定义的实例自己内部的属性这是私有的由实例自己使用)

 

举例一:

In [34]: class TestClass():

  ....:     pass

  ....:

In [35]: type(TestClass)

Out[35]: classobj

In [36]: obj1=TestClass()

In [37]: type(obj1)

Out[37]: instance

举例二:

In [38]: class FirstClass():   #(类名)

  ....:     span=30   #(类数据属性)

  ....:     def display(self):   #(类方法,属性可调用的属性)

  ....:         print self.span   #(创建实例属性)

  ....:        

In [39]: x=FirstClass()

In [40]: x.<TAB>

x.display x.span    

In [40]: x.display

Out[40]: <bound methodFirstClass.display of <__main__.FirstClass instance at 0x1551128>>

In [41]: x.display()   #(调用方法时必须要加小括号,表示调用)

30

In [42]: x.span

Out[42]: 30

举例三:

In [1]: class SecClass():

  ...:     data='hello SecClass'

  ...:     def setData(self,x):

  ...:         self.x=x

  ...:     def printData(self):

  ...:         print self.x

  ...:        

In [2]: ins1=SecClass()

In [3]: type(ins1)

Out[3]: instance

In [4]: ins1.

ins1.data       ins1.printData  ins1.setData   

In [4]: ins1.data

Out[4]: 'hello SecClass'

In [5]: ins1.setData('hello instance')   #(有self执行时自动转换为SecClass.setData(ins1,'helloinstance')

In [6]: ins1.printData()

hello instance

 

python类、方法、调用:

实例通常包含属性,可调用的属性即方法,如object.method()

oop中,实例就像是带有数据的记录,而类是处理这些记录的程序;

通过实例调用方法相当于调用所属的方法处理当前实例,如instance.method(args...)会自动转换为class.method(instance,args...)x,display()会自动转为FirstClass.display(x)即调用类的方法来处理实例x

因此,类中的每个方法必须具有self参数,它隐含当前实例之意;

在方法内对self属性作赋值运算会产生每个实例自己的属性;

python规定,没有实例,则方法不允许被调用,此即为“绑定”;

 

举例:

In [1]: class MyClass():

  ...:     gender='Male'

  ...:     def setName(self,who):

  ...:         self.name=who

   ...:        

 

In [2]: x=MyClass()

In [3]: x.<TAB>   #(在未调用setName之前仅有x.gender类属性和x.setName()类方法)

x.gender  x.setName 

In [3]: x.name   #(在setName()方法调用之前,MyClass类不会把name属性附加到实例x上,可以用__init__创建构造器直接为实例提供)

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

AttributeError                            Traceback (mostrecent call last)

<ipython-input-3-ebfcbb65f7c8> in<module>()

----> 1 x.name

AttributeError: MyClass instance has noattribute 'name'

In [4]: x.setName('jowin')  

In [5]: x.<TAB>   #(赋值后即可用x.name属性)

x.gender  x.name     x.setName 

In [5]: x.name

Out[5]: 'jowin'

In [6]: x.gender

Out[6]: 'Male'

 

 

__init__构造器:

以单一下划线开始的变量名不会被from MODULE import *导入,如_x;前后有双下划线的变量名是系统定义的变量名,对python解释器有重要意义,如__x__print a+b解释器会将运算转为内置的方法调用print a__add__(b);仅以双下划线开头的变量名是类的本地变量,如__x;交互式模式下,变量名为“_”用于保存最后表达式的结果;

创建实例时,python会自动调用类中的__init__方法,以隐性的方式为实例提供属性,如果类中没有定义__init__方法,实例创建之初仅是一个简单的命名空间;

In [1]: class MyClass():

  ...:     gender='Male'

   ...:     def __init__(self,who):

  ...:         self.name=who

  ...:        

 

In [2]: x=MyClass('jowin')

In [4]: x.<TAB>

x.gender x.name   

In [4]: x.name

Out[4]: 'jowin'

In [5]: x.gender

Out[5]: 'Male'

 

 

__del__析构器:

构造器有必要用到;析构器可以不用,因为当对象未被引用时有GC回收;

In [6]: class Animal():

  ...:     name='someone'

  ...:     def__init__(self,voice='hi'):

  ...:         self.voice=voice

  ...:     def __del__(self):

  ...:         pass

  ...:     def saySomething(self):

  ...:         print self.voice

  ...:        

In [7]: tom=Animal()   #(创建实例)

In [8]: tom.<TAB>

tom.name          tom.saySomething  tom.voice        

In [8]: tom.name

Out[8]: 'someone'

In [9]: tom.voice

Out[9]: 'hi'

In [10]: tom.saySomething()

hi

In [12]: jerry=Animal('xiang')

In [13]: jerry.name

Out[13]: 'someone'

In [14]: jerry.saySomething()

xiang

 

 

类的特殊属性:

可使用python内置的dir([object])函数或类的__dict__字典属性来获取类的属性;

C.__name__(类的名字,返回字符串);

C.__doc__(类的docstring);

C.__bases__(类的所有父类构成的元组);

C.__dict__(类的属性);

C.__module__(类定义所在的模块,1.5版本新增);

C.__class__(实例C对应的类(仅新式类))

举例:

In [1]: class MyClass():

  ...:     gender='Male'

  ...:     def __init__(self,name):

  ...:         self.name=name

  ...:        

In [2]: dir(MyClass)

Out[2]: ['__doc__', '__init__','__module__', 'gender']

In [3]: MyClass.__dict__

Out[3]:

{'__doc__': None,

 '__init__': <function__main__.__init__>,

 '__module__': '__main__',

 'gender': 'Male'}

In [5]: MyClass.__name__

Out[5]: 'MyClass'

In [6]: MyClass.__bases__

Out[6]: ()

In [8]: MyClass.__module__

Out[8]: '__main__'

In [9]: MyClass.__class__

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

AttributeError                            Traceback (mostrecent call last)

<ipython-input-9-a20d42661166> in<module>()

----> 1 MyClass.__class__

AttributeError: class MyClass has noattribute '__class__'

 

实例属性:

实例仅拥有数据属性,严格意义上说,方法是类属性;

通常通过构造器__init__为实例提供属性,这些数据属性独立于其它实例类,实例释放时其属性也将被清除;

内建函数dir()或特殊属性__dict__可用于查看实例属性;

实例的特殊属性(TestClass.__class__实例化TestClass的类,TestClass.__dict__TestClass的属性);

 

python类方法中可用的变量:

实例变量(指定变量名称及实例自身进行引用,如self.VARIABLE);

局部变量(方法内部创建的变量,可直接使用);

类变量(也称静态变量,通过指定变量名与类名进行引用,如ClassName.VARIABLE);

全局变量(直接使用);

举例:

In [10]: class FirstClass():

  ....:     span=30

  ....:     def display(self):

  ....:         print self.span

   ....:        

In [11]: x=FirstClass()

In [12]: x.span   #(实例继承类的属性)

Out[12]: 30

In [13]: x.span(40)   #(属性不可调用,应该赋值)

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

TypeError                                 Traceback(most recent call last)

<ipython-input-13-c5d884e91308> in<module>()

----> 1 x.span(40)

TypeError: 'int' object is not callable

In [14]: x.span=40   #(为实例继承的属性重新赋值)

In [15]: x.span

Out[15]: 40

In [16]: FirstClass.span=50   #(为类重新赋值,数字为不可变类型,类的这个属性将指向56所指向的内存空间,若之后实例化出的对象会会继承类的这个属性)

In [17]: x.span

Out[17]: 40

In [18]: y=FirstClass()

In [19]: y.span

Out[19]: 50

 

类继承:

描述了基类的属性如何遗传给派生类;

子类可继承它的基类的任何属性,包括数据属性和方法;

一个未指定的基类,其默认有一个名为object的基类;

python允许多重继承;

创建子类时,只需要在类名后跟一个或从其中派生的父类:

class SubClassName(ParentClass1[,ParentClass2,...]):

         'Optionalclass documentation string.'

         class_suite

举例:

In [20]: class ParentClass(object):   #(此行括号中的object可省略不写)

  ....:     'Parent class'

  ....:     gender='Male'

  ....:     def __init__(self,name):

  ....:         self.name=name

  ....: class ChildClass(ParentClass):

  ....:     'child class'

  ....:     def displayInfo(self):

  ....:         printself.gender,self.name

  ....:        

In [21]: ins1=ChildClass()   #(由于使用了构造器,实例化时要跟参数)

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

TypeError                                 Traceback(most recent call last)

<ipython-input-21-f64d4480c7bf> in<module>()

----> 1 ins1=ChildClass()

TypeError: __init__() takes exactly 2 arguments(1 given)

In [22]: ins1=ChildClass('tom')   #(实例化对象ins1

In [23]: ins1.displayInfo()   #(实例调用方法)

Male tom

In [24]: dir(ParentClass)   #(此基类所支持的属性和方法)

Out[24]:

['__class__',

 '__delattr__',

 '__dict__',

 '__doc__',

 '__format__',

 '__getattribute__',

 '__hash__',

 '__init__',

 '__module__',

 '__new__',

 '__reduce__',

 '__reduce_ex__',

 '__repr__',

 '__setattr__',

 '__sizeof__',

 '__str__',

 '__subclasshook__',

 '__weakref__',

 'gender']

In [25]: ChildClass.__dict__   #(子类所支持的属性和方法)

Out[25]:

<dictproxy {'__doc__': 'child class',

 '__module__': '__main__',

 'displayInfo': <function__main__.displayInfo>}>

In [26]: ChildClass.__doc__

Out[26]: 'child class'

In [27]: ParentClass.__doc__

Out[27]: 'Parent class'

 

python类的继承和属性搜索:

python中几乎所有属性的获取都可以使用object.attribute的格式,不过此表达式会在python中启动搜索,搜索连续的树;

class语句会产生一个类对象,对class的调用会创建实例,实例自动连结至创建了此实例的一个或多个类;

类连结至超类的方式,将超类列在类头部的括号内,其从左至右的顺序会决定树中的顺序,由下至上,同一层级由左至右;

爬树方式,由下而上搜索此树来寻找属性名称所出现的最低位置;

 

继承方法专用化:

继承会先在子类寻找变量名,然后再查找超类,因此,子类可以对超类的属性重新定义来取代继承而来的行为;

子类可以完全取代从超类继承而来的属性,也可以通过已覆盖的方法回调超类来扩展超类的方法;

覆盖父类;扩展父类;

举例(覆盖父类):

In [1]: class ParClass(object):

  ...:     defsetInfo(self,sex='Male'):

  ...:         self.gender=sex

  ...: class ChildClass(ParClass):

  ...:     def setInfo(self,who):

  ...:         self.name=who

  ...:        

In [2]: ins1=ChildClass()

In [3]: ins1.setInfo('tom')

In [4]: ins1.

ins1.name     ins1.setInfo 

In [4]: ins1.name

Out[4]: 'tom'

In [5]: ins1.gender   #(由于已覆盖了父类的属性,报错)

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

AttributeError                            Traceback (mostrecent call last)

<ipython-input-5-4b30cbebe078> in<module>()

----> 1 ins1.gender

AttributeError: 'ChildClass' object has noattribute 'gender'

举例(扩展父类):

In [1]: class ParClass(object):

  ...:     defsetInfo(self,sex='Male'):

  ...:         self.gender=sex

  ...: class ChildClass(ParClass):

  ...:     def setInfo(self,who):

  ...:         self.name=who

  ...:         ParClass.setInfo(self)

  ...:        

In [2]: ins2=ChildClass()

In [3]: ins2.setInfo('jerry')

In [4]: ins2.

ins2.gender   ins2.name    ins2.setInfo 

In [4]: ins2.name

Out[4]: 'jerry'

In [5]: ins2.gender

Out[5]: 'Male'

 

类、实例、其它对象的内建函数:

issubclass()(布尔函数,判断一个类是否由另一个类派生,语法:issubclass(subclass,superclass);

isinstance()(布尔函数,判断一个对象是否是给定的类的实例,语法:isintance(object1,class object));

hasattr()(布尔函数,判断一个对象是否拥有指定的属性,同类的还有getattr()setattr()delattr(),语法:hasattr(object,attribute));

super()(在子类中找出其父类,以便于调用其属性,一般情况下仅能采用非绑定方式调用祖先类方法,而super()可用于传入实例或类型对象,语法:super(type[,object]));

举例:

In [10]: issubclass(ChildClass,ParClass)

Out[10]: True

In [11]: isinstance(ins2,ChildClass)

Out[11]: True

In [12]: isinstance(ins2,ParClass)

Out[12]: True

In [13]: l1=[1,2,3]

In [14]: isinstance(l1,list)

Out[14]: True

In [15]: type(l1)

Out[15]: list

In [16]: type(ins2)

Out[16]: __main__.ChildClass

In [17]: type(ChildClass)

Out[17]: type

In [18]: str1='jowin'

In [19]: isinstance(str1,str)

Out[19]: True

In [20]: type(str1)

Out[20]: str