@yanglt7
2018-12-03T07:03:48.000000Z
字数 4162
阅读 674
Python
在 OOP 程序设计中,当我们定义一个 class 的时候,可以从某个现有的 class 继承,新的 class 称为子类(Subclass),而被继承的 class 称为基类、父类或超类(Base class、Super class)。子类可获得父类的全部功能。当然,也可以对子类增加一些方法。
>>> class Animal(object):... def run(self):... print('Animal is running...')...>>> class Dog(Animal):... pass...>>> dog=Dog()>>> dog.run()Animal is running...>>> class Dog(Animal):... def run(self):... print('Dog is running...')...>>> dog=Dog()>>> dog.run()Dog is running...
当子类和父类都存在相同的 run() 方法时,子类的 run() 覆盖了父类的 run(),在代码运行的时候,总是会调用子类的 run()。这样,我们就获得了继承的另一个好处:多态。
当我们定义一个 class 的时候,我们实际上就定义了一种数据类型。我们定义的数据类型和 Python 自带的数据类型,比如 str、list、dict 没什么两样:
a = list() # a 是 list 类型b = Animal() # b 是 Animal 类型c = Dog() # c 是 Dog 类型
判断一个变量是否是某个类型可以用 isinstance() 判断:所以,在继承关系中,如果一个实例的数据类型是某个子类,那它的数据类型也可以被看做是父类。但是,反过来就不行:
>>> isinstance(a, list)True>>> isinstance(b, Animal)True>>> isinstance(c, Dog)True>>> isinstance(c, Animal)True>>> b = Animal()>>> isinstance(b, Dog)False
要理解多态的好处,我们还需要再编写一个函数,这个函数接受一个 Animal 类型的变量:
>>> def run_twice(animal):... animal.run()... animal.run()...>>> run_twice(Animal())Animal is running...Animal is running...>>> run_twice(Dog())Dog is running...Dog is running...
再定义一个Tortoise类型,也从Animal派生:
>>> class Tortoise(Animal):... def run(self):... print('Tortoise is running slowly...')...>>> run_twice(Tortoise())Tortoise is running slowly...Tortoise is running slowly...
“开闭”原则:
对扩展开放:允许新增 Animal 子类;
对修改封闭:不需要修改依赖 Animal 类型的 run_twice() 等函数。
基本类型都可以用 type() 判断,如果一个变量指向函数或者类,也可以用 type() 判断:
>>> type(123)<class 'int'>>>> type('str')<class 'str'>>>> type(None)<class 'NoneType'>>>> type(abs)<class 'builtin_function_or_method'>>>> a=Animal()>>> type(a)<class '__main__.Animal'>
type() 函数返回对应的 Class 类型。如果我们要在 if 语句中判断,就需要比较两个变量的 type 类型是否相同:
>>> type(123)==type(456)True>>> type(123)==intTrue>>> type('abc')==type('123')True>>> type('abc')==strTrue>>> type('abc')==type(123)False
判断基本数据类型可以直接写 int,str 等,但如果要判断一个对象是否是函数怎么办?可以使用 types 模块中定义的常量:
>>> import types>>> def fn():... pass...>>> type(fn)==types.FunctionTypeTrue>>> type(abs)==types.BuiltinFunctionTypeTrue>>> type(lambda x:x)==types.LambdaTypeTrue>>> type((x for x in range(10)))==types.GeneratorTypeTrue
对于 class 的继承关系来说,使用 type() 就很不方便。我们要判断 class 的类型,可以使用 isinstance() 函数。
object -> Animal -> Dog -> Husky>>> a=Animal()>>> d=Dog()>>> h=Husky()>>> isinstance(h,Husky)True>>> isinstance(h,Dog)True>>> isinstance(h,Animal)True>>> isinstance(d,Dog) and isinstance(d,Animal)True
能用 type() 判断的基本类型也可以用 isinstance() 判断:
>>> isinstance('a',str)True>>> isinstance(123,int)True>>> isinstance(b'a',bytes)True
并且还可以判断一个变量是否是某些类型中的一种,比如下面的代码就可以判断是否是 list 或者 tuple:
>>> isinstance([1,2,3],(list,tuple))True>>> isinstance((1,2,3),(list,tuple))True
如果要获得一个对象的所有属性和方法,可以使用 dir() 函数,它返回一个包含字符串的 list,比如,获得一个 str 对象的所有属性和方法:
>>> dir('ABC')['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
配合 getattr()、setattr() 以及 hasattr(),我们可以直接操作一个对象的状态:
>>> class MyObject(object):... def __init__(self):... self.x=9... def power(self):... return self.x*self.x...>>> obj=MyObject()>>> hasattr(obj,'x')True>>> obj.x9>>> hasattr(obj,'y')False>>> setattr(obj,'y',19)>>> hasattr(obj,'y')True>>> getattr(obj,'y')19>>> obj.y19>>> getattr(obj,'z')Traceback (most recent call last):File "<stdin>", line 1, in <module>AttributeError: 'MyObject' object has no attribute 'z'>>> getattr(obj,'z',404)404>>> hasattr(obj,'power')True>>> getattr(obj,'power')<bound method MyObject.power of <__main__.MyObject object at 0x000001B3F75461D0>>>>> fn=getattr(obj,'power')>>> fn<bound method MyObject.power of <__main__.MyObject object at 0x000001B3F75461D0>>>>> fn()81