一、面向对象
1、面向过程
a、优点:极大的降低了写程序的复杂度,只需要顺着执行的步骤,堆叠代码即可
b、缺点:一套流水线或者流程就是来解决一个问题,代码就是牵一发而东莞全身
2、面向对象
a、优点:解决程序的扩展性,对某一个对象单独修改,会立刻反应到整个体系中
b、缺点:可控性差,无法向面向过程的程序设计流水线式的可以很精准的预测问题的处理流程与结果,面向对象的程序一旦开始就有对象之间的交互解决问题。
3、 类:具有相同特征的一类事物(人、狗、老虎)
4、对象/实例:具体的某一个事物(隔壁阿花、楼下旺财)
5、实例化:类——>对象的过程
6、 在python中,用变量表示特征,用函数表示技能,因而具有相同特征和技能的一类事物就是‘类’,
7、对象是则是这一类事物中具体的一个
class Person: #定义一个人类 role = 'person' #人的角色属性都是人 def walk(self): #人都可以走路,也就是有一个走路方法,也叫动态属性 print("person is walking...")
class 类名: 类属性 = None def __init__(self,对象属性): self.对象属性 = 对象属性 def 方法名(self): pass 实例 = 类名(10) 实例.方法名()
8、类的两种作用:属性引用和实例化
9、属性引用(类名.属性)
class Person: #定义一个人类 role = 'person' #人的角色属性都是人 def walk(self): #人都可以走路,也就是有一个走路方法 print("person is walking...") print(Person.role) #查看人的role属性 print(Person.walk) #引用人的走路方法,注意,这里不是在调用
10、例化:类名加括号就是实例化,会自动触发__init__函数的运行,可以用它来为每个实例定制自己的特征
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) #引用人的走路方法,注意,这里不是在调用
11、
类名 类名.类属性 类名.方法名 实例 = 类名(参数,参数) #实例就是对象 实例 实例.方法名() 实例.对象属性 实例增加属性 实例.新的属性名 = 1000 print(实例.新的属性名)
12、关于self
self:在实例化时自动将对象/实例本身传给__init__的第一个参数,你也可以给他起个别的名字.
对象/实例只有一种作用:属性引用
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 #查看对象的属性,直接用 对象名.属性名 即可 对象名.方法名() #调用类中的方法,直接用 对象名.方法名() 即可
dir(类) #返回类中的所有名字列表 isinstance(对象,类) #判断对象是否为类的实例 print(Person.__dict__) # 返回一个字典 key是属性名,value是属性值 print(Person.__module__) #person类所在的模块 print(Person.__name__,type(Person.__name__)) #字符串数据类型的类名
13、类命名空间与对象、实例的命名空间
a、常见一个类就会创建一个类的名称空间,用来储存类中定义的所有名字,这些名字成为类的属性
b、而类有两种属性:静态属性和动态属性
- 静态属性就是直接在类中定义的变量
- 动态属性就是定义在类中的方法
创建一个对象/实例就会创建一个对象/实例的名称空间,存放对象/实例的名字,称为对象/实例的属性
面相对象的组合用法:
组合指的是,在一个类中以另外一个类的对象作为数据属性,称为类的组
列子:
from math import pi class Circular: def __init__(self,radius): self.radius=radius def area(self): return self.radius **2 * pi def perimeter(self): return 2 * self.radius * pi circu=Circular(10) print(circu.area()) print(circu.perimeter())
14、面向对象的三大特征
a、继承
class Animal: #父类 基类 超类 def __init__(self,name,life_value,aggr): self.name = name self.life_value = life_value self.aggr = aggr class Person(Animal): #子类 派生类 pass class Dog(Animal): #子类 派生类 pass egg = Person('egon',1000,50) print(egg.name) print(egg.aggr
python2 class Dad: #经典类 class Dag(object) #新式类 python3 class Dad == class Dag(object) #新式类
1、继承的语法
class 类名(父类名): 想在子类中实现调用父类的方法 在类内 ——super(子类名,self).方法名() 在类外面 ——super(子类名,对象名).方法名() 如果不指定继承的父类,默认继承object 子类可以使用父类的所有属性和方法 如果子类有自己的方法就执行自己的的 如果是子类没有的方法就执行父类的 如果子类父类都没有这个方法就报错
继承、抽象、派生
继承 是从大范围到小范围
抽象 小范围到大范围
派生 就是在父类的基础上又产生子类——派生类
父类里没有的 但子类有的 ——派生方法
派生属性
方法的重写
父类里有的方法,在子类里重新实现
2、继承的两种用途:
b:继承基类的方法,并且做出自己的改变或者扩展(代码重用)
a:声明某个子类兼容于某基类,定义一个接口类Interface,接口类中定义
了一些接口名(就是函数名)且并未实现接口的功能,子类继承接口类,并且实现接口中的功能
b、封装
1、优点:
a、将变化隔离
b、封装使用
c、提高复用性
d、提高安全性
2、封装原则:
a、将不需要对外提供的内容都隐藏起来
b、把属性都隐藏起来提供公共方法对其访问
3、私有变量和私有方法
a、在python中用双划线的开头的的方式降属性隐藏起来(设置私有的)
property属性
property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值
c、多态:”多态指的是一类事物有多种形态(比如:老师.下课铃响了(),学生.下课铃响了(),老师执行的是下班操作,学生执行的是放学操作,虽然二者消息一样,但是执行的效果不同)
多态指的是:一类实物有多种状态
python自带多态:
多态:同一类事物的多种状态
python里处处都是多态,只是我们一般发现不了
操作的时候不需要关心这个对象的数据类型,你只要用就行了
15、反射
1、 反射:可以用字符串的方式去访问对象的属性,调用对象的方法(但是不能去访问方法),python中一切皆对象,都可以使用反射。
2、反射有四种方法:
hasattr:hasattr(object,name)判断一个对象是否有name属性或者name方法。有就返回True,没有就返回False
getattr:获取对象的属性或者方法,如果存在则打印出来。hasattr和getattr配套使用
需要注意的是,如果返回的是对象的方法,返回出来的是对象的内存地址,如果需要运行这个方法,可以在后面添加一对()
setattr:给对象的属性赋值,若属性不存在,先创建后赋值
delattr:删除该对象指定的一个属性
a、内置方法:isinstance和issubclass
isinstance(obj,cls)检查是否obj是否是类 cls 的对象
class Foo: pass class Son(Foo): pass s=Son() print(isinstance(s,Son))
b、内置方法:issubclass(sub, super)检查sub类是否是 super 类的派生类
class Foo(object): pass class Bar(Foo): pass issubclass(Bar, Foo)
c、python面向对象中的反射:通过字符串的形式操作对象相关的属性,python中一切事物都是对象(都可以用反射)
检查是否含有某属性---hasattr 返回布尔值 获取属性---getattr 没有就会报错 设置属性---setattr 删除属性---delattr
d、内置方法:__del__
析构方法,当对象在内存中被释放时,自动触发执行。
注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。
class Foo: def __del__(self): print('fgs') f=Foo() print(123) print(123) del f print(123) print(123) print(123)
e、内置方法:item系列
__getitem__\__setitem__\__delitem__
__new__
class A: def __init__(self): #有一个方法在帮你创造self print('in init function') self.x=1 def __new__(cls, *args, **kwargs): print('in init funct') return object.__new__(A,*args,**kwargs) a=A()
f、__str__和__repr__改变对象的字符串显示
class Foo: 2 def __init__(self,name): 3 self.name = name 4 def __repr__(self): 5 return 'obj in str' #这里只能是return 6 # def __str__(self): 7 # return '%s obj in str'%self.name 8 f = Foo('egon') 9 print(f) #优先执行__str__里面的内容 10 # 那么你是不是据地__repr__没用呢? 11 # print('%s'%f) #执行的是__str__里面的返回值 12 # print('%r'%f) #执行的是__repr__里面的返回值 13 print('==============') 14 print(str(f)) #当执行str(f)时,会去找__str__这个方法,如果找不到的时候,__repr__这个方法就给替补了 15 print(repr(f)) 16 #1.当打印一个对象的时候,如果实现了__str__方法,打印__str__中的返回值 17 # 2.当__str__没有被实现的时候,就会调用__repr__方法 18 # 3.但是当你用字符串格式化的时候,%s和%r会分别调用__str__和__repr__方法 19 # 4.不管是在字符串格式化的时候还是在打印对象的时候, 20 # __repr__方法都可以作为__str__方法的替补,但反之则不行 21 # 5.用于友好的表示对象。如果__str__和__repr__方法你只能实现一个:先实现__repr__
15、内置方法
a、静态方法和类方法
1、类方法:有个默认参数cls,并且可以直接用类名去调用,可以与类属性交互(也就是可以使用类属性)
2、静态方法:让类里的方法直接被类调用,就像正常调用函数一样
b、类方法和静态方法的相同点:都可以直接被类调用,不需要实例化
c、类方法和静态方法的不同点:
类方法必须有一个cls参数表示这个类,可以使用类属性
静态方法不需要参数
d、绑定方法:分为普通方法和类方法
普通方法:默认有一个self对象传进来,并且只能被对象调用-------绑定到对象
类方法:默认有一个cls对象传进来,并且可以被类和对象(不推荐)调用-----绑定到类
e、非绑定方法:静态方法:没有设置默认参数,并且可以被类和对象(不推荐)调用-----非绑定
16、接口类与抽象类
a、 接口类:(在抽象类的基础上)
在python中,默认是没有接口类的
接口类不能被实例化(如果实例化会报错)
接口类中的方法不能被实现
接口也就是做约束,让下面的类的方法都按照接口类中给出的方法去定义。如果接口类里面有的方法类里面没有,那么那个类就不能被实例化。(字面理解)
继承的第二种含义非常重要。它又叫“接口继承”。
接口继承实质上是要求“做出一个良好的抽象,这个抽象规定了一个兼容接口,使得外部调用者无需关心具体细节,可一视同仁的处理实现了特定接口的所有对象”——这在程序设计上,叫做归一化。
b、抽象类
在python中,默认是有的
父类的方法,子类必须实现
抽象类(父类)的方法可以被实现
抽象类和接口类的区别:接口类不能实现方法,抽象类可以实现方法里面的内容
抽象类和接口类的相同点:都是用来做约束的,都不能被实例化
抽象类和接口类的使用:
当几个子类的父类有相同的功能需要被实现的时候就用抽象类
当几个子类有相同的功能,但是实现各不相同的时候就用接口类