面向对象

面向对象

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.debuglogging.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))
posted @ 2020-03-09 17:36  Hedger_Lee  阅读(110)  评论(0编辑  收藏  举报