Python之路【第五篇续】:面向对象编程二
类成员
一、字段
字段包括:普通字段和静态字段,他们在定义和使用中有所区别,而最本质的区别是内存中保存的位置不同,
普通字段属于对象
静态字段属于类
#!/usr/bin/env python #-*- coding:utf-8 -*- class Dbcontrl(object): action = 'contrl' def __init__(self,hostname,port,username,password,dbname,arg): self.hostname = hostname self.port = port self.username = username self.password = password self.dbname = dbname self.arg = arg def fetch(self): #连接数据库 hostname,prot,username,password,dbname #打开 #操作 #关闭 def modify(self): #连接数据库 hostname,prot,username,password,dbname #打开 #操作 #关闭 def remove(self): #连接数据库 hostname,prot,username,password,dbname #打开 #操作 #关闭 def create(self): #连接数据库 hostname,prot,username,password,dbname #打开 #操作 #关闭 obj1 = Dbcontrl('1.1.1.1',80,'tianshuai','shuaige','testdb',[11,22,33,44,]) print obj1.dbname #普通字段的调用方法 Dbcontrl.action #静态字段的调用方法
由上述代码可以看出【普通字段需要通过对象来访问】【静态字段通过类访问】,在使用上可以看出普通字段和静态字段的归属是不同的。
静态字段属于类,且仅保留一份,普通字段保存在对象中!
二、方法
方法包含:普通方法、静态方法、类方法,他们在内存中都属于类,只是调用方式不同。
#!/usr/bin/env python #-*- coding:utf-8 -*- class Dbcontrl(object): action = 'contrl' def __init__(self,hostname,port,username,password,dbname,arg): self.hostname = hostname self.port = port self.username = username self.password = password self.dbname = dbname self.arg = arg def modify(self): pass #连接数据库 hostname,prot,username,password,dbname #打开 #操作 #关闭 @staticmethod def tools_db(): pass """ 定义静态方法 ,无默认参数""" @classmethod def class_func(cls): pass """ 定义类方法,至少有一个cls参数 """ obj1 = Dbcontrl('1.1.1.1',80,'tianshuai','shuaige','testdb',[11,22,33,44,]) obj1.modify() #调用普通方法 Dbcontrl.tools_db() #调用静态方法 Dbcontrl.class_func() #调用类方法
普通方法:由对象调用;至少一个self参数;执行普通方法时,自动将调用该方法的对象赋值给self;
比如:调用obj1.modify() 在调用的时候就相当于把对象赋值给方法:Dbcontrl.modify(obj1) 他的触发者是对象!
类方法:由类调用; 至少一个cls参数;执行类方法时,自动将调用该方法的类复制给cls;
类方法的触发者是类,当类在触发的时候,把自己当作参数传给cls = class
类方法很少用!
静态方法:由类调用;无默认参数;
其实你在类中使用静态方法:类+静态方法其实就等于一个函数!
触发者是类,常用于一个工具类,在调用的时候不需要实例化!举例来说有个工具类,如果是普通方法每次调用的都需要实例化,如果有非常非常多的人来调用难道每次都需要实例化吗?浪费内存空间,用静态方法那么你在调用的时候就不需要实例化他了!
三、属性
在python中属性的使用是非常少的,但是在其他的语言中属性用的非常多,因为在python中属性是后来才有的,他的功能目前还不是很强大!
但是他要告诉人们我也是支持属性的,所以才有了这个属性!
属性由方法变种而来,如果Python中没有属性,方法完全可以代替其功能。
属性存在意义是:访问属性时可以制造出和访问字段完全相同的假象
1、属性的基本使用
例子:摘自武老师的博客:
# ############### 定义 ############### class Pager: def __init__(self, current_page): # 用户当前请求的页码(第一页、第二页...) self.current_page = current_page # 每页默认显示10条数据 self.per_items = 10 @property def start(self): val = (self.current_page - 1) * self.per_items return val @property def end(self): val = self.current_page * self.per_items return val # ############### 调用 ############### p = Pager(1) p.start 就是起始值,即:m p.end 就是结束值,即:n
从上述可见,Python的属性的功能是:属性内部进行一系列的逻辑计算,最终将计算结果返回
2、属性的两种定义方式
属性的定义有两种方式:
装饰器 即:在方法上应用装饰器
静态字段 即:在类中定义值为property对象的静态字段
装饰器方式:在类的普通方法上应用@property装饰器
Python中的类有经典类和新式类,新式类的属性比经典类的属性丰富。( 如果类继object,那么该类是新式类 )
经典类 具有一种@property装饰器
# ############### 定义 ############### class Goods: @property def price(self): return "wupeiqi" # ############### 调用 ############### obj = Goods() result = obj.price # 自动执行 @property 修饰的 price 方法,并获取方法的返回值
新式类,具有三种@property装饰器
# ############### 定义 ############### class Goods(object): @property def price(self): print '@property' @price.setter def price(self, value): print '@price.setter' @price.deleter def price(self): print '@price.deleter' # ############### 调用 ############### obj = Goods() obj.price # 自动执行 @property 修饰的 price 方法,并获取方法的返回值 obj.price = 123 # 自动执行 @price.setter 修饰的 price 方法,并将 123 赋值给方法的参数 del obj.price # 自动执行 @price.deleter 修饰的 price 方法
经典类中的属性只有一种访问方式,其对应被 @property 修饰的方法,新式类中的属性有三种访问方式,并分别对应了三个被@property、@方法名.setter、@方法名.deleter修饰的方法
静态字段方式,创建值为property对象的静态字段当使用静态字段的方式创建属性时,经典类和新式类无区别
class Foo: def get_bar(self): return 'wupeiqi' BAR = property(get_bar) obj = Foo() reuslt = obj.BAR # 自动调用get_bar方法,并获取方法的返回值 print reuslt
property的构造方法中有个四个参数
- 第一个参数是方法名,调用
对象.属性
时自动触发执行方法 - 第二个参数是方法名,调用
对象.属性 = XXX
时自动触发执行方法 - 第三个参数是方法名,调用
del 对象.属性
时自动触发执行方法 - 第四个参数是字符串,调用
对象.属性.__doc__
,此参数是该属性的描述信息
class Foo: def get_bar(self): return 'wupeiqi' # *必须两个参数 def set_bar(self, value): return return 'set value' + value def del_bar(self): return 'wupeiqi' BAR = property(get_bar, set_bar, del_bar, 'description...') obj = Foo() obj.BAR # 自动调用第一个参数中定义的方法:get_bar obj.BAR = "alex" # 自动调用第二个参数中定义的方法:set_bar方法,并将“alex”当作参数传入 del Foo.BAR # 自动调用第三个参数中定义的方法:del_bar方法 obj.BAE.__doc__ # 自动获取第四个参数中设置的值:description...
所以,定义属性共有两种方式,分别是【装饰器】和【静态字段】,而【装饰器】方式针对经典类和新式类又有所不同。
类成员修饰符
类的所有成员在上一步骤中已经做了详细的介绍,对于每一个类的成员而言都有两种形式
公有
私有
从字面上就能看出来,公有是外面的、内部的、和继承的都可以访问。
私有:仅在内部可以访问! 私有成员命名时,前两个字符是下划线。(特殊成员除外,例如:__init__、__call__、__dict__等)
class C: def __init__(self): self.name = '公有字段' self.__foo = "私有字段"
只要记住,私有成员是不能被外面访问的,仅能在内部访问,如果外面想访问私有的成员的可以通过间接的方式访问!
PS:如果想要强制访问私有字段,可以通过 【对象._类名__私有字段明 】访问(如:obj._C__foo),不建议强制访问私有成员。
类的特殊成员
1. __doc__ 表示类的描述信息
class Foo: """ 描述类信息,这是用于看片的神奇 """ def func(self): pass print Foo.__doc__ #输出:类的描述信息
2. __module__ 和 __class__
__module__ 表示当前操作的对象在那个模块
__class__ 表示当前操作的对象的类是什么
#!/usr/bin/env python # -*- coding:utf-8 -*- class C: def __init__(self): self.name = 'tianshuai'
from lib.aa import C obj = C() print obj.__module__ # 输出 lib.aa,即:输出模块 print obj.__class__ # 输出 lib.aa.C,即:输出类
3. __init__ 构造方法,通过类创建对象时,自动触发执行。
class Dbcontrl(object): action = 'contrl' def __init__(self,hostname,port,username,password,dbname,arg): self.hostname = hostname self.port = port self.username = username self.password = password self.dbname = dbname self.arg = arg obj1 = Dbcontrl('1.1.1.1',80,'tianshuai','shuaige','testdb',[11,22,33,44,]) #实例化的时候,构造方法自动执行!
4. __del__ 析构方法,当对象在内存中被释放时,自动触发执行,是程序自动执行的不需要人为参与
注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。
class Foo: def __del__(self): pass
5. __call__ 对象或类后面加括号,触发执行。
PS:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
class Foo: def __init__(self): pass def __call__(self, *args, **kwargs): print '__call__' obj = Foo() # 执行 __init__ obj() # 执行 __call__
6. __dict__ 类或对象中的所有成员,把类中的成员以字典的形式打印出来
class Province: country = 'China' def __init__(self, name, count): self.name = name self.count = count def func(self, *args, **kwargs): print 'func' # 获取类的成员,即:静态字段、方法、 print Province.__dict__ # 输出:{'country': 'China', '__module__': '__main__', 'func': <function func at 0x10be30f50>, '__init__': <function __init__ at 0x10be30ed8>, '__doc__': None} obj1 = Province('HeBei',10000) print obj1.__dict__ # 获取 对象obj1 的成员 # 输出:{'count': 10000, 'name': 'HeBei'} obj2 = Province('HeNan', 3888) print obj2.__dict__ # 获取 对象obj1 的成员 # 输出:{'count': 3888, 'name': 'HeNan'}
7. __str__ 如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值。
class Foo: def __str__(self): return 'wupeiqilaoshi' obj = Foo() print obj # 输出:wupeiqilaoshi
8、__getitem__、__setitem__、__delitem__ 用于索引操作,如字典。以上分别表示获取、设置、删除数据
#!/usr/bin/env python # -*- coding:utf-8 -*- class Foo(object): def __getitem__(self, key): print '__getitem__',key def __setitem__(self, key, value): print '__setitem__',key,value def __delitem__(self, key): print '__delitem__',key obj = Foo() result = obj['k1'] # 自动触发执行 __getitem__ obj['k2'] = 'wupeiqi' # 自动触发执行 __setitem__ del obj['k1'] # 自动触发执行 __delitem__
9、__getslice__、__setslice__、__delslice__该三个方法用于分片操作,如:列表
#!/usr/bin/env python # -*- coding:utf-8 -*- class Foo(object): def __getslice__(self, i, j): print '__getslice__',i,j def __setslice__(self, i, j, sequence): print '__setslice__',i,j def __delslice__(self, i, j): print '__delslice__',i,j obj = Foo() obj[-1:1] # 自动触发执行 __getslice__ obj[0:1] = [11,22,33,44] # 自动触发执行 __setslice__ del obj[0:2] # 自动触发执行 __delslice__
10. __iter__ 用于迭代器,之所以列表、字典、元组可以进行for循环,是因为类型内部定义了 __iter__
#没有定义__iter__方法会报错!不能迭代 class Foo(object): pass obj = Foo() for i in obj: print i # 报错:TypeError: 'Foo' object is not iterable #定义了__iter__方法但是没有设置值也会报错 #!/usr/bin/env python # -*- coding:utf-8 -*- class Foo(object): def __iter__(self): pass obj = Foo() for i in obj: print i # 报错:TypeError: iter() returned non-iterator of type 'NoneType' #定义了__iter__方法并且定义了参数 #!/usr/bin/env python # -*- coding:utf-8 -*- class Foo(object): def __init__(self, sq): self.sq = sq def __iter__(self): return iter(self.sq) obj = Foo([11,22,33,44]) for i in obj: print i 输出结果: ''' 11 22 33 44 '''
11、__new__ 和 __metaclass__
都知道python中一切实物都是对象,对象又是有类创建的! 那么类是什么?谁创建的类呢?
python中一切事物都是对象,那么类也是一个对象,既然他是一个对象,那么肯定也有一个创建他的类!!!!
class Foo(object): def __init__(self): pass obj = Foo() # obj是通过Foo类实例化的对象
print type(obj) # 输出:<class '__main__.Foo'> 表示,obj 对象由Foo类创建 print type(Foo) # 输出:<type 'type'> 表示,Foo类对象由 type 类创建
所以,obj对象是Foo类的一个实例,Foo类对象是 type 类的一个实例,即:Foo类对象 是通过type类的构造方法创建。
普通方法创建
class Foo(object): def func(self): print 'hello wupeiqi'
特殊方式(type类的构造函数)
def func(self): print 'hello wupeiqi' Foo = type('Foo',(object,), {'func': func}) #type第一个参数:类名 #type第二个参数:当前类的基类 #type第三个参数:类的成员
小总结:类是有type类实例化产生的
那么问题来了,类默认是由 type 类实例化产生,type类中如何实现的创建类?类又是如何创建对象?
类中有一个属性 __metaclass__,其用来表示该类由 谁 来实例化创建,所以,我们可以为 __metaclass__ 设置一个type类的派生类,从而查看 类 创建的过程。由 type 类实例化产生!
武老师画的这个图太NICE了!http://www.cnblogs.com/wupeiqi/p/4766801.html
上面的图需要了解__init__、__call__
部分内容摘自武老师的博客:http://www.cnblogs.com/wupeiqi/p/4766801.html