本文主要参考 廖雪峰python教程.
Obeject-Oriented Programing (OOP)
类和实例
创建类和实例
面向对象最重要的概念就是类(Class)和实例(Instance)。类是抽象的模板,比如Student类,而实例是根据类创建出来的一个个具体的“对象”。每个对象都拥有相同的方法,但各自的数据可能不同。
下面举了一个创建类和实例的例子。
Class后面紧接着是类名,即Student,类名通常是大写开头的单词,紧接着是(object),表示该类是从哪个类继承下来的。如果没有合适的继承类,就使用object类,这是所有类最终都会继承的类。
class Student(object):
pass
bart = Student()
print(bart)
print(Student)
<__main__.Student object at 0x7f7830a62280>
<class '__main__.Student'>
__init__方法
下面创建了一个带有初始化实例函数的类。
由于类可以起到模板的作用,因此,可以在创建实例的时候,把一些我们认为必须绑定的属性强制填写进去。通过定义一个特殊的__init__
方法,在创建实例的时候,就把name
,score
等属性绑上去。
class Student(object):
def __init__(self, name, score):
self.name = name
self.score = score
bart = Student('Bart Simpson', 59)
print(bart.name)
print(bart.score)
# 在__init__ 方法中 self. 之后才是变量的名字。而不是 __init__(self,name,score)中的 name 和 score。
# 如下例子所示,将输入的name,score 传递给变量 A,B。然后从外部调用变量 A,B。
class Student(object):
def __init__(self, name, score):
self.A = name
self.B = score
bart = Student('Bart Simpson', 59)
print(bart.A)
print(bart.B)
Bart Simpson
59
Bart Simpson
59
数据封装
面向对象编程的一个重要特点就是数据封装。在上面的Student类中,每个实例就拥有各自的name和score这些数据。我们可以通过函数来访问这些数据。
class Student(object):
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)
print(bart.print_score)
print(bart.get_grade)
print(bart.print_score())
print(bart.get_grade())
<bound method Student.print_score of <__main__.Student object at 0x7f7830a6b670>>
<bound method Student.get_grade of <__main__.Student object at 0x7f7830a6b670>>
Bart Simpson: 59
None
C
访问限制
在Class内部,可以有属性和方法,而外部代码可以通过直接调用实例变量的方法来操作数据。
从前面Student类的定义来看,外部代码还是可以自由地修改一个实例的name、score属性。
如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__,实例的变量名如果以__开头,就变成了一个私有变量(private)。私有变量只有内部可以访问,外部不能访问。
但是如果外部代码要获取name和score怎么办?可以给Student类增加get_name和get_score这样的方法。如果又要允许外部代码修改score怎么办?可以再给Student类增加set_score方法。因为在方法中,可以对参数做检查,避免传入无效的参数。
class Student(object):
def __init__(self, name, score):
self.__name = name
self.__score = score
def print_score(self):
print('%s: %s' % (self.__name, self.__score))
def get_name(self):
return self.__name
def get_score(self):
return self.__score
def set_score(self, score):
self.__score = score
def set_score(self, score):
if 0 <= score <= 100:
self.__score = score
else:
raise ValueError('bad score')
bart = Student('Bart Simpson', 59)
print(bart.get_name)
print(bart.get_score)
print(bart.get_name())
print(bart.get_score())
# 需要注意的是,在Python中,变量名类似__xxx__的,也就是以双下划线开头,并且以双下划线结尾的,是特殊变量。
# 特殊变量是可以直接访问的,不是private变量,所以,不能用__name__、__score__这样的变量名。
<bound method Student.get_name of <__main__.Student object at 0x7f7830a62070>>
<bound method Student.get_score of <__main__.Student object at 0x7f7830a62070>>
Bart Simpson
59
继承和多态
OOP程序设计中,当我们定义一个class的时候,可以从某个现有的class继承。新的class称为子类(Subclass),而被继承的class称为基类、父类或超类(Base class、Super class)。子类会自动继承父类的全部功能。如下面例子所示,Dog和Cat作为Animal的子类,什么事也没干,就自动拥有了run()方法。
class Animal(object):
def run(self):
print('Animal is running...')
class dog(Animal):
pass
class cat(Animal):
pass
dog = dog()
cat = cat()
print(dog.run())
print(cat.run())
在定义自类时,还可以重写父类里的方法。使子类的方法更精确。当子类和父类都存在相同的run()方法时,我们说,子类的run()覆盖了父类的run()。在代码运行的时候,总是会调用子类的run()。我们就获得了继承的另一个好处:多态。
继承还可以一级一级地继承下来,就好比从爷爷到爸爸、再到儿子这样的关系。而任何类,最终都可以追溯到根类object。
class Animal(object):
def run(self):
print('Animal is running...')
class dog(Animal):
def run(self):
print('Dog is running')
def eat(self):
print('Eating meat')
class cat(Animal):
def run(self):
print('Cat is running')
def eat(self):
print('Eating fish')
class tortoise(Animal):
def run(self):
print('tortoise is running slowly')
def eat(self):
print('Eating small shrimp')
dog1 = dog()
cat1 = cat()
tot = tortoise()
dog1.run()
dog1.eat()
cat1.run()
cat1.eat()
tot.run()
tot.eat()
Dog is running
Eating meat
Cat is running
Eating fish
tortoise is running slowly
Eating small shrimp
要理解什么是多态,我们首先要对数据类型再作一点说明。当我们定义一个class的时候,我们实际上就定义了一种数据类型。
a = list() # a是list类型
b = Animal() # b 是Animal类型
c = dog() # c 是 dog类型
# 判断一个变量是否是某个类型可以用isinstance()判断
print(isinstance(a, list))
print(isinstance(b, Animal))
print(isinstance(c, dog))
print(isinstance(c, Animal))
True
True
True
True
获取对象信息
使用type()函数。 type()函数返回数据类型为class类型。
print(type(123))
print(type(abs))
print(type(123)==type(456))
print(type(123)==int)
print(type('abc')==type('123'))
print(type('abc')==str)
print(type('abc')==type(123))
# 判断一个对象是否是函数,可以使用types模块中定义的常量
import types
def fn():
psss
print(type(fn)==types.FunctionType)
print(type(abs)==types.BuiltinFunctionType)
print(type(lambda x: x)==types.LambdaType)
print(type((x for x in range(10)))==types.GeneratorType)
# 使用 isinstance()
# 对于class的继承关系来说,使用type()就很不方便。我们要判断class的类型,可以使用isinstance()函数。
sunyu = Animal()
dawei = dog()
kunge = cat()
print(isinstance(sunyu, Animal))
print(isinstance(dawei, dog))
print(isinstance(kunge, cat))
# 使用dir()
# 如果要获得一个对象的所有属性和方法,可以使用dir()函数,它返回一个包含字符串的list,比如,获得一个str对象的所有属性和方法
print(dir('ABC'))
<class 'int'>
<class 'builtin_function_or_method'>
True
True
True
True
False
True
True
True
True
True
True
True
['__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', 'isascii', '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']
实例属性和类属性
由于Python是动态语言,根据类创建的实例可以任意绑定属性。
class Student(object):
name = 'Student'
def _init_(self,name):
self.name = name
# 上面Student Class里 name 是类的属性归Student类所有。类的所有实例都可以访问到
s1 = Student()
s2 = Student()
s2.name = 'Bob'
s3 = Student()
s3.name = 'Michael'
print(s1.name)
print(Student.name)
print(s2.name) # 由于实例属性优先级比类属性高,因此,它会屏蔽掉类的name属性
print(s3.name) # 由于实例属性优先级比类属性高,因此,它会屏蔽掉类的name属性
Student
Student
Bob
Michael