面向对象

编程范式
面向过程编程:
优点:复杂的问题流程化,进而简单化
缺点:可扩展性差
面向对象编程:
优点:扩展性好
缺点:编程复杂度高

如何编写面向对象的程序
1、将函数归类+提取公共值(反推)
2、在指定类中编写和当前类相关的所有代码+提取公共值

面向对象的三大特性:封装/继承/多肽

封装
1、将相关功能封装到一个类中,封装方法:目的是隔离复杂度
2、将数据封装到一个对象中,封装数据,对外提供操作该数据的接口,然后我们可以在接口附加上对该数据操作的限制,以此完成对数据属性操作的严格控制。

继承
为何要有继承========为了提高代码的重用性
父类(基类)
子类(派生类)
原则:先在自己类中找,没有就去父类找
支持多继承,先左后右
python支持多继承,Java、Php等都不支持

多态
多种形态或多种状态
鸭子模型:只要可以嘎嘎叫就是鸭子
意义:由于python自带原生就是多肽,所以没有特殊性
在Java中,参数是需要定义数据类型的,这样在传参的时候,就必须是规定数据类型的对象或者是规定数据类型派生类的对象,这就是参数的多种形态,简称多肽。而python,不需要规定参数的数据类型,只要他能执行就可以。

python原生支持多肽,崇尚鸭子模型。由于python函数传参时,无需指定类型:

def func(arg):   # arg可以是多种类型,只要其中有send方法即可。
	arg.send()

重点
1、编写方式和执行流程
2、如何归类?反向:归类+提取公共值。正向:类相关的功能+提取公共值
3、三大特性

面向对象能帮你解决什么问题
1、归类,将相关函数封装到一个类中
2、将数据打包封装到一个对象中

self到底是谁
self参数是python帮助我们自动传递。
如果执行面向对象中的方法时,前面必须有一个对象,self就是这个对象。

构造方法
创建对象时自动执行
实例变量/字段

类的成员分三类

1、变量(字段)
——实例变量(字段)
————公有的实例变量(字段)
————私有的实例变量(字段)====找一个内部人func,让func帮你执行内部私有__name
——类变量(静态字段)
————公有的类变量(字段)
————公有的类变量(字段)
准则:实例变量(字段)访问时,使用对象访问。即obj1.name
类变量(静态字段)访问时,使用类方法。即Foo.country (实在不方便,才使用对象)
什么时候用类变量:当所有对象中有共同的字段,且要改都改,要删都删时,可以将实例变量提取到类变量。

2、方法
实例方法====方法中会调用构造函数的变量才有必要写
静态方法(@staticmethod)====如果方法中无需使用对象中封装的值,那么就可以使用静态方法
——方法上方写@staticmethod
——方法参数可有可无
——调用可以类调用,也可以对象调用
类方法(@classmethod)====想用当前类,才写类方法,自动传递当前类为第一个参数
——方法上方写@classmethod
——调用可以类调用,默认会将当前类传递到参数中
——如果在方法中会使用到当前类,那么就可以使用类方法

class Foo:
    @classmethod
    def func1(cls):
        print(cls)

    @staticmethod
    def func2(a):
        print(a)

方法同样也有私有方法,类似于变量。

3、属性(通过方法改造出来的)
编写:在方法上方加 @property,
调用:在调用时就不用加括号
应用场景:对于简单的方法,无需传参,且有返回值时,就可以使用@property

面试题:静态方法和实例方法的区别?
定义:类方法和静态方法要加自己的装饰器,而实例方法不用
调用:类方法和静态方法通过类.调用,实例方法先实例化,再调用
应用场景:如果在方法内部不会用到对象相关数据时,用静态方法或者类方法,否则用实例方法。如果方法内部要使用当前类,则使用类方法会自动传入当前类,更方便。

嵌套
一个对象里嵌套另一个对象
类或对象能否做字典的key====可以

总结:
1、对象中封装了什么?
2、self到底是谁?

主动调用其他类的成员(在子类派生出的新的方法中重用父类的方法)
方式一:
指名道姓的调用,不依赖继承

class Foo1:
    def f1(self):
        print('五个功能')
        
class Foo2:
    def f2(self):
        print('三个功能')
        Foo1.f1(self)      # 主动调用其他类的方法,与继承无关

方式二:
super().f1() # 按照当前类的继承顺序,找下一个f1,不是简单的找父类

class Foo:
    def f1(self):    # self是Info的对象
        super().f1()   # 按照类的继承顺序,找下一个,self是Info的对象,找到Bar中的f1执行
        print('三个功能')

class Bar:
    def f1(self):
        print('六个功能')

class Info(Foo,Bar):
    pass
obj = Info()
obj.f1()

这两种方式的区别是:方式一是跟继承没有关系的,而方式二的super()是依赖于继承的,并且即使没有直接继承关系,super仍然会按照mro继续往后查找

类中的内置方法

1、__init__=======类名()====自动执行 __init__ (构造方法)   # 为对象赋值,做初始化
2、__call__=======对象()====自动执行 __call__
3、__getitem__======对象【】====自动执行 __getitem__
4、__setitem__=========对象【】=val ==== 自动执行 __setitem__  (无返回值)
5、__delitem__========del  对象【】 ==== 自动执行 __delitem__  (无返回值)
6、__add__===========对象+对象 ==== 自动执行 __add__
7、__enter__======__exit__====with  对象 as f ==== 自动执行 __enter__   和 __exit__  ,一个开始,一个结束,f是enter的返回值
8、__new__========真正的构造方法 ==== __new__   # 真正的创建一个空对象
9、__str__  ==== 返回值必须是一个字符串,在终端打印对象时,打印这个返回值
10、__doc__ ==== 获取这个对象所在类的注释
11、__dict__  ====  将对象中封装的值以字典的形式打印出来
12、__iter__  ==== 返回一个迭代器或生成器,有这个方法的类,对象才能被迭代。
									如果想要把不可迭代的对象转变为可迭代的对象
									1、在类中定义__iter__方法
									2iter内部返回一个迭代器(生成器也是一种特殊的迭代器)
# 8、真正的构造方法 ==== __new__   # 真正的创建一个空对象
class Foo(object):
    def __init__(self, a):   # 往对象里面放东西
        self.a = a

    def __new__(cls, *args, **kwargs):    # 这个方法实际上是创建一个空对象
        return object.__new__(cls)     # python内部创建一个当前类的对象(初创对象时空的)

面向对象相关

1、isinstance/issubclass/type
isinstance() 第一个参数是对象,第二个参数是类 检查第一个参数是否是第二个参数(及父类)的对象
issubclass(a,b) 两个参数都是类 检查第一个参数是否是第二个参数的派生类
type() 获取当前对象是有哪个类创建的

2、方法和函数
print(函数名)
print(obj.xxx)

from types import MethodType, FunctionType
def check(arg):
    if isinstance(arg, MethodType):
        print(arg,'是一个方法')
    elif isinstance(arg, FunctionType):
        print(arg,'是一个函数')
    else:
        print('不知道是什么')

总结:有对象调用时方法,无对象调用时函数。

3、反射
基础部分的重点:迭代器,生成器,装饰器,列表推导式,面向对象,反射
v=getattr(obj,“func”) # 根据字符串(第二个参数),去对象中寻找与之同名的成员
hasattr # 根据字符串(第二个参数),判断对象中是否有成员
setattr # 根据字符串(第二个参数),第三个参数为设置的变量或函数,动态设置一个成员 (内存)
delattr # 根据字符串(第二个参数),动态删除一个成员(内存)
以上所有第一个参数可以是模块,类或者对象。

from types import FunctionType
import demo01
val = input('请输入要执行的函数')
if hasattr(demo01,val):
    func_or_val = getattr(demo01,val)    # 根据字符串为参数,去对象中寻找与之同名的成员
    if isinstance(func_or_val, FunctionType):
        func_or_val()
    else:
        print(func_or_val)
else:
    print('不存在的属性名')

模块也可以反射:

import sys


def s1():
    print 's1'


def s2():
    print 's2'


this_module = sys.modules[__name__]

hasattr(this_module, 's1')
getattr(this_module, 's2')

问题:你见过的什么后面可以加括号?
类()
对象()==== 对象要有__call__方法
函数()
obj.方法()
以上的所有都可以被调用。可以通过callable()判断。
判断对象是否可以被调用

问题:匿名函数是否可以放在类中?
匿名函数在类中的写法

约束
Base类用于约束,约束其派生类必须编写一个方法,不然执行可能就会报错

class BaseMessage(object):
    def send(self):
        """
        必须继承BaseMessage,然后其中必须编写send方法,用于完成具体的业务逻辑
        :return:
        """
        raise NotImplementedError('.send()必须被重写')
        # raise Exception('.send()必须被重写')      这样写是不专业的
import abc

class Base(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def save_db(self):
        pass

python:类
Java、c#:接口,类
接口中不允许在方法内部写代码,只能约束继承他的类必须实现接口中定义的是有方法。
类又分为类和抽象类,抽象类中有抽象方法。
抽象类,用于约束,约束继承他的派生类必须实现他其中的抽象方法。

总结:
1、什么事接口以及作用?
接口是一种数据类型,主要用于约束派生类中必须实现指定的方法。
python中不存在,Java和c#中是存在的。
2、python中使用什么来约束呢?
(1)抽象类+抽象方法 ——编写上麻烦
(2)认为主动抛出异常——简洁
3、约束是抛出的异常是否可以用其他的呢?
专业的写法:raise NotImplementedError(’.send()必须被重写’)
不专业的写法:raise Exception(’.send()必须被重写’)
4、以后看代码,揣摩写代码人的心思
5、写代码:raise NotImplementedError(’.send()必须被重写’)
6、应用场景:多个类内部都必须有某些方法时,需要使用基类+异常进行约束

一切皆对象
1.都可以被引用
2.都可以当作函数的参数传入
3.都可以当作函数的返回值
4.都可以当作容器类的元素

元类
产生类的类称之为元类。
定义类的两种方式:
方式一:class
方式二:type
类的三要素:1.类名。2.类的基类们。 3.类的名称空间

class_name = 'Chinese'
class_bases = (object,)
class_body = """
country = 'china'
def __init__(self,name,age):
	self.name = name
	self.age = age
def talk(self):
	print('%s is talking' %self.name)
"""
class_dic = {}
exec(class_body,globals(),class_dic)
Chinese = type(class_name,class_bases,class_dic)

自定义异常业务逻辑复杂的情况下使用
1、如何自定义异常类?
2、如何主动抛出异常?
3、如何捕获异常?

class MyException(Exception):
    def __init__(self, code, msg):
        self.code = code
        self.msg = msg

try:
    raise MyException(1000,'操作异常')
except KeyError as obj:
    print(obj)
except MyException as obj:
    print(obj)
except Exception as obj:
    print(obj)

加密(hashlib模块)

import hashlib

def md5(pwd):
    obj = hashlib.md5(b'shiqian')    # 实例化对象    加盐
    obj.update('admin'.encode('utf-8'))   # 加密的必须是字节
    v = obj.hexdigest()   # 获取密文
    return v

# e5b1948d78e22233663b5ca9df7a3da6
username = input('请输入用户名:')
pwd = input('请输入密码:')
if username == 'shiqian' and md5(pwd) == 'e5b1948d78e22233663b5ca9df7a3da6':
    print('登录成功')

关键词:撞库,加盐

面向对象多继承
python2
经典类:
新式类:如果自己或自己的前辈,只要有人继承object,那么此类就是新式类
python3
新式类:python3全部都是新式类,类似于全部继承object

经典类和新式类查找成员的顺序不一样
经典类:一条道走到黑。(深度优先)
新式类:通过c3的算法实现。 print(Foo.mro) 通过这个方法查找继承的顺序。super是遵循.__mro__执行顺序。
c3算法:获取第一个表头和其他表尾进行比较,不存在则拿走,如果存在,则放弃,然后获取第二个表的表头和其他表尾进行比较。(简单的就留个根,根最后找。)

为何还是不会写面向对象的程序
领域建模:找名词,加属性,连关系

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值