一 反射

  python中的反射功能是由以下四个内置函数提供:hasattr、getattr、setattr、delattr,改四个函数分别用于对对象内部执行:检查是否含有某成员、获取成员、设置成员、删除成员。

 反射:
通过字符串的形式导入模块
通过字符串的形式,去模块中寻找指定的函数,并执行 __import__(字符串) 将字符串作为模块名导入 赋值的话就相当于 as 反射:
根据字符串的形式取某个模块中寻找东西
根据字符串的形式取某个模块中判断东西是否存在
根据字符串的形式去某个模中设置东西
根据字符串的形式取某个模块中删除的东西 根据字符串的形式去对象(某个模块)中操作其成员 反射介绍笔记和__import__把字符串当作模块导入
 class Foo(object):

     def __init__(self):
self.name = 'wupeiqi' def func(self):
return 'func' obj = Foo() # #### 检查是否含有成员 ####
hasattr(obj, 'name')
hasattr(obj, 'func') # #### 获取成员 ####
getattr(obj, 'name')
getattr(obj, 'func') # #### 设置成员 ####
setattr(obj, 'age', 18)
setattr(obj, 'show', lambda num: num + 1) # #### 删除成员 ####
delattr(obj, 'name')
delattr(obj, 'func')

1 __import__("模块名的字符串")

from 包 import 模块名  as  别名    ===等价于===     别名 = __import__("模块名的字符串")

 def f1():
return "f1" def f2():
return "f2" def f3():
return "f3"

commons模块内容

 # 正常导入
import commons as CC # == 特殊导入(字符串导入) DD = __import__("commons")
ret = commons.f1()
print(ret)

__import__导入字符串作为模块练习

1.1  特殊__import__情况

  针对该模块同一级下有另一个目录,也就是包,而这个包下有另一个包,而我们需要导入的模块还在其下面,这时候,不能应用包.包.模块作为字符串传入__import__来导入了,因为其只会导入第一层包。需要加入一个参数 fromlist=True

 __import__("a.b.c.file.login",fromlist=True)

1.2 模块导入扩展

 扩展:
导入模块
#单层
a = __import__("模块名") # 多层
#当前目录下有好几层
#
from a.b.c.file import login
#
__import__("a.b.c.file.login") #是不对的 只导入了a目录 包
正确写法:
__import__("a.b.c.file.login",fromlist=True)

2 getattr 反射 可以传入字符串获取变量名或函数

 # 正常导入
import commons as CC # == 特殊导入(字符串导入) DD = __import__("commons")
ret = commons.f1()
print(ret) # 应用
# 根据用户输入字符串,将字符串作为模块名导入并应用其内的方法
mod_name = input("请输入模块:").strip()
print(mod_name,type(mod_name))
DD = __import__(mod_name) #通过字符串形式导入模块
# ret = DD.f1() #正常调用 模块中寻找函数,并执行
fuc_name = input("请输入执行的函数:") ret=getattr(DD,fuc_name)()
print(ret)

3 hasattr  反射 可以传入字符串判断模块是否有这个 变量名或函数

 # 正常导入
import commons as CC # == 特殊导入(字符串导入) DD = __import__("commons")
ret = commons.f1()
print(ret) # 应用
# 根据用户输入字符串,将字符串作为模块名导入并应用其内的方法
mod_name = input("请输入模块:").strip()
print(mod_name,type(mod_name))
DD = __import__(mod_name) #通过字符串形式导入模块
# ret = DD.f1() #正常调用 模块中寻找函数,并执行
fuc_name = input("请输入执行的函数:")
if hasattr(DD,fuc_name):
ret=getattr(DD,fuc_name)()
print(ret)

hasattr 判断传入的字符串是否是某个模块的变量名或者函数

4 简写 输入url尾部判断,反射执行不同的模块的不同函数

 from lib import account
inp_url = input("请输入url:")
#
# if inp_url.endswith("login"):
# print(account.login())
# elif inp_url.endswith("logout"):
# print(account.logout())
#
# else:
# print(account.nb()) #防止出现不能用的场景
#
# inp = inp_url.split("/")[-1]
# if hasattr(account,inp):
# ret = getattr(account,inp)
# print(ret())
# else:
# print(404) # 2 扩展1
target_module,target_func = inp_url.split("/")
m = __import__("lib."+target_module,fromlist=True) if hasattr(m,target_func):
ret = getattr(m,target_func)
print(ret())
else:
print(404)

反射两种思路方法

5 反射的四中方法介绍

 getattr
#
import commons
target_func = getattr(commons,"f1")
target_func()
#
DD = __import__("commons)
target_func = getattr(DD,"f1")
# 设置默认值,没有找到为默认值
target_func = getattr(DD,"f1",None)
# 还可以获取全局变量
str_ = getattr(DD,"name",None)
target_func
hasattr
# 判断 函数或变量存在与否, true or false r= hasattr(commons,"name") setattr
设置 变量或者定义函数 fuc = setattr(commons,"f4", lambda x:x+2)
str_s = setattr(commons,"name", "alex") delattr
删除 变量或者定义函数
f = delattr(commons,"name")

详细解析:

当我们要访问一个对象的成员时,应该是这样操作:

 class Foo(object):

     def __init__(self):
self.name = 'alex' def func(self):
return 'func' obj = Foo() # 访问字段
obj.name
# 执行方法
obj.func()

那么问题来了?
a、上述访问对象成员的 name 和 func 是什么? 
答:是变量名
b、obj.xxx 是什么意思? 
答:obj.xxx 表示去obj中或类中寻找变量名 xxx,并获取对应内存地址中的内容。
c、需求:请使用其他方式获取obj对象中的name变量指向内存中的值 “alex”

 class Foo(object):

     def __init__(self):
self.name = 'alex' # 不允许使用 obj.name
obj = Foo()

答:有两种方式,如下:

 class Foo(object):

     def __init__(self):
self.name = 'alex' def func(self):
return 'func' # 不允许使用 obj.name
obj = Foo() print obj.__dict__['name'] 方式一
 class Foo(object):

     def __init__(self):
self.name = 'alex' def func(self):
return 'func' # 不允许使用 obj.name
obj = Foo() print getattr(obj, 'name') 方式二

d、比较三种访问方式

  • obj.name
  • obj.__dict__['name']
  • getattr(obj, 'name')

答:第一种和其他种比,...
      第二种和第三种比,...

 
web框架实例
 #!/usr/bin/env python
#coding:utf-8
from wsgiref.simple_server import make_server class Handler(object): def index(self):
return 'index' def news(self):
return 'news' def RunServer(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
url = environ['PATH_INFO']
temp = url.split('/')[1]
obj = Handler()
is_exist = hasattr(obj, temp)
if is_exist:
func = getattr(obj, temp)
ret = func()
return ret
else:
return '404 not found' if __name__ == '__main__':
httpd = make_server('', 8001, RunServer)
print "Serving HTTP on port 8000..."
httpd.serve_forever()

结论:反射是通过字符串的形式操作对象相关的成员。一切事物都是对象!!!

反射当前模块成员

 #!/usr/bin/env python
# -*- coding:utf-8 -*- import sys def s1():
print 's1' def s2():
print 's2' this_module = sys.modules[__name__] hasattr(this_module, 's1')
getattr(this_module, 's2') 反射当前模块成员

类也是对象

 class Foo(object):

     staticField = "old boy"

     def __init__(self):
self.name = 'wupeiqi' def func(self):
return 'func' @staticmethod
def bar():
return 'bar' print getattr(Foo, 'staticField')
print getattr(Foo, 'func')
print getattr(Foo, 'bar')

模块也是对象

 #!/usr/bin/env python
# -*- coding:utf-8 -*- def dev():
return 'dev'
 #!/usr/bin/env python
# -*- coding:utf-8 -*- """
程序目录:
home.py
index.py 当前文件:
index.py
""" import home as obj #obj.dev() func = getattr(ob

二 、 面向对象

 面向对象

     面向对象不是所有情况都适用

     类里面的方法都不属于 模块了,而是属于类。

         class Oldboy:
def fetch(self,backend):
pass
def add_record(self,backend,record):
pass obj = Oldboy() #实例化类,创建一个对象,创建obj
obj.techt("www.oldboy.org")
obj.add_record("www.oldboy.org",XXXXXXX) 面向对象简单代码介绍
面向对象编程
a 定义类
class 类名:
def 方法1(self,参数1,参数2):
pass
b 根据类创建对象
使用对象取执行类中方法

面向对象的self解释  

写在前面:self其实就是对象名,实例化成什么对象,self就代表什么对象

self: 对象名
  调用方法的时候,python默认会把对象实例 赋值个self传入 方法

self: 对象名
调用方法的时候,python默认会把对象实例 赋值个self传入 方法
 # 打印self的内存地址

 class Oldboy(object):

     def fecht(self,backend):
print(backend,self)
def add_record(self,backend,record):
pass
"""rf
self: 对象名
调用方法的时候,python默认会把对象实例 赋值个self传入 方法
"""
obj1 = Oldboy()
print("obj1:",obj1) #obj1: <__main__.Oldboy object at 0x0000000000B41400>
obj1.fecht("bbbbackend") #bbbbackend <__main__.Oldboy object at 0x0000000000B41400> # 打印self的内存地址

面向对象概述

  • 面向过程:根据业务逻辑从上到下写垒代码
  • 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可
  • 面向对象:对函数进行分类和封装,让开发“更快更好更强...”

面向过程编程最易被初学者接受,其往往用一长段代码来实现指定功能,开发过程中最常见的操作就是粘贴复制,即:将之前实现的代码块复制到现需功能处。

 while True:
if cpu利用率 > 90%:
#发送邮件提醒
连接邮箱服务器
发送邮件
关闭连接 if 硬盘使用空间 > 90%:
#发送邮件提醒
连接邮箱服务器
发送邮件
关闭连接 if 内存占用 > 80%:
#发送邮件提醒
连接邮箱服务器
发送邮件
关闭连接

随着时间的推移,开始使用了函数式编程,增强代码的重用性和可读性,就变成了这样:

 def 发送邮件(内容)
#发送邮件提醒
连接邮箱服务器
发送邮件
关闭连接 while True: if cpu利用率 > 90%:
发送邮件('CPU报警') if 硬盘使用空间 > 90%:
发送邮件('硬盘报警') if 内存占用 > 80%:
发送邮件('内存报警')

2 创建类和对象

构造函数__init__

 5 类+括号, ====》 自动执行类中的 __init__方法;创建了一个对象

     在 __init__ 方法中执行具体封装的操作
__init__ 有一个特殊的名字: 构造方法 =====>>>> 初始化 __del__解释器销毁对象的时候自动调用,特殊的名字: 析构方法

# 2 利用构造方法 封装 因为类实例化为对象默认执行init构造方法

 class Oldboy2(object):

     def __init__(self,bk):
self.name = "alex" #直接封装一个变量到self内,而self则生成那个对象就等于哪个对象,作为所有对象的公共参数
self.backend = bk # 这个封装是针对不同对象实例传入不同的参数,而进行的封装,属于各自对象,默认实例化传入参数,self为对象名,而bk是参数,而这里又将参数封装给self.backend,而self等于 对象,所以将backend封装给了对象 def fecht(self):
print(self.backend)
def add_record(self,backend,record):
pass
obj2 = Oldboy2("www.obj2.org")
obj2.fecht() obj3 = Oldboy2("www.obj3.org")
obj3.fecht() # 2 利用构造方法 封装 因为类实例化为对象默认执行init构造方法

面向对象编程是一种编程方式,此编程方式的落地需要使用 “类” 和 “对象” 来实现,所以,面向对象编程其实就是对 “类” 和 “对象” 的使用。

  类就是一个模板,模板里可以包含多个函数,函数里实现一些功能

  对象则是根据模板创建的实例,通过实例对象可以执行类中的函数

  • class是关键字,表示类
  • 创建对象,类名称后加括号即可

ps:类中的函数第一个参数必须是self(详细见:类的三大特性之封装)
   类中定义的函数叫做 “方法”

 # 创建类
class Foo: def Bar(self):
print 'Bar' def Hello(self, name):
print 'i am %s' %name # 根据类Foo创建对象obj
obj = Foo()
obj.Bar() #执行Bar方法
obj.Hello('wupeiqi') #执行Hello方法 

诶,你在这里是不是有疑问了?使用函数式编程和面向对象编程方式来执行一个“方法”时函数要比面向对象简便

  • 面向对象:【创建对象】【通过对象执行方法】
  • 函数编程:【执行函数】

观察上述对比答案则是肯定的,然后并非绝对,场景的不同适合其的编程方式也不同。

总结:函数式的应用场景 --> 各个函数之间是独立且无共用的数据

3 面向对象三大特性

面向对象的三大特性是指:封装、继承和多态。

一、封装


封装:
使用场景:当同一类型的方法具有形同参数时候,直接封装到对象即可
使用场景:把类当做模板,创建多个对象()

封装,顾名思义就是将内容封装到某个地方,以后再去调用被封装在某处的内容。

所以,在使用面向对象的封装特性时,需要:

  • 将内容封装到某处
  • 从某处调用被封装的内容

第一步:将内容封装到某处

self 是一个形式参数,当执行 obj1 = Foo('wupeiqi', 18 ) 时,self 等于 obj1

当执行 obj2 = Foo('alex', 78 ) 时,self 等于 obj2

所以,内容其实被封装到了对象 obj1 和 obj2 中,每个对象中都有 name 和 age 属性,在内存里类似于下图来保存。

第二步:从某处调用被封装的内容

调用被封装的内容时,有两种情况:

  • 通过对象直接调用
  • 通过self间接调用

1、通过对象直接调用被封装的内容

上图展示了对象 obj1 和 obj2 在内存中保存的方式,根据保存格式可以如此调用被封装的内容:对象.属性名

 class Foo:

     def __init__(self, name, age):
self.name = name
self.age = age obj1 = Foo('wupeiqi', 18)
print obj1.name # 直接调用obj1对象的name属性
print obj1.age # 直接调用obj1对象的age属性 obj2 = Foo('alex', 73)
print obj2.name # 直接调用obj2对象的name属性
print obj2.age # 直接调用obj2对象的age属性
 # 1封装  封装参数到对象里面,而 self == 对应的对象名  所以对象.变量 可以通过self.变量调取
class Oldboy1(object): def fecht(self):
print(self.backend)
def add_record(self,backend,record):
pass
obj2 = Oldboy1()
obj2.backend="www.obj2.org" #封装到对象里面的变量
obj2.fecht() obj3 = Oldboy1()
obj3.backend="www.obj3.org"
obj3.fecht() # 1封装 封装参数到对象里面,而 self == 对应的对象名 所以对象.变量 可以通过self.变量调取

如上代码 第一种 封装  封装参数到对象里面,而 self == 对应的对象名  所以对象.变量 可以通过self.变量调取

  

第二步:从某处调用被封装的内容

如下代码第二种封装 利用构造方法 封装  因为类实例化为对象默认执行init构造方法

 # 2 利用构造方法 封装  因为类实例化为对象默认执行init构造方法
class Oldboy2(object): def __init__(self,bk):
self.name = "alex" #直接封装一个变量到self内,而self则生成那个对象就等于哪个对象,作为所有对象的公共参数
self.backend = bk # 这个封装是针对不同对象实例传入不同的参数,而进行的封装,属于各自对象,默认实例化传入参数,self为对象名,而bk是参数,而这里又将参数封装给self.backend,而self等于 对象,所以将backend封装给了对象 def fecht(self):
print(self.backend)
def add_record(self,backend,record):
pass
obj2 = Oldboy2("www.obj2.org")
obj2.fecht() obj3 = Oldboy2("www.obj3.org")
obj3.fecht() # 2 利用构造方法 封装 因为类实例化为对象默认执行init构造方法

调用被封装的内容时,有两种情况:

  • 通过对象直接调用
  • 通过self间接调用

1、通过对象直接调用被封装的内容

上图展示了对象 obj1 和 obj2 在内存中保存的方式,根据保存格式可以如此调用被封装的内容:对象.属性名

 class Foo:

     def __init__(self, name, age):
self.name = name
self.age = age obj1 = Foo('wupeiqi', 18)
print obj1.name # 直接调用obj1对象的name属性
print obj1.age # 直接调用obj1对象的age属性 obj2 = Foo('alex', 73)
print obj2.name # 直接调用obj2对象的name属性
print obj2.age # 直接调用obj2对象的age属性

2、通过self间接调用被封装的内容

执行类中的方法时,需要通过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间接获取被封装的内容。

练习一:在终端输出如下信息

  • 小明,10岁,男,上山去砍柴
  • 小明,10岁,男,开车去东北
  • 小明,10岁,男,最爱大保健
  • 老李,90岁,男,上山去砍柴
  • 老李,90岁,男,开车去东北
  • 老李,90岁,男,最爱大保健
 def kanchai(name, age, gender):
print "%s,%s岁,%s,上山去砍柴" %(name, age, gender) def qudongbei(name, age, gender):
print "%s,%s岁,%s,开车去东北" %(name, age, gender) def dabaojian(name, age, gender):
print "%s,%s岁,%s,最爱大保健" %(name, age, gender) kanchai('小明', 10, '男')
qudongbei('小明', 10, '男')
dabaojian('小明', 10, '男') kanchai('老李', 90, '男')
qudongbei('老李', 90, '男')
dabaojian('老李', 90, '男') 函数式编程

函数式编程

 class Foo:

     def __init__(self, name, age ,gender):
self.name = name
self.age = age
self.gender = gender def kanchai(self):
print "%s,%s岁,%s,上山去砍柴" %(self.name, self.age, self.gender) def qudongbei(self):
print "%s,%s岁,%s,开车去东北" %(self.name, self.age, self.gender) def dabaojian(self):
print "%s,%s岁,%s,最爱大保健" %(self.name, self.age, self.gender) xiaoming = Foo('小明', 10, '男')
xiaoming.kanchai()
xiaoming.qudongbei()
xiaoming.dabaojian() laoli = Foo('老李', 90, '男')
laoli.kanchai()
laoli.qudongbei()
laoli.dabaojian() 面向对象 面向对象

面向对象编程

上述对比可以看出,如果使用函数式编程,需要在每次执行函数时传入相同的参数,如果参数多的话,又需要粘贴复制了...  ;而对于面向对象只需要在创建对象时,将所有需要的参数封装到当前对象中,之后再次使用时,通过self间接去当前对象中取值即可。

保存对象的状态 pickle

封装的属性改变后pickle保存状态

 class Person:
def __init__(self,name,age,weight):
self.Name = name
self.Age = age
self.Weight = weight def chi(self):
self.Weight += 2 def duanlian(self):
self.Weight -= 1 o1 = Person("xiaoming",18,200) #实例化后,默认执行init方法,因此,将三个参数封装到o1了
o1.chi()
o1.chi()
o1.chi()
o1.chi()
o1.duanlian()
o1.duanlian()
o1.duanlian()
print(o1.Weight) 封装的属性改变后pickle保存状态

练习二:游戏人生程序

1、创建三个游戏人物,分别是:

  • 苍井井,女,18,初始战斗力1000
  • 东尼木木,男,20,初始战斗力1800
  • 波多多,女,19,初始战斗力2500

2、游戏场景,分别:

  • 草丛战斗,消耗200战斗力
  • 自我修炼,增长100战斗力
  • 多人游戏,消耗500战斗力
 # -*- coding:utf-8 -*-

 # #####################  定义实现功能的类  #####################

 class Person:

     def __init__(self, na, gen, age, fig):
self.name = na
self.gender = gen
self.age = age
self.fight =fig def grassland(self):
"""注释:草丛战斗,消耗200战斗力""" self.fight = self.fight - 200 def practice(self):
"""注释:自我修炼,增长100战斗力""" self.fight = self.fight + 200 def incest(self):
"""注释:多人游戏,消耗500战斗力""" self.fight = self.fight - 500 def detail(self):
"""注释:当前对象的详细情况""" temp = "姓名:%s ; 性别:%s ; 年龄:%s ; 战斗力:%s" % (self.name, self.gender, self.age, self.fight)
print temp # ##################### 开始游戏 ##################### cang = Person('苍井井', '女', 18, 1000) # 创建苍井井角色
dong = Person('东尼木木', '男', 20, 1800) # 创建东尼木木角色
bo = Person('波多多', '女', 19, 2500) # 创建波多多角色 cang.incest() #苍井空参加一次多人游戏
dong.practice()#东尼木木自我修炼了一次
bo.grassland() #波多多参加一次草丛战斗 #输出当前所有人的详细情况
cang.detail()
dong.detail()
bo.detail() cang.incest() #苍井空又参加一次多人游戏
dong.incest() #东尼木木也参加了一个多人游戏
bo.practice() #波多多自我修炼了一次 #输出当前所有人的详细情况
cang.detail()
dong.detail()
bo.detail() 游戏人生 游戏代码

游戏代码

二、继承

继承,面向对象中的继承和现实生活中的继承相同,即:子可以继承父的内容。

例如:

  猫可以:喵喵叫、吃、喝、拉、撒

  狗可以:汪汪叫、吃、喝、拉、撒

如果我们要分别为猫和狗创建一个类,那么就需要为 猫 和 狗 实现他们所有的功能,如下所示:

 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() 代码实例

所以,对于面向对象的继承来说,其实就是将多个类共有的方法提取到父类中,子类仅需继承父类而不必一一实现每个方法。

注:除了子类和父类的称谓,你可能看到过 派生类 和 基类 ,他们与子类和父类只是叫法不同而已。

学习了继承的写法之后,我们用代码来是上述阿猫阿狗的功能:

 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() 代码实例

2.1 继承的两种情况

继承:

   1 子类可以用父类的所有方法

       父类 == 基类
子类 == 派生类 2 派生类和子类中都有同一个方法,调用派生类时候优先执行派生类的方法 3 多继承
派生类可以继承多个类,这在c# 和java是不可以的
可以多个父类的所有功能
优先级:从左到右,如果本身派生类中有就优先执行本身的功能
派生类中没有基类的功能:

 # 1 派生类中没有基类的功能:

 class Animals:

     def chi(self):
print("chi") def he(self):
print("he") class Cat(Animals):
def __init__(self,name):
self.Name = name def jiao(self):
print("%s 叫"%(self.Name)) class Dog(Animals):
def __init__(self,name):
self.Name = name def jiao(self):
print("%s 叫"%(self.Name)) mao1 = Cat("小花")
mao1.jiao()

派生类中有的功能 基类中也有

 2 派生类中有的功能 基类中也有 : 优先执行派生类中的方法。  即从上到下

 class Animals:

     def chi(self):
print("chi") def he(self):
print("he") def piao(self):
print("%s 票 小泽玛利亚" % self.Name) class Cat(Animals):
def __init__(self,name):
self.Name = name def jiao(self):
print("%s 叫"%(self.Name)) def piao(self):
print("%s 票 苍井空" % self.Name) class Dog(Animals):
def __init__(self,name):
self.Name = name def jiao(self):
print("%s 叫"%(self.Name)) mao1 = Cat("小花")
mao1.piao()

2.2 多继承的情况 1 

多继承,1 从左到右去匹配,匹配到就不向右匹配了, 2 派生类中有的就不用了

 # 多继承,1 从左到右去匹配,匹配到就不向右匹配了,  2 派生类中有的就不用了

 class Animals:

     def chi(self):
print("chi") def he(self):
print("he") def piao(self):
print("%s 票 小泽玛利亚" % self.Name) class Dog_F():
def __init__(self,name):
self.Name = name def jiao(self):
print("%s 叫"%(self.Name)) def piao(self):
print("%s 票 苍井空" % self.Name) class Dog(Animals,Dog_F):
def __init__(self,name):
self.Name = name def jiao(self):
print("%s 叫"%(self.Name)) dog1 = Dog("小强")
dog1.piao()

2.3 多继承的混乱点python3版本的两种情况

# 1 第一种情况  顶级 a b 都是单独的情况
# e 继承 c d c继承a d 继承b
"""e执行方法,如果e中没有,从左到右依次找,c中有就执行c的,
c中没有的话就会去c的父类a中找,a中没有的话,返回e的第二个父类d中找,
d中没有的话,去d的父类b中找 """
class A:
def f1(self):
print("a") class B:
def f1(self):
print("b") class C(A):
def f(self):
print("c") class D(B):
def f1(self):
print("d")
class E(C,D):
def f(self):
print("e")
obj = E()
obj.f1()

查找顺序

# 2 第二种个情况 顶级a b 类都继承同一个父类
# e 继承 c d c继承a d 继承b a b 都继承 z
"""e执行方法,如果e中没有,从左到右依次找,c中有就执行c的,
c中没有的话就会去c的父类a中找,a中没有的话,不会去a b 共同的父类z中找,
而是 返回e的第二个父类d中找,
d中没有的话,去d的父类b中找,b中没有的话,去a b 共同的父类z中找
"""
 # 第二种情况

 class Z:
def f1(self):
print("a") class A(Z):
def f(self):
print("a") class B(Z):
def f1(self):
print("b") class C(A):
def f(self):
print("c") class D(B):
def f1(self):
print("d")
class E(C,D):
def f(self):
print("e")
obj = E()
obj.f1()

查找顺序

python2版本 多继承问题

  经典类 :直系找到底在从开始兄弟类开始

  新式类:同py3一样

顶级a b 类都继承同一个父类
# e 继承 c d c继承a d 继承b a b 都继承 z

经典类   #直系找到底    

  如下寻找路径  e -c -a -z -d -b

 class Z:
def f1(self):
print('z') class A(Z):
def f1(self):
print("a") class B(Z):
def f1(self):
print("b") class C(A):
def f(self):
print("c") class D(B):
def f1(self):
print("d") class E(C, D):
def f(self):
print("e") obj = E()
obj.f1()

那么问题又来了,多继承呢?

  • 是否可以继承多个类
  • 如果继承的多个类每个类中都定了相同的函数,那么那一个会被使用呢?

1、Python的类可以继承多个类,Java和C#中则只能继承一个类

2、Python的类如果继承了多个类,那么其寻找方法的方式有两种,分别是:深度优先广度优先

  • 当类是经典类时,多继承情况下,会按照深度优先方式查找
  • 当类是新式类时,多继承情况下,会按照广度优先方式查找

经典类和新式类,从字面上可以看出一个老一个新,新的必然包含了跟多的功能,也是之后推荐的写法,从写法上区分的话,如果 当前类或者父类继承了object类,那么该类便是新式类,否则便是经典类。

 class D:

     def bar(self):
print 'D.bar' class C(D): def bar(self):
print 'C.bar' class B(D): def bar(self):
print 'B.bar' class A(B, C): def bar(self):
print 'A.bar' a = A()
# 执行bar方法时
# 首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去D类中找,如果D类中么有,则继续去C类中找,如果还是未找到,则报错
# 所以,查找顺序:A --> B --> D --> C
# 在上述查找bar方法的过程中,一旦找到,则寻找过程立即中断,便不会再继续找了
a.bar() 经典类多继承
 class D(object):

     def bar(self):
print 'D.bar' class C(D): def bar(self):
print 'C.bar' class B(D): def bar(self):
print 'B.bar' class A(B, C): def bar(self):
print 'A.bar' a = A()
# 执行bar方法时
# 首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去C类中找,如果C类中么有,则继续去D类中找,如果还是未找到,则报错
# 所以,查找顺序:A --> B --> C --> D
# 在上述查找bar方法的过程中,一旦找到,则寻找过程立即中断,便不会再继续找了
a.bar() 新式类多继承

经典类:首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去D类中找,如果D类中么有,则继续去C类中找,如果还是未找到,则报错

新式类:首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去C类中找,如果C类中么有,则继续去D类中找,如果还是未找到,则报错

注意:在上述查找过程中,一旦找到,则寻找过程立即中断,便不会再继续找了

三、多态 

Pyhon不支持多态并且也用不到多态,多态的概念是应用于Java和C#这一类强类型语言中,而Python崇尚“鸭子类型”。

 class F1:
pass class S1(F1): def show(self):
print 'S1.show' class S2(F1): def show(self):
print 'S2.show' # 由于在Java或C#中定义函数参数时,必须指定参数的类型
# 为了让Func函数既可以执行S1对象的show方法,又可以执行S2对象的show方法,所以,定义了一个S1和S2类的父类
# 而实际传入的参数是:S1对象和S2对象 def Func(F1 obj):
"""Func函数需要接收一个F1类型或者F1子类的类型""" print obj.show() s1_obj = S1()
Func(s1_obj) # 在Func函数中传入S1类的对象 s1_obj,执行 S1 的show方法,结果:S1.show s2_obj = S2()
Func(s2_obj) # 在Func函数中传入Ss类的对象 ss_obj,执行 Ss 的show方法,结果:S2.show Python伪代码实现Java或C#的多态 Python伪代码实现Java或C#的多态
 class F1:
pass class S1(F1): def show(self):
print 'S1.show' class S2(F1): def show(self):
print 'S2.show' def Func(obj):
print obj.show() s1_obj = S1()
Func(s1_obj) s2_obj = S2()
Func(s2_obj) Python “鸭子类型”
 多态:
多种形态
python 本身支持多态
class Father(Father):
def f1(self):
print("fa1")
def f2(self):
print("f2a")
class Son1(Father):
def f1(self):
print("f1")
def f2(self):
print("f2")
class Son2(IFather): #如果使用了接口类为基类,必须完成基类的所有方法
def f1(self):
print("f1")
def f2(self):
print("f2") 对于多态:
def fun(arg): # 随便传类
arg().f2()
扩展:
重载,函数名相同,参数个数不同(python不支持)
重写,派生类 重新写实现基类的方法

代码级别接口:
  仅对于接口来说 接口用来约束的 几个方法就得写几个方法
  方法不能写任何 功能, pass

  如果某个类继承了接口,这个接口有几个方法就要实现几个方法,都需要实现

 代码级别接口:
仅对于接口来说 接口用来约束的 几个方法就得写几个方法
方法不能写任何 功能, pass 如果某个类继承了接口,这个接口有几个方法就要实现几个方法,都需要实现 默认是interface IFather: interface IFather:
def f1(self):pass
def f2(self):pass class Son1(IFather):
def f1(self):
print("f1")
def f2(self):
print("f2")
class Son2(IFather): #如果使用了接口类为基类,必须完成基类的所有方法,接口中的方法就是作为一种约束而已。
def f1(self):
print("f1")
def f2(self):
print("f2")
class Son3:
def f1(self):
print("f1")
对于多态:
def fun(interface arg): # 只能传 完成了f2接口的类
arg().f2() 代码级接口

总结

以上就是本节对于面向对象初级知识的介绍,总结如下:

  • 面向对象是一种编程方式,此编程方式的实现是基于对  和 对象 的使用
  • 类 是一个模板,模板中包装了多个“函数”供使用
  • 对象,根据模板创建的实例(即:对象),实例用于调用被包装在类中的函数
  • 面向对象三大特性:封装、继承和多态

问答专区

问题一:什么样的代码才是面向对象?

答:从简单来说,如果程序中的所有功能都是用 类 和 对象 来实现,那么就是面向对象编程了。

问题二:函数式编程 和 面向对象 如何选择?分别在什么情况下使用?

答:须知:对于 C# 和 Java 程序员来说不存在这个问题,因为该两门语言只支持面向对象编程(不支持函数式编程)。而对于 Python 和 PHP 等语言却同时支持两种编程方式,且函数式编程能完成的操作,面向对象都可以实现;而面向对象的能完成的操作,函数式编程不行(函数式编程无法实现面向对象的封装功能)。

所以,一般在Python开发中,全部使用面向对象 或 面向对象和函数式混合使用

面向对象的应用场景:

  1. 多函数需使用共同的值,如:数据库的增、删、改、查操作都需要连接数据库字符串、主机名、用户名和密码
 class SqlHelper:

     def __init__(self, host, user, pwd):

         self.host = host
self.user = user
self.pwd = pwd def 增(self):
# 使用主机名、用户名、密码(self.host 、self.user 、self.pwd)打开数据库连接
# do something
# 关闭数据库连接 def 删(self):
# 使用主机名、用户名、密码(self.host 、self.user 、self.pwd)打开数据库连接
# do something
# 关闭数据库连接 def 改(self):
# 使用主机名、用户名、密码(self.host 、self.user 、self.pwd)打开数据库连接
# do something
# 关闭数据库连接 def 查(self):
# 使用主机名、用户名、密码(self.host 、self.user 、self.pwd)打开数据库连接
# do something
# 关闭数据库连接# do something Demo

2 需要创建多个事物,每个事物属性个数相同,但是值的需求
如:张三、李四、杨五,他们都有姓名、年龄、血型,但其都是不相同。即:属性个数相同,但值不相同

 class Person:

     def __init__(self, name ,age ,blood_type):

         self.name = name
self.age = age
self.blood_type = blood_type def detail(self):
temp = "i am %s, age %s , blood type %s " % (self.name, self.age, self.blood_type)
print temp zhangsan = Person('张三', 18, 'A')
lisi = Person('李四', 73, 'AB')
yangwu = Person('杨五', 84, 'A') Demo Demo

问题三:类和对象在内存中是如何保存?

答:类以及类中的方法在内存中只有一份,而根据类创建的每一个对象都在内存中需要存一份,大致如下图:

如上图所示,根据类创建对象时,对象中除了封装 name 和 age 的值之外,还会保存一个类对象指针,该值指向当前对象的类。

当通过 obj1 执行 【方法一】 时,过程如下:

  1. 根据当前对象中的 类对象指针 找到类中的方法
  2. 将对象 obj1 当作参数传给 方法的第一个参数 self 

python基础-9__import__ 反射和面向对象基础 self 封装 继承(多继承顺序) 多态的更多相关文章

  1. # 095 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 03 封装总结 01 封装知识点总结

    095 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 ...

  2. 094 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 02 static关键字 04 static关键字(续)

    094 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 ...

  3. 093 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 02 static关键字 03 static关键字(下)

    093 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 ...

  4. 092 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 02 static关键字 02 static关键字(中)

    092 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 ...

  5. 091 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 02 static关键字 01 static关键字(上)

    091 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 ...

  6. 090 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 04 使用包进行类管理(2)——导入包

    090 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 ...

  7. 089 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 使用包进行类管理(1)——创建包

    089 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 ...

  8. 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 02 封装的代码实现

    088 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 02 封装的代码实现 本文知识点:Java封装的代码实现 说明:因为时间紧张,本人写博客过程中只 ...

  9. 087 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 01 封装的概念和特点

    087 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 01 封装的概念和特点 本文知识点:封装的概念和特点 说明:因为时间紧张,本人写博客过程中只是对 ...

随机推荐

  1. 源讯科技(中国)有限公司(Atos Worldline)

    源讯公司是欧洲***的IT服务公司,去年营收达到88亿欧元,在全球52个国家拥有77100名员工.Worldline为Atos(源讯)全资子公司,专注于金融支付领域.Worldline在B2B及B2C ...

  2. Bash数组-判断某个元素是否在数组内的几种方法

    声明一个数组array,一个待测试元素var array=( element1 element2 element3 ) var="element1" 接下来用几种方法来分别测试va ...

  3. CCPC-Wannafly Winter Camp Day1 (Div2, onsite) 夺宝奇兵

    题目描述 wlswls所在的王国有nn个居民(不包括wlswls),他们共有mm件神奇的宝物. 对于第ii件宝物,wlswls可以花费a_iai​的金币把它从原来的主人那里买过来. 请问wlswls最 ...

  4. Apache HttpClient 读取响应乱码问题总结

    Apache HttpClient 读取响应乱码问题总结 setCharacterEncoding  Content-Type  HttpClient  起因 最近公司产品线研发人员调整,集中兵力做战 ...

  5. 如何将上个SQL的结果作为参数传递给下个SQL

    如何将上个SQL的结果作为参数传递给下个SQL: ##source认证 kinit认证 source /home/omm/ficlient/bigdata_env kinit -k -t /ETL/c ...

  6. 【leetcode】1104. Path In Zigzag Labelled Binary Tree

    题目如下: In an infinite binary tree where every node has two children, the nodes are labelled in row or ...

  7. php array_shift()函数 语法

    php array_shift()函数 语法 作用:删除数组中第一个元素,并返回被删除元素的值.富瑞联华 语法:array_shift(array) 参数: 参数 描述 array 必需.规定数组. ...

  8. R Seurat 单细胞处理pipline 代码

    options(stringsAsFactors = F ) rm(list = ls()) library(Seurat) library(dplyr) library(ggplot2) libra ...

  9. pytho 解析fiddler 导出的har文件代码,自动录入api

    参考:https://testerhome.com/topics/5276 har导出格式如下: { 'log': { 'pages': [], 'comment': 'exported @ 2019 ...

  10. 模拟vue实现简单的webpack打包

    一.安装nodejs,查看是否安装成功 二.package.json项目初始化 npm init 电脑有node环境,在根目录下运行命令npm init初始化项目,根据提示输入项目相关信息,然后运行. ...