# 一、类和实例
# 1、面向对象最重要的概念就是类(Class)和实例(Instance),必须牢记类是抽象的模板,
# 比如Student类,而实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可能不同。
#
# 2、以Student类为例,在Python中,定义类是通过class关键字:
# class后面紧接着是类名,即Student,类名通常是大写开头的单词,紧接着是(object),
# 表示该类是从哪个类继承下来的,继承的概念我们后面再讲,通常,如果没有合适的继承类,就使用object类,
# 这是所有类最终都会继承的类。
#
# 3、定义好了Student类,就可以根据Student类创建出Student的实例,创建实例是通过类名+()实现的:
#
# 4、注意到__init__方法的第一个参数永远是self,表示创建的实例本身,因此,在__init__方法内部,就可以把各种属性绑定到self,
# 因为self就指向创建的实例本身。有了__init__方法,在创建实例的时候,就不能传入空的参数了,必须传入与__init__方法匹配的参数,
# 但self不需要传,Python解释器自己会把实例变量传进去:
bart = Student() bart #指向student的实例,每个对象的内存地址不一样 Student #这是第一个类 #特殊方法“__init__”前后分别有两个下划线 #1、不能传入空参数要传入除init之外的两个参数 # __init__方法,在创建实例的时候,就不能传入空的参数了,必须传入与__init__方法匹配的参数, # 但self不需要传,Python解释器自己会把实例变量传进去: #数据的封装 #Student类,就只需要知道,创建实例需要给出name和score, # 而如何打印,都是在Student类的内部定义的,这些数据和逻辑被“封装”起来了, # 调用很容易,但却不用知道内部实现的细节。 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'
# 二、访问限制
# 内部属性不被外部访问,可以把属性的名称前加上两个下划线__
# 保证外部代码不能随意访问对象内部 代码更加健壮
# 使用get 和 set方法来访问设置变量
#变量的类型
#__参数/_参数 为私有变量 只能通过 _类名__变量名 来访问,但是根据语法不要随便访问
#__参数__ 为特殊变量 可以直接访问
#如当前的调用
class Student(object):
def __init__(self, name, score):
self.__name = name
self.__score = score
def get_name(self):
return self.__name
def get_score(self):
return self.__score
def print_score(self):
print('%s: %s' % (self.__name, self.__score))
def set_score(self, score):
if 0 <= score <= 100:
self.__score = score
else:
raise ValueError('bad score')
#如当前的调用
#1的情况下调用会是这样
bart = Student('Bart Simpson', 59) #这边的name是_Student__name
bart.__name='AMy' #这边的name是bart.__name
print(bart.get_name())
print(bart.__name)
#此时调用bart.getname(),输出Bart Simpson,student的name并不会被改变
#2的情况下会是这样
# bart = Student('Bart Simpson', 59)
# print(bart.__name)
# #会报错print(bart.__name)
# #AttributeError: 'Student' object has no attribute '__name'
习题
#习题 #请把下面的Student对象的gender字段对外隐藏起来,用get_gender()和set_gender()代替,并检查参数有效性: class Student(object): def __init__(self, name, gender): self.__name = name self.__gender = gender def get_name(self): return self.__name def get_gender(self): return self.__gender def set_gender(self,gender): self.__gender = gender def set_name(self,name): self.__name= name # 测试: bart = Student('Bart', 'male') if bart.get_gender() != 'male': print('测试失败!') else: bart.set_gender('female') if bart.get_gender() != 'female': print('测试失败!') else: print('测试成功!')
#三、继承和多态
#在OOP程序设计中,当我们定义一个class的时候,可以从某个现有的class继承
#新的class称为子类(Subclass),而被继承的class称为基类、父类或超类(Base class、Super class)
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...') class Tortoise(Animal): def run(self): print('Tortoise is running...') #1.子类和父类会是同一种类型 c=Dog() isinstance(c, Animal) #true #run #2.开闭原则: # 对扩展开放:允许新增Animal子类,按照Animal类型进行操作,会自动调用实际类型的run()方法 # 对修改封闭:不需要修改依赖Animal类型的run_twice函数 def run_twice(a): a.run() run_twice(Dog()) run_twice(Cat()) #3.静态语言和动态语言 #静态语言(如java) 如果需要传入Animal类型 传入对象必须是Animal或者是它的子类,否则无法调用run()方法 #动态语言(如python)不一定要传入Animal类型 只要保证传入的对象有一个run()方法就可以了
#四、获取对象信息
#1、type()判断对象类型 #基本类型 type(123) type('str') #函数或类 type(abs) #判断2个变量的type类型是否相同 type(123)==type(456) type(123)==int #2、isinstance() 判断一个对象是否等于一个函数 ,子类的类型会和父类的一致 #3、判断数据类型结构 isinstance((1, 2, 3), (list, tuple)) #4、dir() #如果要获得一个对象的所有属性和方法,可以使用dir()函数,它返回一个包含字符串的list,比如,获得一个str对象的所有属性和方法: dir('ABC') #['__add__', '__class__',..., '__subclasshook__', 'capitalize', 'casefold',..., 'zfill'] #通过内置的一系列函数,我们可以对任意一个Python对象进行剖析,拿到其内部的数据。 #要注意的是,只有在不知道对象信息的时候,我们才会去获取对象信息。如果可以直接写: sum = obj.x + obj.y #判断是否有x属性 hasattr(obj, 'x') #设置一个y属性 setattr(obj, 'y', 19) #获取属性'z',如果不存在,返回默认值404 getattr(obj, 'z', 404) #获取属性'y' getattr(obj, 'y') # 获取属性'y' obj.y #获取对象的方法 #判断有属性power hasattr(obj, 'power') # 获取属性'power' getattr(obj, 'power') # len('ABC') 和 'ABC'.__len__() 都是获取字符串的长度 #假设我们希望从文件流fp中读取图像,我们首先要判断该fp对象是否存在read方法, # 如果存在,则该对象是一个流,如果不存在,则无法读取。hasattr()就派上了用场。 def readImage(fp): if hasattr(fp, 'read'): return readData(fp) return None
#五、实例属性和类属性
#1、给实例绑定属性 class Student(object): def __init__(self): self.name=name # s=Student('Bob') # s.score=90 #2、给类绑定属性 class Student(object): name = 'Student' s = Student() # 创建实例s print(s.name) # 打印name属性为Student,因为实例并没有name属性,所以会继续查找class的name属性, s.name = 'Michael' # 给实例绑定name属性 print(s.name) # 打印name属性为Michael,由于实例属性优先级比类属性高,因此,它会屏蔽掉类的name属性 del s.name # 如果删除实例的name属性 print(s.name) # 打印name属性为Student,再次调用s.name,由于实例的name属性没有找到,类的name属性就显示出来了