面向对象大总结

面向对象和面向过程

面向过程的编程思想

​ 面向过程的核心就是过程二字,过程值得就是解决问题的步骤,即先干什么,再干什么,后干什么;基于该思想的编写程序就好比在设计一条流水线,是一种机械式的思维方式。
​ 优点是复杂的问题流程化,进而简单化,缺点是程序的可扩展性较差

面向对象的编程思想

​ 面向对象的核心就是对象二字,对象是特征与技能的结合体,基于该思想编写的程序就好比在创建一个世界,世界是有一个个对象组成的,在上帝的眼里任何存在的事物都是对象,任何不存在的事物也都可以造出来,是一种上帝式的思维方式
​ 优点是程序的可扩展性较强,缺点是编程的复杂度要高于面向过程

类:

​ 对象是特征与技能的结合体,而类就是一系列对象相同的特征与技能的结合体,在这里需要强调的两点就是:对象是具体存在的事物,而类则是一个抽象的概念;站在不同的角度总结出来的类和对象可以是不同的。

在现实的世界中,先有一个个具体存在的对象,然后随着人类文明的发展才总结出来的概念;但是在程序中,一定是先定义类,在后面调用类来产生对象。

# 先定义类
class Student:
    # 相同的特征
	schoolname = 'XX school'
    # 相同的技能
	def choose_course(self):
        print('正在选课中····')  

类体中最常见的就是变量与函数的定义,但其实类体中是可以存在任意python代码的
类体代码会在类定义阶段立即执行,会产生一个类名称空间,用来将类体代码执行过程中产生的名字都丢进去,可以通过 __ dict __查看方式如下

查看类的名称空间:
print(Student.__dict__) 
查看类的属性:
print(Student.schoolname)   相当于→print(Student.__dict__['schoolname'])
可以对类的属性进行修改,增加,删除等操作:
Student.school='YY school'   相当于→S tudent.__dict__['school']='YY school'
Student.country='China'   相当于→ Student.__dict__['country']='China'
del Student.country   相当于→ del Student.__dict__['country']

小结:

  1. 类的本质就是一个名称空间,或者说是一个用来存放变量与函数的容器。
  2. 类的一个用途就是当作名称空间从其内部取出名字来使用。
  3. 类的第二个用途就是通过调用类产生对象。

对象

调用类的过程称之为类的实例化,调用类的返回值称之为类的一个对象/实例。

调用类发生了什么:
1.先产生一个空对象,然后返回
2.触发类中的函数 __ init __ 的执行,将对象连同调用类括号nei’zhi’d

class Student:
    #相同的特征
    school = 'xx学校'
    def __init__(obj, name, age, sex):
        obj.name = name
        obj.age = age
        obj.sex = sex
    #相同的技能
    def choose_course(self):
        print('choosing course')
stu1 = Student('peter',20,'male')    相当于→__init__(stu1,'李铁蛋',18,'male')
print(stu1.__dict__)
'''
输出:{'name': 'peter', 'age': 20, 'sex': 'male'}
'''

总结 __ init __ 的功能: 是在实例化时就为对象初始自己独有的特征
注意:不能有返回值

对象的属性查找顺序:先从对象自己的名称空间找,没有则去所属的类中找。

类中定义的变量是所有对象共享的,对象可以来用,类也可以来使用,大家都指向同一个内存地址,类变量值一旦改变所有对象都跟着变

类中定义的函数是类的函数属性,类可以用,类来调用就是一个普通的函数,但其实类中定义的函数是给对象用的,而且是绑定给对象用的。
类的函数: 该传几个参数就传几个。
绑定方法,指向类的函数: 特殊之处是绑定给谁就应该由谁来调用,谁来调用就会将谁当做第一个参数自动传入

面向对象的三大特性:封装、继承、多态

继承

继承是一种新建类的方式,新建的类称之为子类或派生类,被继承的类称之为父类、基类或超类

Python 中继承的特点:

  1. 子类可以遗传或重用父类的属性
  2. Python中一个子类可以同时继承多个父类
  3. 在继承背景下说,python中的类可以分为形式类和 经典类

继承的语法:

class People:
    school = 'xx学校'

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

class Student(People):
    def choose_course(self):
        print('%s choosing course' % self.name)

class Teacher(People):
    def score(self,stu,num):
        stu.score=num
     
tea1=Teacher('peter',20,'male')
print(tea1.__dict__)
print(tea1.school)
'''
输出:
{'name': 'peter', 'age': 20, 'sex': 'male'}
xx学校
'''

在单继承背景下属性的查找优先级:对象->对象的类->父类->父类…

在多继承背景下属性的查找优先级:
如果一个子类继承多个分支(多个分支没有共同继承一个非object的类),此时属性的查找优先级是:对象->对象的类->按照从左往右的顺序一个分支一个分支的找下去

菱形继承问题:
新式类 : 广度优先查找,从左往右一个分支一个分支的查找,在最后一个分支才去查找顶级类
经典类 : 深度优先查找,从左往右一个分支一个分支的查找,在第一个分支就查找顶级类

# 第四层:
class G(object):
    # x = 'G'
    pass

# 第三层
class E(G):
    # x = 'E'
    pass
class F(G):
    # x = 'F'
    pass

# 第二层
class B(E):
    # x = 'B'
    pass
class C(F):
    # x = 'C'
    pass
class D(G):
    # x = 'D'
    pass

# 第一层
class A(B, C, D):
    # x = 'A'
    pass

obj=A()
# obj.x=111
print(obj.x)
新式类(广度优先): obj->A->B->E->C-F->D->G->object
经典类(深度优先): obj->A->B->E->G->C-F->D

在子类派生出的新方法中重用父类功能的方式一:
指名道姓地引用某一个类中的函数
总结:

  1. 与继承无关
  2. 访问是类的函数,没有自动传值的效果
class People:
    school = 'xx学校'

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

class Student(People):
    def __init__(self, name, age, sex, score=0):
        People.__init__(self,name,age,sex)
        self.score = score

在子类派生出的新方法中重用父类功能的方式二:super()必须在类中用
在python2中:super(自己的类名,自己的对象)
在python3中:super()
调用该函数会得到一个特殊的对象,该对象专门用来访问父类中的属性,完全参照mro列表
总结:

  1. 严格依赖继承的mro列表
  2. 访问是绑定方法,有自动传值的效果
class People:
    school = 'xx学校'

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

class Student(People):
    def __init__(self, name, age, sex, score=0):
        super(Student,self).__init__(name,age,sex)
        self.score = score

    def choose_course(self):
        print('%s choosing course' % self.name)

多态

多态指的是同一种/类事物的不同形态,在多态的背景下,可以在不用考虑对象具体类型的前提下而直接使用对象
多态性的精髓:统一

import abc
class Animal(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def speak(self):
        pass
    def run(self):
        print('running')
# Animal() # 父类只是用来建立规范的,不能用来实例化的,更无需实现内部的方法

class People(Animal):
    def speak(self):
        print('say hello')

class Dog(Animal):
    def speak(self):
        print('汪汪汪')

class Pig(Animal):
    def speak(self):
        print('哼哼哼')


obj1=People()
obj2=Dog()
obj3=Pig()
obj1.speak()
obj2.speak()
obj3.speak()
obj1.run()
'''
输出:
say hello
汪汪汪
哼哼哼
running
'''

python崇尚鸭子类型

class Disk:
    def read(self):
        print('Disk read')
    def write(self):
        print('Disk write')
class Memory:
    def read(self):
        print('Mem read')
    def write(self):
        print('Mem write')
class Cpu:
    def read(self):
        print('Cpu read')
    def write(self):
        print('Cpu write')
obj1=Disk()
obj2=Memory()
obj3=Cpu()
obj1.read()
obj2.read()
obj3.read()

封装

把一堆数据属性与方法属性 整合 到对象里面。

隐藏:
    __属性 ---> 把属性变形了,即隐藏起来了!
# 封装函数属性:隔离复杂度
class ATM:
    def __card(self):
        print('插卡')
    def __auth(self):
        print('用户认证')
    def __input(self):
        print('输入取款金额')
    def __print_bill(self):
        print('打印账单')
    def __take_money(self):
        print('取款')

    def withdraw(self):
        self.__card()
        self.__auth()
        self.__input()
        self.__print_bill()
        self.__take_money()

a=ATM()
a.withdraw()

property装饰器是用来将类内的函数属性伪装成数据属性

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

    # 对象的方法:一般的实现需求都是,这些方法只在内部使用
    def __test(self):
        pass

    # __money被封装,外界还是可以通过 对象.money 取值赋值
    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):
        del self.__money

绑定方法:绑定给谁就应该由谁来调用,谁来调用就会将谁当做第一个参数传入
1.绑定给对象的方法: 类中定义的函数默认就是绑定给对象的
2.绑定给类的方法: 为类中定义的函数加上一个装饰器classmethod

非绑定方法: 既不与类绑定,又不与对象绑定,意味着对象和类都可以来调用,无论谁来调用都是一个普通的函数,没有自动传值的效果

# settings
IP='10.10.10.11'
PORT=3306
import settings
class MySql:
    def __init__(self, ip, port):
        self.id = self.create_id()
        self.ip = ip
        self.port = port
    def tell_info(self):
        print('<id:%s ip:%s port:%s>' % (self.id, self.ip, self.port))

    @classmethod
    def from_conf(cls):
        return cls(settings.IP, settings.PORT)
    @staticmethod
    def create_id():
        import uuid
        return uuid.uuid4()
obj2 = MySql.from_conf()
obj2.tell_info()
'''
输出:<id:0adaa769-c7ba-4015-8928-5c8be9afd714 ip:10.10.10.11 port:3306>
'''

组合

组合指的是一个对象拥有某一个属性,该属性的值是来自于另外一个类的对象,是为了解决类与类之间代码冗余的问题。

class Teacher:
    def __init__(self, name, age):
        self.name = name
        self.age = age
t1 = Teacher("Ben", 17)

class Student:
    # 学生可以有 老师 属性
    def __init__(self, name, age, teacher):
        self.name = name
        self.age = age
        # 组合
        self.teacher = teacher
stu = Student('Bob', 18, t1)

# 访问老师具体的信息
print(stu.teacher.name)
print(stu.teacher.age)
'''
输出:
Ben
17
'''

issubclass 和 sinstance

issubclass() 方法用于判断参数 class 是否是类型参数 classinfo 的子类。

class Bar:
    pass
class Foo(Bar):
    pass
print(issubclass(Foo,Bar))
# 返回 True

isinstance(obj,cls)检查是否obj是否是类 cls 的对象

class Foo(object):
   pass
obj = Foo()
isinstance(obj, Foo)
# 返回 True

反射

通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)

hasattr()
判断对象或者类的属性是否存在!

getattr()
获取对象或者类的属性
参数1: 对象
参数2: ‘属性名’
参数3: 默认值

setattr()
设置对象或者类的属性

delattr()
删除对象或者类的属性

class People:
    school = 'school'
    def __init__(self, name):
        self.name = name
p = People('peter')

print(hasattr(p, 'school_s'))  # False
print(hasattr(p, 'school'))  # True
print(hasattr(People, 'school'))  # True
print(getattr(People, 'name', 'Bob'))  # Bob
print(getattr(People, 'school', 'Bob'))  # school
print(getattr(p, 'name', 'Bob'))  # peter
# print(p.age)  # 报错!
setattr(p, 'age', 18)
print(p.age)  # 18
print(p.name)  # peter
delattr(p, 'name')
# print(p.name)  # 报错!

内置方法

__init__(): 调用类的时候自动触发__init__。
__str__(): 打印对象的时候出发此方法。 (此方法内,必须return一个字符串)
__del__(): 在对象 占用空间被清掉了,会自动触发__del__方法的执行。
__setattr__(): 修改对象的属性会自动触发此方法的执行。
__deleter__: 删除属性的时候会自动触发。
__call__: 调用对象的时候会自动触发。 讲元类的时候会有用!

猜你喜欢

转载自blog.csdn.net/linwow/article/details/89481744