目录
一、鸭子类型和多态
看到一只鸟走起来像鸭子,游泳起来像鸭子,叫起来也像鸭子,那么这只鸟就可以被称为鸭子。
class Cat(object):
def say(self):
print("i am a cat")
class Dog(object):
def say(self):
print("i am a fish")
class Duck(object):
def say(self):
print("i am a duck")
animal_list = [Cat, Dog, Duck]
for animal in animal_list: # 每个类中有同样的方法,可以同时调用,就是鸭子类型的用法
animal().say()
天然支持多态。
二、抽象基类(abc模块)
1、在抽象基类中实现某些方法,继承的类必须重载这些方法。
2、抽象基类无法实例化。
import abc
class CacheBase(metaclass=abc.ABCMeta):
@abc.abstractmethod # 抽象方法,继承后必须实现
def get(self, key):
pass
@abc.abstractmethod
def set(self, key, value):
pass
class RedisCache(CacheBase):
def set(self, key, value):
pass
redis_cache = RedisCache()
三、isinstance和type的区别
尽量使用isinstance
class A:
pass
class B(A):
pass
b = B()
print(isinstance(b, B)) #True
print(isinstance(b, A)) #True
print(type(b) is B) #True
print(type(b) is A) #False
四、类变量和实例变量
class A:
aa = 1
def __init__(self, x, y):
self.x = x
self.y = y
a = A(2, 3)
A.aa = 11 #类变量
a.aa = 100 #实例变量
print(a.x, a.y, a.aa) # 2 3 100
print(A.aa) # 11
五、类和实例属性的查找顺序:__mro__
#新式类
class D:
pass
class E:
pass
class C(E):
pass
class B(D):
pass
class A(B, C):
pass
print(A.__mro__)
>>>(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.D'>,
<class '__main__.C'>, <class '__main__.E'>, <class 'object'>)
六、 静态方法、类方法以及对象方法
classmethod。 : 定义操作类, 而不是操作实例的方法。 classmethod 改变了调用方法的方式, 因此类方法的第一个参数是类本身, 而不是实例。 classmethod 最常见的用途是定义备选构造方法。
staticmethod: 装饰器也会改变方法的调用方式, 但是第一个参数不是特殊的值。 其实, 静态方法就是普通的函数, 只是碰巧在类的定义体中, 而不是在模块层定义。
class Demo(object):
@classmethod
def klassmeth(*args):
return args
@staticmethod
def statmeth(*args):
return args
print(Demo.klassmeth()) #返回全部位置参数
print(Demo.klassmeth('spam')) #不管怎样调用类方法装饰器装饰过的方法,第一个参数始终是类本身
print(Demo.statmeth()) #静态方法装饰器装饰后与普通函数类似
print(Demo.statmeth('spam'))
classmethod装饰器非常有用,staticmethod装饰器并非必须使用,也可以在模块中定义函数。
七、数据封装和私有属性
from class_method import Date #上一个的Date类
class User:
def __init__(self, birthday):
self.__birthday = birthday #私有属性
def get_age(self):
#返回年龄
return 2019 - self.__birthday.year
if __name__ == "__main__":
user = User(Date(1998,2,9))
print(user._User__birthday) #虽然是私有的属性,但是也可以通过 对象._类__属性 获得属性,并不是绝对安全的
print(user.get_age())
八、python的自省机制
在计算机编程中,自省是指这种能力:检查某些事物以确定它是什么、它知道什么以及它能做什么。自省向程序员提供了极大的灵活性和控制力。
说的更简单直白一点:自省就是面向对象的语言所写的程序在运行时,能够知道对象的类型。简单一句就是,运行时能够获知对象的类型。
Python中比较常见的自省(introspection)机制(函数用法)有: dir(),type(), hasattr(), isinstance(),__dict__,通过这些函数,我们能够在程序运行时得知对象的类型,判断对象是否存在某个属性,访问对象的属性。
九、super
super并不是调用父类的方法,而是按照__mro__方法的顺序调用的。
class A:
def __init__(self):
print ("A")
class B(A):
def __init__(self):
print ("B")
super().__init__()
class C(A):
def __init__(self):
print ("C")
super().__init__()
class D(B, C):
def __init__(self):
print ("D")
super().__init__()
if __name__ == "__main__":
print(D.__mro__)
d = D()
>>>(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class
'__main__.A'>, <class 'object'>)
>>>D
>>>B
>>>C
>>>A
十、with语句:上下文管理器
1、
上下文管理器对象存在的目的是管理with语句,就像迭代器的存在是为了管理for语句一样。
with语句的目的是简化try/finally模式。这种模式用于保证一段代码运行完毕后执行某项操作,即便那段代码由于异常、return语句或sys.exit()调用而中止,也会执行指定的操作。finally语句中的代码通常用于释放重要的资源,或者还原临时变更的状态。
上下文管理器协议包含__enter__和__exit__两个方法。with语句开始运行时,会在上下文管理器对象上调用__enter__方法,with语句结束运行后,会在上下文管理器对象上调用__exit__方法,以此扮演finally子句的角色。
#上下文管理器协议 class Sample: 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()
2、简化上下文管理器
contextlib中的contextmanager装饰器可以把简单的生成器函数变成上下文管理器,这样就不用创建类去实现管理器协议了。
import contextlib
@contextlib.contextmanager
def file_open(file_name):
print("file open")
yield {} # 必须是一个生成器
print("file end")
with file_open(".txt") as f_opened:
print("file processing")