目录
继承和多态
定义:
eg:?
1)在()里面直接加父类名
2)实例化一下Dog和Cat?
3)?继承的第二个好处
4)多态
获取对象信息
使用type()
基本类型
一个变量指向函数或者类
判断是否相同类型?
使用isinstance()
使用dir()?
eg:
实例属性和类属性
练习
继承和多态
定义:
在OOP程序设计中,当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类、父类或超类(Base class、Super class)
eg:?
??Animal 的class,Dog 和Cat 类时,就可以直接从Animal 类继承:
1)在()里面直接加父类名
class Animal(object):
def run(self):
print('Animal is running...')
class Dog(Animal):
pass
class Cat(Animal):
pass
2)实例化一下Dog和Cat?
3)?继承的第二个好处
需要我们对代码做一点改进。你看到了,无论是Dog 还是Cat ,它们run() 的时候,显示的都是Animal is running... ,符合逻辑的做法是分别显示Dog is running... 和Cat is running... ,因此,对Dog 和Cat 类改进如下:(引出多态)
class Animal(object):
def run(self):
print('Animal is running...')
class Dog(Animal):
def run(self):
print('Dog is running...')
class Cat(Animal):
def run(self):
print('Cat is running...')
dog = Dog()
dog.run()
cat = Cat()
cat.run()
4)多态
我们就获得了继承的另一个好处:多态。?
当子类和父类都存在相同的run() 方法时,我们说,子类的run() 覆盖了父类的run() ,在代码运行的时候,总是会调用子类的run() 。
获取对象信息
使用type()
基本类型
>>> type(123)
<class 'int'>
>>> type('str')
<class 'str'>
>>> type(None)
<type(None) 'NoneType'>
一个变量指向函数或者类
>>> type(abs)
<class 'builtin_function_or_method'>
>>> type(a)
<class '__main__.Animal'>
判断是否相同类型?
>>> type(123)==type(456)
True
>>> type(123)==int
True
>>> type('abc')==type('123')
True
>>> type('abc')==str
True
>>> type('abc')==type(123)
False
>>> 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
使用isinstance()
对于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
>>> isinstance(d, Husky)
False
?我们总是优先使用isinstance()判断类型,可以将指定类型及其子类都包含。
使用dir()?
如果要获得一个对象的所有属性和方法,可以使用dir() 函数,
它返回一个包含字符串的list
eg:
比如,获得一个str对象的所有属性和方法:
>>> dir('ABC')
['__add__', '__class__',..., '__subclasshook__', 'capitalize', 'casefold',..., 'zfill']
问题来了:这些__xxx__是什么来的??
?类似__xxx__ 的属性和方法在Python中都是有特殊用途的,
比如__len__ 方法返回长度。在Python中,如果你调用len() 函数试图获取一个对象的长度,实际上,在len() 函数内部(__len__就是等价于len() )
?剩下的都是普通属性或方法,比如lower()
>>> 'ABC'.lower()
'abc'
仅仅把属性和方法列出来是不够的,配合获取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') # 有属性'x'吗?
True
>>> obj.x
9
>>> hasattr(obj, 'y') # 有属性'y'吗?
False
>>> setattr(obj, 'y', 19) # 设置一个属性'y'
>>> hasattr(obj, 'y') # 有属性'y'吗?
True
>>> getattr(obj, 'y') # 获取属性'y'
19
>>> obj.y # 获取属性'y'
19
如果试图获取不存在的属性,会抛出AttributeError的错误:
>>> getattr(obj, 'z') # 获取属性'z'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'MyObject' object has no attribute 'z'
可以传入一个default参数,如果属性不存在,就返回默认值:
>>> getattr(obj, 'z', 404) # 获取属性'z',如果不存在,返回默认值404
404
实例属性和类属性
由于Python是动态语言,根据类创建的实例可以任意绑定属性。
给实例绑定属性的方法是通过实例变量,或者通过self 变量:
class Student(object):
def __init__(self, name):
self.name = name
s = Student('Bob')
s.score = 90
?但是,如果Student类本身需要绑定一个属性呢?可以直接在class中定义属性,这种属性是类属性,归Student类所有:
class Student(object):
name = 'Student'
完整代码:
相当于默认名为Student
>>> class Student(object):
... name = 'Student'
...
>>> s = Student() # 创建实例s
>>> print(s.name) # 打印name属性,因为实例并没有name属性,所以会继续查找class的name属性
Student
>>> print(Student.name) # 打印类的name属性
Student
>>> s.name = 'Michael' # 给实例绑定name属性
>>> print(s.name) # 由于实例属性优先级比类属性高,因此,它会屏蔽掉类的name属性
Michael
>>> print(Student.name) # 但是类属性并未消失,用Student.name仍然可以访问
Student
>>> del s.name # 如果删除实例的name属性
>>> print(s.name) # 再次调用s.name,由于实例的name属性没有找到,类的name属性就显示出来了
Student
练习
为了统计学生人数,可以给Student类增加一个类属性,每创建一个实例,该属性自动增加:
class Student(object):
count = 0
def __init__(self, name):
self.name = name
self.__set_count()
def __set_count(self):
Student.count += 1
if Student.count != 0:
print('测试失败!')
else:
bart = Student('Bart')
if Student.count != 1:
print('测试失败!')
else:
lisa = Student('Bart')
if Student.count != 2:
print('测试失败!')
else:
print('Students:', Student.count)
print('测试通过!')
?
|