【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学习笔记

原文地址:https://www.cnblogs.com/cac2020/p/10815231.html