面向对象
面向对象
1.类和对象
- 什么是类:具有相同方法和属性的一类事物
- 什么是对象、实例 : 一个拥有具体属性值和动作的具体个体
- 实例化 :从一个类 得到一个具体对象的过程
1.1类的定义
class 类名:
def __init__(self, x):
self.x = x
def func(self, name):
print(name)
1.2类的调用
# 1.创建该类的对象
obj = 类名(666)
# 2.通过对象调用方法
result = obj.方法名('alex')
print(result)
1.3新式类和经典类
-
新式类
class 类名(object): pass
- 继承object
- 支持super
- 多继承时,使用广度优先
C3
算法 - 支持
mro
方法
-
经典类
class 类名(object): pass
py2
中不继承object- 没有super语法
- 多继承时,使用深度优先算法
- 没有
mro
方法
-
注意点
py2
继承object就是新式类,不继承默认是经典类py3
都是新式类,默认继承object
1.4类的组合
- 类名也可以看做变量名,可以当作参数进行传递
1.5类的加载
- 代码从上到下执行,遇到类时,加载类中的内容,方法只是加载但不执行,类中嵌套另一个类,同样也会加载内层中的内容
1.6面向对象使用场景
- 函数(业务功能)比较多,可以使用面向对象来进行归类。
- 想要做数据封装(创建字典存储数据时,面向对象)。
2.面向对象三大特性
2.1封装
-
广义的封装:类成员的封装
- 数据的封装
- 方法的封装
-
狭义的封装:私有成员
-
__名字
-
只能在类的内部使用,既不能在类的内部调用,也不能在子类中使用
-
本质:_类名__名字
-
强制访问私有成员
class Foo: def __init__(self,name): self.__x = name obj = Foo('alex') print(obj._Foo__x)
-
-
2.2继承
- 应用场景:多个类中如果有公共的方法,可以放到基类中避免重复编写
- 相关概念
- 父类、基类、超类
- 子类、派生类
- 单继承、多继承
class Base:
def f1(self):
pass
class Foo(Base):
def f2(self):
pass
obj1 = Foo()
obj1.f2()
obj1.f1()
obj2 = Base()
obj2.f1()
- 继承中的查找顺序:所有的查找名字(调用方法和属性)都是先找自己的,自己没有找父类,如果自己和父类都有,希望自己和父类都调用,super()/指定类名直接调
- 本质:遵循广度优先算法,
mro
顺序
- 本质:遵循广度优先算法,
2.3多态
-
一个类表现出来的多种状态 --> 多个类表现出相似的状态
-
鸭子模型:对于一个函数而言,Python对于参数的类型不会限制,那么传入参数时就可以是各种类型,
在函数中如果有例如:
arg.send
方法,那么就是对于传入类型的一个限制(类型必须有send方法)。
这就是鸭子模型,类似于上述的函数我们认为只要能呱呱叫的就是鸭子(只有有send方法,就是我们要想的类型)
3.类成员
3.1类变量
class Foo:
city = '北京'
def __init__(self):
pass
def func(self):
pass
print(Foo.city)
- 调用方式
- 类名.变量名
3.2绑定方法
class Foo:
def func(self,a,b):
print(a,b)
obj = Foo()
obj.func(1,2)
-
就是普通的方法,但必须有一个self参数
-
调用方式
- 先创建对象,由对象调用:对象名.方法名()
3.3静态方法
class Foo:
@staticmethod
def f1():
print(123)
Foo.f1()
- 使用
staticmethod
装饰器,参数可传可不传 - 调用方式
- 类名.方法名()
3.4类方法
class Foo:
@classmethod
def f2(cls,a,b):
print('cls是当前类',cls)
print(a,b)
Foo.f2(1,2)
- 使用
classmethod
装饰器,至少有一个cls
参数 - 调用方式
- 类名.方法名()
3.5属性
class Foo:
@property
def func(self):
print(123)
return 666
obj = Foo()
result = obj.func
print(result)
- 使用
property
装饰器,有且仅有一个self参数 - 调用方式
- 先创建对象,由对象调用:对象名.方法名
- 注意点:方法名后面不用加括号
4.双下划线方法
- 也可以叫做 双下方法/魔术方法/内置方法
4.1__str__
- 直接打印对象时,会自动调用此方法,并将其返回值打印出来
class Foo(object):
def __str__(self):
return 'asdfasudfasdfsad'
obj = Foo()
print(obj)
4.2__new__
- 构造方法
- 类实例化时,最先调用
__new__
方法,创建一个空的对象
class Foo(object):
def __new__(cls, *args, **kwargs):
return object.__new__(cls)
obj = Foo()
4.3__init__
- 初始化方法
- 在实例化的过程中,给对象初始化值
class Foo:
def __init__(self,a1):
self.a1 = a1
obj = Foo('alex')
4.4__call__
- 源码中很容易写这个用法
- 当给对象加括号时,自动执行
__call__
中的方法
class Foo(object):
def __call__(self, *args, **kwargs):
print('执行call方法')
# obj = Foo()
# obj()
Foo()()
4.5__enter__ __exit__
- 上下文管理(使用with方法)
- 先执行
__enter__
中的内容 - 最后执行
__exit__
中的内容
- 先执行
class Foo(object):
def __enter__(self):
self.x = open('a.txt',mode='a',encoding='utf-8')
return self.x
def __exit__(self, exc_type, exc_val, exc_tb):
self.x.close()
with Foo() as ff:
ff.write('alex')
4.6__getitem__
__settitem__
__delitem__
class Foo(object):
def __setitem__(self, key, value):
pass
def __getitem__(self, item):
return item + 'uuu'
def __delitem__(self, key):
pass
obj1 = Foo()
obj1['k1'] = 123 # 内部会自动调用 __setitem__方法
val = obj1['xxx'] # 内部会自动调用 __getitem__方法
print(val)
del obj1['ttt'] # 内部会自动调用 __delitem__ 方法
4.7__add__
- 两个对象相加,自动调用
__add__
方法
class Foo(object):
def __add__(self, other):
return 123
obj1 = Foo()
obj2 = Foo()
val = obj1 + obj2
print(val)
4.8__iter__
- 将对象变成一个可迭代对象
class Foo:
def __iter__(self):
return iter([1,2,3,4])
obj = Foo()
class Foo:
def __iter__(self):
yield 1
yield 2
yield 3
obj = Foo()
4.9__dict__
- 去对象中找到所有变量并将其转换为字典
class Foo(object):
def __init__(self,name,age,email):
self.name = name
self.age = age
self.email = email
obj = Foo('alex',19,'xxxx@qq.com')
val = obj.__dict__ # 去对象中找到所有变量并将其转换为字典
print(val)
5.有关内置函数
5.1 type
-
查看类型
class Foo: pass obj = Foo() if type(obj) == Foo: print('obj是Foo类的对象')
5.2isinstance
-
判断一个实例化对象是否是某个类或者该类的基类的实例化对象
class Base(object): pass class Foo(Base): pass obj = Foo() print(isinstance(obj,Foo)) print(isinstance(obj,Base))
5.3issubclass
-
判断一个类是否是某个类的子类
class Base: pass class Base1(Base): pass class Foo(Base1): pass class Bar: pass print(issubclass(Bar,Base)) print(issubclass(Foo,Base))
5.4super
-
按照
mro
顺序或者广度优先算法顺序去执行某个方法class Base(object): # Base -> object def func(self): super().func() print('base.func') class Bar(object): def func(self): print('bar.func') class Foo(Base,Bar): # Foo -> Base -> Bar pass obj = Foo() obj.func()
6.异常处理
6.1通用版格式
try:
# 要检测的代码
except Exception as e:
pass
6.2完整版
try:
v = []
v[11111] # IndexError
except ValueError as e:
pass
except IndexError as e:
pass
except Exception as e:
print(e) # e是Exception类的对象,中有一个错误信息。
finally:
print('最后')
- finally中的语句不管有没有检测到错误,最后都会执行
6.3主动触发异常
try:
int('123')
raise Exception('阿萨大大是阿斯蒂') # 代码中主动抛出异常
except Exception as e:
print(e)
6.4自定义异常
class MyException(Exception):
def __init__(self,message):
self.message = message
try:
raise MyException('asdf')
except MyException as e:
print(e.message)
7.抽象类/接口类
- 就是给子类一个规范,让子类必须按照抽象类的规范来实现方法
class Foo:
def func(self):
raise NotImplementedError
class Son(Foo):
def func(self):
pass
s = Son()
s.func()
8.反射
- 以字符串的形式去某个对象中 操作 对象的成员
8.1getattr
getattr
(对象,"字符串") 根据字符串的形式去某个对象中 获取 对象的成员
class Foo(object):
def __init__(self,name):
self.name = name
def login(self):
pass
obj = Foo('alex')
# 获取变量
v1 = getattr(obj,'name')
# 获取方法
method_name = getattr(obj,'login')
method_name()
8.2hasattr
hasattr
(对象,'字符串') 根据字符串的形式去某个对象中判断是否有该成员。
class Foo(object):
def __init__(self,name):
self.name = name
def login(self):
pass
obj = Foo('alex')
v1 = hasattr(obj,'name')
v2 = hasattr(obj,'login')
print(v1, v2)
8.3setattr
setattr
(对象,'变量名','值') 根据字符串的形式去某个对象中设置成员。
class Foo:
pass
obj = Foo()
setattr(obj,'k1',123) # obj.k1 = 123
print(obj.k1)
8.4delattr
delattr
(对象,'变量名') 根据字符串的形式去某个对象中删除成员。
class Foo:
pass
obj = Foo()
obj.k1 = 999
delattr(obj,'k1')
print(obj.k1)
8.5反射场景
-
通过 对象 来获取 实例变量、绑定方法
-
通过 类 来获取 类变量、类方法、静态方法
-
通过 模块名 来获取 模块中的任意变量(普通变量 函数 类)
-
通过 本文件 来获取 本文件中的任意变量
getattr(sys.modules[__name__],'变量名')
8.6相关模块importlib
- 根据字符串的形式导入模块
import_module
方法获取,结合反射进行使用
import importlib
# 用字符串的形式导入模块。
redis = importlib.import_module('utils.redis')
# 用字符串的形式去对象(模块)找到他的成员。
getattr(redis,'func')()
- 使用
importlib.reload
方法再次加载模块
import importlib
import jd
importlib.reload(jd) # 再次加载jd
print(456)
9.单例模式
- 无论实例化多少次,永远用的都是第一次实例化出的对象
- 修改
__new__
中的方法即可
class Singleton(object):
instance = None
def __new__(cls, *args, **kwargs):
if not cls.instance:
cls.instance = object.__new__(cls)
return cls.instance
obj1 = Singleton()
obj2 = Singleton()
10.日志
- 使用logging模块
- 记录日志的
- 统计用的
- 用来做故障排除的
- 用来记录错误,完成代码的优化
10.1基础配置方法
-
basicConfig
-
使用方便
-
不能实现编码问题,不能同时向文件和屏幕上输出
-
logging.debug
,logging.warning
import logging
logging.basicConfig(
filename='cmdb1.log', # 日志写入的位置
format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s', # 日志写入的格式
datefmt='%Y-%m-%d %H:%M:%S %p', # 日志写入时间的格式
level=logging.ERROR # 要写入日志的等级
)
logging.error('alex')
10.2logger
对象
####创建####
# 创建一个logger对象
# 创建一个文件操作符
# 创建一个屏幕操作符
# 创建一个格式
####关联绑定####
# 给logger对象绑定 文件操作符
# 给logger对象绑定 屏幕操作符
# 给文件操作符 设定格式
# 给屏幕操作符 设定格式
####操作####
# 用logger对象来操作
import logging
logger = logging.getLogger()
fh = logging.FileHandler('log.log')
sh = logging.StreamHandler()
logger.addHandler(fh)
logger.addHandler(sh)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setFormatter(formatter)
sh.setFormatter(formatter)
logger.warning('message')
10.3日志切割
import time
import logging
from logging import handlers
# file_handler = logging.FileHandler(filename='x1.log', mode='a', encoding='utf-8',)
file_handler = handlers.TimedRotatingFileHandler(filename='x3.log', when='s', interval=5, encoding='utf-8')
logging.basicConfig(
format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S %p',
handlers=[file_handler,],
level=logging.ERROR
)
for i in range(1,100000):
time.sleep(1)
logging.error(str(i))