面向对象编程学习笔记

面向对象的编程

面向过程的编程:
  • 核心:过程(过程指的是解决问题的步骤,机械式的思维方式)
  • 优点:将复杂的问题流程化,进而简单化
  • 缺点:可扩展性差

    面向对象编程
  • 核心:对象(对象就是特征与技能的结合体)
  • 对象:python中一切是对象
  • 优点:可扩展性强
  • 缺点:编程复杂度高
  • 应用场景:用户需求经常变化,互联网应用,游戏,企业内部应用

  • 类:就是一 系列对象相似的特征与技能的结合体(站在不同角度,得到的分类是不同的)
  • 对象:特征与技能结合体
  • 在现实世界中:一定先有对象,后有类
  • 在程序中:一定得先定义类,后调用类来产生对象
  • 查看名称空间:
stu1 = LufftStudent()
print(stu1.__dict__)

类:

class LuffyStudent:
    school = 'luffycity' #数据属性
    
    def learn(self):# 函数属性
        print('is learing')
    
    def eat(self):
        print('is eating')
        
        
stu1 = LuffyStudent() #实例化对象


# # 查看类的名称空间
# print(LuffyStudent.__dict__)
# print(LuffyStudent.__dict__['school'])
# print(LuffyStudent.__dict__['learn'])

# 查看类的属性
#print(LuffyStudent.school) #LuffyStudent.__dict__['school']

# 增加类的属性
LuffyStudent.county = 'China'

# 删除
del LuffyStudent.county

# 改
LuffyStudent.school = 'Luffycity'
__init__方法
class LuffyStudent:
    school = 'luffycity' #数据属性
    def __init__(self,name,sex,age):# __init__方法用来对象定制对象独有的特征
        self.Name = name
        self.Sex = sex
        self.Age = age

    def learn(self):# 函数属性
        print('is learing')

    def eat(self):
        print('is eating')

# 后产生的对象
stu1 = LuffyStudent('wualin','man',29)#LuffyStudent.__init__(stu1,'wualin','man',20)

# 加上__init__方法后,实例化步骤
# 1. 先产生一个空对象stu1
# 2. 触发LuffyStudent.__init__(stu1,'wualin','man',29)

#
# # 查
# print(stu1.Name)
# print(stu1.Sex)
# print(stu1.Age)
# # 改
# stu1.Name='520'
#
# # 删除
# del stu1.Name
#
# # 增
# stu1.class_name = 'python开发'
属性查找
  • 类中的数据属性:是所有对象共有的

  • 类中的函数属性:是绑定给对象,绑定到不同的对象是不同的绑定方法,对象调用绑定方式时,会把对象本身当作第一个传入,传个self
class LuffyStudent:
    school = 'luffycity' #数据属性
    def __init__(self,name,sex,age):# __init__方法用来对象定制对象独有的特征
        self.Name = name
        self.Sex = sex
        self.Age = age

    def learn(self):# 函数属性
        print('is learing')

    def eat(self):
        print('is eating')

# 后产生的对象
stu1 = LuffyStudent('wualin','man',29)
stu2 = LuffyStudent('张宝宝','man',19)

# 类的数据属性
print(stu1.school)


# 类的函数属性,类中函数属性是给对象使用的,谁调用就绑定给它使用,自动将对象传入第一个参数


stu1.learn()#learn(stu1)

#对象在访问一个属性的时候会先在对象里面的名称空间找,如果对象里面没有则去类里面找。不会到全局变量里面找
python中一切皆对象:
  • 对象之间的交互:
class Girlun:
    faction = 'Demasia'
    def __init__(self,name,life,attack):
        self.name = name
        self.life = life
        self.attack = attack
    def attack_1(self,enemy):
        enemy.life = enemy.life-self.attack
        print('%s攻击了%s'%(self.name,enemy.name))


class Riwen:
    faction = 'Demasia'

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

    def attack_1(self, enemy):
        enemy.life = enemy.life - self.attack
        print('%s攻击了%s' % (self.name, enemy.name))
g1 = Girlun('草丛伦',100,10)
r1 = Riwen('锐萌萌',80,20)
print(r1.life)
g1.attack_1(r1)
print(r1.life)

继承与重用

  • 继承指的是类与类之间的关系
  • 查看继承自父类的哪些东西:
print(<类名>.__bases__)
  • 继承示例:
class Hero:
    def __init__(self,name,life,attack):
        self.name = name
        self.life = life
        self.attack = attack
    def attack_1(self,enemy):
        print('%s攻击了%s'%(self.name,enemy.name))

class Griren(Hero):
    pass

class Riven(Hero):
    pass

g1 = Griren('盖伦',80,50)
r1 = Riven('锐雯',50,50)

g1.attack_1(r1)
派生
  • 当子类中有需要的属性则不会去父类中查找
继承的实现原理:
  • 原则:
    • 子类会先余父类被检查
    • 多个父类会根据他们在列表中的顺序被检查(从左到右)
    • 如果下一个类存在两个合法的选择,会选择第一个父类
  • MRO查找方法
print(<类名>.__mro__
在子类中重用父类的方法或属性
  • 方式一:指名道姓,类名+方法(不依赖继承)
class Hero:
    def __init__(self,name,life,attack):
        self.name = name
        self.life = life
        self.attack = attack
    def attack_1(self,enemy):
        enemy.life -=self.attack

class Griren(Hero):
    def attack_1(self,enemy):
        Hero.attack_1(self,enemy) # 不依赖于继承
        print('%s攻击了%s'%(self.name,enemy.name))
class Riven(Hero):
    pass

g1 = Griren('盖伦',80,50)
r1 = Riven('锐雯',100,50)
print(r1.life)
g1.attack_1(r1)
print(r1.life)
  • 方式二:super()
    • super()查找方法基于mro列表往后找
class Hero:
    def __init__(self,name,life,attack):
        self.name = name
        self.life = life
        self.attack = attack
    def attack_1(self,enemy):
        enemy.life -=self.attack

class Griren(Hero):

    def __init__(self,name,life,attack,weapon):
        super().__init__(name,life,attack)# 第一种写法,依赖于继承
    def attack_1(self,enemy):
        super(Griren,self).attack_1(enemy)# 第二种写法,依赖于继承
        print('%s攻击了%s'%(self.name,enemy.name))
class Riven(Hero):
    pass

g1 = Griren('盖伦',80,50,'大保健')
r1 = Riven('锐雯',100,50)
print(r1.life)
g1.attack_1(r1)
print(r1.life)
print(g1.__dict__)
组合
  • 将两个类生成的实例对象组合在一起
抽象类与归一化
  • 通过抽象类使子类中的方法名统一起来
  • 抽象类只能被继承,不能实例化
import abc
class Animal(metaclass=abc.ABCMeta):# 通过抽象类使子类中的方法名统一起来
    @abc.abstractmethod
    def run(self):
        pass

    @abc.abstractmethod
    def eat(self):
        pass

class People(Animal):

    def run(self):
        pass

    def eat(self):
        pass

class Pig(Animal):

    def run(self):
        pass

    def eat(self):
        pass

多态与多态性

  • 同一种事物的多种形态

    多态性:
  • 可以在不考虑对象的类型的情况下而直接使用对象
    • 如抽象类中只要是动物都有的属性,不管属于什么分类,都有这一个方法,可以直接使用
  • 多态性的好处:
  1. 增加类程序的灵活性
    • 以不变应万变,不论对象千变万化,都可以通过统一接口调用
  2. 增加类程序可扩展性
    • 通过继承父类创建类一个新类,使用者无需更改自己的代码,还是用同样的方法去调用
  • python崇尚的是一种鸭子类型

封装

如何实现属性的隐藏
class A:
    __x = 1 #_A__x=1
    
    def __init__(self,name):
        self.__name=name
        
    def __foo(self):
        print('run foo')
  • 特点:
  1. 在类外部无法直接使用
  2. 在类内部可以直接使用
  3. python并不真正隐藏,只是在类定义是进行了变形操作
  4. 子类无法覆盖父类__开头的属
封装的意义
  • 封装数据属性:明确区分内外,控制外部对隐藏的属性的操作行为

  • 封装方法:隔离复杂度

封装与扩展性
property的使用

propert:特性

 class People:
    def __init__(self,name):
        self.__name = name
    @property
    def name(self):
        return self.__name

    @name.setter
    def name(self,val):
        if not isinstance(val,str):
            print('val is not str')
            return
        self.__name = val
    @name.deleter
    def name(self):
        print('不允许删除')

p = People('wualin')
print(p.name)
绑定方法与非绑定方法
  • 绑定方法:
    • 绑定给谁,就应该由谁来调用,谁来调用就把调用者当作第一个参数自动传入
    • 绑定到对象的方法:在类内定义的没有被任务装饰器修饰的

    • 绑定到类的方法:在类内部定义的装饰器classmethod修饰的方法

  • 非绑定方法:不会自动传值,就是类中的普通工具,类和对象都可以使用
    • 非绑定方法:不与类或者对象绑定
class Foo:
    def __init__(self,name):
        self.name = name

    def tell(self):# 绑定到对象的函数
        print('name:%s'%self.name)

    @classmethod
    def func(cls): #cls=Foo 绑定到类的方法
        print(cls)

    @staticmethod
    def func1(x,y):#类中的普通函数
        print(x+y)

f = Foo('wualin')
Foo.func1(1,2)
f.func1(1,3)
  • 绑定方法与非绑定方法的实际应用场景

反射

  • 通过字符串映射到对象的属性
hasattr(obj,'name')# 判断对象有没有'name'属性 obj.__dict__['name']

getattr(obj,'name') # 拿到对象的属性

setattr(obj,'name','wualin')#修改 obj.name = 'wualin'

delattr(obj,'age')# del obj.age
以上方法同样适用于类
  • 反射的应用:
class Service:
    def run(self):
        while True:
            cmd = input('>>>:').strip()
            if hasattr(self,cmd):
                func = getattr(self,cmd)
                func()
    def get(self):
        print('get...')
        
    def put(self):
        print('put...')
obj = Service()
obj.run()
内置方法
  • isinstance(obj,cls) 检查obj是否是类cls的对象
class Foo(object):
    psss
obj = Foo()
isinstance(obj,Foo)
  • issubclass(sub,super) 检查sub类是否是super的派生类(子类)
class Foo():
    pass
class Bar(Foo):
    pass
issubclass(Bar,Foo)
  • item系列:
# item
class Foo():
    def __init__(self,name):
        self.name = name

    def __getitem__(self, item):#查看

        return self.__dict__.get(item)

    def __setitem__(self, key, value):#增加
        self.__dict__[key] = value

    def __delitem__(self, key):#删除
        del self.__dict__[key]

obj = Foo('wualin')
#操作字典的方式去操作obj对象
#查看
print(obj['name']) #obj.name

#增加
obj['age'] = 20 #obj.age = 20
print(obj['age'])

#删除
del obj['name'] #del obj.name
  • str
class Foo():
    def __init__(self,name,age):
        self.name = name
        self.age = age

    def __str__(self):

        return '<name:%s age:%s>'%(self.name,self.age)

f = Foo('wualin',20)
print(f)
  • del:在对象被删除时先触发__del__,可自定义回收系统资源
class Open():
    def __init__(self,filename):
        print('Open...')
        
    def __del__(self):
        print('del...')
f = Open('a.txt')
print('---main---')
  • call
class Foo:
    def __call___(self,*args,**kwargs)
        print(self)
        print(args)
        print(kwargs)
obj = ()
obj(1,2,3,a=1,b=2,c=3)#obj.__call__(obj,1,2,3,a=1,b=2,c=3)

元类介绍

  • exec命令的使用:
  1. 参数1:字符串形式的命令
  2. 参数2:全局作用域(字典形式),如果不指定默认使用globals()
  3. 参数3:局部作用域(字典形式),如果不指定默认使用locals()
  • 对象可以怎么使用?
    • 都可以被引用:x = obj
    • 都可以当作函数的参数传入
    • 都可以当作函数的返回值
    • 都可以当作容器类
  • 产生类的类称之为元类,默认使用class定义的类,他们的元类是type
  • 定义类的三要素:
  1. 类名
  2. 类的基类
  3. 类的局部名称空间:obj.__dict__()
  • 定义类的两种方式:
    • 方式1:class

    • 方式2:type
    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)
    Chinese1 = type(class_name,class_bases,clsaa_dic)
    自定义元类控制类的行为
    class Mymeta(type):
      '''
      给传入class_name添加首字母必须大写,否则抛出异常,如果定义类的元类是Mymeta(metaclass=),就必须遵循自定义规则
      '''
      def __init__(self,class_name,class_bases,class_dic):
          if not class_name.istitle():
              raise TypeError('首字母大写') #raise主动抛出错误
    class Chinese(object,metaclass=Mymeta):
      def __init__(self,name,age):
          self.name = name
          self.age = age
    
      def tall_info(self):
          print('Name: %s Age: %s'%(self.name,self.age))
自定义元类控制类的实例化行为
class Mymeta(type):
    def __call__(self, *args, **kwargs):
        '''
        实例化类的步骤:
        1. 生成obj对象
        2. 初始化obj对象
        3. 返回obj
        :param args:
        :param kwargs:
        :return:
        '''
        obj = object.__new__(self)
        self.__init__(obj,*args,*kwargs)
        return obj

class Chinese(object,metaclass=Mymeta):
    def __init__(self,name,age):
        self.name = name
        self.age = age

    def tall_info(self):
        print('Name: %s Age: %s'%(self.name,self.age))
obj = Chinese('WUALIN',20)
print(obj.__dict__)
自定义元类控制类的实例化行为的应用
  • 单例模式:
class MySQL:
    '''
    假如一个类初始化属性都是一样的,可以使用单例模式节省内存空间
    '''
    __instance = None
    def __init__(self):
        self.host = '127.0.0.1'
        self.port = 3306
    
    @classmethod
    def singleton(cls): #单例模式函数,生成实例化对象时调用该函数
        if not cls.__instance:
            obj=cls()
            cls.__instance=obj
        return cls.__instance
# 两次实例化对象内存地址是一样的   
obj1 = MySQL.singleton()
obj2 = MySQL.singleton()
  • 通过元类实现单例模式:
class Mymeta(type):
    def __init__(self,class_name,class_bases,class_dic):
        if '__doc__' not in class_dic or not class_dic['__doc__'].strip():
            raise TypeError('注释不能为空')

        super(Mymeta,self).__init__(class_name,class_bases,class_dic)

        self.__instance = None
    def __call__(self, *args, **kwargs):
        if not self.__instance:
            obj = object.__new__(self)
            self.__init__(obj)
            self.__instance = obj
        return self.__instance

class Mysql(object,metaclass=Mymeta):
    '''
    xxx
    '''
    def __init__(self):
        self.host = '127.0.0.1'
        self.port = 3306

obj1 = Mysql()
obj2 = Mysql()
print(obj1 is obj2)
面向对象的软件开发

猜你喜欢

转载自www.cnblogs.com/wualin/p/9777548.html