编程范式:面向过程,面向对象
面向过程 VS 面向对象
面向过程编程
核心是过程二字
过程指的是解决问题的步骤,程序从上到下一步一步执行,设计思路是:将大问题分解成一个一个小问题或子程序,再将子程序 分解成小问题,直到借到足够简单的问题的思想
应用场景:一旦完成基本很少改变的场景,著名的例子有Linux內核,git,以及Apache HTTP Server等。
面向对象编程
核心是对象二字OOP编程是利用“类”和“对象”来创建各种模型来实现对真实世界的描述,解决扩展性
应用场景:需求经常变化的软件,一般需求的变化都集中在用户层,互联网应用,企业内部软件,游戏等都是面向对象的程序设计大显身手的好地方
两者的优缺点:
面向过程编程
优点:复杂度的问题流程化,进而简单化
缺点:难维护,改一个组件,牵一发而动全身
面向对象编程
优点:易维护,易扩展,开发效率高
缺点:复杂度高,只有经过实例化后的对象交互才知道结果
面向对象的特征:
类,对象,封装,继承,多态
类(class)
一类有相同属性的对象的模型,在类中定义对象的相同属性和方法
类有两种属性:数据属性和函数属性
1. 类的数据属性是所有对象共享的,在obj.name会先从obj自己的名称空间里找name,找不到则去类中找,类也找不到就找父类...最后都找不到就抛出异常
2. 类的函数属性是绑定给对象用的,类中定义的函数(没有被任何装饰器装饰的),主要是给对象使用的,虽然所有对象指向的都是相同的功能,但是绑定到不同的对象就是不同的绑定方法
#python为类内置的特殊属性 类名.__name__# 类的名字(字符串) 类名.__doc__# 类的文档字符串 类名.__base__# 类的第一个父类(在讲继承时会讲) 类名.__bases__# 类所有父类构成的元组(在讲继承时会讲) 类名.__dict__# 类的字典属性 类名.__module__# 类定义所在的模块 类名.__class__# 实例对应的类(仅新式类中) 类的特殊属性(了解即可)
对象(Object)
类的实例化——对象
通过类可以进行对象的交互
封装
封装:顾名思义就是将内容封装到某个地方,以后再去调用被封装在某处的内容
所以,在使用面向对象的封装特性时,需要:
- 将内容封装到某处
- 从某处调用被封装的内容
1,先封装
class foo(object): def __init__(self,name,age): #构造方法 self.name=name #普通属性 self.age=age #根据类创建俩个实例 #自动执行__init__方法 obj1=foo('aaa',10) obj2=foo('bbb',12)
self 是一个形式参数,当执行 obj1 = Foo(''aaa'‘,10 ) 时,self 等于 obj1
当执行 obj2 = Foo(''bbb'’,12 ) 时,self 等于 obj2
所以,内容其实被封装到了对象 obj1 和 obj2 中,每个对象中都有 name 和 age 属性,在内存里类似于下图来保存。
2,再调用封装
调用被封装的内容时,有两种情况:
- 通过对象直接调用
- 通过self间接调用
1、通过对象直接调用被封装的内容(对象.属性名)
class foo(object): def __init__(self,name,age): #构造方法 self.name=name #普通属性 self.age=age obj1=foo('aaa',10) obj2=foo('bbb',12) #直接通过对象调用 print(obj1.name,obj1.age) print(obj2.name,obj2.age)
2,通过self间接调用被封装的内容
class Foo: def __init__(self, name, age): self.name = name self.age = age def detail(self): print(self.name) #被封装起来的内容 print(self.age) obj1 = Foo('wupeiqi', 18) obj1.detail() # Python默认会将obj1传给self参数,即:obj1.detail(obj1),所以,此时方法内部的 self = obj1,即:self.name 是 wupeiqi ;self.age 是 18 obj2 = Foo('alex', 73) obj2.detail() # Python默认会将obj2传给self参数,即:obj1.detail(obj2),所以,此时方法内部的 self = obj2,即:self.name 是 alex ; self.age 是 78
对于面向对象的封装来说,其实就是使用构造方法将内容封装到 对象 中,然后通过对象直接或者self间接获取被封装的内容。
继承
继承,面向对象中的继承和现实生活中的继承相同,即:子可以继承父的内容。
对于面向对象的继承来说,其实就是将多个类共有的方法提取到父类中,子类仅需继承父类而不必一一实现每个方法。
class F1: def __init__(self,name): self.n=name print('F1') class F2: def __init__(self,a): self.a=a print('F2') class F3: def __init__(self,b): self.b=b print('F3') f1=F1('aaa') #f1.n='aaa' f2=F2(f1) #f2=F2(F1('aaa')) f3=F3(f2) #f3=F3(F2(F1('aaa'))) print(f3.b.a.n)
多态
接口重用
补:
hasattr() getattr() setattr() 函数使用方法详解
hasattr(object, 'name')
判断一个对象里面是否有name属性或者name方法,返回BOOL值,有name特性返回True, 否则返回False。
class Eg(object): name='zyp' age=12 def eg(self): print("runuing ……") return hasattr(self,'name') e=Eg() D=e.eg() print(D) # runuing …… # True print(hasattr(e,'age')) #True print(hasattr(e,'ID')) #False
getattr(object, name[,default])
获取对象object的属性或者方法,如果存在打印出来,如果不存在,打印出默认值,默认值可选。需要注意的是,如果是返回的对象的方法,返回的是方法的内存地址,如果需要运行这个方法,
可以在后面添加一对括号
class Eg(object): name='zyp' age=12 def eg(self): print('name',getattr(self,'name')) return hasattr(self,'name') e=Eg() e.eg() #name zyp print('eg:',getattr(e,'eg')) #打印内存地址 eg: <bound method Eg.eg of <__main__.Eg object at 0x02151E70>> print('name',getattr(Eg,'name')) # name zyp getattr(e,'eg')() # name zyp 执行eg方法 print(getattr(e,'aa',123)) # 若方法或属性不存在,打印默认值 123
setattr(object, name, values)
给对象的属性赋值,若属性不存在,先创建再赋值。
def eat(self): print("将类外面的方法装配到类里面",self.name) class Eg(object): name='zyp' age=12 def eg(self): print('name',getattr(self,'name')) return hasattr(self,'name') e=Eg() e.eg() print(hasattr(e,'id')) #False setattr(e,'id',1234) #添加没有的属性 print(hasattr(e,'id')) #True print(e.id) # 1234 打印对象新添加的属性 setattr(e,'talk',eat) #talk为类中创建的方法名,创建类中不存在的方法。这样创建的是静态方法 e.talk(e) #调用的时候使用talk,而不是eat,需要手动将对象传入
上例中talk写成固定值,因此在调用的时候可以使用e.talk,如果这里talk为用户输入的动态值,则需要先通过getattr()获取信息,通过调用getattr获得的结果去调用对应的属性或方法,
delattr 删除方法
delattr(e,'talk') e.talk(e) #AttributeError: 'Eg' object has no attribute 'talk' 此时已经删除了talk方法
def eat(self):
print("将类外面的方法装配到类里面",self.name)
class Eg(object):
name='zyp'
age=12
def eg(self):
print('name',getattr(self,'name'))
return hasattr(self,'name')
e=Eg()
e.eg()
print(hasattr(e,'id')) #False
setattr(e,'id',1234) #添加没有的属性
print(hasattr(e,'id')) #True
print(e.id) # 1234 打印对象新添加的属性
setattr(e,'talk',eat) #talk为类中创建的方法名,创建类中不存在的方法。这样创建的是静态方法
e.talk(e) #调用的时候使用talk,而不是eat,需要手动将对象传入