zoukankan      html  css  js  c++  java
  • 【Python学习之七】类和对象

    环境
      虚拟机:VMware 10
      Linux版本:CentOS-6.5-x86_64
      客户端:Xshell4
      FTP:Xftp4
      python3.6

    一、面向对象编程
    1、概念
    (1)面向对象编程(OOP),是一种程序设计思想。OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数。面向对象是一种对现实世界理解和抽象的方法。
    面向过程是一件事“该怎么做“,面向对象是一件事“该让谁来做”,然后那个“谁”就是对象,他要怎么做是他自己的事,反正最后一群对象合力能把事做好就行了。
    面向对象三个特性:继承,封装,多态。
    (2)类:具有相同属性和行为事物的统称:类(Class) 由3个部分构成:类的名称:类名;类的属性:一组数据;类的方法:允许对进行操作的方法 (行为)
    (3)对象:某一个具体事物的存在 ,在现实世界中可以是看得见摸得着的,可以是直接使用的;
    (4)类和对象关系:类就是创建对象的模板;

    2、定义类
    格式:class 类名: 方法列表
    (1)定义类时有2种:新式类和经典类,下面的Car为经典类,如果是Car(object)则为新式类;
    (2)类名的命名规则按照"大驼峰";

    #定义一个Car类
    class Car:
        def move(self):
            print('车正在移动...')
        def getCarInfo(self):
            print('车油耗数:%d, 颜色%s'%(self.oil, self.color))

    3、创建对象
    当创建一个对象时,就是用一个模子,来制造一个实物
    格式:对象名 = 类名()

    #创建对象     
    bmw=Car()
    #给对象bmw添加属性
    bmw.color='白色'
    bmw.oil=30
    #调用对象的方法
    bmw.getCarInfo()
    bmw.move()
    print(bmw.color)
    print(bmw.oil)

    (1)创建实例对象,一定在内存中有一块空间存放对象的数据信息。此时也可以通过实例对象bmw来访问属性或者方法,bmw是一个对象,它拥有属性(数据)和方法(函数);

    (2)第一次使用bmw.color = '白色'表示给bmw这个对象添加属性,如果后面再次出现bmw.color = xxx表示对属性进行修改;

    4、self
    类定义的方法中的参数self,可以理解为自己,可以把self当做C++中类里面的this指针一样理解,就是对象自身的意思。
    (1)某个对象调用其方法时,python解释器会把这个对象作为第一个参数传递给self,所以开发者只需要传递后面的参数即可;
    (2)self可以不写self,方法中至少有一个参数,第一个参数表示当前对象。名字随便取,但是习惯都写self;

    5、__init__()方法:初始化函数,用来完成一些默认的设定;该方法在创建对象后,就立刻被默认调用了。

    (1)__init__()方法,在创建一个对象时默认被调用,不需要手动调用;
    (2)__init__(self)中,默认有1个参数名字为self,如果在创建对象时传递了2个实参,那么__init__(self)中出了self作为第一个形参外还需要2个形参,例如__init__(self,x,y);
    (3)__init__(self)中的self参数,不需要开发者传递,python解释器会自动把当前的对象引用传递进去;

    示例:

    class Car:
        def __init__(self):
            self.color='白色'
            self.wheel=4
            self.oil=10
                    
        def move(self):
            print('车正在移动...')
            
        def getCarInfo(self):
            print('车油耗数:%d, 颜色%s'%(self.oil, self.color))

    初始化函数使用入参:

    class Car:
        def __init__(self,color,wheel,oil):
            self.color=color
            self.wheel=wheel
            self.oil=oil
                    
        def move(self):
            print('车正在移动...')
            
        def getCarInfo(self):
            print('车油耗数:%d, 颜色%s'%(self.oil, self.color))
    
    bmw=Car('黑色',4,10)
    print('汽车颜色=%s,轮子数量=%d,油耗数量=%d'%(bmw.color,bmw.wheel,bmw.oil))

    6、__new__方法
    (1)__new__至少要有一个参数cls,代表要实例化的类,此参数在实例化时由Python解释器自动提供
    (2)__new__必须要有返回值,返回实例化出来的实例,这点在自己实现__new__时要特别注意,可以return父类__new__出来的实例,或者直接是object的__new__出来的实例
    (3)__init__有一个参数self,就是这个__new__返回的实例,__init__在__new__的基础上可以完成一些其它初始化的动作,__init__不需要返回值
    (4)我们可以将类比作制造商,__new__方法就是前期的原材料购买环节,__init__方法就是在有原材料的基础上,加工,初始化商品环节

    __new__与__init__关系:
    (1)__new__方法(第一个执行)先于__init__方法执行;
    (2)__new__方法是传入类(cls),而__init__方法传入类的实例化对象(self);
    (3)__new__方法的第一个参数是这个类,而其余的参数会在调用成功后全部传递给__init__方法初始化;
    (4)__new__和__init__想配合才是python中真正的类构造器;

    示例:

    class Dog(object):
        #创建对象
        def __new__(cls,name,age):
            print('__new__方法')
            print("类内存地址:%s"%id(cls))
            #return super().__new__(cls)
            ret=object.__new__(cls)
            print("实例化对象:%s"%ret)
            return ret
        
        def __init__(self,name,age):
            print('__init__方法')
            print("实例化对象:%s"%self)
            self.name=name
            self.age=age
    
    print('类内存地址:%s'%id(Dog))
    d=Dog('haha',12)
    
    # 类内存地址:3992792
    # __new__方法
    # 类内存地址:3992792
    # 实例化对象:<__main__.Dog object at 0x0000000002961390>
    # __init__方法
    # 实例化对象:<__main__.Dog object at 0x0000000002961390>

    7、__del__方法

    当内存中销毁(释放)一个对象时回调__del__()方法;

    import time
    class Animal(object):
        def __init__(self,name,age):
            print('__init__被调用...')
            self.__name=name
            self.__age=age
        def __del__(self):
            print('__del__被调用...')
            print('%s对象马上被干掉了'%self.__name)
        def __str__(self):
            return '名字'+self.__name+',年龄:'+str(self.__age)
        
    #创建对象
    dog=Animal('哈皮狗',1)
    #删除对象
    del dog
    # __init__被调用...
    # __del__被调用...
    # 哈皮狗对象马上被干掉了
    
    cat=Animal('波斯猫',2)
    print(cat)
    cat2=cat
    cat3=cat
    print("---马上 删除cat对象") 
    del cat 
    print("---马上 删除cat2对象") 
    del cat2 
    print("---马上 删除cat3对象") 
    del cat3 
    print("程序2秒钟后结束") 
    time.sleep(2)
    
    # __init__被调用...
    # 名字波斯猫,年龄:2
    # ---马上 删除cat对象
    # ---马上 删除cat2对象
    # ---马上 删除cat3对象
    # __del__被调用...
    # 波斯猫对象马上被干掉了
    # 程序2秒钟后结束

    关于对象被其他变量引用时,删除对象时的处理:
    (1)当有1个变量保存了对象的引用时,此对象的引用计数就会加1
    (2)当使用del删除变量指向的对象时,如果对象的引用计数不是1,比如3,那么此时只会让这个引用计数减1,即变为2,当再次调用del时,变为1,如果再调用1次del,此时会真的把对象进行删除

    8、魔法方法
    在python中方法名如果是__xxxx__()的,那么就有特殊的功能,因此叫做“魔法”方法
    __str__()类似toString()
    当使用print输出对象的时候,只要自己定义了__str__(self)方法,那么就会打印从在这个方法中return的数据

    9、id()用于打印对象内存地址

    二、类和对象的属性
    1、公有属性和私有属性
    (1)Python中没有像C++中public和private这些关键字来区别公有属性和私有属性;
    (2)它是以属性命名方式来区分,如果在属性名前面加了2个下划线'__',则表明该属性是私有属性,否则为公有属性(方法也是一样,方法名前面加了2个下划线的话表示该方法是私有的,否则为公有的)。

    2、类属性和实例属性
    (1)类属性:所属类,类似C++,java中类的静态成员变量;
    公有的类属性,在类外可以通过类和实例对象访问;
    私有的类属性,类和实例对象均不能在类外访问。
    (2)实例属性:在__init__通过self.XXX方式添加或者创建对象后,使用对象变量.XXX=数据时添加的

    class People(object):
        name='Tom'#公有类属性
        __age=10#私有的类属性
        def __init__(self,address):
            self.address=address
        
    p=People('山东')
    #公有类属性与私有类属性
    print(p.name)
    print(People.name)
    # print(p.__age)#报错:AttributeError: 'People' object has no attribute '__age'
    # print(People.__age)#报错:AttributeError: 'People' object has no attribute '__age'
    
    #实例属性与类属性
    print(p.address)
    # print(People.address)#报错:AttributeError: type object 'People' has no attribute 'address'
    
    #通过实例(对象)去修改类属性
    print(p.name)#Tom
    p.name='Jack'
    print(p.name)#实例属性会屏蔽掉同名的类属性 :Jack
    print(People.name)#Tom
    del p.name#删除实例属性
    print(p.name)#Tom

    注意:
    如果需要在类外修改类属性,必须通过类去引用然后进行修改。
    如果通过实例对象去引用,会产生一个同名的实例属性,这种方式修改的是实例属性,不会影响到类属性,并且之后如果通过实例对象去引用该名称的属性,实例属性会强制屏蔽掉类属性,即引用的是实例属性,除非删除了该实例属性。

    三、类方法和静态方法

    1、类方法
    (1)是类所拥有的方法,用修饰器@classmethod来标识;
    (2)第一个参数必须是类对象,一般以cls做标识(可用其他名称);
    (3)可以通过实例对象和类调用类方法;

    2、静态方法
    通过修饰器@staticmethod来进行修饰,静态方法不需要多定义参数。

    class Person(object):
        country='山东'
        
        @classmethod
        def getCountry(cls):
            return cls.country 
        @classmethod
        def setCountry(cls,country):
            cls.country=country
        
        @staticmethod
        def getCountry2():
            return Person.country
    
    pn=Person()
    #通过实例对象和类调用类方法
    print(pn.getCountry())#山东
    print(Person.getCountry()) #山东
    pn.setCountry('北京')
    print(pn.getCountry())#北京
    print(Person.getCountry()) #北京
    #静态方法
    print(Person.getCountry2())#北京

    方法类别

    语法

    描述

    类方法

    @classmethod

    第一个形参cls,默认传递, 通过cls引用的必定是类对象的属性和方法

    静态方法

    @staticmethod

    没有默认传递的形参

    对象方法(成员方法)

    def  方法名

    第一个形参self ,默认传递,通过self引用的可能是类属性、也有可能是实例属性, 不过在存在相同名称的类属性和实例属性的情况下,实例属性优先级更高。

    四、继承、多继承、多态
    1、继承
    (1)子类在继承的时候,在定义类时,小括号()中为父类的名字;
    (2)父类的属性(不包括私有属性)、方法(不包括私有方法),会被继承给子类

    class Animal(object):
        def __init__(self,name='动物',color='白色'):
            self.__name=name
            self.color=color
        def __test(self):
            print(self.__name)
            print(self.color)
        def test(self):
            print(self.__name)
            print(self.color)
    
    class Dog(Animal):
        def doTest(self):
            #print(self.__name)#不能访问到父类的私有属性
            print(self.color)
            
        def doTest2(self):
            #self.__test()#不能访问父类中的私有方法
            self.test()
        
    a=Animal()
    # print(a.__name)#报错:AttributeError: 'Animal' object has no attribute '__name'
    print(a.color)
    # a.__test()#报错:AttributeError: 'Animal' object has no attribute '__test'
    a.test()
    print('-'*30)
    d=Dog(name='小花',color='花色')
    d.doTest()
    d.doTest2()

    2、多继承,即子类有多个父类,并且具有它们的特征

    class Base(object):
        def test(self):
            print('---Base test---')
            
    class A(Base):
        def test(self):
            print('---A test---')
            
    class B(Base):
        def test(self):
            print('---B test---')
            
    class C(A,B):
        pass
    
    c=C()
    c.test()#---A test---
    #可以查看C类的对象搜索方法时的先后顺序,C.__mro__算法得到一个元组
    print(C.__mro__)#(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.Base'>, <class 'object'>)

    注意:按照继承顺序调用父类的方法

    3、重写

    所谓重写,就是子类中,有一个和父类相同名字的方法,在子类中的方法会覆盖掉父类中同名的方法

    class Cat(object):
        def __init__(self,name):
            self.name=name
            self.color='黑色'
            
        def sayHello(self):
            print('-----Cat-----')
        
    class Bosi(Cat):
        def __init__(self,name):
            # 调用父类的__init__方法1(python2) 
            Cat.__init__(self, name)
            # 调用父类的__init__方法2 
            super(Bosi,self).__init__(name)
            # 调用父类的__init__方法3 
            super().__init__(name)
            
        def sayHello(self):
            print('-----Bosi-----')
            
    bosi=Bosi('小花') 
    bosi.sayHello()#-----Bosi-----
    print(bosi.name)#小花
    print(bosi.color)#黑色

    4、多态
    所谓多态:定义时的类型和运行时的类型不一样,此时就成为多态

    class Animal(object):
        def run(self):
            print('Animal is running...')
            
    class Dog(Animal):
        def run(self):
            print('Dog is running...')
    
    class Cat(Animal):
        def run(self):
            print('Cat is running...')
    
    def run_twice(animal):
        animal.run()
    
    run_twice(Animal())#Animal is running...
    run_twice(Dog())#Dog is running...
    run_twice(Cat())#Cat is running...

    参考:
    Python学习笔记

  • 相关阅读:
    python note 30 断点续传
    python note 29 线程创建
    python note 28 socketserver
    python note 27 粘包
    python note 26 socket
    python note 25 约束
    Sed 用法
    python note 24 反射
    python note 23 组合
    python note 22 面向对象成员
  • 原文地址:https://www.cnblogs.com/cac2020/p/10815231.html
Copyright © 2011-2022 走看看