Python007

学习总结七

面向对象进阶

@property属性装饰器

关于Python中属性和方法访问权限的问题,虽然我们不建议将属性设置为私有的,但是如果直接将属性暴露给外界也是有问题的,比如我们没有办法检查赋给属性的值是否有效。我们之前的建议是将属性命名以单下划线开头,通过这种方式来暗示属性是受保护的,不建议外界直接访问,那么如果想访问属性可以通过属性的getter(访问器)和setter(修改器)方法进行对应的操作。如果要做到这点,就可以考虑使用@property包装器来包装getter和setter方法,使得对属性的访问既安全又方便,代码如下练习所示

@—.setter属性修改器
练习1
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' % (self._name, course))

    # 方法重写(override)
    # 子类在继承父类方法之后,对方法进行了重新实现
    # 当我们给子类对象发送watch_av消息时执行的是子类重写过的方法
    def watch_av(self):
        print('%s正在和苍老师学习技术' % self._name)


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():
    stu1 = Student('王大锤', 16, 5)
    stu1.study('HTML网页设计')
    stu1.watch_av()
    teacher1 = Teacher('骆昊', 30, '叫兽')
    teacher1.teach('python')
    teacher1.watch_av()


if __name__ == '__main__':
    main()
slots魔法

Python是一门动态语言。通常,动态语言允许我们在程序运行时给对象绑定新的属性或方法,当然也可以对已经绑定的属性和方法进行解绑定。但是如果我们需要限定自定义类型的对象只能绑定某些属性,可以通过在类中定义slots变量来进行限定。需要注意的是slots的限定只对当前类的对象生效,对子类并不起任何作用。
通过slots魔法限定对象可以绑定的成员变量

练习2

分数计算

from math import gcd


class Fraction(object):

    def __init__(self, num, den):
        if den == 0:
            raise ValueError('分母不能为0!')  # 分母为0直接报错 raise - 引发
        self._num = num
        self._den = den

    def simplify(self):    # 化简分子分母
        if self._num != 0 and self._den != 1:
            factor = gcd(abs(self._num), abs(self._den))   # abs表示绝对值,gcd表示求最大公约数
            if factor > 1:    # 对分子分母进行约分
                self._num //= factor
                self._den //= factor

    def normalize(self):   # 分数正规化(处理负号的问题)
        if self._den < 0:
            self._num = - self._num
            self._den = - self._den
            self.simplify()

    def __str__(self):
        if self._num == 0:
            return '0'       # 分子为0 ,直接输出0(字符串)
        elif self._den == 1:
            return str(self._num)        # 分母为1,直接输出分子(字符串)
        else:
            return '%d/%d' % (self._num, self._den)

    @property
    def num(self):
        return self._num

    @property
    def den(self):
        return self._den

    def add(self, other):
        # 加法运算
        return Fraction(self._num * other.den + self._den * other.num, self._den * other.den)

    def __add__(self, other):     # 运算符重载(后面调用函数,可以直接运用符号进行运算)
        return self.add(other)

    def sub(self, other):
        # 减法运算
        return Fraction(self._num * other.den - self._den * other.num, self._den * other.den)

    def __sub__(self, other):
        return self.sub(other)

    def mul(self, other):
        # 乘法运算
        return Fraction(self._num * other.num, self._den * other.den)

    def __mul__(self, other):
        return self.mul(other)

    def div(self, other):
        # 除法运算
        return Fraction(self._num * other.den, self._den * other.num)

    def __truediv__(self, other):
        return self.div(other)


def main():
    f1 = Fraction(1, 2)
    f2 = Fraction(1, 3)
    print(f1.add(f2))
    print(f1 + f2)
    print(f1 - f2)
    print(f1 * f2)
    print(f1.div(f2))
    print(f1 / f2)


if __name__ == '__main__':
    main()

抽象类

抽象类就是不能够创建对象的类,这种类的存在就是专门为了让其他类去继承它。Python从语法层面并没有像Java或C#那样提供对抽象类的支持,但是我们可以通过abc模块的ABCMeta元类和abstractmethod包装器来达到抽象类的效果,如果一个类中存在抽象方法那么这个类就不能够实例化(创建对象)。上面的代码中,Dog和Cat两个子类分别对Pet类中的make_voice抽象方法进行了重写并给出了不同的实现版本,当我们在main函数中调用该方法时,这个方法就表现出了多态行为(同样的方法做了不同的事情)

练习3
from abc import ABCMeta, abstractmethod


class Employee(object): # 定义员工(父类)

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

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

    @abstractmethod  # abstractmethod可以规定后面子类必须重写方法
    def get_salary(self):
        pass
    # 定义方法。提醒子类需要实现重写方法


class Manager(Employee):

     def get_salary(self):
         return 15000


class Programmer(Employee):

    def __init__(self, name):
        super().__init__(name)
        self._working_hour = 0

    @property
    def working_hour(self):
        return self._working_hour

    @working_hour.setter
    def working_hour(self, working_hour):
        self._working_hour = working_hour if working_hour > 0 else 0

    def get_salary(self):
        return 150 * self._working_hour


class Salesman(Employee):
    def __init__(self, name):
        super().__init__(name)
        self._sales = 0

    @property
    def sales(self):
        return self._sales

    @sales.setter
    def sales(self, sales):
        self._sales = sales if sales > 0 else 0

    def get_salary(self):
        return 1200 + self._sales * 0.05


def main():
    # 抽象类不能创建对象
    emps = [Manager('刘备'), Programmer('诸葛亮'), Salesman('吕布')]
    for emp in emps:

        # isinstange 表示判断是什么对象

        if isinstance(emp, Programmer):
            emp.working_hour = int(input('请输入%s本月工作时间:' % emp.name))
        elif isinstance(emp, Salesman):
            emp.sales = int(input('请输入%s本月销售额:' % emp.name))

        # 同样是接受get_salary这个消息,但是不同的员工表现出不同的行为
        # 因为三个子类都重写了get_salary方法,所以此处有多态行为

        print('%s本月工资为:¥%.2f元' %(emp.name, emp.get_salary()))


if __name__ == '__main__':
    main()
练习4

银行账号存钱取钱转账

class Account(object):
    def __init__(self, card_number, owner, balance=0):
        self._card_number = card_number
        self._owner = owner
        self._balance = balance

    @property
    def balance(self):
        return self._balance

    def deposit(self, money):  # 存钱
        if money > 0:
            self._balance += money
            return True
        return False

    def withdraw(self, money):  # 取钱
        if 0 < money <= self._balance:
            self._balance -= money
            return True
        return False

    def transfer(self, other, money):  # 转账
        if self.withdraw(money):   # 从一个账户中取钱,直接调用前面的行为
            other.deposit(money)   # 向另一个账户中存钱,直接调用前面行为
            return True
        return False


def main():
    account = Account('11223344', '王大锤')
    print(account.balance)
    account.deposit(1000)
    print(account.balance)

    if account.withdraw(5000):
        print(account.balance)
    else:
        print('余额不足!')

    account2 = Account('11223355', '王小锤', balance=100)

    if account.transfer(account2, 800):
        print(account.balance)
        print(account2.balance)
    else:
        print('转账失败!')


if __name__ == '__main__':
    main()
练习5

21点扑克游戏(完成发牌)

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(13):
                card = Card(suite, face + 1)
                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)


def get_key(card):
    return card.face


def main():
    p = Poker()
    p.shuffle()   # 洗牌
    players = [Player('a'), Player('b'), Player('c'), Player('d')]
    while p.has_next:
    # for _ in range(13):
        for player in players:
            player.get(p.next)  # 发牌
    for player in players:
        print(player.name + ':', end=' ')
        player.arrange()   # 排序
        for card in player.cards_on_hand:
            print(card, end=' ')
        print()


if __name__ == '__main__':
    main()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值