什么时候使用面向对象? 当某些函数具有相同参数时,可以使用面向对象的方式,讲参数值一次的封装到对象,以后去对象中取值即可
面向对象的特点:
封装,继承,多态 #多态(意义不大,java等强类型,应用多)
类和对象
一 创建类
class 类名:
def 方法名(self,***):
pass
二 创建对象
对象=类名()
三 通过对象执行方法
对象.方法名(123)
self是python会自动传值的参数
构造方法: __init__() #自动被执行, ()中可填参数
类定义
#类通过函数改变class Person:def __init__(self,name,age,money):self.name=nameself.age=ageself.money=moneydef shopping(self):self.money=self.money -200print(self.money)long=Person("龙",18,400)hu=Person("虎",18,300)long.shopping()hu.shopping()# 200# 100
计数器
class Foo:count=0def __init__(self,name):Foo.count+=1 #写Foo.count Foo代表类self.name=nameobj1=Foo("egon1")obj2=Foo("egon2")# print(Foo.count)# print(obj2.count)class Student:tag = "tag值" #灵活性,可增加参数def __init__(self,ID,name,age):self.id=IDself.name=nameself.age=agedef walk(self):print("%s is waokking"%self.name)s1=Student(1,"egon",18)s2=Student(2,"alex",1000)s1.walk()s2.walk()print(s1.id,s1.name,s1.age,s1.tag)print("用户数量",Foo.count)# egon is waokking# alex is waokking# 1 egon 18 tag值# 用户数量 2
类的传参可以是另一个类
class c1:def __init__(self,name,obj):self.name = nameself.obj=objclass c2:def __init__(self,name,age):self.name = nameself.age=agedef show(self):print(self.age)c2_obj=c2("aa",11) #c2("aa", 11).show() 这样也行c2_obj.show() #显示show函数值#11print(c2_obj.name) #也可以调用变量,显示变量要加print#aac1_obj=c1("alex",c2_obj) #c1_obj的参数可以是c2_obj函数print(c1_obj.obj.name) #c1_obj.obj.name =c2_obj.name#aa
继承
继承是一种创建类的方式
F2继承F1所有数据
class F1:def show(self):print("show")class F2(F1):def bar(self):print("bar your right")obj = F2()obj.bar()#bar your right
F2继承F1
F2继承了F1的函数 如果F2和F1中有同名函数执行F2函数(子类优先)
class F1: #父类,基类def show(self):print("show")def foo(self):print(self.name)class F2(F1): #子类,派生类def __init__(self,name):self.name = namedef bar(self):print("bar your right")def show(self):print("F2,show")obj = F2("alex")obj.foo()
父类不变,子类改变
class Animal:def __init__(self,name,age,sex):self.name=nameself.age=ageself.sex=sexdef eat(self):print("%s eat"%self.name)def takl(self):print("%s say"%self.name)class People(Animal):def __init__(self,name,age,sex,education):Animal.__init__(self,name,age,sex) #这是调用父类初始化self.education=educationpeo1=People("alex",18,"male","小学")print(peo1.__dict__) #不加__dict__是内存地址
class Animal:def __init__(self,name,age,sex):self.name=nameself.age=ageself.sex=sexdef eat(self):print("eating")def talk(self):print("="*8)print("%s 在干嘛" %self.name)class People(Animal):def __init__(self,name,age,sex,education):Animal.__init__(self,name,age,sex)self.education=educationdef talk(self):Animal.talk(self)print("%s say hello %s"%(self.name,self.education))class Pig(Animal):def __init__(self,name,age,sex):Animal.__init__(self,name,age,sex)def talk(self):Animal.talk(self) #执行Peple中的tailk子类优先print("%s 哼哼哼"%self.name)class dig(Animal):def __init__(self,name,age,sex):Animal.__init__(self,name,age,sex)def talk(self):Animal.talk(self) #执行Peple中的tailk子类优先print("%s 汪汪汪汪"%self.name)peo1=People("alex",18,"male","小学文凭")pig=Pig("wupeiqi",20,"female")dig=dig("haha",20,"male")#print(peo1.education)peo1.talk()pig.talk()dig.talk()
继承组合调用
- #组合也可以解决代码冗余问题,但是组合反映是一种什么有什么的关系
class People:def __init__(self,name,age,sex):self.name=nameself.age=ageself.sex=sex# class Teacher(People):# def __init__(self,name,age,sex,salary):# People.__init__(self,name,age,sex)# self.salary=salary## class Student(People):# passclass Date:def __init__(self,year,mon,day):self.year=yearself.mon=monself.day=daydef tell(self):print('%s-%s-%s' %(self.year,self.mon,self.day))class Teacher(People):def __init__(self,name,age,sex,salary,year,mon,day):self.name=nameself.age=ageself.sex=sexself.salary=salaryself.birth=Date(year,mon,day) #组合调用class Student(People):def __init__(self,name,age,sex,year,mon,day):self.name=nameself.age=ageself.sex=sexself.birth=Date(year,mon,day)t=Teacher('egon',18,'male',3000,1995,12,31)t.birth.tell()
类查询对象顺序
#先查C1的所有父类,有f2,匹配退出,如果没有,再查C1,有f2,匹配退出,都没有报错class C1:def f2(self):print("C1中的f2")class C2:def f2(self):print("C2中的f2")class C3(C1,C2):def f3(self):print("C3中的f3")obj=C3()obj.f2()
2种类
经典类:
深度优先 (python2 ,特定是N条父类连接相同父父类, 第一条生效)
新式类:
广度优先 (python2+python3 特定是N条父类连接相同父父类, 最后一条生效)
#python2中用新式类父父类要加object 例如class C0(object):
多继承
#新式类, 特定是N条父类连接相同父父类, 最后一条生效#查询顺序 C3(自己)-C2-C1-C5-C4-C0class C0:def test(self):print("C0")class C1(C0):# def test(self):# print("C1")passclass C2(C1):# def test(self):# print("C2")passclass C4(C0):# def test(self):# print("C4")passclass C5(C4):# def test(self):# print("C5")passclass C3(C2,C5):# def test(self):# print("C3")passobj=C3()obj.test()-
print(C3.mro()) -
#mro显示执行过程(最后一位提供返回值) 执行C3的test函数,看执行过程
-
#[<class '__main__.C3'>, <class '__main__.C2'>, <class '__main__.C1'>, <class '__main__.C5'>, <class '__main__.C4'>, <class '__main__.C0'>, <class 'object'>]
class Animal:home="oldboy"def __init__(self,name,age,sex):self.name=nameself.age=ageself.sex=sexdef eat(self):print("%s eat"%self.name)def takl(self):print("%s say"%self.name)class People(Animal):def __init__(self,name,age,sex,education):#Animal.__init__(self,name,age,sex) #这是调用父类初始化super().__init__(name,age,sex,) #这是调用父类初始化的另一种方法#super(People,self).__init__(name,age,sex,) #python2写法#print(super().home) #使用super.可直接调用父类的(对象,函数,变量) = print(Animal.home)self.education=educationpeo1=People("alex",18,"male","小学")print(peo1.__dict__) #不加__dict__是内存地址#{'name': 'alex', 'age': 18, 'sex': 'male', 'education': '小学'}peo1.eat()#alex eatprint(People.mro()) #查新式类最后调用#[<class '__main__.People'>, <class '__main__.Animal'>, <class 'object'>]#super的另一种含义是直接调用最后一个父类class A:def test(self):super().test() #此时的super是从<class '__main__.A'>后 继续调用mro继续查看,继续则是C(B),得到B父类的testclass B:def test(self):print('B')class C(A,B):pass# a=A()# a.test()print(C.mro())c=C()c.test()#[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]#B
抽象类
#一个抽象类有多个子类,因而多态的概念依赖于继承
#主要作用:函数规范 , 只要是调用这个父级的read函数 子级也必须用readimport abc #利用abc模块实现抽象类class All_file(metaclass=abc.ABCMeta):all_type='file'@abc.abstractmethod #定义抽象方法,无需实现功能def read(self):'子类必须定义读功能'pass#定义其他抽象类就继续仿照read写class Txt(All_file): #子类继承抽象类,但是必须定义read和write方法def read(self):print('文本数据的读取方法')class Process(All_file): #子类继承抽象类,但是必须定义read和write方法def read(self):print('进程数据的读取方法')guolm=Txt()qiqi=Process()#规范了必须用read函数, 如果把guolm的类中read函数名改变,就会报错#Can't instantiate abstract class Txt with abstract methods readguolm.read()qiqi.read()print(guolm.all_type)print(qiqi.all_type)# 文本数据的读取方法# 进程数据的读取方法# file# file
多态和多态性
多态
多态指的是一类事物有多种形态,(一个抽象类有多个子类,因而多态的概念依赖于继承
#多态:调用父类有共同的参数,返回子类又增加各自子类的变化
多态性
多态性是指具有不同功能的函数可以使用相同的函数名,这样就可以用一个函数名调用不同功能的函数。
- import abc
class Animal(metaclass=abc.ABCMeta): #同一类事物:动物@abc.abstractmethod #抽象def talk(self):passclass People(Animal): #动物的形态之一:人def talk(self):print('say hello')class Dog(Animal): #动物的形态之二:狗def talk(self):print('say wangwang')class Pig(Animal): #动物的形态之三:猪def talk(self):print('say aoao')People=People()People.talk()Dog=Dog()Dog.talk()Pig=Pig()Pig.talk()# say hello# say wangwang# say aoao
封装
1 类把某些属性和方法隐藏起来(或者说定义成私有的,)只在类的内部使用,外部无法访问,或者留下少量接口(函数)供外部访问
隐藏封装
在内部使用__ 会调用值 在外部不成立
#类中定义的__x只能在内部使用,如self.__x,引用的就是变形的结果。#这种变形其实正是针对外部的变形,在外部是无法通过__x这个名字访问到的。#这种变形其实正是针对外部的变形,在外部是无法通过__x这个名字访问到的。#在子类定义的__x不会覆盖在父类定义的__x,因为子类中变形成了:_子类名__x,而父类中变形成了:_父类名__x,即双下滑线开头的属性在继承给子类时,子类是无法覆盖的。class People:def __init__(self,name,age,sex):self.__name=nameself.__age=ageself.__sex=sexdef tell_info(self):#print("人的名字是:%s, 人的性别是:%s, 人的年龄是:%s "%(self.__name,self.__age,self.__sex))return "人的名字是:%s,人的性别是:%s,人的年龄是:%s "%(self.__name,self.__age,self.__sex)p=People("alex",18,"male")print(p.tell_info()) #显示结果#人的名字是:alex,人的性别是:18,人的年龄是:maleprint(p.__dict__) #显示p的字典状态#{'_People__name': 'alex', '_People__age': 18, '_People__sex': 'male'}
父子类函数同名,调用父类函数
class Parent:__x=1def foo(self):print("from parent.foo")self.__bar() #值是完整文件名_parent__foo__bar, 相当于指定调用def __bar(self):print("from parent.bar")class Sub(Parent):def bar(self):print("from Sub.bar")s=Sub()s.foo()#from parent.foo #from parent.bar-
print(Parent.__dict__) #看Parent的所以含义
#{'__module__': '__main__', '_Parent__x': 1, 'foo': <function Parent.foo at 0x101448598>, '_Parent__bar': <function Parent.__bar at 0x1014486a8>, '__dict__': <attribute '__dict__' of 'Parent' objects>, '__weakref__': <attribute '__weakref__' of 'Parent' objects>, '__doc__': None}
super
根据mro查找
父类改变 子类只需要改变类调用 不需要改子类函数
class Foo1: #父类名改变def test(self):print("from foo.test")class Bar(Foo1): #子类名改变,不需要改子类的test函数def test(self):#Foo.test(self) 相对于如下super(Bar,self).test() #使用super,父类改变 子类只需要改变类调用 不需要子类改函数print("bar222")a=Bar()a.test()#from foo.test #bar222
内置装饰器
内置的装饰器有三个:staticmethod(静态类方法) classmethod, 类方法 property
staticmethod,(静态类方法)
基本上跟一个全局函数相同,一般来说用的很少
classmethod
- classmethod 是一个函数修饰符,它表示接下来的是一个类方法,而对于平常我们见到的则叫做实例方法。 类方法的第一个参数cls,而实例方法的第一个参数是self,表示该类的一个实例。
- 普通对象方法至少需要一个self参数,代表类对象实例
- 类方法有类变量cls传入,从而可以用cls做一些相关的处理。并且有子类继承时,调用该类方法时,传入的类变量
staticmethod+classmethod实例setting.py文件host="192.168.1.1"port=3004
import settingimport uuidclass Mysql:def __init__(self,host,port):self.host=hostself.port=portself.id=self.create_id()@classmethod #绑定方法,绑定给class类def from_conf(cls): #cls=Mysql()return cls(setting.host)#setting是模块,setting.host中host是模块变量def func(self): #绑定给object对象pass@staticmethod #非绑定方法,变成普通函数,不绑定给类或对象def create_id():return str(uuid.uuid1())conn_one=Mysql("1.1.1.1",3306)conn_tow=Mysql.from_conf()print(conn_one.host)print(conn_tow.host)#1.1.1.1#192.168.1.1print(Mysql.from_conf) #这是显示绑定类#<bound method Mysql.from_conf of <class '__main__.Mysql'>>print(Mysql.func) #这是显示绑定对象#<function Mysql.func at 0x101c287b8>print(conn_one.id) #这是显示非绑定方法#5da84770-81dc-11e7-9569-48bf6be5ec1a
property
计算bmi(健康状态)
#定义好数值,外部传参 可修改数值class People:def __init__(self,name,weight,height):self.name=nameself.weight=weightself.height=height@property #类似装饰器,装饰下边def bmi(self):return self.weight / (self.height ** 2)p=People("egon",75,1.80)p.height=1.84 #外部可改传参print(p.bmi)#22.152646502835537
封装之更改和删除
class People:def __init__(self,name,permmission=False): #permmission=False 定义默认值 用于增加权限self.name=nameself.permmission=permmission@property #继承def name(self):return self.__name@name.setter #装饰器增加增加功能def name(self,value):if not isinstance(value,str):raise TypeError("名字必须是字符串类型")self.__name=value@name.deleter #装饰器增加删除功能def name(self):if not self.permmission: #permminsion值为False#这样写permmission值必须为True 加not为False, 而设置是permminsion值就是Falseraise PermissionError("不允许的操作")del self.__namep=People("egon")p.permmission=Truedel p.name- 另一种方法 效果相同
class People:def __init__(self,name,permmission=False):self.name=nameself.permmission=permmissiondef get_name(self):return self.__namedef set_name(self,value):if not isinstance(value,str):raise TypeError("名字必须是字符串类型")self.__name=valuedef del_name(self):if not self.permmission:raise PermissionError("不允许的操作")del self.__namename=property(get_name,set_name,del_name)p=People("egon")
设计模式之单例模式(23,goF设计模式)
单例模式
用来创建单个实例


练习:
1 对象调用class 显示调用次数
#Foo是类#self是对象自己class Foo:count=0def __init__(self,x,y,z):self.x=xself.y=yself.z=zdef aa(self):Foo.count+=1return Foo.countobj1=Foo("guolm",18,"linux")obj2=Foo("wy",28,"linux")obj3=Foo("haha",38,"yw")print(obj1.aa())print(obj2.aa())print(obj3.aa())print(obj3.aa())# 1# 2# 3# 4