三大特性:封装、继承和多态
OOP 把对象作为程序的基本单元,一个对象包含了数据和
操作数据的函数(方法)。
类是抽象的模板;实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可能不同。
class Student(object):
# 第一个参数self表示创建的实例本身,该函数用于初始化,构造函数
def __init__(self, name, score):
self.name = name
self.score = score
pass
bart = Student('Bart Simpson', 59)
print(bart.name)
print(bart.score)
可以在类的方法定义时访问数据的函数。
class Student(object):
# 第一个参数self表示创建的实例本身,该函数用于初始化,构造函数
def __init__(self, name, score):
self.name = name
self.score = score
def print_score(self):
print('%s: %s' % (self.name, self.score))
def get_grade(self):
if self.score >= 90:
return 'A'
elif self.score >= 60:
return 'B'
else:
return 'C'
bart = Student('Bart Simpson', 59)
bart.print_score()
print(bart.get_grade())
输出结果
Bart Simpson: 59
C
为了让变量只有内部可以访问,外部不能访问,可以把属性的名称前加上两个下划线__==》私有变量(private)
==》代码更加健壮
==》要获取,则添加新的方法:
class Student(object):
# 第一个参数self表示创建的实例本身,该函数用于初始化,构造函数
def __init__(self, name, score):
self.__name = name
self.__score = score
def print_score(self):
print('%s: %s' % (self.__name, self.__score))
# 用于获取name数据
def get_name(self):
return self.__name
def get_score(self):
return self.__score
# 用于设置score数据,可以对参数做检查,避免传入无效的参数
def set_score(self, score):
if 0 <= score <= 100:
self.__score = score
else:
raise ValueError('bad score')
def get_grade(self):
if self.__score >= 90:
return 'A'
elif self.__score >= 60:
return 'B'
else:
return 'C'
从某个现有的 class 继承,新的 class 称为子类( Subclass),而被继承的 class 称为基类、父类或超类( Base class、 Super class)。
==》
# object是所有类的父类,若定义的类没有其他父类,则父类为object
class Animal(object):
def run(self):
print('Animal is running...')
class Dog(Animal):
def run(self): # 子类的 run()覆盖了父类的 run()
print('Dog is running...')
def eat(self):
print('Eating meat...')
class Cat(Animal):
def run(self):
print('Cat is running...')
class Tortoise(Animal):
def run(self):
print('Tortoise is running slowly...')
dog = Dog()
dog.run()
cat = Cat()
cat.run()
print('----------------------------------------------------')
def run_twice(Animal):
Animal.run()
Animal.run()
run_twice(Animal())
run_twice(Dog())
run_twice(Cat())
run_twice(Tortoise())
输出结果
Dog is running...
Cat is running...
----------------------------------------------------
Animal is running...
Animal is running...
Dog is running...
Dog is running...
Cat is running...
Cat is running...
Tortoise is running slowly...
Tortoise is running slowly...
run_twice() 函数传入的任意类型,只要是 Animal 类或者子类,就会自动调用实际类型的 run()方法。==》多态
==》“开闭” 原则
静态语言 vs. 动态语言
## 基本类型
print(type(123))
print(type('str'))
print(type(None))
## 变量类型
print(type(abs))
print(type(dog))
## if 语句中判断两个变量的类型
print(type(123) == type(456))
print(type(123) == int)
print(type('abc')==type('456'))
输出结果
True
True
True
判断一个对象是否是函数
import types
def fn():
pass
print(type(fn) == types.FunctionType)
print(type(fn) == types.BuiltinFunctionType)
print(type(lambda x: x) == types.LambdaType)
print(type((x for x in range(10))) == types.GeneratorType)
输出结果
True
False
True
True
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
能用 type()判断的基本类型也可以用 isinstance()判断;
isinstance('a', str)
# True
判断一个变量是否是某些类型中的一种;
isinstance([1, 2, 3], (list, tuple))
# True
dir()函数:获取一个对象的所有属性和方法,返回一个包含字符串的 list。
print(dir('ABC'))
输出结果
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__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']
==》其中,类型__xxx__的属性和方法是有特殊用途的,其余的为普通属性或方法。
场景:只有在不知道对象信息的时候,我们才会去获取对象信息。
getattr()、 setattr() 以及 hasattr() ==》直接操作一个对象的状态。
class MyObject(object):
def __init__(self):
self.x = 9
def power(self):
return self.x * self.x
obj = MyObject()
## 测试该对象的属性
print(hasattr(obj, 'x')) # 有属性'x'吗?
print(obj.x)
print(hasattr(obj, 'y')) # 有属性'y'吗?
print(setattr(obj, 'y', 19)) # 设置属性'y'?
print(hasattr(obj, 'y')) # 有属性'y'吗?
print(getattr(obj, 'y'))
print(obj.y)
print(getattr(obj, 'z', 404)) # 获取属性'z',如果不存在,返回默认值 404
## 测试该对象的方法
print(hasattr(obj, 'power')) # 有属性'power'吗?
print(getattr(obj, 'power')) # 获取属性'power'
fn = getattr(obj, 'power') # fn 指向 obj.power
print(fn())
输出结果
True
9
False
None
True
19
19
404
True
>
81
常见做法:假设我们希望从文件流 fp 中读取图像,我们首先要判断该 fp 对象是否存在 read 方法,如果存在,则该对象是一个流,如果不存在,则无法读取。 hasattr()就派上了用场。
def readImage(fp):
if hasattr(fp, 'read'):
return readImage(fp)
return None
Python 中可根据类创建的实例可以任意绑定属性,绑定方法:通过实例变量,或者通过 self 变量。
class Student(object):
def __init__(self, name):
self.name = name
s = Student('Bob')
s.score = 90
print(s.name) # Bob
print(s.score) # 90
直接在 class 中定义属性 ==》类属性
实例属性优先级比类属性高,因此,调用实例属性时,若实例属性存在,会产生屏蔽类属性的现象
class Student(object):
name = 'Student'
s = Student() # 创建实例 s
# 打印实例 name 属性,因为实例无 name 属性,所以会继续查找 class 的 name 属性
print(s.name)
print(Student.name) # 打印类属性
s.name = 'Michael'
print(s.name) # 实例属性存在
print(Student.name)
del s.name # 删除实例属性存在
print(s.name)
输出结果
Student
Student
Michael
Student
Student