博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
python 类,面向对象初探
阅读量:2268 次
发布时间:2019-05-09

本文共 16733 字,大约阅读时间需要 55 分钟。

概述:

面向对象   是一种编程方式(OOP Object Oriented  Programming). 

三大编程范式:

一、面向过程

二、函数式编程

三、面向对象编程

Why:

面向对象的程序的程序设计

     python里要不就用面向过程,要不就用面向对象,两种编程网络

面向对象的程序设计:

     可控性差,面向对象只解决了可扩展性的问题,一个软件包括了多个特性如图:

可见,面向对象并不是万能的。

HowSad smile ( 如何使用面象对象编程)

第一步:面向对象的程序设计:OOD:

    ------找--------〉 对象归类(归纳对象共同的特征与技能,还有每个对象独有的特征。)

    先定义类: 实例化对象

EXAMPLE: 如下例子,

程序设计:例如学校有:# 定义学生类共同的特征:Country=’China’共同的技能:查看成绩独有的特征:ID、名字,性别,省

编程:

用def 做面向对象编程

编程:def Student:    country='China'    def __init__(self,ID,NAME,SEX,PROVINCE):        self.id=ID        self.name=NAME        self.sex=SEX        self.province=PROVINCE    def search_score(self):        print('tell score')    def study(self):        print('study')

用class 面向对象编程:

例如,  恐怖份子这一类,基本上都人手一把AK47 ,  这是必须的,因为他们想捣乱, .  然后他们可以去破坏五角大楼,  还能引起国家战争, .

#defind class

class terrorist: #恐怖份子 这个类
    gun='ak47'  #都有AK47
    def trouble():  #能去破坏五角大楼
        print('destory Amercan the Pentagon')
    def warfare(self):  #能引起国家战争
        print('country  warfare %s'%self)

# print(terrorist.gun)

# terrorist.trouble()  # . 类. 点后面就可以调用 这个类的功能,  这个类能干什么.
# terrorist.warfare('Iraq,muslin')

 

WHAT?

类型与类:

Python3 中,将类型统称为

 

经典类与新式类:

在python3 当中类都是新式类(广度优先)。  而在python2.x当中新式类是class B(objcet) : pass

例如继承 B 的类    class C(B)

python2.x中的是经典类:经典类是深度优先

 

面向对象编程OOP:

类 是同一类事物特征的集合,对象是技能的结合体。

 

类的属性:

类的属性:数据属性与函数属性

调用方式通过 .点的方式就可引用类的属性

 

类属性的增、删、改、查

class Chinese:    'this is chinese class'    dang='中华人民'    country='China'    def __init__(self,name,age,gender):        # print('I"m initailize ')        self.name=name        self.age=age        self.gender=gender        # self.sui_di_tu_tan='ok tu'        # print('I"m over ')    def sui_di_tu_tan(self):        print('吐一口痰')    def cha_dui(self):        print('插到了前面')    def eat_food(self,food):        print('%s 正在吃 %s'%(self.name,food))    def play_basketball(self,ball):        print('%s 正在打 %s'%(self.name,ball))# p1=Chinese('tony',19,'male')# print(p1.__dict__) #查看对象的属性字典,这里对象只有数据属性,函数属性都是引用类的函数属性。 对象(实例)是没有自己的函数属性的。# print(p1.gender)# print(p1.name)# print(p1.sui_di_tu_tan)# p1.eat_food('baozi')# p2=Chinese('wu sir ',100,'nianmen')# p2.eat_food('jiucaixianbin')# print(dir(p2))# print(Chinese.country)# Chinese.country='American'# print(Chinese.country)# p1=Chinese('tony','29','male')# print(p1.country)## Chinese.food='fang'# print(Chinese.food)# del Chinese.eat_food# print(Chinese.food)# def dance(self,wu):#     print('%s 正在跳%s'%(self.name,wu))# Chinese.dance=dance# # print(Chinese.dan)# p1.dance('tuoyiwu')# print(Chinese.dang)# # print(Chinese.sui_di_tu_tan())# # print(dir(Chinese))# Chinese.__dict__['sui_di_tu_tan']()# Chinese.__dict__['cha_dui']('af')# # print(Chinese.__doc__)# print(Chinese.__class__)p1=Chinese('liang',18,'man')# print(p1.name)# p1.play_basketball('backetball')# print(p1.play_basketball)p1.hobby='women'# print(p1.hobby)def aihao(self):    print(‘women’)p1.aihao=aihao# print(p1.__dict__)# p1.aihao('self')#实例不能自己定义函数属性,因为这违反了class自动传self 的功能。#
所以实例只能有数据属性,能定义函数属性是因为修改了__dict__
del p1.gender# p1.gender='women'# print(p1.gender)# print(p1.__dict__)# p1.gender='male'# print(p1.gender)class People:    contry='China'    l=[1,2,3]    def __init__(self,name):        self.name=namep1=People('liang')print(p1.l)# p1.l=['a','b']p1.l.append('cc')p1.contry='japan'print(People.l)print(p1.__dict__)print(p1.l)

 

继承:

继承是一种创建新的类:解决代码重用

定义一个电脑的类,电脑有很多的品牌,再多的牌子它们还是电脑

继承父类与子类的关系是  ‘是’  的关系,如:人是动物,狗也是动物,

都继承动物类。

#!-*- coding:utf-8 -*-class Compute:    def __init__(self,name,cpu,disk,mem):        self.name=name        self.cpu=cpu        self.disk=disk        self.mem=mem    def read_file(self,cpu):        print('cpu running read_file')    def brand(self,name):        print('brand is %s'%name)class Thinkpad(Compute):    def __init__(self,name,cpu,disk,mem,small_read):        Compute.__init__(self,name,cpu,disk,mem)        self.small_read=small_read        print(small_read,disk)    def price(self,price):        print('price is %s'%price)Thinkpad_x220=Thinkpad(Thinkpad,'thinkpad_x220','i7','200GB','yes',)Thinkpad_x220.price(20000)print(Thinkpad_x220)print(Thinkpad.__bases__)

查看继承:

print('我是继承查看',Thinkpad.__bases__)

继承不是遗传

组合:(为了节省代码) 组合是‘有’的关系,电脑可以WIND7 MACOS ,但电脑不是 WIN7 MACOS

#使用组合  实现功能class Thinkpad:    def __init__(self,name,years,system):        self.name=name        self.years=years        self.system=systemclass lenvo:    def __init__(self,name,years,system):        self.name=name        self.years=years        self.system=systemclass Mac:    def __init__(self,name,years,system):        self.name=name        self.years=years        self.system=systemclass System:    def __init__(self,name):        self.name=name        # print('oprate system is %s'%name)oprate_sys=System(['windows 7 ','Mac OS'])oprate_mac=System('Mac OS')compute1=Thinkpad('x220','2010',oprate_sys)compute2=lenvo('lenvo E430','2010',oprate_sys)compute3=Mac('Mac Air','2010',oprate_sys)print(compute1.system.name[0])print(compute2.system.name[0])print(compute3.system.name[1])import abcprint(lenvo.__bases__)print(Mac.__bases__)

 

接口归一化设计:

把应该有的功能实现一个集合体,然后子类来实现

抽象类: 上述的rais 抛出异常的方式不可取,

本质还是类,与类的区别在于,与变通类的额外的特点是:加了装饰器函数,子类必须实现他们

练习:

定义老师类,把老师的属性:薪资,隐藏起来,然后针对该属性开放访问接口苑昊老师有多种癖好,把这种癖好隐藏起来,然后对外提供访问接口,而且以后还会苑昊老师培养很多其他的癖好,对外开放修改接口,可以新增癖好,并且需要保证新增的癖好都是字符串类型,否则无法增加成功。class Teacher(object):    __salary=25000    __hobby=['somke','drink']    def __init__(self,name,age,sex):        self.name=name        self.age=age        self.sex=sex    def hobby_modify(self,mod_hobby):        if type(mod_hobby) is str:            Teacher.__hobby.append(mod_hobby)            print('you hobby very special')        else:            print('Can\'t be number or sign')    def salary(self):        """隐藏属性 查看接口"""        print('salary: %s'%Teacher.__salary)    def hobby(self):        return(Teacher.__hobby)T1=Teacher('yh','23','male')T4=Teacher('eg','22','male')T2=Teacher.hobby(T1)T2=T2[:]T3=','.join(T2)#teacher eg hobbyprint('__________________________________________________')def func1(n):    n.namefunc1(T4)T4.salary()T4.hobby_modify('running')print(T4.name,T4.age,'%s habby %s'%(T4.name,T4.hobby()))print('__________________________________________________')# 访问隐藏属性def func(n):    n.salary()func(T1)print('teacher %s have %s'% (T1.name,T3))mod_hobby=Teacher.hobby_modify(T1,'drive car')print(Teacher.hobby(T1))print('----------------------------')

 

 

多态与多态性:

一种事物 不同的形态,多态指的是一类事物有多种形态,(一个抽象类有多个子类,因而多态的概念依赖于继承)

##一切皆文件:多态 与多态性练习题 import abc class All_file(metaclass=abc.ABCMeta):     @abc.abstractmethod def all(self): pass class disk(All_file): def all(self): print('disk is file') class process(All_file): def all(self): print('process  is file') class Txt(All_file): def all(self): print('Txt file  is file') d1=Txt() d2=disk() # print(d1.all()) def func(d1):     d1.all() func(d1) func(d2)

多态性:

多态性是指具有不同功能的函数可以使用相同的函数名,这样就可以用一个函数名调用不同内容的函数。

多态性分为静态多态性和动态多态性

多态性是‘一个接口(函数func),多种实现(如f.click())

派生:

继承是子类继承父类,但是子类都有自己类的特征,这个就叫做“派生”。如果子类有自已的特征且与父类的特征有重名,就找自己的特征

但是又要在父类的基础上增加自己的功能,那就是重用父类的特征加上自己的特征。

在子类中调用父类的特征。

 

封装:

封装:

第一层封装:

第一个层面的封装(什么都不用做):创建类和对象会分别创建二者的名称空间,我们只能用类名.或者obj.的方式去访问里面的名字,这本身就是一种封装

第二层封装:

__名字(双下划线),这种语法,只在定义的时候才会有变形的效果,如果类或者对象已经产生了,就不会有变形效果。

在python中用双下划线的方式实现隐藏属性(设置成私有的)

要想不让外部访问需要用到一个函数__getattr__ 详细见 进阶篇

 

特性:

property 是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值

import mathclass Circle:    def __init__(self,radius):        self.radius=radius    @property    def area(self):        return math.pi * self.radius**2  #计算机面积    @property    def perimeter(self):        return 2**math.pi*self.radius #计算周长c=Circle(10)print(c.area)  #可以像访问 “数据属性” 一样去访问area ,一访问就会触发一个函数的执行,动态计算出一个值print(c.perimeter)  #和上面一样----------------------------------------------------------如果不用porperty  , 那访问就不能像访问数据属性一样去访问了class Circle:    def __init__(self,radius):        self.radius=radius    def area(self):        return math.pi * self.radius**2    def perimeter(self):        return 2**math.pi*self.radiusc=Circle(10)   print(c.area)print(c.perimeter)

使用了property 以后不能被赋值:

不使用porperty 可以被赋值:

 

为什么要用property:

将一个类的函数定义成特性以后,对象再去使用的时候  obj.name根本无法察觉自己的name是执行了一个函数,这种特性的使用方式遵循了

 

统一访问的原则

除此之外:

面向对象的封装有三种方式:

[public]

    这种其实就是不封装,是对外公开的

[protected]

    这种封装方式对外不公开,但对朋友或者子类公开

[private]

             这种封装对谁都不公开

python 没有将以上三个内建到自己的class机制中,在python中通过porperty  实现。

class Foo:    def __init__(self,val):        self.__name=val  #将数据属性都隐藏起来    @property    def name(self): #执行查询操作此函数运行        print('我是查看')        return self.__name  #f.name 访问的是self.__name(这才是真实值的存放位置)    @name.setter    def name(self,value): #执行设置操作此函数运行(设置就是赋值)        print('我是设置')        if not isinstance(value,str):            raise TypeError('must be str')        self.__name=value    @name.deleter #执行删除操作此函数运行    def name(self):        print('我是删除')        raise TypeError('Can not delete ')f=Foo('tony')print(f.name)
 
从外面访问不到类里的数据属性 print(Foo.__name)

通过对象才能访问到类的数据属性 

print(f.name)

这就是封装

查询:

删除:

设置:

练习:

 
#!/usr/bin/env python#!-*- coding:utf-8 -*-def write_func():    with open('user.db','w') as file_write:        file_write.write(str({
'tony':{
"password":"123",'status':False,'timeout':0},'liang':{
"password":"456",'status':False,'timeout':0},}))def read_func(): with open('user.db','r') as file_read: f=file_read.read() data=eval(f) print(data['tony']['status']) print(data['liang']['status'])# write_func()# read_func()#要求三:分析下述代码的执行流程class User: db_path='user.db' def __init__(self,username): self.username=username @property def db(self): data=open(self.db_path,'r').read() return eval(data) # @setattr() # def db(self): # raise TypeError:("cat't delete "# u=User('tony')# print(u.db['tony']['age'])import timeclass User: db_path='user.db' def __init__(self,name): self.name=name @property def db(self): with open(self.db_path,'r') as locked_check: info=locked_check.read() data=eval(info) return 'locked time %s '%data[self.name]['locked_time'] # @property # def db(self): # with open(self.db_path,'r') as read_file: # info=read_file.read() # return eval(info) @db.setter def db(self,value): with open(self.db_path,'w') as write_file: write_file.write(str(value)) write_file.flush() def login(self): data=self.db if data[self.name]['status']: print('已经登录') return True if data[self.name]['timeout'] < time.time(): count=0 while count < 3: passwd=input('password>>: ') if not passwd:continue if passwd == data[self.name]['password']: data[self.name]['status']=True data[self.name]['timeout']=0 self.db=data break count+=1 else: data[self.name]['timeout']=time.time()+10 if data[self.name]['status']: return else: data[self.name]['locked_time']=time.ctime() print('locked time %s'%data[self.name]['locked_time']) self.db=data else: print('账号已经锁定10秒')u1=User('tony')# u1.login()# u2=User('liang')# print(u1.db)#要求四:根据上述原理,编写退出登录方法(退出前要判断是否是登录状态),自定义property,供用户查看自己账号的锁定时间class User: db_path='user.db' def __init__(self,name): self.name=name @property def db(self): with open(self.db_path,'r') as locked_check: info=locked_check.read() data=eval(info) return 'locked time %s '%data[self.name]['locked_time'] @property def db(self): with open(self.db_path,'r') as read_file: info=read_file.read() return eval(info) @db.setter def db(self,value): with open(self.db_path,'w') as write_file: write_file.write(str(value)) write_file.flush() def login(self): data=self.db if data[self.name]['status']: print('已经登录') return True if data[self.name]['timeout'] < time.time(): count=0 while count < 3: passwd=input('password>>: ') if not passwd:continue if passwd == data[self.name]['password']: data[self.name]['status']=True data[self.name]['timeout']=0 print('welecome') self.db=data break count+=1 else: data[self.name]['timeout']=time.time()+10 if data[self.name]['status']: return else: data[self.name]['locked_time']=time.ctime() print('locked time %s'%data[self.name]['locked_time']) self.db=data else: print('账号已经锁定10秒') # @property def logout(self): with open('user.db','r') as logout_check: f=logout_check.read() data=eval(f) # return 'login status "%s" '%data[self.name]['status'] if data[self.name]['status']: # return ('alread login ,logout? "y" or continue "n"') choice=input('alread login ,logout? "y" or continue "n": ').strip() if choice=='y': data[self.name]['status']=False self.db=data print('logout') # return 'logout' else: return# u1=User('tony')# u1.login()u2=User('liang')u2.logout()# u2.login()

 

封装与扩展性:

封装在于明确区分内外,使得类实现者可以修改封装内的东西而不影响外部调用者的代码,而外部调用者只知道一个接口(函数),只要接口(函数)名、参数不变,使用者的代码永远无需改变。这就提供了一个良好的合作基础---或者说,只要接口这个基础约定不变,则代码改变不足虑。

class Room:    def __init__(self,name,owner,width,length,high):        self.name=name        self.owner=owner        self.__width=width        self.__length=length        self.__high=high    def tell_area(self):  #对外提供的接口,隐藏了内部的实现细节,此时要求的是面积        return self.__width*self.__lengthr1=Room('badroom','tony',20,20,20)print(r1.tell_area()) #使用者调用接口tell_area

再看:

class Room:    def __init__(self,name,owner,width,length,high):        self.name=name        self.owner=owner        self.__width=width        self.__length=length        self.__high=high    def tell_area(self):
#对外提供的接口,隐藏了内部的实现细节,此时要求的是面积,,现在内部逻辑变了,而外部调用者感知不到,仍然使用该方法,但是功能已经变了
return self.__width*self.__length*self.__highr1=Room('badroom','tony',20,20,20)print(r1.tell_area()) #使用者调用接口tell_area ,已经使用新功能

 

 

静态方法和类方法:

通常情况下,在类中定义的所有函数(所有 ,包括self,它只不过也是个普通的参数而已)都是对象的绑定方法,对象在调用绑定方法时会将自己做为参数传递给方法的第一个参数。除此之外还有两种常见的方法: 静态方法和类方法,二者为类量身定制,但是实例非要使用,也不会报错,后续将介绍

1、静态方法

是一个普通函数,位于类定义的 命名空间 中,不会对任何实例类型进行操作,python为我们内置了函数staticmethod来把类中的函数定义成静态方法

class Foo:    def spam(x,y,z): #类中的一个函数,self和x 没有什么区别        print(x,y,z)    spam=staticmethod(spam) #将spam函数做成静态方法#简单写法class Foo:    @staticmethod  #等同于spam=staticmethod(spam)    def spam(x,y,z):        print(x,y,z)#调用print(type(Foo.spam))#类型本质就是函数Foo.spam(1,2,3) #调用函数应该有几个参数就传几个参数
f1=Foo() f1.spam(1,2,4) #实例也可以使用,但通常静态方法都是给类用的,实例在使用的时候丧失了自动传值的功能

 

#应用场景:编写类时需要采用很多不同的方式来创建实例,而我们只有一个__init__函数,此时静态方法就派上用场了

import timeclass Date:    def __init__(self,year,month,day):        self.year=year        self.month=month        self.day=day    @staticmethod    def now():#用Date.now()形式去产生实例,该实例用的是当前时间        t=time.localtime() #获取结构化的时间格式        return Date(t.tm_year,t.tm_mon,t.tm_mday) #新建实例并返回    @staticmethod    def tommorrow(): #用Date.tommorrow()的形式去产生实例,该实例用的是明天的时间        t=time.localtime(time.time()+86400)        return Date(t.tm_year,t.tm_mon,t.tm_mday)a=Date('1929',11,23) #自定义时间b=Date.now() #采用当前时间c=Date.tommorrow() #采用明天时间print(a.year,a.month,a.day)print(b.year,b.month,b.day)print(c.year,c.month,c.day)

2、类方法

类方法是给类用的,类在使用时会将类本身当做参数传给类方法的第一个参数,python 为我们内置了classmethod来把类中的函数定义成类方法

class A:    x=1    @classmethod    def ceshi(cls):        print(cls,cls.x)class B(A):    x=2B.ceshi()

实际应用:

class Date:    def __init__(self,year,month,day):        self.year=year        self.month=month        self.day=day    @staticmethod    def now():        t=time.localtime()        return Date(t.tm_year,t.tm_mon,t.tm_mday)class EuroDate(Date):    def __str__(self):        return 'year:%s month:%s day:%s'%(self.year,self.month,self.day)e=EuroDate.now()print(e)  #这里是想触发EuroDate.__str__,但是结果是<__main__.Date object at 0x000000000113C080>#因为e就是用Date类产生的,所以根本不会触发EuroDate.__str__,解决方法就是用classmethod

classmethod 修改

class Date:    def __init__(self,year,month,day):        self.year=year        self.month=month        self.day=day    @classmethod    def now(cls):        t=time.localtime()        return cls(t.tm_year,t.tm_mon,t.tm_mday)class EuroDate(Date):    def __str__(self):        return 'year:%s month:%s day:%s'%(self.year,self.month,self.day)e=EuroDate.now()print(e)

结果:

转载于:https://www.cnblogs.com/tonycloud/articles/6882242.html

你可能感兴趣的文章
Tomcat连接Apache之mod_proxy模块
查看>>
sersync+rsync数据同步
查看>>
使用com.aspose.words将word模板转为PDF文件时乱码解决方法
查看>>
Linux发送邮件
查看>>
YUM安装PHP5.6
查看>>
YUM源安装MySQL5.7
查看>>
Tomcat日志切割cronolog
查看>>
glibc-2.14安装
查看>>
升级openssl zlib版本 安装nginx
查看>>
ab压力测试
查看>>
SVN指定端口启动
查看>>
网站访问速度一般检查参数
查看>>
编译安装过程
查看>>
HTTP常见返回码信息
查看>>
WEB集群session处理方案
查看>>
JDK命令行(jps、jstat、jinfo、jmap、jhat、jstack、jstatd、hprof)与JConsole
查看>>
JAVA 对象访问: 句柄和指针
查看>>
秒杀系统优化思路
查看>>
dubbo 报错:java.lang.NoClassDefFoundError: org/I0Itec/zkclient/exception/ZkNoNodeException
查看>>
logback的使用和logback.xml详解
查看>>