深入python--类与对象

类与对象

python语言是基于鸭子类型去设计的

鸭子类型和多态

什么是鸭子类型呢?
百度的解释是这样说的,当看到一只鸟走起来像鸭子,游泳起来像鸭子,叫起来也像鸭子,那么这只鸟就可以被称为鸭子。

在python中,在每一个类中实现共同的方法名,就是多态的体现。

抽象基类(abc模块)

这里如果我们不实现get、set方法就会报错

# 如何去模拟一个抽象基类
import abc
class CacheBase(metaclass=abc.ABCMeta):
    @abc.abstractclassmethod
    def get(self, key):
        pass

    @abc.abstractclassmethod
    def set(self, key, value):
        pass

class RedisCache(CacheBase):
    def get(self, key):
        pass

    def set(self, key, value):
        pass


redis_cache = RedisCache()

类方法,静态方法与实例方法

假如我们要输出日期,但输入的是以下形式(xxx-xxx-xxx),这样我们每次都要将它切片。

class Date:
    def __init__(self, year, month, day):
        self.year = year
        self.month = month
        self.day = day

    def tomorrow(self):
        self.day += 1

    def __str__(self):
        return "{year}/{month}/{day}".format(year=self.year, month=self.month, day=self.day)


if __name__ == '__main__':
    new_day = Date(2018, 12, 31)
    new_day.tomorrow()
    print(new_day)

    # 2018-12-31
    date_str = '2018-12-31'
    year, month, day = date_str.split('-')
    new_day = Date(int(year), int(month), int(day))
    print(new_day)

我们可以使用静态方法来初始化,以解决问题

class Date:
    def __init__(self, year, month, day):
        self.year = year
        self.month = month
        self.day = day

    def tomorrow(self):
        self.day += 1

    @staticmethod
    def parse_from_string(date_str):
        year, month, day = date_str.split('-')
        return Date(int(year), int(month), int(day))

    def __str__(self):
        return "{year}/{month}/{day}".format(year=self.year, month=self.month, day=self.day)


if __name__ == '__main__':
    # 用staticmethod完成初始化
    new_day = Date.parse_from_string(date_str)

我们也可以使用类方法去完成初始化

class Date:
    def __init__(self, year, month, day):
        self.year = year
        self.month = month
        self.day = day

    def tomorrow(self):
        self.day += 1

    @classmethod
    def from_string(cls, date_str):
        year, month, day = date_str.split('-')
        return cls(int(year), int(month), int(day))

    def __str__(self):
        return "{year}/{month}/{day}".format(year=self.year, month=self.month, day=self.day)


if __name__ == '__main__':
    # 用classmethod完成初始化
    new_day = Date.from_string(date_str)
    print(new_day)

设置一个静态方法来检查输入的字符串是否合理

class Date:
    def __init__(self, year, month, day):
        self.year = year
        self.month = month
        self.day = day

    def tomorrow(self):
        self.day += 1

    @staticmethod
    def valid_str(date_str):
        year, month, day = date_str.split('-')
        if int(year) > 0 and (int(month) > 0 and int(month) <= 12) and (int(day) > 0 and int(day) <= 31):
            return True
        else:
            return False

    def __str__(self):
        return "{year}/{month}/{day}".format(year=self.year, month=self.month, day=self.day)


if __name__ == '__main__':
    print(Date.valid_str('2018-12-31'))

在类里面没有@classmethod和@staticmethod的就都是实例方法

数据封装和私有属性

这里可以直接拿到用户的生日日期

class User:
    def __init__(self, birthday):
        self.birthday = birthday

    def get_age(self):
        # 返回年龄
        return 2018 - self.birthday.year



if __name__ == '__main__':
    user = User(Date(1990, 2, 1))
    print(user.birthday)
    print(user.get_age())

但我们不希望这样,我们希望的是生日日期保密,只是能知道用户的岁数。所以就要用到python的私有属性,但python没有private关键字,它用的是双下划线开头。这样打印生日日期就会报错。

class User:
    def __init__(self, birthday):
        self.__birthday = birthday

    def get_age(self):
        # 返回年龄
        return 2018 - self.__birthday.year



if __name__ == '__main__':
    user = User(Date(1990, 2, 1))
    print(user.__birthday)
    print(user.get_age())

python对象的自省机制

通过__dict__看不到name属性,因为它不是Student类里面的,它是通过继承得来的,但调用user.name可以看到,因为python会从下往上搜索这个属性,叫做mro查找,用dir可以看到这个实例化对象的所有属性与所有的魔法方法,更加全面

class Person:
    name = 'user'

class Student(Person):
    def __init__(self, school_name):
        self.school_name = school_name


if __name__ == '__main__':
    user = Student("慕课网")

    # 通过__dict__查看属性
    print(user.__dict__)
    print(dir(user))
    print(user.name)

super调用父类

我们有时候子类继承了父类,但既需要实现子类的初始化方法,也需要实现父类的初始化方法,就需要用super

class A:
    def __init__(self):
        print("A")

class B(A):
    def __init__(self):
        print("B")
        # 这里super是调用父类的__init__方法
        super().__init__()
        # python2要使用这种写法
        # super(B, self).__init__()

from threading import Thread
class MyThread(Thread):
    def __init__(self, name, user):
        self.user = user
        # self.name = name
        # 父类的__init__方法中有name属性,直接重用
        super.__init__(name=name)

if __name__ == '__main__':
    b = B()

但实际上,super调用的也不能只是说父类的方法,更准确的说是调用python中mro查找模式的下一个类,下面这个例子输出的是:D B C A

class A:
    def __init__(self):
        print("A")

class B(A):
    def __init__(self):
        print("B")
        # 这里super是调用父类的__init__方法
        super().__init__()


class C(A):
    def __init__(self):
        print("C")
        super().__init__()


class D(B, C):
    def __init__(self):
        print("D")
        # super函数调用的是python中mro查找模式的下一个类
        super().__init__()


if __name__ == '__main__':
    print(D.__mro__)
    d = D()

上下文管理器

开始调用with语句会打印enter,结束with语句会打印exit

class Sample(object):
    def __enter__(self):
        print("enter")
        return self
    def __exit__(self, exc_type, exc_val, exc_tb):
        print("exit")
    def do_something(self):
        print("doing something")

with Sample() as sample:
    sample.do_something()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值