面向对象编程进阶

前言

我们在了解面向对象的入门知识,知道如何定义一个类和对象的时候,我们应该向它更深的知识进行拓展。

@property 装饰器

它的功能就是将一个隐喻的属性进行包装,该属性是设计者不希望使用者直接访问该属性,这个时候就使用装饰器@property。例如:

class Person(object):
    def __init__(self, name, age):
        self._name = name
        self._age = age

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, name):
        self._name = name

    # getter - 访问器
    @property
    def age(self):
        return self._age

    # setter - 修改器
    @age.setter
    def age(self, age):
        self._age = age if 20 < age < 60 else 30

    def watch_av(self):
        if self._age >= 18:
            print('看片')
        else:
            print('看动漫')

slots魔法

slots可以限定当前的类中的属性的个数,需要注意的是它只能限定该类的对象并不能限定其子类。例如:

class Student(object):
    #  __slots__魔法的使用
    __slots__ = ('_name', '_age')

    def __init__(self, name, age):
        self._name = name
        self._age = age

    @property   # 属性访问器
    def age(self):
        return self._age

    @age.setter  # 属性修改器
    def age(self, age):
        self._age = age if 15 < age < 25 else 20

    def watch_av(self):
        if self._age >= 18:
            print('看片')
        else:
            print('看动漫')

静态方法和类方法

所谓的静态方法就是一个方法是属于那一个类而不属于该对象,关键字@staticmethod,类方法就是对象所拥有的某些行为。

class Tr(object):

    def __init__(self, a, b, c):
        self._a = a
        self._b = b
        self._c = c

    @property
    def a(self):
        return self._a

    @property
    def b(self):
        return self._b

    @property
    def c(self):
        return self._c

    # 判断是不是三角形
    @staticmethod
    def is_tr(a, b, c):
        return a + b > c and a + c > b and b + c > a

    def perimer(self):
        return self._a + self._b + self._c

def main():
    a = 10
    b = 10
    c = 12
    if Tr.is_tr(a, b, c):
        tr = Tr(a, b, c)
        print('周长是:%d' % tr.perimer())

if __name__ == '__main__':
    main()

和在类中定义静态的方法一样,我们也可以在类中定义类关键字@classmethon 例如:

没有在类中定义类的时候:
import time


class Rectangle:

    def __init__(self, width, height):
        self._width = width
        self._height = height

    def perimeter(self):
        return (self._width + self._height) * 2

    def area(self):
        return self._height * self._width


class Clock(object):
    local_time = time.localtime()
    get_time = list(local_time)

    def __init__(self, hour=get_time[3], minute=get_time[4], second=get_time[5]):
        # 不要参数 使用系统时间  python中的time模块
        self._hour = hour
        self._minute = minute
        self._second = second

    def run(self):
        self._second += 1
        if self._second == 60:
            self._minute += 1
            self._second = 0
            if self._minute == 60:
                self._minute =0
                self._hour += 1
                if self._hour == 24:
                    self._hour =0

    def show(self):
        return '%02d:%02d:%02d' % (self._hour, self._minute, self._second)

    # 下面的方法可以获得对象的字符串表示形式
    # 当我们用print打印对象时候会自动调用该方法
    # def __str__(self):
    #     return '%02d:%02d:%02d' % (self._hour, self._minute, self._second)


def main():
    clock = Clock()
    while True:
        print(clock.show())
        clock.run()
        time.sleep(1)


if __name__ == '__main__':
    main()

使用了之后:

from time import time, localtime, sleep


class Clock(object):
    """数字时钟"""

    def __init__(self, hour=0, minute=0, second=0):
        self._hour = hour
        self._minute = minute
        self._second = second

    @classmethod
    def now(cls):
        ctime = localtime(time())
        return cls(ctime.tm_hour, ctime.tm_min, ctime.tm_sec)

    def run(self):
        """走字"""
        self._second += 1
        if self._second == 60:
            self._second = 0
            self._minute += 1
            if self._minute == 60:
                self._minute = 0
                self._hour += 1
                if self._hour == 24:
                    self._hour = 0

    def show(self):
        """显示时间"""
        return '%02d:%02d:%02d' % \
               (self._hour, self._minute, self._second)


def main():
    # 通过类方法创建对象并获取系统时间
    clock = Clock.now()
    while True:
        print(clock.show())
        sleep(1)
        clock.run()


if __name__ == '__main__':
    main()

类之间的关系有如下:

类和类之间的关系有三种:is-a, has-a, use-a
is-a : 简单说就是一个继承关系,比如学生和人类,老鼠和动物。
has-a : 是一种强关联的关系,比如汽车和轮子,4
use-a :是一种依赖关系,比如人撞墙,人使用了墙,否则无墙可撞。


20180313194509293.png

继承和多态

何为继承,就是一个类从另外的一个类中得到该类的属性和方法就称之为继承。得到属性和方法的就叫做子类,提供属性和方法的就叫做父类。子类之中除了父类之中的那些东西之外还可以添加自己需要的方法和属性。当子类继承父类的方法的时候可以重新修改该方法,这就称之为多态
继承:

# 继承-- 从已经有的类创建新类的过程
# 提供继承信息的称为父类(超类/基类)
# 得到继承信息的称为子类(派生类/衍生类)
# 通过继承我们可以将子类中的重复代码抽取到父类中
# 子类通过继承并复用这些代码来减少重复代码的编写
# 将来如果要维护子类的公共代码只需要在父类中进行操作即可
# has - a 关联关系  (人和手)
# use - a 依赖关系  (人和房子)
# is - a  继承关系  (老师和人类,学生和人类)
# 任何时候子类可以替换掉父类


class Person(object):
    """人"""

    def __init__(self, name, age):
        self._name = name
        self._age = age

    @property
    def name(self):
        return self._name

    @property
    def age(self):
        return self._age

    @age.setter
    def age(self, age):
        self._age = age

    def play(self):
        print('%s正在愉快的玩耍.' % self._name)

    def watch_av(self):
        if self._age >= 18:
            print('%s正在观看爱情动作片.' % self._name)
        else:
            print('%s只能观看《熊出没》.' % self._name)


class Student(Person):
    """学生"""

    def __init__(self, name, age, grade):
        super().__init__(name, age)
        self._grade = grade

    @property
    def grade(self):
        return self._grade

    @grade.setter
    def grade(self, grade):
        self._grade = grade

    def study(self, course):
        print('%s的%s正在学习%s.' % (self._grade, self._name, course))


class Teacher(Person):
    """老师"""

    def __init__(self, name, age, title):
        super().__init__(name, age)
        self._title = title

    @property
    def title(self):
        return self._title

    @title.setter
    def title(self, title):
        self._title = title

    def teach(self, course):
        print('%s%s正在讲%s.' % (self._name, self._title, course))


def main():
    stu = Student('王大锤', 15, '初三')
    stu.study('数学')
    stu.watch_av()
    t = Teacher('mr.l', 26, '博士')
    t.teach('人体学')
    t.watch_av()


if __name__ == '__main__':
    main()

多态:

from abc import ABCMeta, abstractmethod


class Pet(object, metaclass=ABCMeta):
    """宠物"""

    def __init__(self, nickname):
        self._nickname = nickname

    @abstractmethod
    def make_voice(self):
        """发出声音"""
        pass


class Dog(Pet):
    """狗"""

    def make_voice(self):
        print('%s: 汪汪汪...' % self._nickname)


class Cat(Pet):
    """猫"""

    def make_voice(self):
        print('%s: 喵...喵...' % self._nickname)


def main():
    pets = [Dog('旺财'), Cat('凯蒂'), Dog('大黄')]
    for pet in pets:
        pet.make_voice()


if __name__ == '__main__':
    main()

上面代码中的Pet是一个抽象类,不能直接使用它来创建一个对象,但是可以使用子类来继承它,在子类继承它的时候必须继承该抽象类的抽象方法,

综合案例

1 奥特曼打小怪兽

from random import randint


class Ultraman(object):

    __slots__ = ('_name', '_hp', '_mp')  # 限定当前这个类里面只有这三个字段

    def __init__(self, name, hp, mp):
        self._name = name
        self._hp = hp
        self._mp = mp

    @property
    def name(self):
        return self._name

    @property
    def hp(self):
        return self._hp

    @hp.setter
    def hp(self, hp):
        self._hp = hp if hp > 0 else 0

    @property
    def mp(self):
        return self._mp

    @mp.setter
    def mp(self, mp):
        self._mp = mp if mp >= 0 else 0

    def attack(self, monster):
        injury = randint(15, 25)
        monster.hp -= injury

    def huge_attack(self, monster):
        if self._mp >= 50:
            self._mp -= 50
            injury = monster.hp * 3 // 4
            injury = injury if injury >= 50 else 50
            monster.hp -= injury
        else:
            self.attack(monster)

    def magic_attack(self, monsters):
        if self.mp >= 20:
            self.mp -= 20
            for monster in monsters:
                monster.hp -= randint(10, 15)

    def __str__(self):
        return '%s奥特曼\n' % self._name + \
            '生命值: %d\n' % self._hp + \
            '魔法值: %d\n' % self._mp


class Monster(object):

    __slots__ = ('_name', '_hp')

    def __init__(self, name, hp):
        self._name = name
        self._hp = hp

    @property
    def name(self):
        return self._name

    @property
    def hp(self):
        return self._hp

    @hp.setter
    def hp(self, hp):
        self._hp = hp if hp >=0 else 0

    def attack(self, ultraman):
        injury = randint(10, 20)
        ultraman.hp -= injury

    def __str__(self):
        return '%s怪兽\n' % self.name + \
                '生命值: %d\n' % self.hp


def main():
    u = Ultraman('骆昊', 1000, 500)
    print(u)
    m1 = Monster('舒玲1', 250)
    m2 = Monster('舒玲2', 250)
    m3 = Monster('舒玲3', 250)
    ms = [m1, m2, m3]
    for val in ms:
        print(val, end=' ')
    attack_round = 1
    while u.hp > 0 and (m1.hp + m2.hp + m3.hp) > 0:
        print('====第%d回合====' % attack_round)
        a = randint(1, 10)
        b = randint(0, 2)
        if a <= 6:
            while ms[b].hp <= 0:
                b = randint(0, 2)
            u.attack(ms[b])
        elif 6 < a <= 9:
            u.magic_attack(ms)
        else:
            u.huge_attack(ms[b])
        for index in range(len(ms)):
            if ms[index].hp > 0:
                ms[index].attack(u)
        print(u)
        for val in ms:
            print(val, end=' ')
        attack_round += 1
    if u.hp > 0:
        print('%s奥 特曼胜利' % u.name)
    else:
        print('小怪兽获胜')


if __name__ == '__main__':
    main()

2 Puke

from random import randrange


class Card(object):
    """一张牌"""
    def __init__(self, suite, face):
        self._suite = suite
        self._face = face

    @property
    def face(self):
        return self._face

    @property
    def suite(self):
        return self._suite

    def __str__(self):
        if self._face == 1:
            face_str = 'A'
        elif self._face == 11:
            face_str = 'J'
        elif self._face == 12:
            face_str = 'Q'
        elif self._face == 13:
            face_str = 'K'
        else:
            face_str = str(self._face)
        return '%s%s' % (self._suite, face_str)


class Poker(object):
    """一副牌"""
    def __init__(self):
        self._cards = []
        self._current = 0
        for suite in '♠♥♦♣':
            for face in range(1, 14):
                card = Card(suite, face)
                self._cards.append(card)

    @property
    def cards(self):
        return self._cards

    def shuffle(self):
        """洗牌"""
        self._current = 0
        cards_len = len(self._cards)
        for index in range(cards_len):
            pos = randrange(cards_len)
            self._cards[index], self.cards[pos] = \
                self._cards[pos], self.cards[index]

    # 使用属性一般需要返回一个值
    @property
    def next(self):
        """发牌"""
        card = self.cards[self._current]
        self._current += 1
        return card

    @property
    def has_next(self):
        """还有没有牌"""
        return self._current < len(self._cards)


class Player(object):

    def __init__(self, name):
        self._name = name
        self._cards_on_hand = []

    @property
    def name(self):
        return self._name

    @property
    def cards_on_hand(self):
        return self._cards_on_hand

    # 得到卡片
    def get(self, card):
        self._cards_on_hand.append(card)

    # 排序
    def arrange(self):
        self._cards_on_hand.sort(key=get_key)

    # 点数计数
    @property
    def count(self):
        total = 0
        for val in self._cards_on_hand:
            total += val.face
        return total


def get_key(card):
    return card.face


def main():
    p = Poker()
    p.shuffle()
    user = Player('ljl')
    com1 = Player('c1')
    while p.has_next:
        print()
        print('玩家:%d-------电脑:%d' % (user.count, com1.count))
        if user.count > 0:
            for i in user.cards_on_hand:
                print(i, end='')
            print('-------------', end='')
            for i in com1.cards_on_hand:
                print(i, end='')
        f = input('是否还要继续游戏y or n:')
        if f == 'y':
            user.get(p.next)
            if user.count > 21:
                print('%d玩家输了' % user.count)
                return False
        if com1.count < 15:
            com1.get(p.next)
        if com1.count > 21:
            print('玩家胜利')
            return False


if __name__ == '__main__':
    main()


©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,064评论 5 466
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,606评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,011评论 0 328
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,550评论 1 269
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,465评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,919评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,428评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,075评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,208评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,185评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,191评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,914评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,482评论 3 302
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,585评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,825评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,194评论 2 344
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,703评论 2 339

推荐阅读更多精彩内容

  • 类动态绑定方法与限定实例属性 类动态绑定方法 前面我们说了如何给类动态的添加属性,那么如何动态绑定方法呢?如下示例...
    DramaScript阅读 538评论 0 0
  • 写在之前 因为简书字数限制,完整版地址:https://www.zybuluo.com/hainingwyx/no...
    hainingwyx阅读 13,846评论 0 41
  • java继承 继承的概念 继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类。 继承就是子类继...
    863cda997e42阅读 651评论 0 1
  • 面向对象笔记 一、 对象在内存中的存放方法以及被调用过程 class文件首先被加载到方法区中的class文件内容区...
    VictorBXv阅读 454评论 0 2
  • 无形之中 被束缚 下午趴在桌上 听见同事发语音 说 喜欢就不怕难坚持 是啊 若没有喜欢 请问坚持什么呢 妈妈说 你...
    林小胆阅读 379评论 0 0