python之面向对象的三大特性,私有属性与私有方法,类的结构,设计模型

1.面向对象的三大特性

(1)封装:

根据职责将属性和方法封装到一个抽象的类中定义的准则

(2)继承:

实现代码的重用,相同的代码不需要重复的编写,设计类的技巧,子类针对自己特有的需求,编写特定的代码

(3)多态:

不同的子类对象调用相同的方法,产生不同的执行结果

 

 1.封装

(1).封装是面向对象编程的一大特点

(2).面向对象编程的第一步,将属性和方法封装到一个抽象的类中

(3).外界使用类创建对象,然后让对象调用的方法

(4).对象方法的细节的都被封装在类的内部

 

例1:

xxx喜欢跑步

1.xxx体重为75.0公斤

2.xxx每次跑步会减肥0.5公斤

3.xxx每次吃定西会增加1公斤

 

代码:

class Person():

    def __init__(self,name,weight):

        self.name = name

        self.weight = weight

    def __str__(self):

        return '我的名字叫 %s 体重为 %.2f' % (self.name,self.weight)

    def run_dec(self):

        print '%s 喜欢跑步' % self.name

        self.weight -= 0.5

    def eat_inc(self):

        print '%s 喜欢吃东西' % self.name

        self.weight += 1

 

lily = Person('lily',75)

lily.run_dec()

lily.eat_inc()

print lily

执行结果:

 

例2:

1.xxx和xxx喜欢跑步

2.xxx体重为75.0公斤

3.xxx每次跑步会减肥0.5公斤

4.xxx每次吃定西会增加1公斤

 

代码:

# 创建人类

class Person():

    #初始化方法定义属性

    def __init__(self, name, weight):

        self.name = name

        self.weight = weight

    def __str__(self):

        return '我的名字叫 %s 体重为 %.2f' % (self.name, self.weight)

    def run_dec(self):

        print '%s 喜欢跑步' % self.name

        self.weight -= 0.5

    def eat_inc(self):

        print '%s 喜欢吃东西' % self.name

        self.weight += 1

 

# 创建类对象lily

lily = Person('lily', 75)

lily.run_dec()

lily.eat_inc()

print lily

 

# 创建类对象tom

tom = Person('tom', 45)

tom.run_dec()

tom.eat_inc()

print tom

执行结果:

 

实例:

1.摆放家具

需求:

1.房子有户型,总面积和家具名称列表

    新房子没有任何家具

2.家具有名字和占地面积,其中

      床:占4平方米

    衣柜:占2平方米

    餐桌:占1.5平方米

3.将以上三件家具添加到房子中

4.打印房子时,要求输出:户型,总面积,剩余面积,家具名称列表

 

代码:

# 定义家具类

class Further():

    # 初始化方法定义属性

    def __init__(self, name, area):

        self.name = name

        self.area = area

    def __str__(self):

        return '%s 占地面积为 %.2f' % (self.name, self.area)

# 创建家具对象

bed = Further('bed', 5)

chest = Further('chest', 3)

desk = Further('desk', 4)

 

# 定义房子类

class Home():

    def __init__(self, house_type, area):

        self.house_type = house_type

        self.area = area

        # 定义剩余面积

        self.free_area = area

        # 定义家具列表

        self.item_list = []

    def __str__(self):

        return '户型:%s \n总面积:%.2f \n剩余面积%.2f: \n家具名称列表%s:'% (self.house_type, self.area, self.free_area,self.item_list)

    def add_item(self, item):

        print '要添加 %s' % item

        # 1.判断家具的面积

        if item.area > self.free_area:

            print '%s 的面积太大了,无法添加!' % item.name

        # 2.将家具的名称添加到列表中

        self.item_list.append(item.name)

        # 3. 计算剩余面积

        self.free_area -= item.area

 

# 创建房子对象

my_home = Home('两室一厅', 100)

my_home.add_item(bed)

my_home.add_item(chest)

my_home.add_item(desk)

print my_home

执行结果:

 

2.士兵开枪

需求:

1.士兵瑞恩有一把AK47

2.士兵可以开火

3.枪能够发射子弹

4.枪能够装填子弹

 

代码:

class Gun():

    def __init__(self,model):

        # 枪的型号

        self.model = model

        # 子弹的数量

        self.buttet_count = 0

    def add_buttet(self,count):

        self.buttet_count += count

    def shoot(self):

        # 1.判断子弹的数量

        if self.buttet_count <= 0:

            print '%s没有子弹了'%self.model

            return

        # 2.发射子弹

        self.buttet_count -= 1

        # 3.提示发射信息

        print '%s突突突%d' %(self.model,self.buttet_count)

class Soldier():

        def __init__(self,name):

                self.name = name

                self.gun = None

        def fire(self):

            # 1.判断士兵有没有枪

            if self.gun == None:

                print '%s没有枪!!!'%self.name

            # 2.高喊口号

            print 'go!!!!%s' %self.name

            # 3.让枪装填子弹

            self.gun.add_buttet(50)

            # 4.发射子弹

            self.gun.shoot()

# 1.创建枪对象

ak47 = Gun('Ak47')

# 2.创建士兵

ryan = Soldier('Ryan')

ryan.gun = ak47

ryan.fire()

print ryan.gun

执行结果:

 2.继承

(1)单继承:

       1.继承的概念:

子类拥有父类的所有方法和属性,只需要封装自己特有的属性和方法

       2.语法格式:

class 类名(父类):

    def 子类特有的方法和属性

 

代码:

class Animal():

    def eat(self):

        print '吃'

    def drink(self):

        print '喝'

    def run(self):

        print '跑'

    def sleep(self):

        print '睡'

# 继承

class Cat(Animal):

    # 子类特有的方法

    def call(self):

        print '喵喵'

 

fentiao= Cat()

#子类拥有父类的所有属性和方法

fentiao.eat()

fentiao.drink()

fentiao.run()

fentiao.sleep()

fentiao.call()

#子类继承自父类,可以直接享受父类中已经封装好的方法

#子类中应该根据自己的职责,封装子类特有的属性和方法

执行结果:

 

      3.继承的传递性:(爷爷,父亲,儿子)

C类从B类继承,B类从A类继承

那么C类具有A类和B类的所有方法和属性

 

代码:

class Animal():

    def eat(self):

        print '吃'

    def drink(self):

        print '喝'

    def run(self):

        print '跑'

    def sleep(self):

        print '睡'

 

# 继承Animal类

class Cat(Animal):

    # 子类拥有父类的所有属性和方法

    def call(self):

        print '喵喵'

 

# 继承Cat类

class Hollekitty(Cat):

    def speak(self):

        print '我可以说日语'

 

kt = Hollekitty()

# 由继承的传递性知Hollekitty类具有Cat类和Animal类的所有方法和属性

kt.speak()

kt.call()

kt.eat()

kt.drink()

kt.run()

kt.sleep()

执行结果:

(3)多继承:

子类拥有多个父类,并且具有所有父类的属性和方法

例如:孩子会继承自己父亲和母亲的特性

语法格式:

class 子类名(父类名1,父类名2...)

 

代码1:

class A():

    def test(self):

        print 'test'

class B():

    def kisk(self):

        print 'kisk'

# 多继承可以让子类对象,同时具有多个父类的属性和方法

class C(A, B):

    pass

c = C()

c.test()

c.kisk()

执行结果:

 

代码2:

class A():

    def test(self):

        print 'test'

    def kisk(self):

        print 'A---kisk'

 

class B():

    def kisk(self):

        print 'B---kisk'

 

# 继承的两个父类具有相同的方法按照继承顺序进行继承

class C(B, A):

    pass

 

c = C()

c.test()

# 当父类A与父类B拥有同名的方法时

# 调用子类的此方法时,会执行放在前边的父类

c.kisk()

执行结果:

(4)重写父类有两种情况:

  1.覆盖父类的方法

使用情景:

如果在开发中,父类的方法的实现和子类的方法的实现完全不同

就可以使用覆盖的方法在子类中重写父类的方法

具体实现方式:

在子类中定义一个和父类同名的方法,并且实现重写之后

在运行时,只会调用子类的重写方法,而不会调用父类的重写方法

 

代码:

class Animal():

    def eat(self):

        print '吃'

    def drink(self):

        print '喝'

    def run(self):

        print '跑'

    def sleep(self):

        print '睡'

class Cat(Animal):

    # 子类拥有父类的所有属性和方法

    def call(self):

        print '喵喵'

class Hollekitty(Cat):

    def speak(self):

        print '我可以说日语'

    # 覆盖父类的方法

    def call(self):

        print '欧哈哟,空尼其瓦'

 

kt = Hollekitty()

kt.call()

执行结果:

 

2.扩展父类的方法

具体实现方式:

(1)在子类中重写父类的方法(方法名要相同)

(2)在需要的位置使用 父类名.方法名(self) 来调用父类原有的方法

(3)在其他的位置针对子类的需求,编写子类特有的属性和方法

 

代码:

class Animal():

    def eat(self):

        print '吃'

    def drink(self):

        print '喝'

    def run(self):

        print '跑'

    def sleep(self):

        print '睡'

class Cat(Animal):

    def call(self):

        print '喵喵'

class Hollekitty(Cat):

    # 子类特有的方法

    def speak(self):

        print '我可以说日语'

    def call(self):

        print '欧哈哟,空尼其瓦'

        # 调用原本在父类中封装的方法

        Cat.call(self)

        # 子类特有的功能

        print '#@!$%'

kt = Hollekitty()

kt.call()

执行结果:

 

 

覆盖与扩展的实例

 

代码:

class Bird():

    def __init__(self):

        self.hungry = True

    def eat(self):

        if self.hungry:

            print 'Enenenen....'

            self.hungry = False

        else:

            print 'No Thanks'

 

class SongBird(Bird):

    def __init__(self):

        self.sound = 'Squawk'

        # 调用Bird类原有的属性

        Bird.__init__(self)

    # 子类特有的方法

    def sing(self):

        print self.sound

 

bird = Bird()

bird.eat()

 

littlebird = SongBird()

littlebird.eat()

littlebird.sing()

执行结果:

 

 3.多态

 不同的子类对象调用相同的方法,产生不同的执行结果

 

代码:

class Dog(object):

    def __init__(self, name):

        self.name = name

    def play(self):

        print '%s 蹦蹦跳跳的玩耍' % self.name

# 继承

class Xiaotianquan(Dog):

    def play(self):

        print '%s 飞到天上玩耍' % self.name

# 定义一个人类,让人和狗一起玩耍

class Person(object):

    def __init__(self, name):

        self.name = name

    def person_with_dog(self, dog):  # dog为形参

        print '%s 和 %s 一起开心的玩耍' % (self.name, dog.name)

        dog.play()

# wangcai = Dog('旺财')

wangcai = Xiaotianquan('旺财')

xiaohua = Person('小花')

# wangcai 与 wangcai = Xiaotianquan('旺财') 联系

xiaohua.person_with_dog(wangcai)

执行结果:

2.私有属性和私有方法

应用场景:

    在实际开发中,对象的某些属性或方法只希望在对象内部使用,而不希望在对象外部使用

    私有属性就是对象不希望公开的属性;私有方法就是方法不希望公开的方法

定义方法:

    在定义属性或方法时,在属性或方法前面加两个下划线,定义的就是私有属性和私有方法

 

代码:

class Women():

    def __init__(self, name):

        self.name = name

        self.__age = 18

    def __secret(self):

        print '%s 的年龄是 %d' % (self.name, self.__age)

 

# 创建对象

lily = Women('lily')

# 在外界,无法直接访问私有属性

print lily.age

# 在外界,无法直接访问私有方法

lily.secret()

# 程序会报错无法访问

执行结果:

 

3.父类的私有属性和私有方法

私有属性:私有属性是对象的隐私,不对外公开,外界以及子类都不能直接访问

私有方法:私有方法常用做一些内部的事情

注意:

1.子类对象不能在自己的方法内部,直接访问父类的私有属性和私有方法

2.子类对象不能在外部直接访问父类的私有属性和私有方法

解决方案:

子类对象可以通过父类的公有方法间接访问到私有属性和私有方法

 

代码:

class A(object):

    def __init__(self):

        self.num1 = 1

        # 初始化方法创建私有属性

        self.__num2 = 2

 

    # 创建私有方法

    def __test(self):

        print '私有方法 %d %d' % (self.num1,self.__num2)

 

    # 要想使子类访问到父类的私有属性和私有方法

    # 需要创建一个公有方法

    def test(self):

        # 访问私有属性

        print '%d' % self.__num2

        # 访问私有方法

        self.__test()

class B(A):

    def demo(self):

        # 在子类的方法中,不能访问父类的私有属性

        print '访问父类的私有属性 %d'% self.__num2

        # 在子类的方法中,不能访问父类的私有方法

        self.__test()

 

#创建子类对象

b = B()

print b

# 无法访问父类的私有属性

# print b.__num2

# 无法调用父类的私有方法

# b.test

b.test()

执行结果:

 

4.类的结构:

实例:

1.使用面向对象开发,第一步是设计类

2.使用类名()创建对象,创建对象的动作有两步

    1.在内存中为对象分配空间

    2.调用__init__初始化方法为对象初始化

3.对象创建后,内存中就有了一个对象的实实在在的存在--->实例

因此:

1.创建出来的对象叫做类的实例

2.创建对象的动作叫做实例化

3.对象的属性叫做实例属性

4.对象调用的方法叫做实例方法

在程序执行时:

1.对象各自调用自己的实例属性

2.调用对象的方法,可以通过self

             访问自己的属性

             调用自己的方法

结论:

1.每一个对象有自己独立的内存空间,保存各自不同的属性

2.多个对象的方法,在内存中只有一份,在调用方法时,需要把对象的传递到方法内部

 

(1)类属性

 类是一个特殊的对象

python中的所有对象

      class A:  定义的类属性属于类对象

      obj1 = A: 属于实例对象

在运行程序时,类同样会被加载到内存,在python中,类是一个特殊的对象 -- 类对象

除了封装 实例(对象)的属性和方法外,类对象还可以有自己的属性

通过 类名.属性名/方法名 的方式直接访问类的属性或者方法

 

代码:

"""使用附值语句定义类属性,记录所有工具的数量"""

class Tool(object):

    count = 0                   # count 为 类属性

    def __init__(self, name):

        self.name = name        # name 为 实例属性

        # 计数

        Tool.count += 1

# 创建工具对象时,会自动调用初始化方法

# 故创建一个工具便会自加1,达到计数的目的

tool1 = Tool('斧头')

tool2 = Tool('榔头')

tool3 = Tool('梯子')

# 输出工具对象的数目

# 必须是 类名.属性名

print Tool.count

执行结果:

 

(2)类方法

类属性就是针对类对象定义的方法

在类方法内部就可以直接访问类属性或者调用其他类方法

语法结构:

@classmethod

def 类方法名(cls):

    pass

 

通过类名.类方法名 来调用

 

代码:

"""   利用类方法,记录所有玩具的数量  """

class Toy(object):

    count = 0

    # 类方法

    @classmethod

    def show_toy_count(cls):

        # 在类方法的内部,访问当前的类属性

        print '玩具对象的数量为: %d' % cls.count

    def __init__(self, name):

        self.name = name

        Toy.count += 1

# 创建类对象

toy1 = Toy('乐高')

toy2 = Toy('小珠佩琦')

toy3 = Toy('叮当猫')

# 在方法的内部,可以直接访问类属性

# 调用 类对象

Toy.show_toy_count()

执行结果:

 

(3)静态方法

在开发时,如果需要在类中封装一个方法,这个方法既不需要访问实例属性或者调用实例方法

也不要需要访问类属性或者调用类方法,此时便可以把这个方法封装成一个静态方法

语法结构:

@staticmethod

    def 静态方法名():

    pass

静态方法需要修饰器@staticmethod来标识,告诉解释器这是一个静态方法

通过类名.静态方法名 来调用

 

代码:

class Cat(object):

    # 静态方法不需要传递参数self

    @staticmethod

    def call():

        print '小猫喵喵叫~'

# 通过类名.静态方法名 调用

# 不需要创建对象,可以直接使用

Cat.call()

执行结果:

实例:

需求

1.设计一个Game类

(1)属性:

记录游戏的历史最高分(类属性,因为它只与游戏类有关,而与游戏对象无关)

记录当前游戏玩家的玩家姓名(实例属性)

(2)方法:

显示游戏帮助信息(静态方法)

显示历史最高分(类方法)

开始当前玩家的游戏(实例方法)

2.主程序

查看那帮助信息

查看历史最高分

创建游戏对象,开始游戏

 

代码:

class Game(object):

    # 类属性

    top_scorce = 103

    # 实例属性

    def __init__(self,name):

        self.name = name

    # 静态方法

    @staticmethod

    def show_help():

        print '帮助手册'

    # 类方法

    @classmethod

    def show_top_scorce(cls):

        print '历史最高分为: %d ' % cls.top_scorce

    # 实例方法

    def start_game(self):

        print '%s 开始游戏!' % self.name

# 查看游戏帮助信息

Game.show_help()

# 查看历史最高分

Game.show_top_scorce()

# 创建类对象,开始游戏

lily = Game('lily')

lily.start_game()

执行结果:

 

案例小结:

1.实例方法:方法内部需要访问实例属性

2.类方法:  方法内部只需要访问类属性

3.静态方法:方法内部不需要访问实例属性和类属性

如果方法内部,既要访问实例属性,又要访问类属性,应该定义实例方法

 

 

5.设计模型

需求:模拟播放器 一个播放器同一时刻只能播放一首歌曲!

 

代码1:(不会自动执行初始化)

class MusicPlayer(object):

    # 在创建对象时,new方法会自动被调用,new方法为对象分配内存空间

    # 重写new方法(覆盖)

    def __new__(cls, *args, **kwargs):

        # cls 表示哪一个类调用就传递哪一个类

        # *args 表示多值参数

        # **kwargs 表示多值的字典参数

        print '创建对象,分配空间'

    # 创建对象时 会自动执行初始化方法

    # 实际上 在创建对象时 执行初始化之前会

    # 自动执行原本的new方法对象分配内存空间

    def __init__(self):

        print '播放器初始化'

player = MusicPlayer()

print player

""" 以覆盖的形式重写new方法后,创建类对象时便不会给它分配内存空间,

    故此时便无法自动执行初始化方法"""

执行结果:

 

 

代码2:(可以自动执行初始化,但会因对象不同,而使其分配的内存地址不同)

class MusicPlayer(object):

    # 扩充new方法

    def __new__(cls, *args, **kwargs):

        # 1.创建对象 new方法会自动被调用

        print '创建对象,分配空间'

        # 2.为对象分配空间

        # 调用object基类原本的new方法,并将其赋值给instance

        instance = object.__new__(cls)

        # 3. 返回对象引用(地址)

        return instance

    def __init__(self):

        print '播放器初始化'

player1 = MusicPlayer()

print player1

player2 = MusicPlayer()

print player2

""" 以扩充的方式重写new方法,创建类对象时便不会影响自动执行初始化方法"""

执行结果:

 

代码3:(虽对象不同但分配的内存地址仍然相同,但初始化会执行两次)

class MusicPlayer(object):

    instance = None

    # 创建对象时 new方法会自动被调用

    def __new__(cls, *args, **kwargs):

        if cls.instance is None:

            cls.instance = object.__new__(cls)

        return cls.instance

    def __init__(self):

        print '播放器初始化'

player1 = MusicPlayer()

print player1

player2 = MusicPlayer()

print player2

执行结果:

 

 

代码4:(初始化只执行1次)

class MusicPlayer(object):

    instance = None

    init_flag = False

 

    # 创建对象 new方法会自动被调用

    def __new__(cls, *args, **kwargs):

        if cls.instance is None:

            cls.instance = object.__new__(cls)

        return cls.instan

    def __init__(self):

        if MusicPlayer.init_flag:

            return

        print '播放器初始化'

        MusicPlayer.init_flag = True

player1 = MusicPlayer()

print player1

player2 = MusicPlayer()

print player2

执行结果:

猜你喜欢

转载自blog.csdn.net/love_sunshine_999/article/details/81169335