学习python_day6
面向对象
面向对象的特性:封装、继承、多态
类、方法
一、面向对象编程
OOP编程是利用“类”和“对象”来创建各种模型来实现对真实世界的描述,使用面向对象编程的原因一方面是因为它可以使程序的维护和扩展变得更简单,并且可以大大提高程序开发效率 ,另外,基于面向对象的程序可以使它人更加容易理解你的代码逻辑,从而使团队开发变得更从容。
面向对象的几个核心特性如下
Class 类
一个类即是对一类拥有相同属性的对象的抽象、蓝图、原型。在类中定义了这些对象的都具备的属性(variables(data))、共同的方法
Object 对象
一个对象即是一个类的实例化后实例,一个类必须经过实例化后方可在程序中调用,一个类可以实例化多个对象,每个对象亦可以有不同的属性,就像人类是指所有人,每个人是指具体的对象,人与人之前有共性,亦有不同
Encapsulation 封装
在类中对数据的赋值、内部调用对外部用户是透明的,这使类变成了一个胶囊或容器,里面包含着类的数据和方法
Inheritance 继承
一个类可以派生出子类,在这个父类里定义的属性、方法自动被子类继承
Polymorphism 多态
多态是面向对象的重要特性,简单点说:“一个接口,多种实现”,指一个基类中派生出了不同的子类,且每个子类在继承了同样的方法名的同时又对父类的方法做了不同的实现,这就是同一种事物表现出的多种形态。例如len() 可以传递str、list、tuple等就是一个借口多种实现。
类的语法
最简单的语法:
class Dog(object): print("I am a dog") d = Dog()#实例化这个类 #此时的d就是类Dog的实例化对象 #实例化,其实就是以这个类Dog为模板。在内存里开辟一块空间,存上数据,赋值成一个变量名
给dog传名字加功能
class Dog(object): def __init__(self,name,type):#初始化对象 self.name = name#d.name = name self.type = type#d.type = type def balk(self):#定义其功能,所以在调用初始化函数定义的name时把d传进来,此时的self=d print("[%s] wang wang ..."%self.name) def eat(self,food): print("[%s] eating %s"%(self.name,food)) d = Dog("AA","京巴") d.balk()#调用balk功能 #对class中self的例子解析 def dog(name,type): data ={"name":name,"type":type} return data def balk(dog_name): print("[%s] wang wang ..."%dog_name["name"]) d1 = dog("BBB","京巴")#把dog的执行结果赋给d1,d1["name"]=name d1["type"]=type balk(d1)#balk函数想要调用dog函数中定义的变量name 只能把d1当做参数传进去,调用name就是d1["name"]
小结:
你执行d = Dog("AAA","京巴")时,python的解释器其实干了两件事:
- 在内存中开辟一块空间指向d这个变量名
- 调用Dog这个类并执行其中的__init__(…)方法,相当于Dog.__init__(d,"AAA","京巴"),这么做是为什么呢? 是为了把'd,"AAA","京巴"这3个值跟刚开辟的d关联起来, 因为关联起来后,你就可以直接d.name, d.type 这样来调用啦。所以,为实现这种关联,在调用__init__方法时,就必须把r1这个变量也传进去,否则__init__不知道要把那3个参数跟谁关联呀。
- 明白了么哥?所以这个__init__(…)方法里的,self.name = name , self.type = type 等等的意思就是要把这几个值 存到d的内存空间里。

根据上图我们得知,其实self,就是实例本身!你实例化时python会自动把这个实例本身通过self参数传进去。
类变量、实例变量、私用变量、封装
class Dog(object): age = 22#类变量,存在类的内存地址中,可以被所有实例共享引用,作用:作为默认共有属性,全局修改或增加新属性 def __init__(self,name,type): self.name = name#这些都是实例变量(成员属性),每个实例存在自己内存空间里的属性 self.type = type# def balk(self): print("[%s] wang wang ..."%(self.name,self.age))#当构造函数中没有定义self.age = 22时,可以引用类变量中的 #当构造方法中定义时则直接引中构造方法中的 d = Dog("AAA","京巴") class Pepole(object): def __init__(self,name,sex): self.name = name self.__sex = sex#定义私有属性用两个下划线__,外部调用不到,内部各函数中可以被调用,封装的一个特性 def go_to_toilet(self): if self.__sex == "F": print("standup") else: print("跪着。。。") def get_sex(self):#封装的另一个特性:隐藏一些功能的实现细节,只给外部暴露调用接口 return self.__sex p = Pepole("alex","F") # print(p.__sex)#这样会报错,外面调用不到 p.go_to_toilet() #内部可以调用 print(p.get_sex())#这样就可以访问到,但不能修改
继承
面向对象编程 (OOP) 语言的一个主要功能就是“继承”。继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。
通过继承创建的新类称为“子类”或“派生类”。
被继承的类称为“基类”、“父类”或“超类”。
继承的过程,就是从一般到特殊的过程。
要实现继承,可以通过“继承”(Inheritance)和“组合”(Composition)来实现。
在某些 OOP 语言中,一个子类可以继承多个基类。但是一般情况下,一个子类只能有一个基类,要实现多重继承,可以通过多级继承来实现。
继承概念的实现方式主要有2类:实现继承、接口继承。
最简单的继承方法
class SchoolMember(): def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex def tell(self): info = """ _____info of %s______ name:%s age:%s sex:%s """%(self.name,self.name,self.age,self.sex) class Teacher(SchoolMember): #直接继承SchoolMember类 pass t = Teacher("alex",22,"F") print(t.name) print(t.age)
即继承父类又为子类添加新功能
class SchoolMember(): def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex def tell(self): info = """ _____info of %s______ name:%s age:%s sex:%s """%(self.name,self.name,self.age,self.sex) class Teacher(SchoolMember): def __init__(self,name,age,sex,salary):#重构方法为子类添加新功能 SchoolMember.__init__(self,name,age,sex)#继承父类中定义的变量#等同于super().__init__(name,age,sex)不用写类名和self self.salary = salary t = Teacher("alex",22,"F",5000) print(t.name) print(t.age) print(t.salary)
class SchoolMember(): Members = 0#初始化一个变量 def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex SchoolMember.Members +=1#每实例化一个对象,members就+1(是在父类地址空间中) def tell(self): info = """ _____info of %s______ name:%s age:%s sex:%s """%(self.name,self.name,self.age,self.sex) print(info) def __del__(self):#析构方法 SchoolMember.Members -=1 # print("%s 被开除了"%self.name) class Teacher(SchoolMember): def __init__(self,name,age,sex,salary):#重构方法为子类添加新功能 SchoolMember.__init__(self,name,age,sex)#继承父类中定义的变量 self.salary = salary def teaching(self,course): print("%s is teaching %s"%(self.name,course)) class Student(SchoolMember): def __init__(self,name,age,sex,grade): SchoolMember.__init__(self, name, age, sex) self.grade = grade def pay_tuition(self,amount): self.paid_tuition = amount print("student %s has paid tuition amount %s"%(self.name,amount)) s = Student("chen",25,"F","pys16") s2 = Student("li",30,"F","pys16") t = Teacher("alex",22,"F",5000) # s.tell() # t.tell()#都可以调用父类中的功能 # s2.tell() # t.teaching("python")#执行各自类中定义的功能 # s.pay_tuition(10000) # print(SchoolMember.Members)#统计所有的实例 del s2 s.pay_tuition(10000) print(SchoolMember.Members) # s2.pay_tuition(10000)
小结继承:
- 直接调用父类方法
- 继承父类方法并重构父类方法,先重构,在重构的方法里手动调用父类方法
- 可以定义子类自己的方法
- 析构方法
多继承
class School(): course_name ="python" grade = "pys16" test = 123 class People(): test = 321 def __init__(self,name,age): self.name = name self.age = age class Zgr(People,School):#继承多个,继承顺序从右到左,如果两个父类有同样的变量继承时左边的会覆盖右边的 def __init__(self,name,age,sex): People.__init__(self,name,age) self.sex = sex r = Zgr("alex",18,"F") print(r.course_name) #直接继承School print(r.test) #打印321
多态与多态性
多态:是指一类事物有多种形态
1. 序列类型有多种形态:字符串,列表,元组。
2. 动物有多种形态:人,狗,猪
多态性:多态与多态性是两种不同的概念
多态性是指具有不同功能的函数可以使用相同的函数名,这样就可以用一个函数名调用不同内容的函数。
# 多态与多态性 # 多态 class Animal: def talk(self): pass class Pepole(Animal): print("say hello") class Pig(Animal): print("sya aoao ") class Dog(Animal): print("say wangwang") p = Pepole() pig =Pig() d = Dog() # 多态性 def func(obj): obj.talk() func(p) func(pig) func(d)
使用多态性的好处:
1.增加了程序的灵活性
以不变应万变,不论对象千变万化,使用者都是同一种形式去调用,如func(animal)
2.增加了程序额可扩展性
通过继承animal类创建了一个新的类,使用者无需更改自己的代码,还是用func(animal)去调用
封装
封装数据的主要原因是:保护隐私
封装方法的主要原因是:隔离复杂度
用下划线的方式实现隐藏属性(设置成私有的)
类中所有双下划线开头的名称如__x都会自动变形成:_类名__x的形式:
class Foo: def __init__(self,name,money): self.name = name self.__money = money#隐藏了属性,其实已变形为self._Foo__money = money f = Foo("alex",20000) # print(f.__money)直接调用会报错AttributeError: 'Foo' object has no attribute '__money' print(f._Foo__money) #这样才能被调用到
也可以通过调用方法获取
class Foo: def __init__(self,name,money): self.name = name self.__money = money def get_money(self):#通过内部方法调用隐藏的属性 return self.__money f =Foo("alex",2000) print(f.get_money())#外部通过调用方法访问隐藏属性
实例和类共用的属性__dict__
#类和对象都有的属性__dict__ print(Foo.__dict__)#类的字典(类里面定义的名字,类变量、函数等) print(f.__dict__)#把f的属性以字典的形式存储起来,f.就是在调用自己的字典,当自己的字典中没有会去类的字典中找
隐藏方法
class Foo: def __init__(self,name,money): self.name = name self.__money = money def get_money(self): print(self.__money) self.__spam()#内部调用 def __spam(self):#隐藏方法,变形为_Foo__spam print("from spam") f = Foo("alex",2000) f.get_money()
property
property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值,内置函数,把类的方法做成实例的数据属性
import math class Circle: def __init__(self,radius): #圆的半径radius self.radius=radius @property#area = property(area) def area(self): return math.pi * self.radius**2 #计算面积 @property#perimeter = prooerty(perimeter) def perimeter(self): return 2*math.pi*self.radius #计算周长 c=Circle(10) print(c.radius) print(c.area) #可以向访问数据属性一样去访问area,会触发一个函数的执行,动态计算出一个值 print(c.perimeter) #就像实例访问自己的数据属性一样,如果不加property,访问就是在调用类方法print(c.perimeter())
class A: def __init__(self,name): self.__name = name @property def name(self): print("name.......") return self.__name @name.setter def name(self,value): print("newname") if not isinstance(value,str): raise TypeError("%s must be str" %value)#异常处理,当赋的值不是字符串,抛出异常 self.__name = value @name.deleter def name(self): print("delte") raise AttributeError("can not delte")#如果执行删除会抛出这条异常不让删除 n = A("alex") # print(n.name)#调用name方法 n.name = 123465#当赋值是会调用@name.setter下面的方法 # print(n.name) # del n.name #执行del时会调用@name.deleter下面的方法
静态方法
是一种普通函数,位于类定义的命名空间中,不会对任何实例类型进行操作,python为我们内置了函数staticmethod来把类中的函数定义成静态方法
class Foo: def spam(x,y,z): #类中的一个函数,千万不要懵逼,self和x啥的没有不同都是参数名 print(x,y,z) spam=staticmethod(spam) #把spam函数做成静态方法 # 等同于 class Foo: @staticmethod def spam(x,y,z): print(x,y,z) #类在调用时 Foo.spam(4,5,6)
应用场景:编写类时需要采用很多不同的方式来创建实例,而我们只有一个__init__函数,此时静态方法就派上用场了
# 应用场景可以有多种的实例化方式 import time class Date: def __init__(self,year,mon,day): self.year = year self.mon = mon self.day = day @staticmethod def now():#用Date.now()的形式去产生实例,该实例用的是当前时间 t = time.localtime() return Date(t.tm_year,t.tm_mon,t.tm_mday) #这时实例化时可以选择 d = Date(1998,2.12)#自己定义的时间 #或者 d1 = Date.now()#采用当前的时间
类方法:
类方法是给类用的,类在使用时会将类本身当做参数传给类方法的第一个参数,python为我们内置了函数classmethod来把类中的函数定义成类方法
#类方法 class A: x = 1 @classmethod def test(cls):#会自动补上cls也就是class print(cls.x,cls)#有了cls就可以调用类下的数据属性和方法了 A.test() #在调用方法时会把类自己当做参数传递给函数A.test(A)
应用场景
# 类方法的应用场景同静态方法 import time class Date: def __init__(self,year,mon,day): self.year = year self.mon = mon self.day = day @classmethod def now(cls): t = time.localtime() return cls(t.tm_year,t.tm_mon,t.tm_mday) d1 = Date.now() print(d1.year,d1.mon,d1.day)
类的内置方法__str__的应用
class D: def __init__(self,name): self.name = name def __str__(self):#类的内置方法,在打印实例的时候才会触发 # print("----->") # return "ok" return "%s"%self.name#可以在打印实例时用于实例数据属性的调用可同时一下显示所有的数据属性,定制显示信息 d = D("egon") print(d)
类方法和静态方法的区别
# 静态方法和类方法的区别 import time class Date: def __init__(self,year,mon,day): self.year = year self.mon = mon self.day = day # @staticmethod # def now(): # t = time.localtime() # return Date(t.tm_year,t.tm_mon,t.tm_mday) @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,mon:%s,day:%s"%(self.year,self.mon,self.day) e = EuroDate.now()#用EuroDate继承Date在EuroDate类中找不到now就可以去父类中找 #当时@staticmethod时会触发Date去实例化,而再print(e)时就是Date实例化后的对象不会触发EuroDate #定义的__str__方法。当是@classmethod时遇到now()就会谁调用我就把谁传进去,这样就是EuroDate #去实例化了EuroDate(t.tm_year, t.tm_mon, t.tm_mday)这样实例化产生的对象在遇到打印时就会触发 #自己定义的__str__方法了 print(e)
反射
python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)
四个可以实现自省的函数
下列方法适用于类和对象(一切皆对象,类本身也是一个对象)
hasattr(object,name)
getattr(object, name, default=None)
setattr(x, y, v)
delattr(x, y)
class Foo: def __init__(self,name): self.name = name def func(self): print("funct") f = Foo("egon") print(hasattr(Foo,"func"))#判断类Foo中有没有定义func这个名字,有就打印Ture # print(hasattr(f,"x"))#同样也可以判断实例中有没有这个名字,这个名字一定要是字符串 # print(getattr(Foo,"func"))#获取func没有会报错 print(getattr(Foo,"y",None))#这样获取y没有会显示None而不会报错 # print(getattr(f,"x"))#其实都是在__dict__中找有没有这个key值 if hasattr(f,"func"): aa = getattr(f,"func") aa() setattr(f,"x",1) #用于设定值等同于f.x = 1,其实都是操作的底层字典 delattr(f,"x")#用于删除值的

浙公网安备 33010602011771号