zoukankan      html  css  js  c++  java
  • 面向对象基础

    初识面向对象

    概述

    • 面向过程: 根据业务逻辑从上到下 垒代码
    • 函数式: 将某功能代码封装到函数中,日后便无需重复编写,直接调用函数即可。
    • 面向对象:将对象进行分类和封装。让开发更快更好更强

    创建类和对象

    面向对象编程(oop),是一种编程方式。此编程方式的落地需要使用’类‘和’对象‘来实现,所以,面向对象编程其实就是对’类‘和’对象‘的使用。

    class 类名:
    	属性 = 'a'
        
    对象 = 类()
    

    类名的作用就是 操作属性,查看属性。

    类的定义

    类就是一个模板,模板里可以包含多个函数,函数里实现一些功能。

    对象则是根据模板创建的实例,通过实例对象可以执行类中的函数。

    class Person:	# 类名
        country = 'China' # 创造了一个只要是这个类就一定有的属性。类属性,静态属性
        
        def __init__(self,*args):	#初始化方法。self是对象,是一个必须传的参数。
            #self就是一个可以存储很多属性的大字典。self拥有的属性都属于对象。
            self.name = 'nick'
        
        # 方法,一般情况下必须传self参数,且必须写在第一个
        # 后面还可以传其它参数,
        def walk(self,n):
            print(f'{self.name}走了{n}步')
            
    print(Person.country)  # 类名 可以查看类中的属性,不需要实例化即可查看
    
    nick = Person('nick') # 类名可以实例化对象。nick对象
    
    print(nick.name) # 查看所有的属性,通过 . 点出
    
    nick.walk() # Person.walk(nick,5) # 调用方法 类名.方法名(对象名)
    
    
    

    示例

    class Person:
        country = 'China'
    
        def __init__(self,name,age,sex):
            self.name = name
            self.age = age
            self.sex = sex
    
        def walk(self,n):
            print(f'{self.name}都{self.age}岁了,还没走过{n}步。')
    
    nick = Person('nick',5,'man')
    nick.walk(1)
    print(nick.name)
    print(nick.age)
    print(nick.sex)
    
    1. 定义一个类,必须class+类名:
    2. 类里可以定义静态属性,这个属性可以直接使用使用类名调用,也称类属性
    3. 类里可以定义动态属性,也就是方法。每个方法都有一个必须传的self属性。类调用这个方法时,需要自己传self,实例化后的对象会自动传self
    4. __init__方法是类的初始化方法。
      1. 实例化的时候,python帮我们创建了一个对象self
      2. 每当我们调用类的时候就会自动触发这个方法。默认传self
      3. 在init方法里面可以对self进行赋值
    5. self是什么。
      1. self就是一个大字典
      2. self拥有的属性都属于对象
      3. 在类的内部,self就是一个对象

    实例化

    对象 = 类名()

    过程:

    1. 类名() 首先会创造出一个对象,创建了一个self变量
    2. 调用__init__方法,类名括号里的参数会被这里接收
    3. 执行__init__方法
    4. 返回self

    对象能做什么

    1. 对象可以查看类中的属性,
    2. 可以调用类中所用的方法。
    3. __dict__ 对于对象的增删改查都可以通过字典的语法 进行

    类名能做什么

    1. 实例化对象
    2. 调用方法:只不过要自己传递self参数
    3. 调用类中的属性,也就是调用静态属性
    4. __dict__ 对类中的名字只能看 不能操作
    # 代码演示
    # 人狗大战
    class Dog:
        def __init__(self,name,blood,aggr,kind):
            self.name = name
            self.hp = blood
            self.aggr = aggr
            self.kind = kind
        def bite(self,person):
            # 狗咬人,人掉血
            person.blood -= self.aggr
    
    class Person:
        def __init__(self,name,blood,aggr,sex):
            self.name = name
            self.blood = blood
            self.aggr = aggr
            self.sex = sex
        def attack(self,dog):
            dog.hp -= self.aggr
            if dog.hp <= 0:
                print('%s打了%s,%s被打死了,扑街~~~'%(self.name,dog.name,dog.name))
            else:
                print('%s打了%s,掉了%s血'%(self.name,dog.name,self.aggr))
    
    jin = Dog('金老板',100,20,'teddy')
    # print(jin.name)
    alex = Person('alex',999,998,'不详')
    jin.bite(alex)   # Dog.bite(jin,alex)
    print(alex.blood)
    # alex attack
    alex.attack(jin)  # Person.attack(alex,jin)
    print(jin.hp)
    

    类和对象的命名空间

    类里面我们可以定义两种属性:静态属性和动态属性。

    类中的静态属性 可以被对象和类 调用。

    1. 对于不可变数据类型来说,类变量最好用类名操作
    2. 对于可变数据类型来说,对象名的修改是共享的,重新赋值是独立的。(对象名的修改,每个实例化后的对象也随着更改,重新赋值的话,只有本对象的数据被重新赋值,其他实例化出来的数据是不变的)

    扩展

    创建一个类,每实例化一个对象就计数,最终所有的对象共享这个数据。

    class Foo:
        count = 0
        
        def __init__(self):
            count += 1
            
    f1 = Foo()
    f2 = Foo()
    print(f1.count)
    print(f2.count)
    f2 = Foo()
    print(f1.count)
    

    绑定方法

    class Foo:
        def func(self):
            pass
    print(Foo.func) #<function Foo.func at 0x055AA4B0>
    
    f1 = Foo()
    print(f1.func) #<bound method Foo.func of <__main__.Foo object at 0x05519EB0>>
    

    创建包的时候,会自动创建一个__init__.py文件

    导入一个模块,就相当于类的实例化的过程

    面向对象的三大特性

    封装,继承,多态

    封装

    封装,顾名思义就是将内容封装到某个地方,以后再去调用被封装在某处的内容。对代码的保护,不让别人看见。

    所以,在使用面向对象的封装特性时,需要

    • 将内容封装到某处
    • 从某处调用被封装的内容

    第一步:将内容封装到某处

    self是一个形参,当执行实例化时,self就是实例化后的对象,所以内容其实被封装到了对象中,每个对象中都有类的属性,在内存里面类似于下图来保存。

    第二步:从某处调用被封装的内容

    调用被封装的内容时,有两种情况:

    • 通过对象直接调用

    • 通过self间接调用

      class Foo:
        
          def __init__(self, name, age):
              self.name = name
              self.age = age
        
          def detail(self):
              print self.name
              print self.age
        
      obj1 = Foo('wupeiqi', 18)
      obj1.detail()  # Python默认会将obj1传给self参数,即:obj1.detail(obj1),所以,此时方法内部的 self = obj1,即:self.name 是 wupeiqi ;self.age 是 18
       
      

      总结:对于面向对象的封装来说,其实就是使用构造方法将内容封装到对象中,然后通过对象直接或self间接获取被封装的内容。

    class Person:
        __key = 123 # 双下划线,表示私有。这里是私有静态属性
        def __init__(self,name,passwd):
            self.name= name
            self.__passwd= passwd  #私有属性
            
        def __get_pwd(self):    # 私有方法
            return self.__passwd # 只要在类的内部使用私有属性,就会自动的带上_类
        def login(self):
            return self.__get_pwd() # 正常的方法调用私有的方法
            
            
    alex = Person('alex','alex3714')
    print(alex._Person__passwd) # _类名__属性名
    
    print(alex.get_pwd()) # 这种调用是错误的,正确方式如下
    print(alex.login())  #要使用正常的方法调用私有的方法
    
    
    
    # 所有的私有 都是在变量的左边加上双下划线
    	# 对象的私有属性
        # 类中的私有方法
        # 类中的静态私有属性
    # 所有的私有的,都不能在类的外部使用
        
    

    继承

    继承,即子类继承父类的内容。

    所以,对于面向对象的继承来说,其实就是将多个类共有的方法提取到父类中,子类仅需继承父类而不必自己再一个一个的实现每个方法。

    一个类可以被 多个类 继承,一个类可以继承多个类

    被继承的类 称之为 父类、基类、超类

    继承父类的类 称之为 子类,派生类

    python3里都是 新式类,没有继承父类的类都默认继承object

    父类中没有的属性,在子类中出现 ,叫做 派生属性

    父类中没有的方法,在子类中出现,叫做 派生方法

    只要是子类的对象调用,子类中有的名字一定是用子类的,子类中没有才找父类的。如果父类也没有这个名字,就报错。

    如果父类中的方法和属性 子类中都有,那就用子类的。如果你仍然想用父类的,需要单独调用父类的这个方法或属性。

    1. 父类.方法名(self,...) 需要自己传self参数
    2. super().方法名 不需要自己传self---只有新式类中可以使用这种方法

    正常的代码中, 使用单继承,可以减少代码的重复

    继承表达的是一种 子类 是父类的关系。

    注意:上述的查找过程中,一旦找到,则立即中断寻找过程,不会继续找下去了。

    多态

    python不支持Java和c# 这一类强类型语言中多态的写法,但是原生多态,其python崇尚’鸭子类型‘

    class F1:
        pass
    
    
    class S1(F1):
    
        def show(self):
            print 'S1.show'
    
    
    class S2(F1):
    
        def show(self):
            print 'S2.show'
    
    def Func(obj):
        print obj.show()
    
    s1_obj = S1()
    Func(s1_obj) 
    
    s2_obj = S2()
    Func(s2_obj) 
    
    Python “鸭子类型”
    

    总结

    • 面向对象是一种编程方式,此编程方式的实现是基于 对象的使用。
    • 类 是一个模板,模板中包装了多个’函数‘供使用。
    • 对象,根据模板创建的实例(即 对象),对象用于调用被包装在类中的函数
    • 面向对象的三大特性:封装、继承和 多态

    组合的用法

    一个对象的属性值 是另外一个类的对象。

    # 组合
    # 人狗大战
    class Dog:
        def __init__(self,name,aggr,hp,kind):
            self.name = name
            self.aggr = aggr
            self.hp = hp
            self.kind = kind
    
        def bite(self,person):
            person.hp -= self.aggr
    
    class Person:
        def __init__(self,name,aggr,hp,sex):
            self.name = name
            self.aggr = aggr
            self.hp = hp
            self.sex = sex
            self.money = 0
    
        def attack(self,dog):
            dog.hp -= self.aggr
    
        def get_weapon(self,weapon):
            if self.money >= weapon.price:
                self.money -= weapon.price
                self.weapon = weapon
                self.aggr += weapon.aggr
            else:
                print("余额不足,请先充值")
    
    class Weapon:
        def __init__(self,name,aggr,njd,price):
            self.name = name
            self.aggr = aggr
            self.njd = njd
            self.price = price
    
        def hand18(self,person):
            if self.njd > 0:
                person.hp -= self.aggr * 2
                self.njd -= 1
    
    alex = Person('alex',0.5,100,'不详')
    jin = Dog('金老板',100,500,'teddy')
    w = Weapon('打狗棒',100,3,998)
    # alex装备打狗棒
    alex.money += 1000
    alex.get_weapon(w)
    print(alex.weapon)
    print(alex.aggr)
    alex.attack(jin)
    print(jin.hp)
    alex.weapon.hand18(jin)
    print(jin.hp)
    
    # 组合 :一个对象的属性值是另外一个类的对象
    #        alex.weapon 是 Weapon类的对象
    

    继承

    多继承

    新式类中的继承顺序: 广度优先

    经典类中的继承顺序是 : 深度优先,python2 版本

    在单继承中,子类有的用子类的,没有就用父类的。

    在多继承中,默认是就近原则,在经典类中是按照深度优先进行继承,而在新式类中是按照广度优先的顺序进行查找。

    在python2中新式类和经典类是共存的,新式类要继承object。

    在python3 只有新式类,默认继承object

    经典类和新式类的区别

    多继承寻找名字的顺序:新式类广度优先,经典类深度优先

    新式类中有一个类名.mro 方法,查看广度优先的继承顺序

    python3 中 有个super 方法,根据广度优先的继承顺序查找上一个类

    super

    只在python3 中存在,它的本质是: 不是单纯的找父类,而是根据调用者的节点位置的广度优先顺序来找名字的。

  • 相关阅读:
    log4j 配置文件
    log4j安装与简介
    tomcat服务
    查看系统网络连接打开端口、系统进程、DOS打开文件
    find查找指定类型文件并删除
    git/github在windows上使用
    VIM配置自动提示功能
    VIM Taglist安装配置和使用
    python Scipy积分运算大全(integrate模块——一重、二重及三重积分)
    python matplotlib绘图大全(散点图、柱状图、饼图、极坐标图、热量图、三维图以及热图)
  • 原文地址:https://www.cnblogs.com/chenych/p/10996429.html
Copyright © 2011-2022 走看看