Python攻克之路-类的成员
1、类的成员之字段
描述:创建一个类,类里可以定义一个方法,在init里还有self.什么,self.什么,这叫做成员,在类里可以写什么,类中的方法与对象并没联系
class Foo: #代码从是到下执行创建了一个Foo类,Foo类里有一个init函数,还有一个show方法,当代码到show为止,都没有执行,因为没有调用, 相当于show方法整体保存在类里,如果创建一个对象时,这个对象会自动执行init方法,init方法写了self.name = name,self代指 的是当前的方法,name里保存传的值name='reid',它是保存在对象中 def __init__(self, name): self.name = name #self代指是对象,是保存在对象中,实际这种叫做字段,调用字段不用括号() def show(self): #方法 print(self.name) obj = Foo('reid') obj.name #字段直接可以调用 obj.show() #方法要加括号才可以调用
(1).字段分类
普通字段:self.what = what 保存在对象,只能通过对象访问
静态字段:保存在类中,执行可以通过对象访问,也可以通过类访问,只保留一份,如果被修改就是显示修改后的值
场景:列出中国所有省份,用面向对象的知识表示?
分析:要创建一个省份的类
class Province: country = 'china' #静态字段,属于类,与对象无关,代码从上到下执行,当执行到self.name=name,静态字段就被创建了 def __init__(self, name,country='china'): self.name = name #普通字段,属于对象,当p1 = Province('hainan')执行一次,这行代码就会被执行 #self.country = country p1 = Province('hainan') #省份中要保存一个值,它是中国的,也就是说每个省份都是中国的,每个省都保存了一份 p2 = Province('fujian') Province.country #它属于类,可以直接调用,但是不能通过类找对象如Province.name是找不到的 p1.name 使用对象访问 p1.country #对象也可以访问静态字段
2.类的成员之方法
方法:show整体保存在类
- 普通方法:保存在类中,由对象来调用,self是调用者对象
- 静态方法:保存在类中,由类直接调用
- 类方法: 保丰在类中,由类直接调用,cls是当前类
应用场景:
分析:对于普通方法要建立对象,才能访问它,所以对象也要内存
a.如果对象中需要保存一些值,调用方法时需要利用对象中的值时,就用普通方法,因为对象中是封装值的
b.如果要执行某个功能而不依赖其他的值,直接可以调用这个功能,要直接创建这个对象,这个对象是空的,通过对象调用,对象已经创建,但是里面什么值也没有,使用静态方法,与类方法差别不大,有个参数问题,如果在方法中会使用到当前类,不想自己写,使用类方法会帮忙传入,但是没有太大的功能
(1).普通
In [1]: class Foo: ...: def bar(self): ...: print('bar') ...: obj = Foo() ...: obj.bar() #通过对象访问方法,对象通过类对象指针找到这个方法,通过类也可以直接找到,推荐使用 ...: bar In [2]: obj=Foo() In [3]: Foo.bar(obj) #通过类来调用 bar
(2).静态
In [4]: class Foo: ...: def bar(self): ...: print('bar') ...: @staticmethod #装饰器,表示静态方法 ...: def sta(): #传入的参数self不是必需的,不用创建对象,直接使用类就可以调用 ...: print('static') ...: Foo.sta() ...: static 传参: In [6]: class Foo: ...: def bar(self): ...: print('bar') ...: @staticmethod ...: def sta(a1,a2): ...: print(a1,a2) ...: Foo.sta(2,3) 2 3
(3).类方法
In [3]: class Foo: ...: def bar(self): #self是对象 ...: print('bar') ...: @classmethod ...: def classmd(cls): #一定要有一个参数,不写self,要写成cls,它是类名,不依赖于对象 ...: print('classmd') ...: Foo.classmd() #并没传参数,但是有个cls是Python自动传入的参数,传入类名Foo ...: <class '__main__.Foo'> 主程序中的Foo类 classmd
3.成员属性:有方法的影子,也有字段的特性
注:访问时,字段不加括号,对于方法是加括号
In [2]: class Foo: ...: def __init__(self): #字段,obj.name ...: self.name = 'a' ...: def bar(self): #方法 ...: print('bar') ...: def per(self): ...: print('per') ...: obj = Foo() ...: obj.per() per In [3]: class Foo: ...: def __init__(self): ...: self.name = 'a' ...: def bar(self): ...: print('bar') ...: @property #加上装饰器后,不使用括号来调用 ...: def per(self): #定义时像方法,调用时像字段 ...: print('per') ...: obj = Foo() ...: obj.per per In [4]: class Foo: ...: def __init__(self): ...: self.name = 'a' ...: def bar(self): ...: print('bar') ...: @property ...: def per(self): ...: print('per') ...: return 1 #有返回值 ...: obj = Foo() ...: r = obj.per ...: print(r) per 1
(1).成员属性的赋值
描述:需要赋值就要有一个方法帮助接收,所以需要创建一个方法,希望赋值时,执行这个方法
In [9]: class Foo: ...: def __init__(self): ...: self.name = 'a' ...: def bar(self): ...: print('bar') ...: @property #用于执行obj.per ...: def per(self): #当执行r = obj.per时,会执行这个方法 ...: print('per') ...: return 1 ...: @per.setter #通过per来执行 ...: def per(self,val): #新建一个方法,当obj.per = 123时,执行这个方法 ...: print(val) ...: obj = Foo() ...: r = obj.per ...: print(r) ...: obj.per = 123 #重新赋值,无论是写,还是调用都是通过对象.per来执行 ...: ...: per 1 123
(2).删除的实现
分析:再定义一个方法来执行,函数时,定义一个函数名,函数名加个括号就可以执行,函数内的操作是自定义,这是python中规定的语法,这里写了一个类中的方法使用装饰器装饰了,通过对象点什么执行时,自动就会执行这个方法
[root@node2 class]# cat cls.py #!/usr/local/python3/bin/python3 class Foo: def __init__(self): self.name = 'a' def bar(self): print('bar') @property def per(self): print('per') return 1 @per.setter def per(self,val): print(val) @per.deleter ##目的是伪造和字段一样,这种操作不会真实的去获取数据 def per(self): print('del') obj = Foo() r = obj.per print(r) obj.per = 123 del obj.per [root@node2 class]# python3 cls.py per 1 123 del
(3).示例:利用属性实现分页
[root@node2 class]# cat page_show.py #!/usr/local/python3/bin/python3 li = [] for i in range(100): li.append(i) print(li[0:10]) [root@node2 class]# python3 page_show.py #如当输入1时,显示10条 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
编写起始和结尾页
[root@node2 class]# cat page_show.py #!/usr/local/python3/bin/python3 li = [] for i in range(100): li.append(i) p = input('input the page: ') #1,show 10 p = int(p) # 1, 0 to 10 # 2, 10 to 20 start = (p-1) * 10 #当p=1时,1-1=0,再乘以10,还是0 end = p * 10 #p=1时,1*10=10,也就是当输入1时,是1到10 print(li[0:10]) [root@node2 class]# cat page_show.py #!/usr/local/python3/bin/python3 li = [] for i in range(100): li.append(i) while True: p = input('input the page: ') #1,show 10 p = int(p) # 1, 0 to 10 # 2, 10 to 20 start = (p-1) * 10 end = p * 10 print(li[start:end]) [root@node2 class]# python3 page_show.py input the page: 1 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] input the page: 2 [10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
把start,end单独写成一个组件
分析:一般是放在终端上查看的,如果放在web框架会要做更多的操作,还要生成html的页码,所以要把它专门放到一个组件中完成,只需要调用它,它告诉结果就可以了,可以专门写一个类来实现
[root@node2 class]# cat page_show.py #!/usr/local/python3/bin/python3 class Pagecon: def __init__(self,current_page): self.page = int(current_page) def start(self): #使用两个方法来计算开始和结束的 val = (self.page-1) * 10 return val def end(self): val = self.page * 10 return val li = [] for i in range(100): li.append(i) while True: p = input('input the page: ') #1,show 10 obj = Pagecon(p) # 1, 0 to 10 # 2, 10 to 20 print(li[obj.start():obj.end()])
异常处理:当用户输入不是数字时,要做判断和处理
[root@node2 class]# cat page_show.py #!/usr/local/python3/bin/python3 class Pagecon: def __init__(self,current_page): try: #异常处理 p = int(current_page) #如果是传入1,就转换成数字1 except Exception as e: #如果传入是sdfljdsf,不是数字的,就会执行excetpion p = 1 #如果输入不会法,让它的默认值就是1 self.page = p # def start(self): val = (self.page-1) * 10 return val def end(self): val = self.page * 10 return val li = [] for i in range(100): li.append(i) while True: p = input('input the page: ') #1,show 10 obj = Pagecon(p) # 1, 0 to 10 # 2, 10 to 20 print(li[obj.start():obj.end()]) #方法的调用
属性处理时,可以更好的整理,不会太乱
[root@node2 class]# cat page_show.py #!/usr/local/python3/bin/python3 class Pagecon: def __init__(self,current_page): try: p = int(current_page) except Exception as e: p = 1 self.page = p @property ####### def start(self): val = (self.page-1) * 10 return val @property ####### def end(self): val = self.page * 10 return val li = [] for i in range(100): li.append(i) while True: p = input('input the page: ') #1,show 10 obj = Pagecon(p) # 1, 0 to 10 # 2, 10 to 20 print(li[obj.start:obj.end]) #调用时不用带括号 测试: [root@node2 class]# python3 page_show.py input the page: 1 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] input the page: 3 [20, 21, 22, 23, 24, 25, 26, 27, 28, 29] input the page: sdlk [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
4.属性的另一种写法
[root@node2 class]# cat pro.py #!/usr/local/python3/bin/python3 class Foo: def f1(self): return 123 per = property(fget=f1) obj = Foo() ret = obj.per #当执行这行代码时,fget=f1,所以自动执行def f1返回123 print(ret) [root@node2 class]# python3 pro.py 123
相同的写法
@property def per(self): return 123
设置多个参数
[root@node2 class]# cat pro.py #!/usr/local/python3/bin/python3 class Foo: def f1(self): return 123 def f2(self,v): #v来接收多一个参数 print(v) per = property(fget=f1,fset=f2) obj = Foo() #ret = obj.per #print(ret) obj.per = 123456 #赋值 [root@node2 class]# python3 pro.py 123456 [root@node2 class]# cat pro.py #!/usr/local/python3/bin/python3 class Foo: def f1(self): return 123 def f2(self,v): print(v) def f3(self): print('del') per = property(fget=f1,fset=f2,fdel=f3) ####最多三个值,最大三个函数,还有一个参数,doc=是注释 obj = Foo() #ret = obj.per #print(ret) #obj.per = 123456 del obj.per #### [root@node2 class]# python3 pro.py del
对应关系