八、初识面向对象
http://www.cnblogs.com/Eva-J/articles/7293890.html#_label1
1、楔子
#面向对象编程
#面向对象的思想
#对象就是一个实实在在的,可以准确描述出来的实体,比如说egg,alex
#面向对象的编程是一种上帝视角的切换
#之前你使用的面向过程的编程是面向结果去编程,一个流水线下来有固定的结果
#好想 可扩展性差 容易引起代码的安全问题
#面向对象
#类:具有相同属性和方法的一类事物
#对象:具有具体的属性的事物
2、初识类
2.1 类
#面相对象在什么时候用 :需要反复传递相同的参数给一些函数的时候
#类名的首字母要大写
class Person:
role = ‘person‘ #静态属性 类属性:所有的对象共有的属性,可以直接被类调用
def __init__(self,name,sex,aggressive=200):
#对象属性 属性 #是只属于某一个对象的,必须在实例化之后用对象调用
self.name = name #名字 self.name =‘alex’
self.sex = sex #性别
self.aggr = aggressive #攻击力
self.blood = 20000 #血
#self = {‘name‘:name,‘sex‘:sex,‘aggr‘:aggr,‘blood‘:blood,‘attack‘:attack}
def attack(self): #类里面的所有方法本质上就是一个函数,拥有一个必须传的参数self
print(‘%s attack‘%self.name)
print(Person.role)
# print(Person.attack)
#实例化一个对象
alex = Person(‘alex‘,‘male‘,250) #实例化
print(alex.name)
# alex.attack()
egon = Person(‘egon‘,‘female‘)
egon.attack()
2.2 静态属性
定义在类里面的一个变量就是静态属性也就是类属性
所有的对象共有的属性,可以直接被类调用
2.3 属性
定义在类里面的__init__里的变量就是对象属性也就是属性
是只属于某一个对象的,必须在实例化之后用对象调用
2.4 动态属性
定义在类里面的一个函数就是动态属性也就是方法
类里面的所有方法本质上就是一个函数,拥有一个必须传的参数self
2.5 实例化
类()
参数1 = 1
参数2 = 2
对象名 = 类名(参数1,参数2)
2.5 例题1
打印:
‘‘‘
练习一:在终端输出如下信息
小明,10岁,男,上山去砍柴
小明,10岁,男,开车去东北
小明,10岁,男,最爱大保健
老李,90岁,男,上山去砍柴
老李,90岁,男,开车去东北
老李,90岁,男,最爱大保健
老张…
‘‘‘
class Person:
def __init__(self,name,age,sex=‘男‘):
self.name=name
self.age=age
self.sex = sex
def kanchai(self):
print(‘%s,%s岁,%s,上山去砍柴‘%(self.name,self.age,self.sex))
print("%s,%s岁,%s,开车去东北" % (self.name, self.age, self.sex))
print("%s,%s岁,%s,最爱大保健" % (self.name, self.age, self.sex))
小明 = Person(‘小明‘,10)
小明.kanchai()
老张 = Person(‘老张‘,90)
老张.kanchai()
3、面向对象之间的交互
例题2
人狗大战
class Person:
role = ‘person‘ #静态属性 类属性:所有的对象共有的属性,可以直接被类调用
def __init__(self,name,sex,aggressive=200):
#对象属性 属性 #是只属于某一个对象的,必须在实例化之后用对象调用
self.name = name #名字 self.name =‘alex’
self.sex = sex #性别
self.aggr = aggressive #攻击力
self.blood = 2000 #血
def attack(self,dog): #类里面的所有方法本质上就是一个函数,拥有一个必须传的参数self
print(‘%s attack %s‘%(self.name,dog.name))
dog.blood = dog.blood - self.aggr
class Dog:
def __init__(self,name,aggressive=666):
self.name = name
self.aggr = aggressive
self.blood = 8000
def bite(self,person):
print(‘%s 咬了 %s‘%(self.name,person.name))
person.blood = person.blood - self.aggr
if person.blood <= 0:
print(‘game over : %s‘%person.name)
#
alex = Person(‘alex‘,‘male‘,250)
egon = Person(‘egon‘,‘male‘)
teddy = Dog(‘葫芦娃‘)
teddy.bite(alex)
print("alex.blood:",alex.blood)
teddy.bite(alex)
print("alex.blood:",alex.blood)
teddy.bite(alex)
print("alex.blood:",alex.blood)
teddy.bite(alex)
print("alex.blood:",alex.blood)
egon.attack(teddy)
print("teddy.blood:",teddy.blood)
4、例题3
求圆的面积和周长
#类 : 圆
#属性 :圆半径
#方法 :计算圆的周长和面积
from math import pi
class Circle:
def __init__(self,r):
self.r = r
def area(self):
return pi *self.r ** 2
def round(self):
return 2 * pi * self.r
c1 = Circle(10)
print(c1.area())
print(c1.round())
5、类的命名空间
对于类的静态属性:
类.属性 调用的就是类中的属性
对象.属性 先从自己的内存空间里找名字,找到了用自己的,没找到用类的,如果类中也没有就报错。
对于类的动态属性(方法):
这个方法本身就存在类中,并不会存在对象的内存中
但是在对象调用类中的方法的时候,要依赖于一个地址簿去类中寻找对应的方法。
关于对象的属性:
对象的属性就存在对象的命名空间中
只能被对象调用、修改
不能被类调用
例1、
class A:
country = ‘印度‘
def show_name(self):
print(self.name)
a = A() #实例化对象
a.name = ‘alex‘ #给对象创建一个name属性
a.show_name() #调用了showname方法
例2、
class A:
country = ‘印度‘
def show_name(self):
print(self.name)
a = A()
a.name = ‘alex‘
a.show_name = ‘egon‘
a.show_name() #报错
例3、
class A:
country = ‘印度‘
def show_name(self):
print(self.name)
a = A() #a对象
b = A() #b对象
print(A.country)
print(a.country) #先找a对象的内存 再找A的内存
print(b.country)
a.country = ‘中国‘ #给a对象创建了一个属性
print(A.country) #印度
print(a.country) #中国
print(b.country) #印度
6、组合
例1、
#Ring
#圆环的属性:大圆半径和小圆半径
class Circle:
def __init__(self,r):
self.r = r
def area(self):
return self.r*self.r*3.14
def perimeter(self):
return self.r*2*3.14
# c = Circle(10)
# c.area()
# c.perimeter()
class Ring:
#组合表达的是 什么有什么的 一种关系
#组合增强了代码的重用性
def __init__(self,r_out,r_in): #10,5
self.c_out = Circle(r_out)
self.c_in = Circle(r_in)
def area(self):
return self.c_out.area() - self.c_in.area()
def perimeter(self):
return self.c_out.perimeter() + self.c_in.perimeter()
r1 = Ring(10,5)
print(r1.area())
print(r1.perimeter())
例2、
class Birthday:
def __init__(self,year,month,day):
self.year = year
self.month = month
self.day = day
#课程类
#课程的名字
#课程周期
#授课的老师
#课程的价格
class Course:
def __init__(self,name,period,teacher,price):
self.name=name
self.period=period
self.teacher=teacher
self.price=price
class Person:
def __init__(self,name,birth_obj,kecheng):
self.name = name
self.birthday = birth_obj
self.kecheng=kecheng
bith_hai = Birthday(1988,11,11)
py=Course(‘python‘,20,‘jingdao‘,20000)
haijiao = Person(‘海娇‘,bith_hai,py)
print(haijiao.name)
print(haijiao.birthday.year)
print(haijiao.birthday.month)
print(haijiao.kecheng.name)
例3、
class Birthday:
def __init__(self,year,month,day):
self.year = year
self.month = month
self.day = day
class Course:
def __init__(self,name,period,teacher,price):
self.name=name
self.period=period
self.teacher=teacher
self.price=price
class Person:
def __init__(self,name,birth_obj):
self.name = name
self.birthday = birth_obj
bith_hai = Birthday(1988,11,11)
py=Course(‘python‘,20,‘jingdao‘,20000)
lux = Course(‘linux‘,20,‘oldboy‘,20000)
haijiao = Person(‘海娇‘,bith_hai)
print(haijiao.name)
print(haijiao.birthday.year)
print(haijiao.birthday.month)
haijiao.kecheng = py
haijiao.kecheng1 = lux
print(haijiao.kecheng.name)
print(haijiao.kecheng1.name)
例4、
class Person:
def __init__(self,name,sex,aggr,blood):
self.name = name
self.sex = sex
self.aggr = aggr
self.blood = blood
self.money = 0
def attack(self,dog):
dog.blood -= self.aggr
def equip(self,weapon):
self.money -= weapon.price
self.weapon = weapon
def use_weapon(self,dog):
self.weapon.hurt(dog)
self.blood += self.weapon.back_blood
class Dog:
def __init__(self,name,kind,aggr,blood):
self.name = name
self.kind = kind
self.aggr = aggr
self.blood = blood
def bite(self,person):
person.blood -= self.aggr
class Weapon:
def __init__(self,name,attack,price,back_blood):
self.name = name
self.attack = attack
self.price = price
self.back_blood = back_blood
def hurt(self,dog):
dog.blood -= self.attack
egon = Person(‘egon‘,‘不详‘,250,380)
alex = Person(‘alex‘,‘不详‘,20,40000)
dog = Dog(‘egg‘,‘藏獒‘,500,20000)
#加武器
毒包子 = Weapon(‘毒包子‘,10000,200,300)
egon.money = 200
if egon.money >= 毒包子.price:
#egon就装备上毒包子
egon.equip(毒包子)
egon.use_weapon(dog)
print(egon.blood)
print(dog.blood)
7、继承
7.1 继承
7.1.1 什么是继承
#继承:什么是什么的关系
#他大舅打二舅都是他舅
#高桌子低板凳都是木头
继承是一种创建新类的方式,在python中,新建的类可以继承一个或多个父类,父类又可称为基类或超类,新建的类称为派生类或子类
子类 派生类 (派生属性 派生方法)
子类的对象要去调用方法或者属性:自己有的调自己的,自己没有的调父类的
self是什么:谁调用就是谁
子类的对象调用父类的方法,在父类方法中的self是子类的对象
class Animal: #父类、超类
def eat(self):
pass
class Bnimal: #父类、超类
def drink(self):
pass
class Dog(Animal,Bnimal): #子类、派生类
pass
class Cat(Animal): #子类、派生类
pass
7.1.2 查看继承
>>> SubClass1.__bases__ #__base__只查看从左到右继承的第一个子类,__bases__则是查看所有继承的父类
(<class ‘__main__.ParentClass1‘>,)
>>> SubClass2.__bases__
(<class ‘__main__.ParentClass1‘>, <class ‘__main__.ParentClass2‘>)
7.1.3 继承与抽象
继承:是基于抽象的结果,通过编程语言去实现它,肯定是先经历抽象这个过程,才能通过继承的方式去表达出抽象的结构。
抽象只是分析和设计的过程中,一个动作或者说一种技巧,通过抽象可以得到类
7.1.4 解决代码的重用性
#============第一部分===========
#狗
class Dog:
def eat(self):
print(‘eating‘)
def drink(self):
print(‘drinking‘)
def sleep(self):
print(‘sleeping‘)
def say(self):
print(‘汪汪汪‘)
#猫
class Cat:
def eat(self):
print(‘eating‘)
def drink(self):
print(‘drinking‘)
def sleep(self):
print(‘sleeping‘)
def say(self):
print(‘喵喵喵‘)
#============第二部分===========
#解决代码的重用性
class Animal:
def eat(self):
print(‘eating‘)
def drink(self):
print(‘drinking‘)
def sleep(self):
print(‘sleeping‘)
#狗
class Dog(Animal):# 在类后面括号中写入另外一个类名,表示当前类继承另外一个类
def say(self):
print(‘汪汪汪‘)
#猫
class Cat(Animal):# 在类后面括号中写入另外一个类名,表示当前类继承另外一个类
def say(self):
print(‘喵喵喵‘)
7.2 派生
7.2.1 派生
当然子类也可以添加自己新的属性或者在自己这里重新定义这些属性(不会影响到父类),需要注意的是,一旦重新定义了自己的属性且与父类重名,那么调用新增的属性时,就以自己为准了。
#在继承中
#子类可以继承父类的所有属性和方法
#但是 当父类和子类中有同名方法的时候 一定调用子类的
#如果想使用父类该方法的功能 需要借助super方法
7.2.2 super()
如果子类中含有和父类中相同的方法但是还想调用父类的方法就要用super
#父类 animal
class Animal:
def __init__(self,name):
self.name = name
def eat(self):
print(‘%s eating %s‘%(self.name,self.food))
def drink(self):
print(‘drinking‘)
def sleep(self):
print(‘sleeping‘)
#狗
class Dog(Animal):
def __init__(self,name):
# Animal.__init__(self,name) #经典类的调用父类中方法的方式
super().__init__(name) #新式类调用父类中方法的方式
self.food = ‘狗粮‘
def say(self):
print(‘汪汪汪‘)
#猫
class Cat(Animal):
def __init__(self,name):
super().__init__(name) #新式类
self.food = ‘猫粮‘
def say(self):
print(‘喵喵喵‘)
wang = Dog(‘alex‘)
ha2 = Dog(‘二哈‘)
wang.eat()
ha2.eat()
c = Cat(‘egon‘)
c.eat()
7.2.3 例题1
7.2.4 例2
class Animal: #父类 超类 基类
def __init__(self,name,blood,aggr):
self.name = name
self.blood = blood
self.aggr = aggr
class Person(Animal): #继承的语法 Person是子类
def __init__(self, name, blood, aggr,RMB):
super(Person, self).__init__(name,blood,aggr)
self.qian=RMB
def attack(self,dog):
dog.blood -= self.aggr
class Dog(Animal): #Dog是子类
def __init__(self, name, blood, aggr, pinzhong):
super().__init__(name,blood,aggr)
self.breed= pinzhong #派生属性
def bite(self,person): #派生方法
person.blood -= self.aggr
alex = Person(‘alex‘,250,12,1000000) #钱
egg = Dog(‘egg‘,25000,20,‘金毛‘) #品种
8、接口类与抽象类
8.1归一化设计
归一化,就是只要是基于同一个接口实现的类,那么所有的这些类产生的对象在使用时,从用法上来说都一样。
# 编程思想:为子类做规范
#1.接口类 不实现具体的方法,并且可以多继承
#2.抽象类 可以做一些基础实现,并且不推荐多继承
8.2 实现接口类和抽象类的语法
from abc import abstractmethod,ABCMeta
class 父类(metaclass=ABCMeta):
@abstractmethod
def func(self):pass
8.3 接口类
# 接口类:可以多继承,且最好不实现具体功能
from abc import abstractmethod,ABCMeta
# class Payment(metaclass=ABCMeta): #抽象类/接口类:子类的规范
# @abstractmethod
# def payment(self,money):pass
class Applepay():
def payment(self,money):
print(‘apple 支付了 %d元‘%money)
class Alipay():
def payment(self,money):
print(‘支付宝 支付了 %d元‘ % money)
class Wechatpay():
def payment(self,money):
print(‘微信 支付了 %d元‘ % money)
def payment(pay_obj,money): #归一化设计
pay_obj.payment(money)
apple = Applepay()
ali = Alipay()
wechat = Wechatpay()
payment(wechat,100)
payment(apple,100)
payment(ali,100)
8.4 抽象类
# 抽象类:最好单继承,且可以简单的实现功能
from abc import abstractmethod,ABCMeta
class Foo(metaclass=ABCMeta): #抽象类
@abstractmethod
def read(self):
f = open()
f.close()
@abstractmethod
def write(self):
f = open()
f.close()
class File(Foo):
def read(self):
super().read()
def write(self):
super().write()
class Disk(Foo):
def read(self):
super().read()
def write(self):
super().write()
9、钻石继承
# 钻石继承问题
# python的 新式类 和 经典类 在继承顺序上的不同
#新式类:广度优先
#查看继承顺序 子类名.mro()
#经典类:深度优先 #博大精深
# 继承顺序
class A(object):
def test(self):
print(‘from A‘)
class B(A):
def test(self):
print(‘from B‘)
class C(A):
def test(self):
print(‘from C‘)
class D(B):
def test(self):
print(‘from D‘)
class E(C):
def test(self):
print(‘from E‘)
class F(D,E):
# def test(self):
# print(‘from F‘)
pass
f1=F()
f1.test()
print(F.__mro__) #只有新式才有这个属性可以查看线性列表,经典类没有这个属性
#新式类继承顺序:F->D->B->E->C->A
#经典类继承顺序:F->D->B->A->E->C
#python3中统一都是新式类
#pyhon2中才分新式类与经典类
10、多态
多态
python天生支持多态
11、经典类和新式类
经典类和新式类的区别
首先:
Python 2.x中默认都是经典类,只有显式继承了object才是新式类
Python 3.x中默认都是新式类,不必显式的继承object
其次:
------新式类对象可以直接通过__class__属性获取自身类型:type
------继承搜索的顺序发生了改变,经典类深度优先,新式类广度优先
------新式类增加了__slots__内置属性, 可以把实例属性的种类锁定到__slots__规定的范围之中
------新式类增加了__getattribute__方法
12、元类
object是所有类的基类
type #元类是所有类的类型 print(type(list)) #<class ‘type‘>
13、可命名元组
只有属性,没有方法可以用这个可命名元组
#没有方法并且属性不会发生变化的类
#定义简单
#不能改变
14、封装
14.1 私有属性、私有方法、私有静态属性
self.__pwd 双下方法
self.__pwd转换成了_Teacher__pwd
调_Teacher__pwd可以修改
__pwd 双下方法
__pwd转换成了_Teacher__pwd
子类不能继承父类的私有方法
#封装
class Teacher:
__identifier = ‘Teacher‘ #私有静态属性
def __init__(self,name,pwd):
self.name = name
self.__pwd = pwd #私有属性
self.__p()
def __p(self): #私有方法
return hash(self.__pwd)
def login(self,password):
#self.__pwd == password
return hash(password) == self.__p()
# print(Teacher._Teacher__identifier)
alex = Teacher(‘alex‘,‘3714‘)
ret = alex.login(‘3714‘)
print(ret)
# print(alex._Teacher__b)
# print(alex.__dict__)
14.2 私有属性
# 例一:BMI指数(bmi是计算而来的,但很明显它听起来像是一个属性而非方法,如果我们将其做成一个属性,更便于理解)
#
# 成人的BMI数值:
# 过轻:低于18.5
# 正常:18.5-23.9
# 过重:24-27
# 肥胖:28-32
# 非常肥胖, 高于32
# 体质指数(BMI)=体重(kg)÷身高^2(m)
# EX:70kg÷(1.75×1.75)=22.86
class Person:
def __init__(self,name,height,weight):
self.name = name
self.__height = height
self.__weight = weight
def get_bmi(self):
return self.__weight / (self.__height*self.__height)
def change_weight(self,new_weight):
if new_weight > 20:
self.__weight = new_weight
else:
print(‘体重过轻‘)
# jinghong = Person(‘景弘‘,1.81,94)
# print(jinghong.get_bmi())
# jinghong.change_weight()
# print(jinghong.get_bmi())
#房屋 :
# 业主 长 宽
# 面积
class Host:
def __init__(self,owner,length,width):
self.owner = owner
self.__length = length
self.__width = width
def area(self):
return self.__length * self.__width
guo = Host(‘郭磊‘,2,1)
print(guo.area())
私有静态属性
所有的私有属性和私有方法在内部使用的时候不用做变形,在外部使用的时候要做变形如__pwd成_Teacher__pwd
在类外定义双下属性的时候只是定义了普通属性
类外定义:
class A:pass
a = A()
a.__pwd ==10 #这是定义普通属性
14.3、私有方法
#私有方法
#1.有一些方法的返回值只是用来作为中间结果
#2.父类的方法不希望子类继承
#3.不能在类外调用
class Foo:
def __jinghong_sb(self): #_Foo__jinghong_sb
print(‘Foo‘)
class Son(Foo):
# def __jinghong_sb(self):
# print(‘Son‘)
def func(self):
self.__jinghong_sb() #_Son__jinghong_sb
son = Son()
son.func()
15、用装饰器描述的几个方法
15.1 @property
15.1.1 @property
##property方法:讲一个类中的方法伪装成属性,在外面调用的时候可以不加括号
class Person:
def __init__(self,name,height,weight):
self.name = name
self.__height = height
self.__weight = weight
@property
def bmi(self):
return self.__weight / (self.__height*self.__height)
jinghong = Person(‘景弘‘,1.8,94) #方法变属性
print(jinghong.name,jinghong.bmi)
15.2.2 @setter
@setter方法可以修改私有属性
class Shop:
discount = 0.75
def __init__(self,name,price):
self.name = name
self.__price = price
@property #!!!
def price(self):
return self.__price * Shop.discount
@price.setter #!
def price(self,new_price):
self.__price = new_price
apple = Shop(‘apple‘,5)
apple.price = 6
print(apple.__dict__)
print(apple.price)
class A:
pass
a = A()
a.name = ‘jinghong‘
print(a.name)
print(a.__dict__)
del a.name
print(a.__dict__)
15.2 @staticmethod和@classmethod
#静态方法 :没有必须传的参数 方法不需要用对象的属性和类的属性
#类方法:必须传一个类,方法不需要使用对象的属性,但可以使用类的属性
#普通方法 :必须传一个对象 可以使用对象的属性和类的属性
15.2.1 @staticmethod
静态方法
# 不能将函数独立的放在类外面 完全使用面向对象编程的时候
# 并且这个函数完全不需要依赖对象的属性和类的属性
# 就可以用staticmethod装饰这个函数
class Manager:
@staticmethod #静态方法
def create_student(): pass
Manager.create_student()
print(Manager.create_student)
15.2.2 @classmethod
类方法
必须传一个类cls,静态方法不需要
class A:
role = ‘a‘
@classmethod
def class_method(cls):
print(cls.role)
A.class_method()
A.role