标签:
本篇将详细介绍Python 类的成员、成员修饰符、类的特殊成员。
子类有init方法,父类也有init方法和各种属性,,要想让子类也 继承并封装父类的init的属性。
1 #!/usr/bin/env python 2 #-*- coding:utf-8 -*- 3 __author__ = ‘wyf‘ 4 5 6 class Annimal: 7 def __init__(self): 8 print ‘A构造方法‘ 9 self.ty = ‘动物‘ 10 11 class Cat(Annimal): 12 def __init__(self): 13 print ‘B构造方法‘ 14 self.n = ‘猫‘ 15 # #执行父类的构造方法1,推荐这种 继承父类的init所有属性 记住self的位置。由super解决 16 super(Cat,self).__init__() 17 # #执行父类的构造方法2 18 #Annimal.__init__(self) 19 a = Cat() 20 print a.__dict__
#!/usr/bin/env python #-*- coding:utf-8 -*- __author__ = ‘wyf‘ class Foo: def __init__(self,name): self.name = name def show(self): print ‘showwwww‘ obj = Foo(‘alex‘) r = hasattr(obj,‘name‘) print ‘r=‘,r c = hasattr(obj,‘show‘) print ‘c=‘,c a = hasattr(Foo,‘name‘) print ‘a=‘,a b = hasattr(Foo,‘show‘) print ‘b=‘,b #反射 #以字符串的形式去对象(模块)中操作其成员 #反射:类,只能找类里的成员 #反射:对象,既可以找对象,找类的成员
类的成员可以分为三大类:字段、方法和属性
注:所有成员中,只有普通字段的内容保存对象中,即:根据此类创建了多少对象,在内存中就有多少个普通字段。而其他的成员,则都是保存在类中,即:无论对象的多少,在内存中只创建一份。
字段包括:普通字段和静态字段,他们在定义和使用中有所区别,而本质上的区别是内存中保存的位置不同,
#!/usr/bin/env python #-*- coding:utf-8 -*- __author__ = ‘wyf‘ class Province: # 静态字段 country = ‘中国‘ def __init__(self, name): # 普通字段 self.name = name # 直接访问普通字段 obj = Province(‘河北省‘) #print obj.name #print Province.name#报错,类不可以访问对象的字段 # 直接访问静态字段 print obj.country #对象可以访问静态字段 print Province.country #类可以访问静态字段,建议用类访问的方式
由上述代码可以看出【普通字段需要通过对象来访问】【静态字段通过类访问】,在使用上可以看出普通字段和静态字段的归属是不同的。其在内容的存储方式类似如下图:
由上图可知:
静态字段在内存中只保存一份,静态字段在每个对象中都要保存一份。
应用场景:通过类创建对象时,如果每个对象都具有相同的字段,那么就使用静态字段。
方法包括:普通方法、静态方法和类方法,三种方法在内存中都归属于类,区别在于调用方式不同。
比如:调用obj1.modify() 在调用的时候就相当于把对象赋值给方法:Dbcontrl.modify(obj1) 他的触发者是对象!
类方法的触发者是类,当类在触发的时候,把自己当作参数传给cls = clas;类方法很少用!
其实你在类中使用静态方法:类+静态方法其实就等于一个函数!
触发者是类,常用于一个工具类,在调用的时候不需要实例化!举例来说有个工具类,如果是普通方法每次调用的都需要实例化,如果有非常非常多的人来调用难道每次都需要实例化吗?浪费内存空间,用静态方法那么你在调用的时候就不需要实例化他了!
#!/usr/bin/env python #-*- coding:utf-8 -*- __author__ = ‘wyf‘ class Foo: def __init__(self,name): self.name =name def func(self): """ 定义普通方法,至少有一个self参数 """ print ‘普通方法,‘,self.name @classmethod def class_func(cls): """ 定义类方法,至少有一个cls参数 """ print ‘类方法‘ @staticmethod def static_func(): """ 定义静态方法 ,无默认参数""" print ‘静态方法‘ f = Foo(‘haha‘) #调用普通方法 f.func() #调用类方法 Foo.class_func() #调用静态方法 Foo.static_func()
相同点:对于所有的方法而言,均属于类(非对象)中,所以,在内存中也只保存一份。
不同点:方法调用者不同、调用方法时自动传入的参数不同。
如果你已经了解Python类中的方法,那么属相就非常简单了,因为Python中的属性其实是普通方法的变种。
对于属性,有以下三个知识点:
#特性 @propety可以使用对象向访问字段一样访问这个方法。
#@特性方法名.setter 设置方法的返回值
Property装饰函数调用的时候用类调用,并执行无需创建对象,也不用加括号
1 #!/usr/bin/env python 2 #-*- coding:utf-8 -*- 3 __author__ = ‘wyf‘ 4 5 class Foo: 6 7 def func(self): 8 pass 9 10 #定义属性 11 @property 12 def prop(self): 13 print ‘1234‘ 14 15 foo_obj = Foo() 16 foo_obj.func() 17 foo_obj.prop #调用属性,可以用调用实例属性的方式调用方法
由属性的定义和调用要注意一下几点:
方法:foo_obj.func()
属性:foo_obj.prop
注意:属性存在意义是:访问属性时可以制造出和访问字段完全相同的假象
属性由方法变种而来,如果Python中没有属性,方法完全可以代替其功能。
实例:对于主机列表页面,每次请求不可能把数据库中的所有内容都显示到页面上,而是通过分页的功能局部显示,所以在向数据库中请求数据时就要显示的指定获取从第m条到第n条的所有数据(即:limit m,n),这个分页的功能包括:
#!/usr/bin/env python #-*- coding:utf-8 -*- __author__ = ‘wyf‘ #############定义############### 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的属性的功能是:属性内部进行一系列的逻辑计算,最终将计算结果返回。
属性的定义方式有两种方式:
装饰器方式:在类的普通方法上应用@property装饰器
python中的类有经典类和新式类,新式类的属性比经典类的属性丰富。如果继承object,那么该类就是新式类)
经典类 具有一种@property修饰器
1 # ############### 定义 ############### 2 class Goods: 3 4 @property 5 def price(self): 6 return "test123" 7 # ############### 调用 ############### 8 obj = Goods() 9 result = obj.price # 自动执行 @property 修饰的 price 方法,并获取方法的返回值
新式类,具有三种@property装饰器
1 #!/usr/bin/env python 2 #-*- coding:utf-8 -*- 3 __author__ = ‘wyf‘ 4 5 6 class Goods(object): 7 8 @property 9 def price(self): 10 print ‘@property‘ 11 12 @price.setter 13 def price(self,value): 14 print ‘value=‘,value 15 print ‘@price.setter‘ 16 17 @price.deleter 18 def price(self): 19 print ‘@price.deleter‘ 20 21 ###############调用############### 22 obj = Goods() 23 24 obj.price #自动执行@property修饰的 price方法,并获取方法的返回值 25 obj.price = 123 #自动执行 @price.setter修饰的 price方法,并将123赋值给方法的参数 26 27 del obj.price #自动执行@price.deleter 修饰的price方法
经典类中的属性只有一种访问方式,其对应被 @property 修饰的方法,新式类中的属性有三种访问方式,并分别对应了三个被@property、@方法名.setter、@方法名.deleter修饰的方法
#!/usr/bin/env python #-*- coding:utf-8 -*- __author__ = ‘wyf‘ class Goods(object): def __init__(self): # 原价 self.original_price = 100 # 折扣 self.discount = 0.8 @property def price(self): # 实际价格 = 原价 * 折扣 new_price = self.original_price * self.discount return new_price @price.setter def price(self, value): self.original_price = value @price.deleter def price(self): del self.original_price obj = Goods() print obj.price # 获取商品价格 obj.price = 200 # 修改商品原价 print obj.price del obj.price # 删除商品原价
静态字段方式,创建值为property对象的静态字段
当使用静态字段的方式创建属性时,经典类和新式类无区别
1 class Foo: 2 def get_bar(self): 3 return ‘test123‘ 4 5 BAR = property(get_bar) 6 7 obj = Foo() 8 result = obj.BAR #自动调用get_bar方法,并获取方法的返回值 9 print result
property的构造方法中有个四个参数
对象.属性
时自动触发执行方法对象.属性 = XXX
时自动触发执行方法del 对象.属性
时自动触发执行方法对象.属性.__doc__
,此参数是该属性的描述信息class Foo(object): def get_bar(self): return ‘test123‘ #* 必须两个参数 def set_bar(self,value): print ‘set value:‘,value def del_bar(self): print ‘11223‘ BAR = property(get_bar,set_bar,del_bar,‘description...‘) obj = Foo() print obj.BAR #自动调用第一个阐述定义的方法:get_bar obj.BAR = ‘alex‘ #自动调用第二个参数中定义的方法:set_bar 方法,并将’alex‘当做参数传入 del obj.BAR #自动调用第三个参数中定义的方法:del_bar 方法 print obj.BAR.__doc__ #自动获取第四个参数中设置的值:description...
所以,定义属性共有两种方式,分别是【装饰器】和【静态字段】,而【装饰器】方式针对经典类和新式类又有所不同。
类的所有成员在上一步骤中已经做了详细的介绍,对于每一个类的成员而言都有两种形式:
私有成员和公有成员的定义不同:私有成员命名时,前两个字符是下划线。(特殊成员除外,例如:__init__、__call__、__dict__等)
class C: def __init__(self): self.name = ‘公有字段‘ self.__foo = ‘私有字段‘
需要谨记,私有成员是不能被外面访问的,仅能在内部访问,如果外面想访问私有的成员的可以通过间接的方式访问!
ps:如果想要强制访问私有字段,可以通过[对象._类名__私有字段]访问(如:obj._c__foo),不建议强制访问私有成员。
私有静态字段:
class C: name = ‘公有静态字段‘ def func(self): print C.name class D(C): def show(self): print C.name C.name #类访问 obj = C() obj.func() #类内部可以访问 obj_son = D() obj_son.show() #派生类中可以访问
class C: def __init__(self): self.__foo = ‘私有字段‘ def func(self): print self.__foo #类内部访问 class D(C): def show(self): print self.foo #派生类中访问 obj = C() obj.__foo #通过对象访问 ==》错误 obj.func() #类内部访问 ==》正确 obj_son = D() obj_son.show() #派生类中访问 ==》错误
上文介绍了Python的类成员以及成员修饰符,从而了解到类中有字段、方法和属性三大 类成员,并且成员名前如果有两个下划线,则表示该成员是私有成员,私有成员只能由类内部调用。无论人或事物往往都有不按套路出牌的情况,Python的类 成员也是如此,存在着一些具有特殊含义的成员,详情如下:
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 = ‘111111‘
from lib.aa import C obj =C() print obj.__module__ #输出模块 print obj.__class__ #输出类
3.__init__
构造方法,通过类创建对象时,自动触发执行。
class Foo: def __init__(self, name): self.name = name self.age = 18 obj = Foo(‘xiaoxiao‘) # 自动执行类中的 __init__ 方法
4.__del__
析构方法,当对象在内存中被释放时,自动触发执行
注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。
class Foo: def __del__(self): pass
5.__call__
对象后面加括号,触发执行。
注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
#!/usr/bin/env python #-*- coding:utf-8 -*- __author__ = ‘wyf‘ class Foo: def __init__(self): print ‘init‘ def __call__(self, *args, **kwargs): print ‘call‘ return 1 def __getitem__(self, item): print ‘item=‘,item def __setitem__(self, key, value): print ‘key=‘,key print ‘value=‘,value def __delitem__(self, key): print ‘delkey=‘,key r = Foo() #__init__方法 r() #__call__方法 r[‘abc‘] #__getitem__方法 #当对象这样执行的时候,会执行__getitem__方法,同事将‘abc‘参数传入到里面 r[‘abc‘] = 123 #__setitem__方法 #当使用赋值的方式执行的时候,需要使用__getitem__方法,期中会以kv的方式传入变量 del r[‘sdasdasdasdsadsadasdasdasd ‘] #__delitem__方法,前面加一个del的时候,会执行__delitem__方法 #在类对象后面加()会生成一个实例 #在实例对象后面加()会生执行__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 ‘haha‘ obj = Foo() print obj
8.__getitem__、__setitem__、__delitem__
用于索引操作,如字典。以上分别表示获取、设置、删除数据,在看这个方法的时候请自己思考列表的操作
如:a = [1,2,3,4], a[0] 取值,字典dict[‘abc‘]=123,列表的删除 del obj[‘k1‘]
#!/usr/bin/env python #-*- coding:utf-8 -*- __author__ = ‘wyf‘ class Foo: def __init__(self): print ‘init‘ def __call__(self, *args, **kwargs): print ‘call‘ return 1 def __getitem__(self, item): print ‘item=‘,item def __setitem__(self, key, value): print ‘key=‘,key print ‘value=‘,value def __delitem__(self, key): print ‘delkey=‘,key r = Foo() #__init__方法 r() #__call__方法 r[‘abc‘] #__getitem__方法 #当对象这样执行的时候,会执行__getitem__方法,同事将‘abc‘参数传入到里面 r[‘abc‘] = 123 #__setitem__方法 #当使用赋值的方式执行的时候,需要使用__getitem__方法,期中会以kv的方式传入变量 del r[‘sdasdasdasdsadsadasdasdasd ‘] #__delitem__方法,前面加一个del的时候,会执行__delitem__方法 #在类对象后面加()会生成一个实例 #在实例对象后面加()会生执行__call__方法
9.__iter__
用于迭代器,之所以列表、字典、元组可以进行for循环,是因为类型内部定义了 __iter__
class Foo(object): pass obj = Foo() for i in obj: print i # 报错:TypeError: ‘Foo‘ object is not iterable
#!/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‘
#!/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
以上步骤可以看出,for循环迭代的其实是 iter([11,22,33,44]) ,所以执行流程可以变更为:
#!/usr/bin/env python # -*- coding:utf-8 -*- obj = iter([11,22,33,44]) for i in obj: print i
#!/usr/bin/env python # -*- coding:utf-8 -*- obj = iter([11,22,33,44]) while True: val = obj.next() print val
检查是否obj是否是类 cls 的对象,如果是则返回Ture,如果不是则返回False
1 class Foo(object): 2 3 def __init__(self, sq): 4 print ‘haha‘ 5 self.sq = sq 6 7 def __iter__(self): 8 print ‘__iter__‘ 9 return iter(self.sq) 10 class Foo1: 11 pass 12 obj = Foo(11) 13 obj1 = Foo1() 14 print isinstance(obj,Foo) #Ture 15 print isinstance(obj1,Foo)#False
检查sub类是否是 super 类的派生类,如果是则返回True
1 class Foo(object): 2 3 def __init__(self, sq): 4 print ‘haha‘ 5 self.sq = sq 6 7 def __iter__(self): 8 print ‘__iter__‘ 9 return iter(self.sq) 10 class Foo1(Foo): 11 pass 12 13 print issubclass(Foo1,Foo)
参考文章:http://www.cnblogs.com/liujianzuo888/articles/5556470.html
标签:
原文地址:http://www.cnblogs.com/chushiyaoyue/p/5625434.html