@yanglt7
2018-12-03T07:03:48.000000Z
字数 4162
阅读 600
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)==int
True
>>> type('abc')==type('123')
True
>>> type('abc')==str
True
>>> type('abc')==type(123)
False
判断基本数据类型可以直接写 int,str 等,但如果要判断一个对象是否是函数怎么办?可以使用 types 模块中定义的常量:
>>> import types
>>> def fn():
... pass
...
>>> type(fn)==types.FunctionType
True
>>> type(abs)==types.BuiltinFunctionType
True
>>> type(lambda x:x)==types.LambdaType
True
>>> type((x for x in range(10)))==types.GeneratorType
True
对于 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.x
9
>>> hasattr(obj,'y')
False
>>> setattr(obj,'y',19)
>>> hasattr(obj,'y')
True
>>> getattr(obj,'y')
19
>>> obj.y
19
>>> 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