面向对象

一.面向对象初始

函数式编程相较于面向过程编程的优点

1.减少代码的重用性。
2.增强代码的可读性。

面向对象编程相较于函数编程的优点

1.是一类相似功能函数的集合,使代码更清晰化,更合理化。

概念

类的实例化:类名+()的过程称为类的实例化,产生一个对象(实例).
实例化做三件事:
    1.执行object的__new__()方法,产生并返回一个空对象(在内存中开辟了一个对象空间)
    2.自动触发类的内部__init__函数的执行,将空对象作为参数传给__init__函数
    3.在__init__方法中通过self给对象空间添加属性
查看对象的名称空间(只存对象独有的):
	print(obj.__dict__)
对象属性的查找顺序(对象的命名空间->类的命名空间):
    1.类的数据属性(给对象用,不同对象对应的地址相同)
    2.类的函数属性(给对象用,不同对象)
    #1.对象名.__dict__
    #2.类名.__dict__

类的结构

类的结构从大方向来说就分为两部分:

1.静态变量 2.动态方法

class Human:
    '''静态变量'''
    mind = "有思想"
    feeling = "有感情"
    
    '''动态方法'''
    def work(self):
        print("会工作")

二.从类名的角度研究类

类名操作静态属性

1.查看类中所有内容,__dic__方式

class Human:
    mind = "有思想"
    feeling = "有感情"
    
    def work(self):
        print("会工作")
        
print(Human.__dic__)
Human.__dic__['mind'] = "没有思想"  # 错误,通过__dic__只能查询,不能修改

2.万能的.

class Human:
    mind = "有思想"
    feeling = "有感情"
    
    def work(self):
        print("会工作")
# 查 print(Human.mind)
# 改 Human.mind = "五思想"
# 增 Human.hobby = "玩"
# 删 del Human.hobby 

类名操作动态方法

除了两个特殊方法(静态方法,类方法),一般不会通过类名操作类中方法

class Human:
    mind = "有思想"
    feeling = "有感情"
    
    def work(self):
        print("会工作")
Human.work(1)  # 需要传参

三.从对象角度研究类

对象操作对象空间属性

1.对象查询对象中的所有属性

class Human:
    mind = "有思想"
    feeling = "有感情"
    
    def __init__(self,name,age):
        self.name = name
        self.age = age
        
    def work(self):
        print("会工作")
obj = Human("张三",18)
print(obj.__dict__) # {"name":"张三","age":18}

2.对象操作对象中的单个属性,万能的.

class Human:
    mind = "有思想"
    feeling = "有感情"
    
    def __init__(self,name,age):
        self.name = name
        self.age = age
        
    def work(self):
        print("会工作")
obj = Human("张三",18)
# 增 obj.sex = "男"   此举是将sex属性添加到__init__()方法中
# 删 del obj.sex 
# 改 obj.name = "小明"
# 查 print(obj.__dict__)

对象查看类中的属性

class Human:
    mind = "有思想"
    feeling = "有感情"
    
    def __init__(self,name,age):
        self.name = name
        self.age = age
        
    def work(self):
        print("会工作")
        
obj = Human("张三",19)
print(obj.mind)  # 先从对象空间找,找不到去类中找

对象操作类中的方法

class Human:
    mind = "有思想"
    feeling = "有感情"
    
    def __init__(self,name,age):
        self.name = name
        self.age = age
        
    def work(self):
        print("会工作")
        
obj = Human("张三",20)
obj.work()

类中的方法一般都是通过对象执行(除去类方法、静态方法是类本身调用的)的。

四.类与类之间的联系

1.依赖关系

将一个类的类名或者对象传入另一个类的方法

class Elephant:
    def __init__(self,name):
        self.name = name
    def open(self,obj):
        print(f'{self.name}默念三生')
        obj.be_open()

class Refrigerator:
    def __init__(self,name):
        self.name = name
    def be_open(self):
        print(f'{self.name}冰箱被打开了')
        
qiqi = Elephant("琪琪")
haier = Refrigerator("海尔")
qiqi.open(haier)

2.组合关系

给一个类的对象封装一个属性,此属性为另一个类的对象

class Boy:
    def __init__(self,name,girlfriend=None):
        self.name = name
        self.girlfriend = girlfriend
        
    def have_a_dinner(self):
        print(f'{self.name}请他的{self.girlfriend.age}岁的女朋友{self.girlfriend.name}吃饭!')

class GirlFriend:
    def __init__(self,name,age):
        self.name = name
        self.age = age
        
boy = Boy("小明")
girl = GirlFriend("如花",30)
boy.girlfriend = girl
boy.have_a_dinner()

五.单继承

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

1.继承的优点

1.增加了类的耦合性
2.减少了重复代码
3.使代码更加规范化,合理化

2.类名+方法调用父类中方法

严格来说,此方法与继承无关

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

class Son(Father):
    def __init__(self,name,age):
        Father.__init__(self,name,age)

son = Son("小明",20)
print(son.__dict__)

3.super()方法

super()的返回值是一个特殊的对象,专门用来调用父类中的属性

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

    def eat(self):
        print("动物可以吃饭!")
        print(f"{self.name},{self.age},{self.sex}")

class Person(Animal):
    def __init__(self,name,age,sex):
        # super().__init__(name,age,sex)
        super(Person,self).__init__(name,age,sex)

    def eat(self):
        print("人可以吃饭!")
        super().eat()

person = Person("小明",19,"男")
person.eat()

六.多继承

1.继承的分类

只有在python2中才区分新式类和经典类。python3中,所有类都是新式类。

新式类

​ 继承object的类,以及该类的子类,都是新式类

​ 在python3中,如果一个类没有指定继承的父类,默认就继承object

经典类

​ 没有继承object的类,以及该类的子类,都是经典类

2.查找顺序

2.1经典类的深度优先

2.2新式类的mro(c3)算法(参考文献:https://www.cnblogs.com/jin-xin/articles/10274734.html)

七.封装

1.什么是封装

封装就是将属性私有化,提供共有的方法访问私有属性

2.为什么要用封装?

通过封装,可以实现对属性数据的访问限制,同时增加了程序的可维护性

3.图解

将"小明"和18封装给foo对象

八.多态

1.多态定义

同一个对象,多种形态。python默认支持多态。

在python中,定义变量a,a=10,a="hello",a=[1,2,3],就是默认支持多态的体现。在一个类中,实例化出来多个对象,每个对象都有独一的形态,这也是多态的体现。

2.鸭子类型

两个完全没有耦合性的类中有相同功能的方法,我们为这两个方法设定相同的名字,那么这两个方法就互成为鸭子类型。

class A:
    def f1(self):
        print("in A f1")
    def f2(self):
        print("in A f2")
class B:
    def f1(self):
        print("in B f1")
    def f2(self):
        print("in B f2")

# 如上:A和B类中的f1、f2方法互为鸭子类型
# 这样的例子很多:str、tuple、list都有index方法,就是互为鸭子类型

九.类的强制约束

1.提取父类

python语言惯用的一种约束方式,在父类中主动抛出错误

class Payment:
    def pay(self,money):
        raise Exception("你没有实现pay方法")   #尽量抛出的是NotImplementError

class QQpay(Payment):
    def pay(self,money):
        print(f"使用QQ支付了{money}")

class Alipay(Payment):
    def pay(self,money):
        print(f"使用Ali支付了{money}")

class Wechat(Payment):
    def fuqian(self,money):
        print(f"使用Wechat支付了{money}")

def pays(obj,money):   # 新建的统一支付接口
    obj.pay(money)

qqpay = QQpay()
alipay = Alipay()
wechat = Wechat()
pays(qqpay,100)
pays(alipay,200)
pays(wechat,300)    # 子类中没有此方法,会执行父类的,父类抛出错误

2.使用抽象类

借鉴于java语言,定义抽象类的概念,做到真正的强制约束。

'''
抽象类和接口类做的事情 :建立规范
制定一个类的metaclass是ABCMeta,
那么这个类就变成了一个抽象类(接口类)
这个类的主要功能就是建立一个规范

'''

from abc import ABCMeta,abstractmethod
class Payment(metaclass=ABCMeta):
    @abstractmethod
    def pay(self,money):
        pass

class QQpay(Payment):
    def pay(self,money):
        print(f"使用QQ支付了{money}")

class Alipay(Payment):
    def pay(self,money):
        print(f"使用Ali支付了{money}")

class Wechat(Payment):
    def fuqian(self,money):
        print(f"使用Wechat支付了{money}")

def pays(obj,money):   # 新建的统一支付接口
    obj.pay(money)

qqpay = QQpay()
alipay = Alipay()
wechat = Wechat()
pays(qqpay,100)       
pays(alipay,200)
pays(wechat,300)        #初始化对象就会报错


十.super()深入了解

https://www.cnblogs.com/jin-xin/articles/10279154.html
按照self对象从属于类的mro的顺序,执行Foo类的下一个类

class F:
    def f1(self):
        pass
class Foo(F):
    def f1(self):
        super(Foo,self).f1()
foo = Foo()
foo.f1()



#############
class A:

   def __init__(self):
       self.__func()                        # self._A__func()

    def __func(self):                     # _A__func()
        print('in A __func')

class B(A):
   def __func(self):                     # _B__func()
       print('in B __func')


obj = B()         #执行结果:in A_func

十一.类的组成成员

类大致分为两块区域

细分

class A:
    name = 'alex'                  #静态字段
    __iphone = '1259874159'        #私有静态字段
    
    def __init__(self,name,age):   #特殊方法
        self.name = name           #对象普通属性
        self.__age = age           #对象私有属性
    def func1(self):               #普通方法
        pass
    def __func(self):              #私有方法
        pass
    
    @classmethod                   #类方法
    def class_func(cls):
        pass
    
    @staticmethod                  #静态方法
    def static_func():
        pass
    @property                      #属性
    def prop(self):               
        pass



十二.类的私有成员

无论是类的私有属性还是私有方法,都只能在本类内部调用,注意是本类内部。外部和此类的子类都不能调用。如果要想一个变量或方法变成私有的,在前面加上__即可,这样打印a.__dict__,我们可以得到对象a的空间的属性,私有属性默认为设为_A__name,可通过此字段访问私有属性,但建议不要这样做。

1.私有静态字段

# 类内部可访问
class A:
    name = "公有静态字段"
    __name = "私有静态字段"
    
    def func(self):
        print(self.name)
        print(self.__name)
        
a = A()
a.func()  #打印结果:共有静态字段 私有静态字段


# 外部不可访问
class A:
    __name = "私有静态字段"

a = A()
print(a.__name)  # 报错,提示对象a没有此__name属性


# 类的子类不能访问
class A:
    __name = "私有静态字段"
class B:
    def func(self):
        print(self.__name)

b = B()
b.func()   # 报错,提示对象b没有__name属性

2.私有方法

# 类内部可访问
class A:
    def __func(self):
        print("类的私有方法")
    def func(self):
        self.__func()
a = A()
a.func() # 打印结果: 类的私有方法


# 外部不可访问
class A:
    def __func(self):
        print("类的私有方法")
a = A()
a.__func()  # 报错,提示对象a没有__func属性


# 类的子类不能访问
class A:
    def __func(self):
        print("类的私有方法")
class B(A):
    def func(self):
        self.__func()
b = B()
b.func()    # 报错,提示b对象没有__func属性

3.私有对象属性

class A:
    def __init__(self,name,sex):
        self.name = name 
        self.__sex = sex
a = A("小明","男")
print(a.__sex)    # 报错,提示对象a没有__sex属性
print(a.__dict__) # {'name': '小明', '_A__sex': '男'}

十三.类的其他成员

类的其他成员中包括实例方法、类方法、静态方法、双下方法。

1.类方法

一般通过类名调用的方法,并且自动将类名地址传给参数cls。通过实例化对象调用也可以,还是将对象所属类名地址也传给cls。

类方法作用:1.得到类名可以实例化对象。2.可以操作类的属性

# 得到实例化对象的个数
class Student:
    count = 0 
    def __init__(self,name,id):
        self.name = name
        self.id = id
        
    @classmethod
    def addnum(cls):
        cls.count = cls.count + 1
    
    @classmethod
    def getnum(cls):
        return cls.count

obj1 = Student('liye', 12343243243)
obj1 = Student('liye', 12343243243)
print(Student.getnum()) # 2

2.静态方法

使用装饰器@staticmethod

静态方法主要用来存放逻辑性的代码,逻辑上属于类,但是和类本身没有关系。

静态方法作用:1.代码更加规范、合理。2.它仅仅托管于某个类的名称空间中,便于使用和维护。

import time

class TimeTest(object):

    area = '中国'
    def __init__(self, hour, minute, second):
        self.hour = hour
        self.minute = minute
        self.second = second

    def change_time(self):
        print(f'你想调整的时间: {self.hour}时{self.minute}分{self.second}秒')

    @staticmethod
    def showTime():
        return time.strftime("%H:%M:%S", time.localtime())


def showTime():
    return time.strftime("%H:%M:%S", time.localtime())

def time1():
    pass

def time2():
    pass
# t = TimeTest(2, 10, 10)
# # t.change_time()
# print(TimeTest.showTime())

十四.特性property

应用场景:遇到类似于属性的方法名,可以让其伪装成属性

以下两个方法都是将动态方法伪装成一个属性

1.利用装饰器设置属性

class Foo:
    @property
    def bmi(self):
        print("get的时候运行")
    
	@bmi.setter
    def bmi(self,value):
        print("set的时候运行")
    
    @bmi.deleter
    def bmi(self):
        print("delete的时候运行")
        
foo = Foo()
foo.bmi           # 执行@property装饰的方法
foo.bmi = 666     # 不是改变bmi的值,而是执行setter装饰的方法
del foo.bmi       # 执行deleter装饰的方法

2.利用实例化对象的方式设置属性

class Foo:
    def get_A(self):
        print("get的时候运行")
    def set_A(self):
        print("set的时候运行")
    def delete_A(self):
        print("delete的时候运行")
    A = property(get_A,set_A,delete_A)   # 内置property三个参数与get,set,delete

f1 = Foo()
f1.A              # 执行get_A()函数
f1.A = 'aaa'      # 执行set_A()函数
del f1.A          # 执行delete_A()函数

十五.isinstance,issubclass

1.isinstance(对象与类的关系)

判断对象是否是某类某类派生类的实例化对象

class A:
    pass
class B(A):
    pass

obj = B()
print(isinstance(obj,B))  # True
print(isinstance(obj,A))  # True

2.issubclass(类与类的关系)

判断是否是某类某类派生类派生类

class A:
    pass
class B(A):
    pass
class C(B):
    pass

issubclass(B,A)    # True
issubclass(C,A)    # True
posted @ 2019-08-02 17:01  MISF  阅读(328)  评论(0编辑  收藏  举报
     JS过度和变形效果演示   
  
    html5.png