面向对象

面向对象(Object Oriented)缩写OO,是一种设计思想。
面向对象编程(Object Oriented Programming)缩写OOP。
可以使软件设计更加灵活,更好的进行代码复用。

面向对象程序设计的特点

封装:
将对象的属性和行为封装起来成为类;是面向对象的核心思想;
类通常会对外隐藏实现细节,使用该类的用户不能看见类中的数据结构,避免外部对内部数据的影响,提高程序可维护性;

继承:
子类可通过继承复用父类的属性和行为;

多态:
子类继承父类特征同时,也具备自己的属性和行为,实现不同的效果;


具有相同属性和行为的一类叫做类;如人类,鸟类等;
使用class关键字定义;

语法

class ClassName:
    '''类的帮助信息'''
    statement|pass|... #类体

#ClassName:指定类名,采用驼峰式命名法
#类的帮助信息:创建类的对象时,输入类名和左侧的括号,将显示该信息
#statement:类体,主要有类的属性、方法构成,可使用pass空语句占位

案例

class Dog():
    '''模拟小狗类'''
    def __init__(self,name,age):
        '''初始化属性name和age'''
        self.name = name
        self.age = age

    def sit(self):
        '''模拟小狗听到命令时蹲下'''
        print(self.name.title() +'is now sitting.')

    def rol_over(self):
        '''模拟小狗听到命令时打滚'''
        print(self.name.title() +'rolled over!')

''''根据类创建实例'''
my_dog = Dog('xiaobai',6)
print('My dog\'s ' + my_dog.name.title() +'.')
print('My dog is '+str(my_dog.age)+'years old.')
'''
---------------脚本执行结果--------------------
My dog's Xiaobai.
My dog is 6years old.
'''   

类的实例

对象是类的实例;凭类造对象;

案例

your_dog = Dog('xiaobai',5) #生成小狗的实例
print(your_dog) #out: <__main__.Dog object at 0x000001D1F387FAC8>
#直接打印对象会告诉你这个对象的内存地址,self参数就是传递对象的地址

创建类的成员

类的成员包括类方法跟属性;

创建类方法
即类中定义的函数,也是类的行为;如如人类,有跑步,学习,睡觉等行为;
注意:实例方法第一个参数必须时self,必须包含一个self参数;

语法

#创建实例方法
def functionName(self,parameterlist):
    block #方法体
#访问实例方法
instanceName.functionName(parametervalue)

案例
可参考小狗案例

#定义一个人的类
class Person:
    race='人种'
    gender='中性'

    def study(self):
        print('正在学习',self.look)

ruirui=Person()
ruirui.look='学python'
ruirui.study() #out:正在学习 学python

xiaowei=Person()
xiaowei.look='学java'
xiaowei.study() #out:正在学习 学java

'''
self表示自身对象,生成的ruirui对象会将自己传入Person类中的study()中的self,
即self是对象的地址,从而self可以调用ruirui对象的look属性
'''

创建类属性
即类中定义的变量,包括类属性跟实例属性;

类属性:类中定义的变量,可通过类名或实例名访问;

案例

#通过类名访问
class Geese:
    #大雁类
    neck ='长脖子'
    wing ='飞的高'
    leg  ='大长腿'
    def __init__(self): #实例化对象先执行的方法,相当于java中的构造方法
        print('我是大雁,我有以下特征:')
        print(Geese.neck)
        print(Geese.wing)
        print(Geese.leg)
Geese.neck='脖子很长很长很长' #通过类名访问属性并修改它,可以看到输出的内容不再是默认的长脖子
wldGoose = Geese() #生成大雁类的实例
'''
---------------脚本执行结果--------------------
我是大雁,我有以下特征:
脖子很长很长很长
飞的高
大长腿
'''

'''通过实例名访问'''
class Geese:
    '''大雁类'''
    neck ='长脖子'
    wing ='飞的高'
    leg  ='大长腿'
    def __init__(self): #实例化对象先执行的方法,相当于java中的构造方法
        print('我是大雁,我有以下特征:')
        print(self.neck)
        print(self.wing)
        print(self.leg)

wldGoose = Geese()
'''
---------------脚本执行结果--------------------
我是大雁,我有以下特征:
长脖子
飞的高
大长腿
'''

实例属性:类中方法中的变量,只能通过实例名访问;

实例属性案例

'''只能通过实例名访问'''
class Geese:
    '''大雁类'''

    def __init__(self): #实例化对象先执行的方法,相当于java中的构造方法
        self.neck = '长脖子'
        self.wing = '飞的高'
        self.leg = '大长腿'
        print('我是大雁,我有以下特征:')
        print(self.neck)
        print(self.wing)
        print(self.leg)

wldGoose = Geese()

魔术方法__init__()

每创建一个类的实例后,都会自动执行此方法;

__init__():必须包含一个self参数,并且位置是在第一位,该参数指向实例本身的引用,即对象;
方法调用时会自动传递实际参数self,如果没有其他参数,实例化对象可不写self;

案例

class Geese:
    '''大雁类'''
    def __init__(self): #实例化对象先执行的方法,相当于构造方法
        print('我是大雁')

wildGoose = Geese() #生成大雁类的实例,out:我是大雁

#增加其他参数
class Person:
    def __init__(self,name,age): #用来放共有的属性
        self.name = name
        self.age = age

    def eat(self):
        print('{}正在吃红烧肉!'.format(self.name))

    def run(self):
        print('{},今年{}岁,正在跑步!'.format(self.name,self.age))

p = Person('张三',18)
p.eat() #out:张三正在吃红烧肉!
p.run() #out:张三,今年18岁,正在跑步!

访问限制

在类的属性或方法名前添加下划线可闲置访问权限;
__init__:特殊方法,由系统定义;
_foo:protected(保护),只允许类本身和子类访问,以及实例访问;

案例

class Swan:
    '''天鹅类'''
    _neck_swan='天鹅的脖子很长'

swan = Swan()
print(swan._neck_swan) #out:天鹅的脖子很长

__foo:private(私有),只允许定义该方法的类本身访问,不能通过类的实例访问,但可以通过类的实例名._类名.__变量名或方法名方式访问;

案例

class Swan:
    '''天鹅类'''
    __neck_swan='天鹅的脖子很长'

swan = Swan()
print(swan._Swan__neck_swan) #out:天鹅的脖子很长

将方法转换为属性

在python中可以通过@property(装饰器)将一个方法转换为属性,转换为属性后可直接通过方法名来访问方法,不需要添加小括号;
注意:通过@property转换后的属性不能重新赋值,如果创建一个只能读取不能修改的属性,可以使用@property

案例

'''定义一个计算矩形面积的类'''
class Rect:
    def __init__(self,width,height):
        self.width = width
        self.height = height

    '''使用@property将方法转换为属性'''
    @property
    def area(self):
        return self.width*self.height

'''创建计算矩形面积的类的实例'''
rect = Rect(800,600)
'''调用类中由方法转换成的属性'''
print('面积为:',rect.area)
#out:面积为: 480000
    

继承

一个类继承另一个类,它将自动获得另一个类所有属性和方法;
原有的类称为父类或基类以及超类,新类称为子类,子类除了继承父类所有属性和方法还可以定义自己的属性和方法;
注意:创建子类时,父类必须包含在当前文件中,且位于子类前面;

案例

'''定义一个水果类'''
class Fruit:
    '''定义类属性'''
    color = '绿色'
    def harvest(self,color):
        '''输出形参的color'''
        print('水果是:',color,'的')
        print('水果已经收获...')
        '''输出类属性的color'''
        print('水果原来是:',Fruit.color,'的')

'''定义派生类,需要在括号中写明父类'''
class Orange(Fruit):
    color = '橙色'
    def __init__(self):
        print('我是橘子')
    '''重写父类方法'''
    def harvest(self,color):
        print('橘子是:'+color+'的')
        print('橘子已经收获...')
        '''可以调用父类属性'''
        print('橘子原来是:'+Fruit.color+'的')

orange=Orange()
orange.harvest('黄色')
'''
---------------脚本执行结果--------------------
我是橘子
橘子是:黄色的
橘子已经收获...
橘子原来是:绿色的
'''

案例

class Car():
    #模拟汽车类
    def __init__(self,make,model,year):
        self.make=make
        self.model=model
        self.year=year
        self.odometer_reading =0
    #定义描述汽车方法,如年份,制造,型号
    def get_descriptive_name(self):
        long_name =str(self.year)+' '+self.make+' '+self.model
        return long_name.title()
    #读取已行驶的公里数
    def read_odometer(self):
        print("This car has "+str(self.odometer_reading)+"miles on it.")
    #更新公里数
    def update_odometer(self,mileage):
        if mileage >= self.odometer_reading:
            self.odometer_reading=mileage
        else:
            print("You can't roll back an odometer!")
    def increment_odometer(self,miles):
        self.odometer_reading+=miles

my_userd_car = Car('subaru','outback',2013) #假如购买了一辆subaru,型号outback,2013年出厂的车
print(my_userd_car.get_descriptive_name()) #out:2013 Subaru Outback
my_userd_car.update_odometer(23500)
my_userd_car.read_odometer() #out:This car has 23500miles on it.
my_userd_car.update_odometer(100) #out:You can't roll back an odometer!

#创建电动车类,继承汽车类
class ElectricCar(Car):
    def __init__(self,make,model,year):
        #初始化父类属性
        super().__init__(make,model,year) #super()是一个特殊函数,可以让子类调用父类的__init__(),由此父类也称为超类
        #电动车独特属性
        self.battery_size =70
    #打印描述电量的方法
    def describe_battery(self):
        print('This car has a '+str(self.battery_size)+'-kWh battery.')
my_tesla=ElectricCar('tesla','model s',2016)
print(my_tesla.get_descriptive_name()) #out:2016 Tesla Model S
my_tesla.describe_battery() #out:This car has a 70-kWh battery.

重写父类方法

子类的方法名要与父类的方法同名,才可重写父类的方法;

案例

#假设父类中有fill_gas_tank()方法,但是子类电动车类没有油箱则可以如下重写
def ElectricCar(Car):
    #与要重写的父类方法同名
    def fill_gas_tank():
        #电动车没有油箱
        print('This car doesn\'t need a gas tank!')

将实例转换为属性

当类的属性方法越来越多,可以将其部分独立出来当作一个类来处理;

案例

#将电动车ElectricCar类中的属性跟方法独立出来成为一个Battery类
class Battery():
    #模拟电动车电池类
    def __init__(self,battery_size=70):
        #初始化电瓶属性
        self.battery_size = battery_size
    #打印电瓶容量方法
    def describe_battery(self):
        print('This car has a '+str(self.battery_size)+'-kWh battery.')

#定义ElectricCar类继承Car类
class ElectricCar(Car):
    def __init__(self,make,model,year):
        #初始化父类属性
        super().__init__(make,model,year)
        #将Battery类实例化成为电动汽车类对象的属性
        self.battery = Battery()

my_tesla=ElectricCar('tesla','model s',2016)
my_tesla.battery.describe_battery() #out:This car has a 70-kWh battery.


导入类

为了py文件尽可能的整洁,可将类单独保存成模块,在需要的时候导入即可;

导入单个类
例如:将Car()类单独保存成为car.py文件
在需要使用该类的py文件开头导入该类

#格式为 from 模块名 import 类名
from car import Car

导入多个类
类与类之间使用逗号分开;

from car import Car,ElectricCar

导入整个模块
导入整个模块,再使用句点表示要访问的类;

import car
my_beetle = car.Car('volkswagen','beetle',2016)
my_tesla = car.ElectricCar('tesla','roadster',2016)

在一个模块中导入另一个模块
有时候将类存储在多个模块中时,可能会发现一个模块中的类依赖于另一个模块中的类,这种情况下需要依次导入必要的类;

#例如:car.py模块中包含Car类,electric_car.py模块中包含ElectricCar和Battery类,其中ElectricCar继承Car类
from car import Car #先导入父类
from electric_car import ElectricCar #再导入电瓶车类

学习来自:《python从入门到项目实践》明日科技 第十一章
《Python编程:从入门到实践》第九章 (参考一下豆瓣神书,针不戳)
B站大学 P82-P96

posted @ 2020-11-24 17:56  努力吧阿团  阅读(75)  评论(0编辑  收藏  举报