多态
1 class Animal: 2 def __init__(self, name): # Constructor of the class 3 self.name = name 4 def talk(self): # Abstract method, defined by convention only 5 raise NotImplementedError("Subclass must implement abstract method") 6 7 class Cat(Animal): 8 def talk(self): 9 return 'Meow!' 10 11 class Dog(Animal): 12 def talk(self): 13 return 'Woof! Woof!' 14 15 animals = [Cat('Missy'), 16 Dog('Lassie')] 17 18 for animal in animals: 19 print animal.name + ': ' + animal.talk()
你要是觉得列表有点low,还可以定义成一个函数来写,比如:
1 class Animal: 2 def __init__(self, name): # Constructor of the class 3 self.name = name 4 def talk(self): # Abstract method, defined by convention only 5 raise NotImplementedError("Subclass must implement abstract method") 6 7 class Cat(Animal): 8 def talk(self): 9 return 'Meow!' 10 11 class Dog(Animal): 12 def talk(self): 13 return 'Woof! Woof!' 14 15 def animal(obj): 16 print (obj.talk()) 17 18 c= Cat("wuweizhen") 19 animal(c)
类的成员
类的成员可以分为三大类:字段、方法和属性
一、字段
简单的说就是类变量和实例变量
class Province: # 类变量 country = '中国' def __init__(self, name): # 实例变量 self.name = name # 直接访问实例变量 obj = Province('河北省') print obj.name # 直接访问类变量 Province.country 字段的定义和使用
应用场景: 通过类创建对象时,如果每个对象都具有相同的字段,那么就使用类变量
二、方法
方法包括:普通方法、静态方法和类方法,三种方法在内存中都归属于类,区别在于调用方式不同。
- 普通方法:由对象调用;至少一个self参数;执行普通方法时,自动将调用该方法的对象赋值给self;
- 类方法:由类调用; 至少一个cls参数;执行类方法时,自动将调用该方法的类复制给cls;
- 静态方法:由类调用;无默认参数;


1 class Foo: 2 3 def __init__(self, name): 4 self.name = name 5 6 def ord_func(self): 7 """ 定义普通方法,至少有一个self参数 """ 8 9 # print self.name 10 print '普通方法' 11 12 @classmethod 13 def class_func(cls): 14 """ 定义类方法,至少有一个cls参数 """ 15 16 print '类方法' 17 18 @staticmethod 19 def static_func(): 20 """ 定义静态方法 ,无默认参数""" 21 22 print '静态方法' 23 24 25 # 调用普通方法 26 f = Foo() 27 f.ord_func() 28 29 # 调用类方法 30 Foo.class_func() 31 32 # 调用静态方法 33 Foo.static_func() 34 35 方法的定义和使用


1 class Animal: 2 def __init__(self,name): 3 self.name = name 4 hobbie = 'meat' 5 @classmethod #类方法,不能访问实例变量 6 def talk(self): 7 print ("%s is talking..." % self.hobbie) 8 @staticmethod #静态方法,类变量和实例变量都不能访问 9 def walk(): 10 print("wu is walking...") 11 @property #加了proeperty就不再是方法,会变成一个属性 12 def habit(self): 13 print("%s habit is xxoo" % self.name) 14 15 d = Animal("wuweizhen") 16 d.talk() 17 d.walk() 18 d.habit
相同点:对于所有的方法而言,均属于类(非对象)中,所以,在内存中也只保存一份。
不同点:方法调用者不同、调用方法时自动传入的参数不同。
三、属性
如果你已经了解Python类中的方法,那么属性就非常简单了,因为Python中的属性其实是普通方法的变种。
对于属性,有以下三个知识点:
- 属性的基本使用
- 属性的两种定义方式
1、属性的基本使用
1 # ############### 定义 ############### 2 class Foo: 3 4 def func(self): 5 pass 6 7 # 定义属性 8 @property 9 def prop(self): 10 pass 11 # ############### 调用 ############### 12 foo_obj = Foo() 13 14 foo_obj.func() 15 foo_obj.prop #调用属性 16 17 属性的定义和使用
由属性的定义和调用要注意一下几点:
- 定义时,在普通方法的基础上添加 @property 装饰器;
- 定义时,属性仅有一个self参数
- 调用时,无需括号
方法:foo_obj.func()
属性:foo_obj.prop
注意:属性存在意义是:访问属性时可以制造出和访问字段完全相同的假象
属性由方法变种而来,如果Python中没有属性,方法完全可以代替其功能。
实例:对于主机列表页面,每次请求不可能把数据库中的所有内容都显示到页面上,而是通过分页的功能局部显示,所以在向数据库中请求数据时就要显示的指定获取从第m条到第n条的所有数据(即:limit m,n),这个分页的功能包括:
- 根据用户请求的当前页和总数据条数计算出 m 和 n
- 根据m 和 n 去数据库中请求数据


1 # ############### 定义 ############### 2 class Pager: 3 4 def __init__(self, current_page): 5 # 用户当前请求的页码(第一页、第二页...) 6 self.current_page = current_page 7 # 每页默认显示10条数据 8 self.per_items = 10 9 10 11 @property 12 def start(self): 13 val = (self.current_page - 1) * self.per_items 14 return val 15 16 @property 17 def end(self): 18 val = self.current_page * self.per_items 19 return val 20 21 # ############### 调用 ############### 22 23 p = Pager(1) 24 p.start 就是起始值,即:m 25 p.end 就是结束值,即:n
从上述可见,Python的属性的功能是:属性内部进行一系列的逻辑计算,最终将计算结果返回。
2、属性的两种定义方式
属性的定义有两种方式:
- 装饰器 即:在方法上应用装饰器
- 类变量 即:在类中定义值为property对象的类变量
装饰器方式:在类的普通方法上应用@property装饰器
我们知道Python中的类有经典类和新式类,新式类的属性比经典类的属性丰富。( 如果类继object,那么该类是新式类 )
经典类,具有一种@property装饰器(如上一步实例)


1 # ############### 定义 ############### 2 class Goods: 3 4 @property 5 def price(self): 6 return "wupeiqi" 7 # ############### 调用 ############### 8 obj = Goods() 9 result = obj.price # 自动执行 @property 修饰的 price 方法,并获取方法的返回值
新式类,具有三种@property装饰器


1 # ############### 定义 ############### 2 class Goods(object): 3 4 @property 5 def price(self): 6 print '@property' 7 8 @price.setter 9 def price(self, value): 10 print '@price.setter' 11 12 @price.deleter 13 def price(self): 14 print '@price.deleter' 15 16 # ############### 调用 ############### 17 obj = Goods() 18 19 obj.price # 自动执行 @property 修饰的 price 方法,并获取方法的返回值 20 21 obj.price = 123 # 自动执行 @price.setter 修饰的 price 方法,并将 123 赋值给方法的参数 22 23 del obj.price # 自动执行 @price.deleter 修饰的 price 方法
注:经典类中的属性只有一种访问方式,其对应被 @property 修饰的方法
新式类中的属性有三种访问方式,并分别对应了三个被@property、@方法名.setter、@方法名.deleter修饰的方法
由于新式类中具有三种访问方式,我们可以根据他们几个属性的访问特点,分别将三个方法定义为对同一个属性:获取、修改、删除


1 class Goods(object): 2 3 def __init__(self): 4 # 原价 5 self.original_price = 100 6 # 折扣 7 self.discount = 0.8 8 9 @property 10 def price(self): 11 # 实际价格 = 原价 * 折扣 12 new_price = self.original_price * self.discount 13 return new_price 14 15 @price.setter 16 def price(self, value): 17 self.original_price = value 18 19 @price.deltter 20 def price(self, value): 21 del self.original_price 22 23 obj = Goods() 24 obj.price # 获取商品价格 25 obj.price = 200 # 修改商品原价 26 del obj.price # 删除商品原价 27 28 实例
类变量方式,创建值为property对象的类变量
当使用类变量的方式创建属性时,经典类和新式类无区别
1 class Foo: 2 3 def get_bar(self): 4 return 'wuweizhen' 6 BAR = property(get_bar) 7 8 obj = Foo() 9 reuslt = obj.BAR # 自动调用get_bar方法,并获取方法的返回值 10 print reuslt
property的构造方法中有个四个参数
- 第一个参数是方法名,调用
对象.属性
时自动触发执行方法 - 第二个参数是方法名,调用
对象.属性 = XXX
时自动触发执行方法 - 第三个参数是方法名,调用
del 对象.属性
时自动触发执行方法 - 第四个参数是字符串,调用
对象.属性.__doc__
,此参数是该属性的描述信息


1 class Foo: 2 3 def get_bar(self): 4 return 'wupeiqi' 5 6 # *必须两个参数 7 def set_bar(self, value): 8 return return 'set value' + value 9 10 def del_bar(self): 11 return 'wupeiqi' 12 13 BAR = property(get_bar, set_bar, del_bar, 'description...') 14 15 obj = Foo() 16 17 obj.BAR # 自动调用第一个参数中定义的方法:get_bar 18 obj.BAR = "alex" # 自动调用第二个参数中定义的方法:set_bar方法,并将“alex”当作参数传入 19 del Foo.BAR # 自动调用第三个参数中定义的方法:del_bar方法 20 obj.BAE.__doc__ # 自动获取第四个参数中设置的值:description...
由于类变量方式创建属性具有三种访问方式,我们可以根据他们几个属性的访问特点,分别将三个方法定义为对同一个属性:获取、修改、删除


1 class Goods(object): 2 3 def __init__(self): 4 # 原价 5 self.original_price = 100 6 # 折扣 7 self.discount = 0.8 8 9 def get_price(self): 10 # 实际价格 = 原价 * 折扣 11 new_price = self.original_price * self.discount 12 return new_price 13 14 def set_price(self, value): 15 self.original_price = value 16 17 def del_price(self, value): 18 del self.original_price 19 20 PRICE = property(get_price, set_price, del_price, '价格属性描述...') 21 22 obj = Goods() 23 obj.PRICE # 获取商品价格 24 obj.PRICE = 200 # 修改商品原价 25 del obj.PRICE # 删除商品原价 26 27 实例
注意:Python WEB框架 Django 的视图中 request.POST 就是使用的类变量的方式创建的属性
新式类和经典类


1 #!/user/bin/env python 2 ''' 3 class A(): #新式类 4 n = 'A' 5 ''' 6 class A: #经典类 7 n = 'A' 8 def f2(self): 9 print('from A') 10 class B(A): 11 n = 'B' 12 def f1(self): 13 print('from B') 14 def f2(self): 15 print('F2 from B') 16 class C(A): 17 n = 'C' 18 def f2(self): 19 print("from C") 20 class D(B,C): 21 pass 22 d = D() 23 d.f1() 24 d.f2()
d.f2继承A,B,C中谁呢,首先是B,没有则是C,最后是A,因为新式类是广度继承,因为B和C是同一级别,而经典类是深度,继承B之后继承A,聪明的同学就看到了代码中写的class A是经典类形式的,为什么还是广度继承呢,因为我用的是python 3.x自动修复这个问题,python 2.x依然会深度继承。
类的特殊成员
上文介绍了Python的类成员以及成员修饰符,从而了解到类中有字段、方法和属性三大类成员,并且成员名前如果有两个下划线,则表示该成员是私有成员,私有成员只能由类内部调用。无论人或事物往往都有不按套路出牌的情况,Python的类成员也是如此,存在着一些具有特殊含义的成员,详情如下:
1. __doc__
表示类的描述信息
1 class Foo: 2 """ 描述类信息,这是用于看片的神奇 """ 3 4 def func(self): 5 pass 6 7 print Foo.__doc__ 8 #输出:类的描述信息
2. __module__ 和 __class__
__module__ 表示当前操作的对象在那个模块
__class__ 表示当前操作的对象的类是什么


1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 class C: 5 6 def __init__(self): 7 self.name = 'wuweizhen'


1 from lib.aa import C 2 3 obj = C() 4 print obj.__module__ # 输出 lib.aa,即:输出模块 5 print obj.__class__ # 输出 lib.aa.C,即:输出类
3. __init__
构造方法,通过类创建对象时,自动触发执行。


1 class Foo: 2 3 def __init__(self, name): 4 self.name = name 5 self.age = 18 6 7 8 obj = Foo('wupeiqi') # 自动执行类中的 __init__ 方法
4. __del__
析构方法,当对象在内存中被释放时,自动触发执行。
注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。


1 class Foo: 2 3 def __del__(self): 4 pass
5. __call__
对象后面加括号,触发执行。
注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()


1 class Foo: 2 3 def __init__(self): 4 pass 5 6 def __call__(self, *args, **kwargs): 7 8 print '__call__' 9 10 11 obj = Foo() # 执行 __init__ 12 obj() # 执行 __call__
6. __dict__
类或对象中的所有成员
上文中我们知道:类的普通字段属于对象;类中的静态字段和方法等属于类,即:
7.__new__ 和 __metaclass__
阅读以下代码:
1 class Foo(object): 2 3 def __init__(self): 4 pass 5 6 obj = Foo() # obj是通过Foo类实例化的对象
上述代码中,obj 是通过 Foo 类实例化的对象,其实,不仅 obj 是一个对象,Foo类本身也是一个对象,因为在Python中一切事物都是对象。
如果按照一切事物都是对象的理论:obj对象是通过执行Foo类的构造方法创建,那么Foo类对象应该也是通过执行某个类的 构造方法 创建。
1 print type(obj) # 输出:表示,obj 对象由Foo类创建 2 print type(Foo) # 输出:表示,Foo类对象由 type 类创建
所以,obj对象是Foo类的一个实例,Foo类对象是 type 类的一个实例,即:Foo类对象 是通过type类的构造方法创建。
那么,创建类就可以有两种方式:
a). 普通方式
1 class Foo(object): 2 3 def func(self): 4 print 'hello wupeiqi'
b).特殊方式(type类的构造函数)
1 def func(self): 2 print 'hello wupeiqi' 3 4 Foo = type('Foo',(object,), {'func': func}) 5 #type第一个参数:类名 6 #type第二个参数:当前类的基类 7 #type第三个参数:类的成员
==》 类 是由 type 类实例化产生
那么问题来了,类默认是由 type 类实例化产生,type类中如何实现的创建类?类又是如何创建对象?
答:类中有一个属性 __metaclass__,其用来表示该类由 谁 来实例化创建,所以,我们可以为 __metaclass__ 设置一个type类的派生类,从而查看 类 创建的过程。


1 class MyType(type): 2 3 def __init__(self, what, bases=None, dict=None): 4 super(MyType, self).__init__(what, bases, dict) 5 6 def __call__(self, *args, **kwargs): 7 obj = self.__new__(self, *args, **kwargs) 8 9 self.__init__(obj) 10 11 class Foo(object): 12 13 __metaclass__ = MyType 14 15 def __init__(self, name): 16 self.name = name 17 18 def __new__(cls, *args, **kwargs): 19 return object.__new__(cls, *args, **kwargs) 20 21 # 第一阶段:解释器从上到下执行代码创建Foo类 22 # 第二阶段:通过Foo类创建obj对象 23 obj = Foo()
反射
反射的简单含义:
通过类名获得类的实例对象
通过方法名得到方法,实现调用


1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 import sys 4 class WebServer(object): 5 def __init__(self,host,port): 6 self.host = host 7 self.port = port 8 def start(self): 9 print("Server is starting...") 10 def stop(self): 11 print("Server is stopping..") 12 def restart(self): 13 self.stop() 14 self.start() 15 def test_run(self,name): 16 print("running....",name,self.host) 17 18 if __name__ == "__main__": 19 server = WebServer('localhost',333) 20 if hasattr(server,sys.argv[1]): #判断用户输入的在不在server里,返回一个布尔值 21 func = getattr(server,sys.argv[1]) #判断server里面有没有用户输入的方法 22 func() 23 #setattr(server,'run',test_run) #把tes__run关联到server里 24 #server.run(server,'wu') 25 delattr(WebServer,'restart') #删除restart方法 26 print(server.restart)