类与对象
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()