文章目录
- 一、多态
- 1、什么是多态
- 2、多态小实验
- 二、封装
- 1、什么是封装
- 2、内部属性的约定
- 三、反射
- 1、什么是反射
- 2、四个实现自省的函数
- (1)hasattr(object,name)
- (2)getattr(object,name,default=None)
- (3)setattr(object,name,value)
- (4)delattr(object,name)
- 3、反射的用途
- 4、动态导入模块
- 四、attr内置方法
- 1、__getattr__()
- 2、__delattr__()
- 3、__setattr__()
- 五、小实验1:包装标准类型
- 六、小实验2:组合方式完成授权,改写文件处理函数
一、多态
1、什么是多态
多态是指对象通过他们共同的属性和方法来操作及访问,而不需要考虑他们具体的类。
s = "abc"
print(s.__len__()) # 3,等同len(s)l = [1, 3]
print(l.__len__()) # 2,等同len(l)
多态体现在由同一个类实例化出多个对象,这些对象执行相同的方法时,执行的过程和结果是不一样的。
class H2O:def __init__(self, name, tem):self.name = nameself.tem = temdef turn(self):if self.tem > 100:print("%s 变成了水蒸气" % self.name)elif self.tem < 0:print("%s 变成了冰" % self.name)else:print("%s 变成了水" % self.name)class Steam(H2O):pass
class Water(H2O):pass
class Ice(H2O):passs = Steam("s", 1000)
w = Water("w", 50)
i = Ice("i", -10)s.turn() # s 变成了水蒸气
w.turn() # w 变成了水
i.turn() # i 变成了冰
2、多态小实验
模拟 len() 函数,对上述turn方法,做成函数形式。
# 接上述实例化代码后,补充如下代码
def turn(obj):obj.turn()turn(s) # s 变成了水蒸气
turn(w) # w 变成了水
turn(i) # i 变成了冰
二、封装
1、什么是封装
(1)装,即把一些属性装到一个容器中。封,即为隐藏。
(2)类就是一种容器,这本身就是一种封装。
(3)类中定义私有的属性,只有类的内部可以使用,外部无法访问。
(4)封装明确区分内外,内部的实现逻辑,外部无法知晓,并且为封装到内部的逻辑提供一个访问接口给外部使用。
2、内部属性的约定
python并没有严格限制外部访问内部属性,但把单下划线和双下划线开头的属性约定为内部属性。
class People:_age = 18__sex = "f"def __init__(self):passdef info(self):print("age %s,sex %s" %(self._age, self.__sex))
p1 = People()
print(People._age) # 18 但下划线开头属性,外部可以直接访问
print(People._People__sex) # f 双下划线开头属性,会在属性字典中重命名为_类__属性
p1.info() # age 18,sex f 内部可以调用它们
三、反射
1、什么是反射
反射主要是指程序可以访问、检测、和修改它本身状态或行为的一种能力(自省)。
2、四个实现自省的函数
以下四个函数适用于类和对象。
(1)hasattr(object,name)
判断name是否在object中。
(2)getattr(object,name,default=None)
相当于执行object.name
(3)setattr(object,name,value)
设置object的属性
(4)delattr(object,name)
删除object中的name属性
class People:age = 18sex = "f"def __init__(self):self.age = self.agedef info(self):print("age %s,sex %s" % (self.age, self.sex))p1 = People()print(hasattr(p1, "age")) # True 相当于判断p1.age是否可以被调用
getattr(p1, "info")() # age 18,sex f 相当于调用p1.info
# getattr(p1, "info1")() # 没有info1,则报错
print(getattr(p1, "info1", 10)) # 10 没有不报错,返回默认值setattr(p1,"func",lambda x:x*2)
print(p1.func(3)) # 6
print(p1.__dict__) # {'age': 18, 'func': <function <lambda> at 0x000001623A680160>}
delattr(p1,"age") # 删除age属性
print(p1.__dict__) # {'func': <function <lambda> at 0x000001623A680160>}
3、反射的用途
可以事先定义接口,接口只有在被完成后才会真正执行,这实现了即插即用。
prog1代码:
class Ftp:def __init__(self):passdef put(self):print("执行put方法")
调用程序代码:
from prog1 import Ftp
f1 = Ftp()if hasattr(f1,"put"):func_get = getattr(f1,"put")func_get()
else:print("执行其他逻辑")
4、动态导入模块
动态导入模块就是基于反射实现的。
t.py代码:
def test1():print("I am test1")def _test2():print("I am test2")
执行模块代码:
module_t = __import__("d1.t") # d1与执行模块在同级目录,t为d1的子文件
print(module_t) # <module 'd1' (namespace)>
module_t.t.test1() # I am test1
from d1.t import *
_test2() #报错
from d1.t import test1,_test2
_test2() #不报错
from d1 import t
t._test2() # 不报错
import importlib
m = importlib.import_module("d1.t")
m._test2() # 不报错
四、attr内置方法
在不自定义这些内置方法时,程序会执行其自身的对应方法。
1、getattr()
在属性不存在时,会自动触发自定义的__getattr__()。属性存在时,不执行它,而是执行其自身的方法。
class Foo:def __init__(self,y):self.y = ydef __getattr__(self, item):print("执行我")f1 = Foo(10)
print(f1.y) # 10
print(getattr(f1,"y")) # 10
f1.aa # 执行我
2、delattr()
执行 del 对象.属性 时,会触发 __delattr__()
class Foo:x = 1def __init__(self,y):self.y = ydef __delattr__(self, item):print("执行我")self.__dict__.pop(item)f1 = Foo(10)
print(f1.__dict__) # {'y': 10}
del f1.y # 执行我
print(f1.__dict__) # {}
3、setattr()
在执行对象.属性=value时,触发 __setattr__()
class Foo:x = 1def __init__(self,y):passdef __setattr__(self, key, value):print("执行我")self.__dict__[key] = valuef1 = Foo(10)
print(f1.__dict__) # {}
f1.y = 11 # 执行我
print(f1.__dict__) # {'y': 11}
五、小实验1:包装标准类型
重写列表类型:只能向列表中添加字符串元素;删除元素后,要返回该元素值。
class List(list):def append(self, obj):if type(obj) is str:super().append(obj)else:print("必须是字符串")l = List("ab")
print(l) # ['a', 'b']
l.append(1) # 必须是字符串
print(l) # ['a', 'b']
l.append("c")
print(l) # ['a', 'b', 'c']
六、小实验2:组合方式完成授权,改写文件处理函数
授权是包装的一个特性。包装一个类型通常是对已存在的类型的一些定制,这种做法可以新建,修改或删除原有产品的功能,其他的则保持原样。授权的过程是所有更新的功能都是由新类的某部分来处理,但已存在的功能就授权给对象为默认属性。
实验内容:写入文件内容加时间。其他文件处理函数的功能不变。
import time
class FileHandle:def __init__(self,filename,mode="r",encoding="utf-8"):self.f = open(filename,mode,encoding=encoding)def write(self,content):t = time.strftime("%F %X")self.f.write("%s %s" %(t,content))def __getattr__(self, item):return getattr(self.f,item)f1 = FileHandle("a.txt","w+")
f1.write("内存空间不足!\n")
f1.write("磁盘空间不足!")
f1.seek(0)
print(f1.read())
f1.close()'''a.txt内容
2024-02-22 15:57:05 内存空间不足!
2024-02-22 15:57:05 磁盘空间不足!
'''