什么时候使用面向对象? 当某些函数具有相同参数时,可以使用面向对象的方式,讲参数值一次的封装到对象,以后去对象中取值即可
面向对象的特点:
封装,继承,多态 #多态(意义不大,java等强类型,应用多)
类和对象
一 创建类
class 类名:
def 方法名(self,***):
pass
二 创建对象
对象=类名()
三 通过对象执行方法
对象.方法名(123)
self是python会自动传值的参数
构造方法: __init__() #自动被执行, ()中可填参数
类定义
#类通过函数改变
class Person:
def __init__(self,name,age,money):
self.name=name
self.age=age
self.money=money
def shopping(self):
self.money=self.money -200
print(self.money)
long=Person("龙",18,400)
hu=Person("虎",18,300)
long.shopping()
hu.shopping()
# 200
# 100
计数器
class Foo:
count=0
def __init__(self,name):
Foo.count+=1 #写Foo.count Foo代表类
self.name=name
obj1=Foo("egon1")
obj2=Foo("egon2")
# print(Foo.count)
# print(obj2.count)
class Student:
tag = "tag值" #灵活性,可增加参数
def __init__(self,ID,name,age):
self.id=ID
self.name=name
self.age=age
def 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 = name
self.obj=obj
class c2:
def __init__(self,name,age):
self.name = name
self.age=age
def show(self):
print(self.age)
c2_obj=c2("aa",11) #c2("aa", 11).show() 这样也行
c2_obj.show() #显示show函数值
#11
print(c2_obj.name) #也可以调用变量,显示变量要加print
#aa
c1_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 = name
def 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=name
self.age=age
self.sex=sex
def 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=education
peo1=People("alex",18,"male","小学")
print(peo1.__dict__) #不加__dict__是内存地址
class Animal:
def __init__(self,name,age,sex):
self.name=name
self.age=age
self.sex=sex
def 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=education
def 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=name
self.age=age
self.sex=sex
# class Teacher(People):
# def __init__(self,name,age,sex,salary):
# People.__init__(self,name,age,sex)
# self.salary=salary
#
# class Student(People):
# pass
class Date:
def __init__(self,year,mon,day):
self.year=year
self.mon=mon
self.day=day
def 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=name
self.age=age
self.sex=sex
self.salary=salary
self.birth=Date(year,mon,day) #组合调用
class Student(People):
def __init__(self,name,age,sex,year,mon,day):
self.name=name
self.age=age
self.sex=sex
self.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-C0
class C0:
def test(self):
print("C0")
class C1(C0):
# def test(self):
# print("C1")
pass
class C2(C1):
# def test(self):
# print("C2")
pass
class C4(C0):
# def test(self):
# print("C4")
pass
class C5(C4):
# def test(self):
# print("C5")
pass
class C3(C2,C5):
# def test(self):
# print("C3")
pass
obj=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=name
self.age=age
self.sex=sex
def 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=education
peo1=People("alex",18,"male","小学")
print(peo1.__dict__) #不加__dict__是内存地址
#{'name': 'alex', 'age': 18, 'sex': 'male', 'education': '小学'}
peo1.eat()
#alex eat
print(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父类的test
class 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函数 子级也必须用read
import 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 read
guolm.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):
pass
class 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=name
self.__age=age
self.__sex=sex
def 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,人的年龄是:male
print(p.__dict__) #显示p的字典状态
#{'_People__name': 'alex', '_People__age': 18, '_People__sex': 'male'}
父子类函数同名,调用父类函数
class Parent:
__x=1
def 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 setting
import uuid
class Mysql:
def __init__(self,host,port):
self.host=host
self.port=port
self.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.1
print(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=name
self.weight=weight
self.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=name
self.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值就是False
raise PermissionError
("不允许的操作")del self.__name
p=People("egon")
p.permmission=True
del p.name
- 另一种方法 效果相同
class People:
def __init__(self,name,permmission=False):
self.name=name
self.permmission=permmission
def get_name(self):
return self.__name
def set_name(self,value):
if not isinstance(value,str):
raise TypeError("名字必须是字符串类型")
self.__name=value
def del_name(self):
if not self.permmission:
raise PermissionError("不允许的操作")
del self.__name
name=property(get_name,set_name,del_name)
p=People("egon")
设计模式之单例模式(23,goF设计模式)
单例模式
用来创建单个实例
练习:
1 对象调用class 显示调用次数
#Foo是类
#self是对象自己
class Foo:
count=0
def __init__(self,x,y,z):
self.x=x
self.y=y
self.z=z
def aa(self):
Foo.count+=1
return Foo.count
obj1=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