Python学习笔记(五)————面向对象编程

# 一、类和实例
# 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属性就显示出来了

  

  

  

 

posted @ 2021-03-25 21:10  陈晓猛  阅读(60)  评论(0编辑  收藏  举报