18-面向对象之基础
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了18-面向对象之基础相关的知识,希望对你有一定的参考价值。
目录:类和对象,多态与多态性,封装,绑定与非绑定方法,继承,反射
-------------------------------------------
面向过程:根据业务逻辑从上到下写垒代码
函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可
面向对象:对函数进行分类和封装,让开发“更快更好更强...
面向过程编程
核心是过程,过程就是解决问题的步骤,即先做什么,在做什么,基于面向过程设计程序,好比流水线,是一种机械思维方法。
优点:复杂的问题简单化
缺点:可扩展性差,牵一发而动全身
应用场景: linux内核,httpd,git
面向对象编程(Object Oriented Programming,OOP,面向对象程序设计)
核心是对象,要理解对象应该把自己当作上帝,一切事务都是对象,不存在的也可创建出来。
对象(obj)
对象是特征(变量)与技能(函数)的结合体
优点:可扩展性强
缺点:无法像面向过程一样准确的知道什么阶段发生什么事,会有什么结果
应用场景:与用户层交互多的,公司内部的软件,游戏,互联网软件
类(class)
类是一些列对象共有的特征与技能的集合体
在程序中使用,需要先定义类,再定义对象,即实例化出对象
-------------------------------------------
-------------------------------------------
创建类和对象
面向对象编程是一种编程方式,此编程方式的落地需要使用 “类” 和 “对象” 来实现,所以,面向对象编程其实就是对 “类” 和 “对象” 的使用
--类就是一个模板,模板里可以包含多个函数,函数里实现一些功能
--对象则是根据模板创建的实例,通过实例对象可以执行类中的函数
类的语法:
class 类名:
"""
注释
"""
类体(可是任意代码)
示例:
# 定义一个类
class Chinese:
country = ‘China‘ # 属性
def __init__(self, name, age): # 初始化,实例化出来的对象默认拥有name,age等属性
self.name = name # p1.name=name
self.age = age
# p1.age=agedef talk(self): # 技能
print(‘say Chinese‘)
p1 = Chinese(‘rain‘, 18) # 实例化出一个对象p1
print(p1.country) # 类的数据属性
- print(p1.__init__) # 类的函数属性
print(p1.talk()) # 类的函数属性,加括号即可运行
print(p1.name)
print(p1.age)
PS:
1,class是关键字,表示类,注意后面冒号‘:‘
2,创建对象,类名称后加括号即可
3,类中的函数,默认第一个参数都为为self,代表实例化对象自己,self.name相当于p1.name
4,整个函数的功能称作类的方法
5,定义在类内部的变量,是所有对象共有的,id全一样
6,定义在类内部的函数,是绑定到所有对象的,是给对象来用,obj.func()会把obj本身当做第一个参数出入
7,绑定方法:绑定到谁的身上,就是给谁用的,谁来调用就会自动把自己当作第一个参数传入
类的特殊方法:
__dict__:查看类的属性字典或类的名称空间
print(Chinese.__dict__)
运行结果:(一个字典)
{‘talk‘: <function Chinese.talk at 0x0000000000B4E268>, ‘country‘: ‘China‘, ‘__doc__‘: None, ‘__dict__‘: <attribute ‘__dict__‘ of ‘Chinese‘ objects>, ‘__init__‘: <function Chinese.__init__ at 0x0000000000B4E1E0>, ‘__module__‘: ‘__main__‘, ‘__weakref__‘: <attribute ‘__weakref__‘ of ‘Chinese‘ objects>}
-------------------------------------------
-------------------------------------------
练习1:对象个数统计功能
每实例化一次,记一次数,最后统计一个类实例化了几个对象
class Foo:
count = 0
# 类的数据属性def __init__(self, name):
Foo.count += 1
self.name = name
obj1 = Foo(‘rain‘)
obj2 = Foo(‘tom‘)
print(‘该类共实例化了 %s 个对象.‘ % Foo.count)
运行结果:
该类共实例化了 2 个对象.
练习2:对象间的交互
定义2个英雄人物,可以互相攻击,血量减少
class Garen:
camp = ‘Demacia‘ # 定义通用属性:阵营
def __init__(self, nickname, life_value=600, agg = 100):
self.nickname = nickname
self.life_value = life_value
self.agg = agg
def attack(self, enemy):
# 定义攻击方法,攻击敌人enemy.life_value -= self.agg
class Riven:
camp = ‘Noxus‘
def __init__(self, nickname, life_value=400, agg = 150):
self.nickname = nickname
self.life_value = life_value
self.agg = agg
def attack(self, enemy):
enemy.life_value -= self.agg
g = Garen(‘德码‘)
r = Riven(‘瑞文‘)
print(g.life_value) # 查看血量值
print(r.life_value)
g.attack(r) # 模拟攻击
print(r.life_value) # 攻击后血量值
r.attack(g)
print(g.life_value)
-------------------------------------------
继承
1,什么是继承:
继承是一种创建新类的方式,新建的类可以继承一个多个父类,父类又可称为基类或超类,新建的类称为派生类或子类
格式:
class ParentClass1:
pass
class ParentClass2:
pass
class SubClass1(ParentClass1):
"""
继承父类1
"""
pass
class SubClass2(ParentClass1, ParentClass2): # 调用时,会按照从左到右顺序查找
"""
继承2个父类:父类1和父类2
"""
pass
2,继承关系的寻找
先在对象自己里面找,没有再去对象的类中找,再没有去父类找
在Python3中可以使用
print(Foo.mro())
返回值是个列表:
列表元素固定,也就是继承查找的顺序
Python2中的类分为:新式类与经典类
新式类:
class Foo(object):
pass
经典类:
class Foo:
pass
Python3中都为新式类
class Foo:
pass
print(Foo.__dict__())
例如:
关系图如下:
F的父类是A,B,C;
A的父类是D;
B的父类是E;
定义如下类来测试:
class E:
def test(self):
print(‘from E‘)
pass
class A(E):
def test(self):
print(‘from A‘)
pass
class D:
def test(self):
print(‘from D‘)
pass
class B(D):
def test(self):
print(‘from B‘)
pass
class C:
def test(self):
print(‘from C‘)
pass
# 优先找F自己类中的test函数,F类中没有,找A-->D,D没有回来找B-->E,还没有找C
class F(A, B, C):
def test(self):
print(‘from F‘)
pass
f = F()
f.test()
如果是如下图形式:
新式类查找顺序:广度优先
F-->D-->B-->E-->C-->A (不回一找到底,找完分支后,最后找A)
经典类查找顺序:深度优先
F-->D-->B-->A-->E-->C
3,继承可以解决代码冗余问题,继承反映的是一种什么是什么的关系
例如:
class People: # 定义父类
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex
class Teacher(People): # 子类继承父类,且有自己的独特的属性salary
def __init__(self, name, age, sex, salary):
People.__init__(self, name, age, sex)
self.salary = salary
class Student(People):
# 子类继承父类pass
t = Teacher(‘rain‘, 19, ‘male‘, 3000)
print(t.salary)
s = Student(‘a‘, 10, ‘male‘)
print(s.name)
print(s.age)
print(s.sex)
运行结果:
3000
a
10
male
supper().父类的方法名:允许子类重用父类中的方法
例如:
class Foo:
def test(self):
print(‘from foo.test...‘)
class Bar(Foo): # 如果有多个父类,按照从左到右顺序查找,print(Bar.mro())可查看查看顺序
def test(self):
super().test()
# Foo.test(self)- # super(Bar, self).test()
print(‘from Bar...‘)
b = Bar()
b.test()
运行结果:
from foo.test...
from Bar...
组合
组合也可以解决代码冗余问题,组合反映的是什么有什么的关系
将不同的类组合起来相互调用
例如:
class Date:
def __init__(self, year, mon, day):
self.year = year
self.mon = mon
self.day = day
def tell(self):
print(‘%s-%s-%s‘ % (self.year, self.mon, self.day))
class People:
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex
class Teacher(People):
def __init__(self, name, age, sex, salary, year, mon, day):
People.__init__(self, name, age, sex)
self.salary = salary
self.birth = Date(year, mon, day)
class Student(People):
def __init__(self, name, age, sex, year, mon, day):
People.__init__(self, name, age, sex)
self.birth = Date(year, mon, day)
t = Teacher(‘rain‘, 19, ‘male‘, 10000, 1990, 6,20)
print(t.salary)
t.birth.tell()
s = Student(‘a‘, 11, ‘male‘, 2007, 12, 12)
print(s.name)
s.birth.tell()
运行结果:
1000
1990-6-20
a
2007-12-12
组合应用场景:
学生类与学号类
学生类与学生学的课程类
教师类与教师教的课程类
多态和多态性
多态:同一种事物的多种形态,例如:
1,序列类型有多种形态:如字符串,列表,元组等
2,动物有多种形态:人,狗,猫
例如:动物有不同的形态:人, 狗, 猪, 猫,不管你是什么动物,只要知道动物都能发声,有talk方法即可,定义一个通用的接口func,来统一调方法即可。
class Animal:
def talk(self):
print(‘发声...‘)
class People(Animal):
def talk(self):
print(‘人在说话...‘)
class Pig(Animal):
def talk(self):
print(‘猪在叫...‘)
class Dog(Animal):
def talk(self):
print(‘狗在叫...‘)
class Cat(Animal):
def talk(self):
print(‘猫在叫...‘)
def func(obj):
"""
统一接口
obj具有多态性,没有类型概念
:param obj:
:return:
"""
obj.talk()
peo1 = People()
dog1 = Dog()
pig1 = Pig()
cat1 = Cat()
# peo1.talk()
# dog1.talk()
# pig1.talk()
func(peo1)
func(dog1)
func(pig1)
func(cat1)
运行结果:
人在说话...
狗在叫...
猪在叫...
猫在叫...
封装
为啥要封装:
1,封装数据的主要原因是:保护隐私
2,封装方法的主要原因是:隔离复杂度
类中把某些属性和方法隐藏起来(或者说定义成私有的),仅在类的内部使用,外部无法访问,或者留下少量接口(函数)供外部访问.
在python中用双下划线的方式实现隐藏属性(即设置成私有的)
例如:__x
类中所有双下划线开头的名称如__x,都会会自动转换为_类名__x的形式:
示例1:
class Foo:
__x = 1
def test(self):
print(‘from test...‘)
print(Foo.__dict__) # {‘_Foo__x‘: 1}
print(Foo._Foo__x) # 1
实例2:
class People:
"""
变形仅在定义阶段完成,后续不再变形
"""
def __init__(self, name, age, sex):
self.__name = name # self._People__name = name
self.__age = age
# self._People__age = ageself.__sex = sex
# self._People__sex = sexdef tell_info(self):
print(‘人的名字是:%s, 人的性别是: %s, 人的年龄是: %s‘ % (self.__name, self.__sex, self.__age))
p = People(‘rain‘, 18, ‘male‘)
p.tell_info()
运行结果:
人的名字是:rain, 人的性别是: male, 人的年龄是: 18
示例3:
class Parent:
def foo(self):
"""
# 那么我要让他调用父类中的bar呢
改成self.__bar()
:return:
"""
print(‘from parent foo...‘)
self.bar() # self._Parent__bar
def bar(self): # _Parent__bar
"""
改成def __bar(self):
:return:
"""
print(‘from parent bar...‘)
class Sub(Parent):
def bar(self): # _Sub__bar
print(‘from sub bar...‘)
a = Sub()
a.foo() # 默认按照查找顺序,对象本身-->对象所属的类-->父类:from sub bar...
示例4:
class People:
def __init__(self, name, age):
self.__name = name
self.__age = age
def tell_info(self):
print(‘人的名字是:%s, 人的年龄是: %s‘ % (self.__name, self.__age))
def set_info(self, x, y):
"""
我们为了限制输入的类型:
比如名字规定必须是字符串,年龄必须是整形,
就需要加一点逻辑判断:isinstance(a,b)
:param x:
:param y:
:return:
"""
if not isinstance(x, str):
raise TypeError(‘名字必须是字符串...‘)
if not isinstance(y, int):
raise TypeError(‘年龄必须是整形...‘)
self.__name = x
self.__age = y
p = People(‘alex‘, 1000)
p.tell_info()
p.set_info(‘alex‘, 2000) # 修改
p.tell_info()
p.set_info(1111, 3000) # TypeError: 名字必须是字符串...
p.tell_info()
p.set_info(‘alex‘, ‘3000‘) # TypeError: 年龄必须是整形...
p.tell_info()
自动变形的特点:
1,类中定义的__x只能在内部使用,如self.__x,引用的就是变形的结果:self._self__x
2,这种变形起始正式针对外部的变形,在外部是无法通过__x这个名字访问到的
3,在子类定义的__x不会覆盖在父类定义的__x,因为子类中在定义的时候自动变形为了:_子类名__x,而父类中变形成了:_父类名__x,即双下划线开头的属性在继承给子类的时候,子类是无法覆盖的.
注意:对于这一层面的封装(隐藏),我们需要在类中定义一个函数(即接口函数),在它内部访问被隐藏的属性,然后外部就可以正常使用了.
也可以使用property(特性)来代替接口函数
property(特性)
内置函数,装饰器
一旦在函数属性前加上装饰器property,这个函数就会变成一个数据属性
基本语法:
class Foo:
@property
def test(self):
print(‘from Foo.test...‘)
- # test=property(test)
f = Foo()
#f.test() # 结果:from Foo.test...
f.test # 结果:from Foo.test...
实际应用:
示例1:
计算成人BMI值
过轻:低于18.5
正常:18.5-23.9
过重:24-27
肥胖:28-32
非常肥胖:高于32
体质指数(BMI) = 体重(kg) / (身高(m) ^ 2)
class People:
def __init__(self, name, weight, height):
self.name = name
self.weight = weight
self.height = height
- @property
- def bmi(self):
return self.weight / (self.height ** 2)
p = People(‘rain‘, 75, 1.80)
- # print(p.bmi())
- print(p.bmi)
运行结果:
23.148148148148145
示例2:
计算圆的周长和面积
import math
class Circle:
def __init__(self, radius): # 圆的半径radius
self.radius = radius
@property
def area(self): # 计算圆的面积
return math.pi * self.radius ** 2
@property
def perimeter(self): # 计算圆的周长
return 2 * math.pi * self.radius
c = Circle(10)
print(c.radius)
print(c.area)
print(c.perimeter)
运行结果:
10
314.1592653589793
62.83185307179586
[注意:加了装饰器property,arear和perimeter不能被赋值]
示例3:
class People:
def __init__(self, name, permission=False):
self.__name = name # 可转换为:self._People__name = name
self.permission = permission # 用于判断,是否允许删除
@property # 可转换为:name = property(name)
def name(self):
return self.__name # 可转换为:self._People__name
@name.setter # name = name.setter(name)
def name(self, value):
if not isinstance(value, str): # 判断value是否是字符串
raise TypeError(‘输入的内容必须是字符串.‘)
self.__name = value # self._People__name = value
@name.deleter
def name(self):
if not self.permission:
raise TypeError(‘禁止删除.‘)
del self.__name
print(‘已删除名字‘)
p = People(‘rain‘)
print(p.name())
print(p.name)
p.name = ‘rain656‘
print(p.name)
p.name = 123123
print(p.name)
p.permission = True
del p.name
print(p.name)
绑定方法与非绑定方法:
绑定方法:绑定给谁,谁来调用就自动将它本身当作第一个参数传入
-绑定到类的方法:用classmethod装饰器装饰的方法
对象也可以条用,但仍将类当作第一个参数传入
-绑定到对象的方法:没有被任何装饰器装饰的方法
非绑定方法:用staticmethod装饰器装饰的方法
-不与类或对象绑定,类和对象都可以调用,但是没有自动传值那么一说,就是一个普通工具而已
staticmethod示例:
statimethod不与类或对象绑定,谁都可以调用,没有自动传值效果,python为我们内置了函数staticmethod来把类中的函数定义成静态方法
import hashlib
import time
class mysql:
def __init__(self,host,port):
self.id=self.create_id()
self.host=host
self.port=port
@staticmethod
def create_id(): #就是一个普通工具
m=hashlib.md5(str(time.clock()).encode(‘utf-8‘))
return m.hexdigest()
print(MySQL.create_id)
conn=MySQL(‘127.0.0.1‘,3306)
print(conn.create_id)
运行结果:
<function MySQL.create_id at 0x0000000000D6E378>
<function MySQL.create_id at 0x0000000000D6E378>
classmethod示例:
classmehtod是给类用的,即绑定到类,类在使用时会将类本身当做参数传给类方法的第一个参数(即便是对象来调用也会将类当作第一个参数传入),python为我们内置了函数classmethod来把类中的函数定义成类方法
settings.py文件内容:
HOST=‘127.0.0.1‘
PORT=3306
DB_PATH=r‘C:\Users\Administrator\PycharmProjects\test\面向对象编程\test1\db‘
import settings
import hashlib
import time
class MySQL:
def __init__(self, host, port):
self.host = host
self.port = port
@classmethod
def from_conf(cls):
print(cls)
return cls(settings.HOST, settings.PORT)
print(MySQL.from_conf)
conn=MySQL.from_conf()
print(conn.host, conn.port)
conn.from_conf() #对象也可以调用,但是默认传的第一个参数仍然是类
运行结果:
<bound method MySQL.from_conf of <class ‘__main__.MySQL‘>>
<class ‘__main__.MySQL‘>
127.0.0.1 3306
<class ‘__main__.MySQL‘>
比较staticmethod和classmethod的区别
示例1:
import settings
class MySQL:
def __init__(self, host, port):
self.host = host
self.port = port
@staticmethod
def from_conf():
return MySQL(settings.HOST,settings.PORT)
@classmethod
def from_conf(cls):
return cls(settings.HOST,settings.PORT)
def __str__(self):
return ‘就不告诉你...‘
class Mariadb(MySQL):
def __str__(self):
return ‘host:%s, port: %s‘ %(self.host,self.port)
m=Mariadb.from_conf()
print(m)
运行结果:
# @classmethod存在时运行结果:host:127.0.0.1, port: 3306
# @classmethod不存在时运行结果:就不告诉你...
示例2:
定义MySQL类
1.对象有id、host、port三个属性
2.定义工具create_id,在实例化时为每个对象随机生成id,保证id唯一
3.提供两种实例化方式,方式一:用户传入host和port 方式二:从配置文件中读取host和port进行实例化
4.为对象定制方法,save和get,save能自动将对象序列化到文件中,文件名为id号,文件路径为配置文件中DB_PATH;get方法用来从文件中反序列化出对象
import settings
import hashlib
import time
import random
import pickle
import os
class MySQL:
def __init__(self,host,port):
self.id=self.create_id()
self.host=host
self.port=port
def save(self):
file_path=r‘%s%s%s‘ %(settings.DB_PATH,os.sep,self.id)
pickle.dump(self,open(file_path,‘wb‘))
def get(self):
file_path=r‘%s%s%s‘ %(settings.DB_PATH,os.sep,self.id)
return pickle.load(open(file_path,‘rb‘))
@staticmethod
def create_id():
m=hashlib.md5(str(time.clock()).encode(‘utf-8‘))
return m.hexdigest()
@classmethod
def from_conf(cls):
print(cls)
return cls(settings.HOST,settings.PORT)
print(MySQL.from_conf) #<bound method MySQL.from_conf of <class ‘__main__.MySQL‘>>
conn=MySQL.from_conf()
print(conn.id)
print(conn.create_id())
print(MySQL.create_id())
conn.save()
obj=conn.get()
print(obj.id)
运行结果:
<bound method MySQL.from_conf of <class ‘__main__.MySQL‘>>
<class ‘__main__.MySQL‘>
36d644ee6ae993da6a1e9530bbd7edfe
387747d3e0c9034e68cb459b89322364
578a0ec95b1d051128dcdfba3f673754
36d644ee6ae993da6a1e9530bbd7edfe
示例3:
import time
class Date:
def __init__(self,year,month,day):
self.year=year
self.month=month
self.day=day
@staticmethod
def now():
t=time.localtime()
return Date(t.tm_year,t.tm_mon,t.tm_mday)
@staticmethod
def tomorrow():
t=time.localtime(time.time()+86400)
return Date(t.tm_year,t.tm_mon,t.tm_mday)
a=Date(‘1987‘,11,21)
b=Date.now()
c=Date.tomorrow()
print(a.year,a.month,a.day)
print(b.year,b.month,b.day)
print(c.year,c.month,c.day)
运行结果:
1987 11 21
2017 6 13
2017 6 14
示例4:
import time
class Date:
def __init__(self,year,month,day):
self.year=year
self.month=month
self.day=day
@staticmethod
def now():
t=time.localtime()
return Date(t.tm_year,t.tm_mon,t.tm_mday)
class EuroDate(Date):
def __str__(self):
return ‘year:%s month:%s day:%s‘ %(self.year,self.month,self.day)
e=EuroDate.now()
print(e) #我们的意图是想触发EuroDate.__str__,但是结果为
‘‘‘
输出结果:
<__main__.Date object at 0x1013f9d68>
‘‘‘
#因为e就是用Date类产生的,所以根本不会触发EuroDate.__str__,解决方法就是用classmethod
import time
class Date:
def __init__(self,year,month,day):
self.year=year
self.month=month
self.day=day
# @staticmethod
# def now():
# t=time.localtime()
# return Date(t.tm_year,t.tm_mon,t.tm_mday)
@classmethod #改成类方法
def now(cls):
t=time.localtime()
return cls(t.tm_year,t.tm_mon,t.tm_mday) #哪个类来调用,即用哪个类cls来实例化
class EuroDate(Date):
def __str__(self):
return ‘year:%s month:%s day:%s‘ %(self.year,self.month,self.day)
e=EuroDate.now()
print(e) #我们的意图是想触发EuroDate.__str__,此时e就是由EuroDate产生的,所以会如我们所愿
运行结果:
<__main__.Date object at 0x0000000000AA0908>
year:2017 month:6 day:13
__init__:类实例初始化函数
__str__:类实例字符串化函数
反射
反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)
python面向对象中的反射:通过字符串的形式操作对象相关的属性;
python中的一切事物都是对象(都可以使用反射)
例如:
class Chinese:
country = ‘China‘
def __init__(self,name,age):
self.name=name
self.age=age
p=Chinese(‘jack‘, 19)
print(Chinese.country) # 可转换为Chinese.__dict__[‘country]
print(p.name) # 可转换为p.__dict__[‘name‘]
转换的部分就是一种本质上的反射
下列方法可以实现自省的函数:
hasattr(obj,name):判断obj是否有name属性,name需为字符串类型
getattr(obj,name,default=None):获取对象obj的name属性,default表示设置默认返回值
setattr(x,y,v):设置对象x的属性y,值为v,y必须为字符串类型
delattr(x,y):删除类x的属性y,y需为字符串形式
方法示例:
class BlackMedium:
feature=‘Ugly‘
def __init__(self,name,addr):
self.name=name
self.addr=addr
def sell_house(self):
print(‘%s 黑中介卖房子啦,傻逼才买呢,但是谁能证明自己不傻逼.‘ % self.name)
def rent_house(self):
print(‘%s 黑中介租房子啦,傻逼才租呢.‘ % self.name)
# 检测是否含有某个属性
b1 = BlackMedium(‘万成‘,‘回龙观‘)
print(hasattr(b1,‘name‘)) # 判断对象b1是否有‘name‘这个属性,判断的属性必须是字符串形式
print(hasattr(b1,‘sell_house‘))
# 获取某个属性
n = getattr(b1,‘name‘)
print(n)
func=getattr(b1,‘rent_house‘)
func()
# getattr(b1,‘aaaaa‘) # 提示报错
print(getattr(b1,‘aaaaa‘,‘不存在...‘)) # 提示‘不存在‘
# 设置某个属性
setattr(b1,‘sb‘,True) # 设置对象b1的属性‘sb‘,值为True
setattr(b1,‘show_name‘,lambda self:self.name+‘sb‘) # 设置b1属性‘show_name‘
print(b1.__dict__) # 查看对象b1的属性字典
print(b1.show_name(b1))
# 删除属性
delattr(b1,‘addr‘)
delattr(b1,‘show_name‘)
# delattr(b1,‘show_name111‘) # 不存在则报错
print(b1.__dict__)
类也是对象,同对象一样支持反射的四个方法
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 -*-
import sys
def s1():
print ‘s1‘
def s2():
print ‘s2‘
this_module = sys.modules[__name__]
hasattr(this_module, ‘s1‘)
getattr(this_module, ‘s2‘)
导入其他模块,利用反射查找该模块是否存在某个方法
模块文件:module_test.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
def test():
print(‘from the test‘)
导入module.py模块,利用反射查找该模块是否存在
#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
程序目录:
module_test.py
index.py
当前文件:
index.py
"""
import module_test as obj
#obj.test()
print(hasattr(obj,‘test‘))
getattr(obj,‘test‘)()
为什么用反射之反射的好处
好处一:实现可插拔机制
有俩程序员,一个lili,一个是egon,lili在写程序的时候需要用到egon所写的类,但是egon去跟女朋友度蜜月去了,还没有完成他写的类,lili想到了反射,使用了反射机制lili可以继续完成自己的代码,等egon度蜜月回来后再继续完成类的定义并且去实现lili想要的功能。
总之反射的好处就是,可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用,这其实是一种‘后期绑定’,什么意思?即你可以事先把主要的逻辑写好(只定义接口),然后后期再去实现接口的功能
示例1:
1:ftpclient.py文件
class FtpClient:
‘ftp客户端,但是还么有实现具体的功能‘
def __init__(self,addr):
print(‘正在连接服务器[%s]‘ %addr)
self.addr=addr
2:test.py文件
import ftpclient
f1=ftpclient.FtpClient(‘192.168.1.1‘)
if hasattr(f1,‘get‘):
func_get=getattr(f1,‘get‘)
func_get()
- print(‘处理其他的逻辑代码‘)
示例2:
class FtpCLient:
def __init__(self,host):
self.host=host
print(‘connecting...‘)
def run(self):
while True:
inp=input(‘>>: ‘).strip()
inp_l=inp.split()
if hasattr(self,inp_l[0]):
func=getattr(self,inp_l[0])
func(inp_l)
def get(self,arg):
print(‘download file‘,arg[1])
f=FtpCLient(‘192.168.1.2‘)
f.run()
好处二:动态导入模块(基于反射当前模块成员)
以上是关于18-面向对象之基础的主要内容,如果未能解决你的问题,请参考以下文章