面向过程的程序设计的核心是过程(流水线式思惟),过程即解决问题的步骤,面向过程的设计就比如精心设计好一条流水线,考虑周全何时处理什么东西。python
优势是:极大的下降了写程序的复杂度,只须要顺着要执行的步骤,堆叠代码便可。git
缺点是:一套流水线或者流程就是用来解决一个问题,代码牵一发而动全身。程序员
应用场景:一旦完成基本不多改变的场景,著名的例子有Linux內核,git,以及Apache HTTP Server等。面试
面向对象的程序设计的核心是对象(上帝式思惟),要理解对象为什么物,必须把本身当成上帝,上帝眼里世间存在的万物皆为对象,不存在的也能够创造出来。面向对象的程序设计比如如来设计西游记,如来要解决的问题是把经书传给东土大唐,如来想了想解决这个问题须要四我的:唐僧,沙和尚,猪八戒,孙悟空,每一个人都有各自的特征和技能(这就是对象的概念,特征和技能分别对应对象的属性和方法),然而这并很差玩,因而如来又安排了一群妖魔鬼怪,为了防止师徒四人在取经路上被搞死,又安排了一群神仙保驾护航,这些都是对象。而后取经开始,师徒四人与妖魔鬼怪神仙互相缠斗着直到最后取得真经。如来根本不会管师徒四人按照什么流程去取。算法
优缺点编程
优势是:解决了程序的扩展性。对某一个对象单独修改,会马上反映到整个体系中,如对游戏中一我的物参数的特征和技能修改都很容易。编程语言
缺点:可控性差,没法向面向过程的程序设计流水线式的能够很精准的预测问题的处理流程与结果,面向对象的程序一旦开始就由对象之间的交互解决问题,即使是上帝也没法预测最终结果。因而咱们常常看到一个游戏人某一参数的修改极有可能致使阴霸的技能出现,一刀砍死3我的,这个游戏就失去平衡。ide
应用场景:需求常常变化的软件,通常需求的变化都集中在用户层,互联网应用,企业内部软件,游戏等都是面向对象的程序设计大显身手的好地方。函数
在python 中面向对象的程序设计并非所有。加密
面向对象编程可使程序的维护和扩展变得更简单,而且能够大大提升程序开发效率 ,另外,基于面向对象的程序可使它人更加容易理解你的代码逻辑,从而使团队开发变得更从容。
python中一切皆为对象,类型的本质就是类
类: 具备相同属性和相同动做的一类事物,组成一个类
对象:具备的摸一个具备是技术性和具体动做的一个实体
相似抽象的,对象是具体的
类被创造出来,是为了描述对象的
函数版本的代码是面向过程的思想,而类的引入则是面向对象的思想了。你先规划好有哪些角色,角色有哪些相同的属性,有哪些不能的能力,有哪些不一样的属性,先作好规划。而后去一一实现
class Person: #定义一我的类 role = 'person' #人的角色属性都是人 # 静态属性 def walk(self): #人均可以走路,也就是有一个走路方法,也叫动态属性 print("person is walking...")
只要是写在类名中的名字,无论是变量仍是函数名,都不能在类的外部直接调用
只能经过类名来使用它
class Person: #定义一我的类 role = 'person' #人的角色属性都是人 def walk(self): #人均可以走路,也就是有一个走路方法 print("person is walking...") print(Person.role) #查看人的role属性 print(Person.walk) #引用人的走路方法,注意,这里不是在调用
class 类名: 静态属性 = 123 def 动态属性(self): # 在类中的方法的一个默认的参数,但也只是一个形式参数,约定必须叫self print('-->',self) # 只要是写在类名中的名字 无论是变量仍是函数名 都不能在类的外部直接调用 # 只能经过类名来使用它 # 类名的第一个功能是 —— 查看静态属性 print(类名.静态属性) # 查看 类名.静态属性 = 456 # 修改 print(类名.静态属性) 类名.静态属性2 = 'abc'# 增长 print(类名.静态属性2) # del 类名.静态属性2 # print(类名.静态属性2) print(类名.__dict__) # 类中必要的默认值以外 还记录了程序员在类中定义的全部名字
实例化的过程理解
为何会执行init中的内容?
self究竟是什么?
实例化的过程
类名()就是实例化
在实例化的过程当中 发生了不少事情是外部看不到的
1.建立了一个对象
2.自动调用__init__方法
这个被创造的对象会被当作实际参数传到__init__方法中,而且传给第一个参数self
3.执行init方法中的内容
4.自动的把self做为返回值 返回给实例化的地方
class Person: #定义一我的类 role = 'person' #人的角色属性都是人 def __init__(self,name): self.name = name # 每个角色都有本身的昵称; def walk(self): #人均可以走路,也就是有一个走路方法 print("person is walking...") print(Person.role) #查看人的role属性 print(Person.walk) #引用人的走路方法,注意,这里不是在调用 类名能够查看某个方法,可是不能够直接调用方法
实例化的过程就是 类——>对象 的过程
本来咱们只有一个Person类,在这个过程当中,产生了一个egg对象,有本身具体的名字、攻击力和生命值。
语法:对象名 = 类名(参数)
alex = Person('alex') #类名()就等于在执行Person.__init__() #执行完__init__()就会返回一个对象。这个对象相似一个字典,存着属于这我的自己的一些属性和方法。
print(alex.name) #查看属性直接 对象名.属性名 print(alex.walk()) #调用方法,对象名.方法名()
self:在实例化时自动将对象/实例自己传给__init__的第一个参数,你也能够给他起个别的名字,可是正常人都不会这么作。
由于你瞎改别人就不认识
一:咱们定义的类的属性到底存到哪里了?有两种方式查看 dir(类名):查出的是一个名字列表 类名.__dict__:查出的是一个字典,key为属性名,value为属性值 二:特殊的类属性 类名.__name__# 类的名字(字符串) 类名.__doc__# 类的文档字符串 类名.__base__# 类的第一个父类(在讲继承时会讲) 类名.__bases__# 类全部父类构成的元组(在讲继承时会讲) 类名.__dict__# 类的字典属性 类名.__module__# 类定义所在的模块 类名.__class__# 实例对应的类(仅新式类中)
回到人狗大战,如今须要对咱们的类作一点改变。
人类除了能够走路以外吗,还应该具有一些攻击技能
class Person: # 定义一我的类 role = 'person' # 人的角色属性都是人 def __init__(self,name,sex,hp,dps): self.name = name self.sex = sex self.hp = hp self.dps = dps def attack(self,dog): # 人能够攻击狗,这里的狗也是一个对象 # 人攻击狗,那么狗的生命值就壶根据人的攻击力而降低 dog.hp -= self.dps print('%s打了%s,%s掉了%s点血,剩余%s点血' % (self.name, dog.name, dog.name, self.dps, dog.hp))
print(alex.name) print(ha2.name) print(ha2.dps)
你也能够引用一个方法,由于方法也是一个属性,只不过是一个相似函数的属性,咱们也管它叫动态属性。
引用动态属性并非执行这个方法,要想调用方法和调用函数是同样的,都须要在后面加上括号
Person.attack(alex,ha2) ## 调用类中的方法的方式 能够简写下一行为 alex.attack alex.attack(ha2) ha2.bite(alex)
class Circle(): # 定义一个类--圆 def __init__(self,r): self.pi = 3.14 self.r = r def area(self): print('area:',self.pi * self.r ** 2) def perimeter(self): print('perimeter:',self.pi * self.r * 2) r = Circle(5) # 实例化一个半径=5的圆 r.area() r.perimeter()
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 # 查看对象的属性,直接用对象名.属性名 便可 对象名.方法名() # 调用类中的方法。直接用 对象名.方法名() 便可
建立一个类就会建立一个类的Name Space,用来存储类中定义的全部名字,这些名字称为类的属性
而类有两种属性:静态属性和动态属性
4341594072 >>>id(Person.role) 4341594072
>>>egg.attack <bound method Person.attack of <__main__.Person object at 0x101285860>> >>>Person.attack <function Person.attack at 0x10127abf8>
建立一个对象/实例就会建立一个对象/实例的名称空间,存放对象/实例的名字,称为对象/实例的属性
在obj.name会先从obj本身的名称空间里找name,找不到则去类中找,类也找不到就找父类...最后都找不到就抛出异常
class Person: COUNTRY = '中国人' def __init__(self,name): self.name = name alex = Person('alex') egon = Person('egon')
实例化过程:
当实例化一个对象的时候,在内存中间的建立步骤:
1. 在内存中开辟一块地址,存放类的名称,同时开辟类的namespace存放类中的静态属性和动态属性
2. 实例化执行的时候,执行init,开辟一个新的内存空间,self指向这个空间,在里面存放 name='alex'
3. self.name = name 赋值过程
4. alex = Person('alex') # 将对象赋值给alex
class Person: COUNTRY = '中国人' # 静态属性 def __init__(self,name): self.name = name def eat(self): print('%s在吃泔水'%self.name) alex = Person('alex') egon = Person('egon') print(alex.name) print(egon.name) print(alex.COUNTRY) alex.eat() # Person.eat(alex) alex ---> Person 当一个类在建立一个实例的时候 就产生了一个这个实例和类之间的联系 (类对象指针) 能够经过实例 对象 找到实例化它的类 可是 类不能找到它的实例化
class Person: COUNTRY = ['中国人'] # 静态属性 Country = '中国人' # 静态属性 def __init__(self,name): self.name = name def eat(self): print('%s在吃泔水'%self.name) alex = Person('alex') egon = Person('egon') print(alex.Country) alex.Country = '印度人' print(alex.Country) print(egon.Country) print(Person.Country) alex.COUNTRY[0] = '印度人' print(alex.COUNTRY) print(egon.COUNTRY) print(Person.COUNTRY) alex.COUNTRY = ['印度人'] print(egon.COUNTRY) print(Person.COUNTRY)
# 在访问变量的时候,都先使用本身命名空间中的,若是本身的空间中没有,再到类的空间中去找
# 在使用对象修改静态变量的过程当中,至关于在本身的空间中建立了一个新的变量
# 在类的静态变量的操做中 应该使用类名来直接进行操做 就不会出现乌龙问题
建立一个类,可以自动及素颜这个类建立了多少个实例
class Foo: count = 0 def __init__(self): ###每次实例化一个对象,都会自动调用一次__init__函数 Foo.count += 1 f1 = Foo() print(Foo.count) [Foo() for i in range(10)] print(Foo.count)
结论:
对象能够访问类的命名空间
类不能访问对象的命名空间
软件重用的重要方式除了继承以外还有另一种方式,即:组合
组合指的是,在一个类中以另一个类的对象做为数据属性,称为类的组合
一切皆对象
数据类型 -- 都是类
那么任意一个字符串,都是str这个类的对象
人狗大战-- 升级版
class Person: def __init__(self,name,sex,hp,dps): self.name = name self.hp = hp self.dps = dps self.sex = sex self.bag = [] def attack(self,dog): dog.hp -= self.dps print('%s打了%s,%s掉了%s点血,剩余%s点血' % (self.name, dog.name, dog.name, self.dps, dog.hp)) class Dog: def __init__(self,name,kind,hp,dps): self.name = name self.hp = hp self.dps = dps self.kind = kind def bite(self,person): person.hp -= self.dps print('%s打了%s,%s掉了%s点血,剩余%s点血' % (self.name, person.name, person.name, self.dps, person.hp)) class Weapon: def __init__(self,name,price,dps): self.name = name self.price = price self.dps = dps def kill(self,dog): dog.hp -= self.dps alex = Person('alex','N/A',250,5) ha2 = Dog('哈士奇','藏獒',15000,200) roubaozi = Weapon('肉包子',600000,10000) alex.money = 1000000 if alex.money >= roubaozi.price: alex.weapon = roubaozi #把weapon类的肉包子对象座位对象alex的属性。
alex.weapon.kill(ha2) # <==> roubaozi.kill
print(ha2.hp)
pi = 3.14 class Circle: def __init__(self,r): self.r = r def area(self): return pi * self.r ** 2 def perimeter(self): return self.r *pi * 2 # r1 = Circle(2) # # print(r1.area()) class Ring(): def __init__(self,out_r,in_r): self.out_c = Circle(out_r) ## 把圆的实例化过程放在init中作初始化 在这里初始化了两个圆出来 self.in_c = Circle(in_r) def area(self): return self.out_c.area() - self.in_c.area() # 这两个圆调用area方法 相减! def perimeter(self): return self.out_c.perimeter() - self.in_c.perimeter() ring1 =Ring(5,2) print(ring1.area()) print(ring1.perimeter())
继承是一种建立新类的方式,在python中,新建的类能够继承一个或多个父类。父类又可称为基类或者超类,新建的类称为派生类或子类
python中类的继承分为:单继承和多继承
class ParentClass1: #定义父类 pass class ParentClass2: #定义父类 pass class SubClass1(ParentClass1): #单继承,基类是ParentClass1,派生类是SubClass pass class SubClass2(ParentClass1,ParentClass2): #python支持多继承,用逗号分隔开多个继承的类 pass
查看继承
>>> SubClass1.__bases__ #__base__只查看从左到右继承的第一个子类,__bases__则是查看全部继承的父类 (<class '__main__.ParentClass1'>,) >>> SubClass2.__bases__ (<class '__main__.ParentClass1'>, <class '__main__.ParentClass2'>)
提示:若是没有指定基类,python的类会默认继承object类,object是全部python类的基类,它提供了一些常见方法(如__str__)的实现。
>>> ParentClass1.__bases__ (<class 'object'>,) >>> ParentClass2.__bases__ (<class 'object'>,)
抽象即抽取相似或者说比较像的部分。
抽象分红两个层次:
1.将奥巴马和梅西这俩对象比较像的部分抽取成类;
2.将人,猪,狗这三个类比较像的部分抽取成父类。
抽象最主要的做用是划分类别(能够隔离关注点,下降复杂度)
继承:是基于抽象的结果,经过编程语言去实现它,确定是先经历抽象这个过程,才能经过继承的方式去表达出抽象的结构。
抽象只是分析和设计的过程当中,一个动做或者说一种技巧。经过抽象能够获得类。
使用代码能够解决代码重用的问题
==========================第一部分 例如 猫能够:喵喵叫、吃、喝、拉、撒 狗能够:汪汪叫、吃、喝、拉、撒 若是咱们要分别为猫和狗建立一个类,那么就须要为 猫 和 狗 实现他们全部的功能,伪代码以下: #猫和狗有大量相同的内容 class 猫: def 喵喵叫(self): print '喵喵叫' def 吃(self): # do something def 喝(self): # do something def 拉(self): # do something def 撒(self): # do something class 狗: def 汪汪叫(self): print '汪汪叫' def 吃(self): # do something def 喝(self): # do something def 拉(self): # do something def 撒(self): # do something ==========================第二部分 上述代码不难看出,吃、喝、拉、撒是猫和狗都具备的功能,而咱们却分别的猫和狗的类中编写了两次。若是使用 继承 的思想,以下实现: 动物:吃、喝、拉、撒 猫:喵喵叫(猫继承动物的功能) 狗:汪汪叫(狗继承动物的功能) 伪代码以下: class 动物: def 吃(self): # do something def 喝(self): # do something def 拉(self): # do something def 撒(self): # do something # 在类后面括号中写入另一个类名,表示当前类继承另一个类 class 猫(动物): def 喵喵叫(self): print '喵喵叫' # 在类后面括号中写入另一个类名,表示当前类继承另一个类 class 狗(动物): def 汪汪叫(self): print '汪汪叫' ==========================第三部分 #继承的代码实现 class Animal: def eat(self): print("%s 吃 " %self.name) def drink(self): print ("%s 喝 " %self.name) def shit(self): print ("%s 拉 " %self.name) def pee(self): print ("%s 撒 " %self.name) class Cat(Animal): def __init__(self, name): self.name = name self.breed = '猫' def cry(self): print('喵喵叫') class Dog(Animal): def __init__(self, name): self.name = name self.breed='狗' def cry(self): print('汪汪叫') # ######### 执行 ######### c1 = Cat('小白家的小黑猫') c1.eat() c2 = Cat('小黑的小白猫') c2.drink() d1 = Dog('胖子家的小瘦狗') d1.eat() 使用继承来重用代码比较好的例子 使用继承来解决代码重用的例子
在开发程序的过程当中,若是咱们定义了一个类A,而后又想新创建另一个类B,可是类B的大部份内容与类A的相同时
咱们不可能从头开始写一个类B,这就用到了类的继承的概念。
经过继承的方式新建类B,让B继承A,B会‘遗传’A的全部属性(数据属性和函数属性),实现代码重用
回头看咱们的人狗大战代码中,人和狗都有同时拥有的属性,大量代码重复。那么咱们能够把相同的属性抽象出来写一个父类Animal。
而后人和狗分别继承animal的属性,再分别加入本身的属性。
若是子类没有init方法:
若是子类有本身的init方法呢?
若是有本身的init就不回去父类的命名空间去找init方法。
若是仍旧想引用父类的init,就须要用super() 的写法去引用父类的init方法。
# class Animal(): def __init__(self, name, hp, dps): self.name = name self.hp = hp self.dps = dps def eat(self): print('%s吃药回血了' %self.name) class Person(Animal): def __init__(self, name, hp, dps, sex): Animal.__init__(self, name, hp, dps) # 当写成super()的时候,不须要再写self参数 self.sex = sex def attack(self, dog): dog.hp -= self.dps print('%s打了%s,%s掉了%s点血,剩余%s点血' % (self.name, dog.name, dog.name, self.dps, dog.hp)) class Dog(Animal): def __init__(self, name, hp, dps, kind): super().__init__(name, hp, dps) # 当写成super()的时候,不须要再写self参数 self.kind = kind def bite(self, person): person.hp -= self.dps print('%s咬了%s,%s掉了%s点血,剩余%s点血' % (self.name, person.name, person.name, self.dps, person.hp)) alex = Person('alex',250, 5, '不详') ha2 = Dog('哈士奇', 15000, 200, '藏獒') alex.eat() ha2.eat() ha2.bite(alex) alex.attack(ha2)
一道著名的面试题: 下面代码的输出是什么?
class Foo: def __init__(self): self.func() def func(self): print('in Foo') class Son(Foo): def func(self): print('in Son') Son()
答案是: in Son
在涉及到继承的时候,见到self,不要在本类中找它的调用。而要先看看,self究竟是谁。
在这道题中。self是初始化Son的时候执行的,因此调用self.func的时候,执行的是Son中的func函数。
python两种类
经典类 py3已经灭绝了 在python2里还存在,在py2中只要程序员不主动继承object,这个类就是经典类 —— 深度优先
新式类 python3全部的类都是新式类,全部的新式类都继承自object —— 在多继承中遵循广度优先算法
钻石继承问题
python3
广度优先算法--遍历算法
钻石模型和小乌龟模型
class A: def f(self): print('in A') class B(A): pass # def f(self): # print('in B') class C(A): pass # def f(self): # print('in C') class D(B,C): pass # def f(self): # print('in D') class E(C): pass # def f(self): # print('in B') class F(D,E): pass # def f(self): # print('in C') d = D() d.f() print(F.mro()) class A: def f(self): print('in A') class B(A): def f(self): print('in B') super().f() class C(A): pass def f(self): print('in C') super().f() class D(B,C): def f(self): print('in D') super().f() d = D() d.f()
# super和找父类这件事是两回事
# 在单继承中 super就是找父类
# 在多级承中 super的轨迹 是根据整个模型的起始点而展开的一个广度优先顺序 遵循mro规则
多态指的是一类事物有多种形态
动物有多种形态:人,狗,猪
在python中,到处都是多态。
多态性
peo=People() dog=Dog() pig=Pig() #peo、dog、pig都是动物,只要是动物确定有talk方法 #因而咱们能够不用考虑它们三者的具体是什么类型,而直接使用 peo.talk() dog.talk() pig.talk() #更进一步,咱们能够定义一个统一的接口来使用 def func(obj): obj.talk()
广义上的封装 :把变量和函数都放在类中
狭义上的封装 :把一些变量 或者 方法 隐藏起来,不对外公开
公有的 :
私有的 : __名字
class Person: __country = '中国' # 私有的静态属性 print(Person.__country) # AttributeError: type object 'Person' has no attribute '__country' # 私有的名字 只能在类的内部使用 不能在类的外部使用 print(Person.__dict__) # _Person__country print(Person._Person__country) # 不能使用上面这种方式去调用私有的变量 # 若是非要在类的外部调用一个私有的名字,name必须是在私有的名字前面加 _类名__私有的名字 Person.__name = 'XXX' print(Person.__name) # 在类的外部不能第一一个私有变量 print(Person.__dict__)
# 私有的变量 :
# 在类的内部 若是使用__变量的形式会发生变形,python会自动的为你加上_类名
class Person: __country = '中国' def __init__(self,name,pwd): self.name = name self.__pwd = pwd # 私有的对象属性 def login(self): print(self.__dict__) if self.name == 'alex' and self.__pwd == 'alex3714': print('登陆成功') alex = Person('alex','alex3714') alex.login() print(alex.__dict__) #{'name': 'alex', '_Person__pwd': 'alex3714'} print(alex.name) print(alex.__pwd) # 报错 AttributeError: 'Person' object has no attribute '__pwd'
class Person: def __init__(self):pass def __制造密码转换(self,inp): ## 这个制造的密码,是不但愿提供给外部使用的 print('eating') def 注册(self): inp = input('pwd>>>') 加密以后的密码 = self.__制造密码转换(inp)
静态属性 、 对象属性、 方法(动态属性) 前面加上双下划綫都会变成私有的
私有的特色就是只能在类的内部调用,不能在类的外部使用
肯定下面两段代码 输出内容是什么 class Foo: def __init__(self): self.func() def func(self): print('in Foo') class Son(Foo): def func(self): print('in son') s = Son() # in son # 实例化一个对象的时候,把son这个对象传给__init__作初始化。可是Son没有init,回去找父类的init。在这个init中调用了self.func函数,由于self是指向实例的,因此仍旧是Son中的函数被执行
class Foo: def __init__(self): self.__func() # self._Foo__func def __func(self): print('in Foo') class Son(Foo): def __func(self): # _Son__func 只是加载到内存了,没有调用 print('in son') s = Son() # in Foo
# 解析 当调用Son的时候实例化一个对象,会先执行初始化,__init__函数 ,在这个函数中调用的__func。 在哪一个地方指向__方法 就会自动拼接 _类名__方法名。因此拼接出来,被调用的是self._Foo__func。