初识面向对象
内容目录
面向过程
优点是:极大的降低了写程序的复杂度,只需要顺着要执行的步骤,堆叠代码即可
缺点是:一套流水线或者流程就是用来解决一个问题,代码牵一发而动全身
面向对象
优点是:解决了程序的扩展性.对某一个对象单独修改,会立刻反映到整个体系中,如对游戏中一个人物参数的特征和技能修改都很容易。
缺点:可控性差,无法向面向过程的程序设计流水线式的可以很精准的预测问题的处理流程与结果,面向对象的程序一旦开始就由对象之间的交互解决问题,
即便是上帝也无法预测最终结果
对象与类:
具有相同特征和技能的一类事物就是‘类’,对象是则是这一类事物中具体的一个
class Person: #定义一个人类 role = 'person' #人的角色属性都是人 def walk(self): #人都可以走路,也就是有一个走路方法,也叫动态属性 print("person is walking...")
类有两种作用:属性引用和实例化
class Person: # 类名 country = 'China' # 创造了一个只要是这个类就一定有的属性 # 类属性 静态属性 def __init__(self,name,hp,aggr,sex): # 初始化方法,self是对象,是一个必须传的参数 # self就是一个可以存储很多属性的大字典 self.name = name # 往字典里添加属性的方式发生了一些变化 self.hp = hp self.aggr = aggr self.sex = sex def walk(self,n): # 方法,一般情况下必须传self参数,且必须写在第一个 # 后面还可以传其他参数,是自由的 print('%s走走走,走了%s步'%(self.name,n)) #静态属性 #查 print(Person.country) #China print(Person.__dict__['country']) #China #改 Person.country = '美国' print(Person.country) #美国 #动态属性 #查 alex = Person('ale',100,50,'noth') #实例化对象 实例化的过程就是类——>对象的过程 print(alex.__dict__) #{'name': 'ale', 'hp': 100, 'aggr': 50, 'sex': 'noth'} #查看所有属性 print(alex.name) #ale print(alex.__dict__['name']) #ale #改 alex.name = 'sx' print(alex.__dict__['name']) #sx #调用类中的方法 alex.walk(5) #sx走走走,走了5步 Person.walk(alex,5) #sx走走走,走了5步 class Personal: country = '中国' def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex def eat(self,food): print('%s吃%s'%(self.name,food))
类的属性补充
#特殊的类属性 类名.__name__# 类的名字(字符串) 类名.__doc__# 类的文档字符串 类名.__base__# 类的第一个父类(在讲继承时会讲) 类名.__bases__# 类所有父类构成的元组(在讲继承时会讲) 类名.__dict__# 类的字典属性 类名.__module__# 类定义所在的模块 类名.__class__# 实例对应的类(仅新式类中) #类名.__name__# 类的名字(字符串) print(Personal.__name__) #Personal print(Personal.__module__) #__main__ print(Personal.__dict__) #{'__module__': '__main__', 'country......
对象的相关知识
对象是关于类而实际存在的一个例子,即实例
对象/实例只有一种作用:属性引用
class 类名: def __init__(self,参数1,参数2): self.对象的属性1 = 参数1 self.对象的属性2 = 参数2 def 方法名(self):pass def 方法名2(self):pass 对象名 = 类名(1,2) #对象就是实例,代表一个具体的东西 #类名() : 类名+括号就是实例化一个类,相当于调用了__init__方法 #括号里传参数,参数不需要传self,其他与init中的形参一一对应 #结果返回一个对象 对象名.对象的属性1 #查看对象的属性,直接用 对象名.属性名 即可 对象名.方法名() #调用类中的方法,直接用 对象名.方法名() 即可
对象之间的交互
class Personal: def __init__(self,name,arge,bool,money): self.name = name self.arge = arge self.bool = bool self.money = money def Personal_attack_Dog(self,Dog): Dog.bool -= self.arge print('%s掉了%s血'%(Dog.name,self.arge)) def get_weapon(self,Weapon): if self.money > Weapon.cost: self.money -= Weapon.cost self.weapon = weapon self.arge += Weapon.arge else: print('钱不够') class Dog: def __init__(self,name,bite,bool): self.name = name self.bite = bite self.bool = bool def Dog_bite_Personal(self,Personal): Personal.bool -= self.bite class Weapon: def __init__(self,arge,use_times,cost): self.arge = arge self.use_times = use_times self.cost = cost def cut(self,obj): if self.use_times > 0: obj.bool -= self.arge*2 self.use_times -= 1 def func(self): print('我有武器性能了') ale = Personal('ale',10,100,200) ale.money += 2000 snb = Dog('snb',20,100) weapon = Weapon(30,3,100) ale.Personal_attack_Dog(snb) #snb掉了10血 ale.get_weapon(weapon) ale.weapon.func() #我有武器性能了 ale.weapon.cut(snb) print(snb.bool) #30
类命名空间与对象、实例的命名空间
创建一个类就会创建一个类的名称空间,用来存储类中定义的所有名字,这些名字称为类的属性
而类有两种属性:静态属性和动态属性
静态属性就是直接在类中定义的变量
动态属性就是定义在类中的方法
创建一个对象/实例就会创建一个对象/实例的名称空间,存放对象/实例的名字,称为对象/实例的属性
在obj.name会先从obj自己的名称空间里找name,找不到则去类中找,类也找不到就找父类...最后都找不到就抛出异常
类的组合用法
当类之间有显著不同,并且较小的类是较大的类所需要的组件时,用组合比较好
from math import pi class Cricle: def __init__(self,r): self.r = r # @property def square(self): return pi*self.r**2 # print(pi*self.r**2) def perimeter(self): return 2*pi*self.r class Range: def __init__(self,inside,outside): self.inlength = Cricle(inside) #连接cricle的桥梁 self.outlength = Cricle(outside) #连接cricle的桥梁 def square(self): return self.outlength.square() - self.inlength.square() #直接引用cricle的square来求解 def perimeter(self): return self.inlength.perimeter() + self.outlength.perimeter() #直接引用cricle的perimeter来求解 ring = Range(5,10) print(ring.square()) #圆环体积 print(ring.perimeter()) #圆环周长
抽象 --> 继承 --> 派生
python中类的继承分为:单继承和多继承
class Animal: def __init__(self,run,eat): self.run = run self.eat = eat def run1(self): print('我们都会走') def eat1(self): print('我们都会肚子饿') class Dog(Animal): def __init__(self,run,eat,bite): Animal.__init__(self,run,eat) self.bite = bite #派生属性 def bite1(self): #派生方法 print('我会咬人') class People(Animal): def __init__(self,run,eat,think): Animal.__init__(self,run,eat) self.think = think def think1(self): print('我会思考') animal = Animal('feet','food') people = People('feet','food','think') dog = Dog('feet','food','bite') animal.run1() #我们都会走 people.run1() #我们都会走 调用父类中的方法 dog.run1() #我们都会走 调用父类中的方法 people.think1() #我会思考 子类派生方法 dog.bite1() #我会咬人 子类派生方法 print(people.think) #think 子类派生属性 print(dog.bite) #bite 子类派生属性
class Animal: def __init__(self,run,eat): self.run = run self.eat = eat def drink(self): print('我们都会喝水') class People(Animal): def __init__(self,run,eat,think): super(). __init__(run,eat) self.think = think def think1(self): print('我会思考') animal = Animal('foot','food') people = People('foot','food','think') animal.drink() #我们都会喝水 print(people.think) #think 派生属性 people.think1() #我会思考 派生属性
多继承
新式类 继承object类的才是新式类 广度优先(python3.x以上)只有新式类中存在mro()-->查看继承顺序
经典类 如果你直接创建一个类在2.7中就是经典类 深度优先
class A(object): def func(self): print('A') class B(A): def func(self): super().func() print('B') class C(A): def func(self): super().func() print('C') class D(B,C): def func(self): super().func() print('D') b = D() b.func() #A C B D print(B.mro()) #[<class '__main__.B'>, <class '__main__.A'>, <class 'object'>]


继承:是基于抽象的结果,通过编程语言去实现它,肯定是先经历抽象这个过程,才能通过继承的方式去表达出抽象的结构。
派生
当然子类也可以添加自己新的属性或者在自己这里重新定义这些属性(不会影响到父类)
需要注意的是,一旦重新定义了自己的属性且与父类重名,那么调用新增的属性时,就以自己为准了
通过继承建立了派生类与基类之间的关系,它是一种'是'的关系,比如白马是马,人是动物
当类之间有很多相同的功能,提取这些共同的功能做成基类,用继承比较好,比如教授是老师
class Animal: ''' 人和狗都是动物,所以创造一个Animal基类 ''' def __init__(self, name, aggressivity, life_value): self.name = name # 人和狗都有自己的昵称; self.aggressivity = aggressivity # 人和狗都有自己的攻击力; self.life_value = life_value # 人和狗都有自己的生命值; def eat(self): print('%s is eating'%self.name) class Dog(Animal): ''' 狗类,继承Animal类 ''' def bite(self, people): ''' 派生:狗有咬人的技能 :param people: ''' people.life_value -= self.aggressivity class Person(Animal): ''' 人类,继承Animal ''' def attack(self, dog): ''' 派生:人有攻击的技能 :param dog: ''' dog.life_value -= self.aggressivity egg = Person('egon',10,1000) ha2 = Dog('二愣子',50,1000) print(ha2.life_value) print(egg.attack(ha2)) print(ha2.life_value)
继承有两种用途:
一:继承基类的方法,并且做出自己的改变或者扩展(代码重用)
二:声明某个子类兼容于某基类,定义一个接口类Interface,接口类中定义了一些接口名(就是函数名)且并未实现接口的功能,子类继承接口类,并且实现接口中的功能
from abc import abstractmethod,ABCMeta class Payment(metaclass=ABCMeta): @abstractmethod def pay(self,money):pass #子类必须要有这种方法 class Wetpay(Payment): def pay(self,money): print('微信支付了%s'%money) class Alipay(Payment): def pay(self,money): print('支付宝支付了%s'%money) class Applepay(Payment): def pay(self,money): print('Applepay支付了%s'%money) # def pay(obj,money): # obj.pay(money) ale = Wetpay() als = Alipay() alk = Applepay() ale.pay(100) # als.pay(200) # pay(als,200) # pay(alk,300)
依赖倒置原则:
高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该应该依赖细节;细节应该依赖抽象。换言之,要针对接口编程,而不是针对实现编程
与java一样,python也有抽象类的概念但是同样需要借助模块实现,抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化
from abc import abstractmethod,ABCMeta class Fruits(metaclass=ABCMeta): all_fruits = '水果' @abstractmethod def much(self):pass '''子类必须存在的方法''' @abstractmethod def many(self):pass '''子类必须存在的方法''' class Apple(Fruits): def much(self): print('我的价格三元') def many(self): print('我的数量三个') class Banana(Fruits): def much(self): print('我的价格四元') def many(self): print('我的数量四个') apple = Apple() banana = Banana() apple.much() banana.many() print(apple.all_fruits) #水果 print(banana.all_fruits) #水果
多态指的是一类事物有多种形态
动物有 人、猪、狗
文件有可执行、不可执行
多态性
一 什么是多态动态绑定(在继承的背景下使用时,有时也称为多态性)
多态性是指在不考虑实例类型的情况下使用实例
鸭子类型
Python崇尚鸭子类型,即‘如果看起来像、叫声像而且走起路来像鸭子,那么它就是鸭子
隐藏对象的属性和实现细节,仅对外提供公共访问方式。
好处 将变化隔离;便于使用;提高复用性;提高安全性;
封装原则 将不需要对外提供的内容都隐藏起来;把属性都隐藏,提供公共方法对其访问
私有变量和私有方法
在python中用双下划线开头的方式将属性隐藏起来(设置成私有的)
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 room = Room('房间','ale',10,10,10) print(room.tell_area()) #100
from abc import abstractmethod,ABCMeta class Animal(metaclass=ABCMeta): def __init__(self,name,age): self.name = name self.age = age @abstractmethod def eat(self): print('我们都是吃货') def tink(self): print('我会思考?') class People(Animal): def __init__(self,name,age,think): Animal.__init__(self,name,age) self.__think = think def eat(self): print('哈哈,我也会吃东西') def __tink(self): print('我会思考') people = People('ale',22,'思考') def func(obj): #统一接口 obj.eat() people.tink() #先调用子类 我会思考 私有属性,外部调不出来,但内部可以调用 people.think() 私有方法,外部调不出来,但内部可以调用 people.tink() #我会思考? 父类属性 print(people.__dir__()) #查看内部属性,可以得到内部私有属性名,后调动 print(people._People__think) #思考 外部调动了内部私密属性
封装与扩展性
封装在于明确区分内外,使得类实现者可以修改封装内的东西而不影响外部调用者的代码;
而外部使用用者只知道一个接口(函数),只要接口(函数)名、参数不变,使用者的代码永远无需改变。
这就提供一个良好的合作基础——或者说,只要接口这个基础约定不变,则代码改变不足为虑。
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 room = Room('房间','ale',10,10,10) print(room.tell_area()) #100
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.__high room = Room('房间','ale',10,10,10) print(room.tell_area()) #1000
property属性(将函数方法属性化)
什么是特性property
property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值
class Goods: def __init__(self): # 原价 self.original_price = 100 # 折扣 self.discount = 0.8 @property #查看 def price(self): # 实际价格 = 原价 * 折扣 new_price = self.original_price * self.discount return new_price @price.setter #修改 #等价式 price=price.setter(price) def price(self, value): self.original_price = value @price.deleter #删除 #等价式 price = price.deleter(price) def price(self): del self.original_price obj = Goods() print(obj.price) # 获取商品价格 obj.price = 200 # 修改商品原价 print(obj.price) del obj.price # 删除商品原价
staticmathod 静态的方法
classmethod 类方法
class Goods: __discount = 0.8 def __init__(self,name,price): self.name = name self.__price = price @property def price(self): return self.__price * Goods.__discount @classmethod # 把一个方法 变成一个类中的方法,这个方法就直接可以被类调用,不需要依托任何对象 def change_discount(cls,new_discount): # 修改折扣 cls.__discount = new_discount apple = Goods('苹果',5) print(apple.price) Goods.change_discount(0.5) # Goods.change_discount(Goods) print(apple.price) # 当这个方法的操作只涉及静态属性的时候 就应该使用classmethod来装饰这个方法
class Login: def __init__(self,name,password): self.name = name self.pwd = password def login(self):pass @staticmethod def get_usr_pwd(): # 静态方法 usr = input('用户名 :') pwd = input('密码 :') Login(usr,pwd) Login.get_usr_pwd() # 在完全面向对象的程序中, # 如果一个函数 既和对象没有关系 也和类没有关系 那么就用staticmethod将这个函数变成一个静态方法

浙公网安备 33010602011771号