面向过程与面向对象(一)

一.面向过程与面向对象:

  面向过程:

 重过程:解决问题,考虑的是解决问题的流程
 解决问题的思路清晰,但拓展性不强

 

  面向对象:
 重对象:解决问题,找到解决问题的对象
 解决问题的思路可能不止一条(理解解决问题的难度增加),但拓展性强

二.名称空间:

 能产生名称空间的有:文件 | 函数 | 类
 能产生名称空间的对象有__dict__这个值,通过该这个值访问到名字与地址的对应关系

def func():
    pass

func.__dict__['index'] = 10000
print(func.__dict__)
属性:
print(func.__dict__['index']) print(func.index)
方法: func.add
= lambda n1, n2: n1 + n2 print(func.__dict__) print(func.add(10, 20))

 

三.类与对象:

类:具有相同特征与行为个体集合的抽象
 对象:有特征、行为的具体个体,就是类的具体体现

1.类拥有自己的名称空间,类的对象也拥有自己的名称空间

2.属性的访问顺序:对象优先加载自身的属性与方法,如果没有再考虑类的

 

四.对象的特有的名称空间:

class Student:
    # __init__方法会在实例化对象时被调用 , student=Student()
    # 1.会为实例化的对象形成空的名称空间
    # 2.就是一个方法,可以被传参,在 类名(实参) 这种方式下调用并传参 __init__(self, 形参)
    # 3.第一个self就是要产生的当前对象
    # 重点:在方法内部,形参拿到了实参值,利用self.属性名 = 形参 = 实参值,对对象的名称空间添加属性
    def __init__(self, name, sex):
        print('2>>>', self)
        self.name = name
        self.sex = sex


    def fn():
        print('fn run')

五.对象绑定类方法:

class A:
    def test(self):
        print(self)
        pass
a = A()
#绑定的三种方式: a.test() A.test(a) A.
__dict__['test'](a)

六.类方法的调用:

class Tool:
    # 类方法:可以被类与对象调用的方法,第一个参数一定是类
    # 类方法不建议拿对象来调用
    @classmethod
    def add(cls, n1, n2):
        print(id(cls))
        cls.test()
        return n1 + n2

    @classmethod
    def test(cls):
        pass

print(Tool.add(10, 20))
tool = Tool()
print(tool.add(100, 200))
print(id(Tool), id(tool))

# 对象调用所属类的类方法,默认第一个参数传入的是 对象.__class__ 就是所属类

七.属性与方法的总结:

class OldBoy:
    # 属于类的属性
    name = '老男孩'

    # 属于对象的属性
    def __init__(self, name):
        self.name = name

    # 属于类的方法
    # 需求:获取机构的名字
    @classmethod
    def get_class_name(cls):
        return cls.name

    # 属于对象的方法
    # 需求:获取校区的名字
    def get_school_name(self):
        return self.name

# 先创建校区
shanghai = OldBoy('上海校区')
shenzhen = OldBoy('深圳校区')

# 类方法的使用
# 建议使用类调用
print(OldBoy.get_class_name())
# 类方法拿对象调用并没有多少新增的意义,不建议拿对象调用
print(shanghai.get_class_name())
print(shenzhen.get_class_name())

# 对象方法的使用
# 类调用对象方法,必须把要操作的对象手动传入,不建议使用
print(OldBoy.get_school_name(shanghai))
print(OldBoy.get_school_name(shenzhen))
# 对象调用对象方法,默认将自身传入,建议使用
print(shanghai.get_school_name())
print(shenzhen.get_school_name())

八.封装:

      简单地说, 将方法与属性打包封在一个类中称为封装,方便之后调用操作.

九.类的隐藏:

     隐藏:对外隐藏类中一些属性与方法的实现细节
     优点:外界不能直接访问,让内部的属性与方法具有安全保障

class A:
    # __开头的属性,在外界不能通过 cord | __cord 直接访问:对外隐藏了
    __cord = '01012300'

    # __开头的方法,在外界不能通过 get_money | __get_money 直接访问:对外隐藏了
    @classmethod
    def __get_money(cls):
        print('输入密码,取出100w零花钱')

    # 内部还是可以直接访问__开头的属性与方法
    @classmethod
    def test(cls, flag):
        print('test方法被外界调用')
        # 在调用test与访问具体数据与功能间添加安全处理的操作
        if flag == '自家人':
            print(cls.__cord)
            cls.__get_money()

  隐藏原理: 把用__开头的名字更名为 _类名__变量名

# print(A.__dict__)
print(A._A__cord)
A._A__get_money()

十.对象的隐藏(利用接口调用):

class AAA:
    def __init__(self, money):
        self.__money = money

    # 取值
    @property  # 在外界可以 对象.money 进行取值
    def money(self):
        # print('走方法拿到的money')
        return self.__money

    # 赋值
    @money.setter  # 在外界可以 对象.money = 新值 进行赋值
    def money(self, money):
        self.__money = money

    # 删除
    @money.deleter
    def money(self):
        # print('逗你玩')
        del self.__money

    def get_money(self, flag):
        if flag == '自家人':
            return self.__money
        return 0

    def set_money(self, money):
        self.__money += money

 

print(a.money)
a.money = 999999
print(a.money)

del a.money
print(a.money)

 

十一.组合:  自定义类的对象作为另外一个类的属性

  

class Teacher:
    def __init__(self, name, age):
        self.name = name
        self.age = age


t1 = Teacher("Owen", 17)
print(type(t1.name), type(t1.age))


class Student:
    # 学生可以有 老师 属性
    def __init__(self, name, age, teacher):
        self.name = name
        self.age = age
        # 自定义类的对象作为类的属性:组合
        self.teacher = teacher
# 创建一个学生
stu = Student('Bob', 18, t1)
print(stu.__dict__)

# 学生的老师年龄和姓名
print(stu.name)
print(stu.teacher)
print(stu.teacher.name)
print(stu.teacher.age)

十二.继承

    1.继承语法:

继承的语法:
# class 类名(父类名): pass

class A:
    pass

print(A.__bases__)  # object 
没有定义的类都是继承object

print(Leader.__bases__)  # Student
定义了父类就继承父类

   2.父类隐藏后的继承:

class Sup:
    __num = 10

    def __init__(self, name):
        self.__name = name

    @property
    def name(self):
        print(self)            # <__main__.Sub object at 0x02BA8490>
print(self.__dic__) # 名称空间的key是'_Sup_name'
return self.__name @classmethod def __c_fn(cls): print(cls, 'c fn') def __o_fn(self): print(self.name, 'o fn') class Sub(Sup): def test(self): print(self.__dict__) # {'_Sup__name': 'sssssssss'} print(self._Sup__name) pass sub = Sub('sssssssss') print(sub.name) sub.test()
sub._Sup__c_fn()

  3.方法的重写(完全不用父类的):

 有继承关系下的属性查找顺序:
 1.优先找自身,自身没有找父类
 2.父类没有找父类的父类
 3.一直找到最顶级的父类,如果还没有报错

# 两个名词:
先写子类,抽离 出父类
先写父类,派生 出子类
class Sup:
    num = 10

    def test(self):
        print('test sup')

class Sub(Sup):
    num = 100

    # 先写好父类的方法,由于父类方法的功能不满足子类需求,
    # 子类可以重写父类方法:方法名与父类相同,自定义方法的实现体
    def test(self):
        print('test sub')

print(Sub.num)
Sub().test()

  4.方法的重用(部分仍用父类的):

class Sup:
    def test(self):
        print('>>>sup', self)
        print('test sup')


class Sub(Sup):
    pass
    # 重用:还需要父类方法的功能,在父类方法功能基础上再添加新功能
    # 突破点:在子类中去调用父类的方法,还有保证调用者是子类(子类的对象)
    def test(self):
        # Sup().test()

        # python2中写法
        # super(Sub, self).test()
        # python3中简化写法
        super().test()

        print('>>>sub', self)
        print('test sub')


Sub().test()

 5.__init__结合super()使用:

# 人类:只需要初始化 - name
# 老师: 要初始化 - name salary
# 学生: 要初始化 - name grade
class Sup:
    def test(self):
        print(self)

    def __init__(self, name):
        self.name = name

class Sub(Sup):
    # 有继承关系下,只要名字相同,即使产生不同,还是属于同一个方法
    def test(self, num):
        super().test()
        print(num)

    # 默认父级的__init__可以被继承过来,
    # 但是会出现子类对象的属性比父类多

    def __init__(self, name, salary):
        super().__init__(name)  # 父级有的共性功能通过super()交给父级做
        self.salary = salary  # 子类特有的自己来完成

# Sub().test(10)
# Sub().test()  # 使用还是使用自身带参的,不能使用父级不带参的
# (本质名字相同就是一个,优先查找自己的)

     6.多继承:

# 简单的多继承
'''
# 属性的查找顺序:优先找自己的,如果没有,按照继承先后查找父级
class A:
    name = 'A'
    num = 10

class B:
    name = 'B'
    count = 100

# 子类可以继承所有父类的所有可继承属性
class C(A, B):  # 自己 => A => B
    # name = 'C'
    pass

print(C.num)
print(C.count)
print(C.name)
# 打印属性查找的顺序
print(C.mro())
'''

# 复杂的多继承
'''
class A:
    name = "A"
class B(A):
    name = "B"
class C:
    name = "C"
class D(C):
    name = "D"
class E(B, D):
    name = "E"
print(E.mro())
'''

# 经典类:python2中才有,没有继承任何类的类
# 新式类:python2中直接或间接继承object的类,python中所定义的所有类


class G: name = "G"
class C(G): pass
class B(C): pass
class E(G): pass
class D(E): name = "D"
class F(G): pass
class A(B, D, F): pass
print(A.mro())

    7.菱形继承:

 经典类:python2中才有,没有继承任何类的类 - 深度优先 新式类:python2中直接或间接继承object的类,python中所定义的所有类 - 广度优先

 深度优先,在查找第一个分支是就将菱形的头查找了 广度优先,菱形的头在所有分支查找接收后再被查找

 通过 类.mro() 查看继承顺序图

 

十三.接口思想:

# 接口类:用来定义功能的类,为继承它的子类提供功能的,
# 该类的功能方法一般不需要有实现体,实现体有继承它的子类自己去实现
class PetInterface:
    def close_master(self): pass

class WatchInterface:
    def watch_door(self): pass

class Dog(PetInterface, WatchInterface):
    def jiao(self): pass

    def chi(self): pass

    def pao(self): pass

    # 一定要重写接口的方法

十四.抽象类:

# 抽象父类:拥有抽象方法(子类共有的方法,但是父类不能有具体的实现体)的父类
#       抽象方法:方法名是具体的,但是实现体是抽象的(在子类中重写来具象化)

# python中借助abc来实现抽象父类
import abc  # abstract base class
class Quan(metaclass=abc.ABCMeta):
    def __init__(self, name):
        self.name = name
    def run(self):
        print(self.name + 'running')

    # 抽象父类中的抽象方法,在继承它的子类中必须有自己的实现体
    #       -- 抽象父类中的抽象方法实现体就没有意义,实现与不实现都是pass填充
    @abc.abstractmethod
    def chi(self):
        # print(self.name + '肉')
        pass
    @abc.abstractmethod
    def jiao(self):
        # print('汪汪汪')
        pass

    @classmethod
    @abc.abstractmethod
    def fn(cls): pass

class Dog(Quan):
    @classmethod
    def fn(cls): pass

    def kanmen(self):
        print(self.name + '看门')
    def chi(self):
        super().chi()
        print(self.name + '狗粮')
    def jiao(self):
        print('汪汪汪')

class Wolf(Quan):
    @classmethod
    def fn(cls): pass

    def bulie(self):
        print(self.name + '捕猎')
    def chi(self):
        print(self.name + '')
    def jiao(self):
        print('嗷嗷嗷')

dog = Dog('来福')
wolf = Wolf('常委')

dog.jiao()
# wolf.jiao()
# dog.run()
# wolf.run()

十五.多态:

# 多态:对象的多种状态 - 父类对象的多种(子类对象)状态

import abc
class People(metaclass=abc.ABCMeta):
    def __init__(self, name):
        self.name = name

    @abc.abstractmethod
    def speak(self): pass

class Chinese(People):
    def speak(self):
        print('说中国话')

class England(People):
    def speak(self):
        print('说英国话')


if __name__ == '__main__':
    # 多态的体现:功能或是需求,需要父类的对象,可以传入父类对象或任意子类对象均可以
    #       注:一般都是规定需要父类对象,传入子类对象
    def ask_someone(obj):
        print('让%s上台演讲' % obj.name)  # 父类提供,自己直接继承
        obj.speak()  # 父类提供,只不过子类重写了

    ch = Chinese('王大锤')
    en = England('Tom')

    ask_someone(ch)
    ask_someone(en)

十六.鸭子类型

import abc
class People(metaclass=abc.ABCMeta):
    def __init__(self, name):
        self.name = name

    @abc.abstractmethod
    def speak(self): pass

class Chinese(People):
    def speak(self):
        print('说中国话')

class England(People):
    def speak(self):
        print('说英国话')

# 鸭子类型:
# 1.规定有什么属性及什么方法的类的类型叫鸭子类型
# 2.能提供出规定的属性与方法的对象就是鸭子
class Test:
    def __init__(self, name):
        self.name = name
    def speak(self):
        print('说鸟语')

if __name__ == '__main__':
    def ask_someone(obj):
        print('让%s上台演讲' % obj.name)
        obj.speak()

    test = Test('鸭子')
    ask_someone(test)

十七.格式化与析构方法

class A:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    # 格式化方法:在外界打印该类对象是被调用
    # 格式化外界直接打印该类对象的字符串表示结果
    def __str__(self):
        # return 'abc'
        # return super().__str__()
        return '<name:%s | age:%s>' % (self.name, self.age)

    # 析构方法:在对象被消耗的那一刹那被调用,在被消耗前可以做一些事情
    def __del__(self):
        # del会在self代表的对象被消耗的时候被调用
        # 我们可以在析构函数中释放该对象持有的其他资源,
        # 或者将一些持有资源持久化(保存到文件或数据库中)
        del self.name  # 也可以将name存起来

十八.反射:通过字符串与类及类的对象的属性(方法)建立关联

class A:
    num = 10
print(hasattr( A ,'num'))           #判断类中是否有num属性      True
print(getattr(A,'num','default'))   #获取类中num的属性值,没有则拿默认值   10
delattr(A,'num')                    #删除类中num属性
setattr(A,'tag',10)                 #在类中设置一个tag属性


class B:
    def __init__(self,name):
        self.name=name
b = B('BOb')
print(hasattr( b ,'name'))         #判断对象中是否有name属性      True
print(getattr(b,'name','default')) #获取对象中name的属性值,没有则拿默认值   10
delattr(b,'name')                  #删除对象中name属性
setattr(b,'tag',10)                #在对象中设置一个tag属性
print(b.tag)



class C:
    def fn(self):
        print('fn')
    @classmethod
    def func(cls):
        print('func')

#类调对象方法,需要传入对象当做参数
fn=getattr(C,'fn')
c = C()
fn(c)
#对象调对象方法
c = C()
fn=getattr(c,'fn')
fn()
#类调类方法
func = getattr(C,'func')
func()

十九.异常处理:

# 程序运行时的错误
# 程序中的异常处理机制:
# 1.程序中的所有异常都会被处理
# 2.程序中的所有异常都需要手动处理
# 3.如果没有手动处理异常,异常会交给Python解释器处理
#       -- 处理的方式就是打印异常信息,并停止接收器

# 异常信息的三部分:
# 1.异常的追踪信息:提示错误位置
# 2.异常的类型:告知处理异常应该捕获什么类型
# 3.异常的内容:告知错误信息

# 处理异常的语法:
'''
try:
    # 会出现异常的代码块
except  异常类型 as 异常别名:
    # 异常处理逻辑
else:
    # 没有出现异常会执行该分支
finally:
    # 无论是否出现异常都会执行该分支
'''

try:
    print(adsdasadsdasadsdas)
except NameError as e:
    print('异常信息:', e)
else:
    print('被检测的代码块正常')
finally:
    print('异常是否出现都会执行该分支')

print('end')

 

posted @ 2019-06-18 12:18  纵横捭阖行  阅读(403)  评论(0编辑  收藏  举报