python面向对象(一)

一:面向对象编程

        面向对象编程——Object Oriented Programming,简称OOP,是一种程序设计思想。OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数。

       面向过程的程序设计把计算机程序视为一系列的命令集合,即一组函数的顺序执行。为了简化程序设计,面向过程把函数继续切分为子函数,即把大块函数通过切割成小块函数来降低系统的复杂度。

        面向过程:核心在“过程”,分析出解决问题的步骤,先干什么,后干什么;优点是流程化,进而简单化;缺点是可扩展性差

        面向对象的程序设计把计算机程序视为一组对象的集合,而每个对象都可以接收其他对象发过来的消息,并处理这些消息,计算机程序的执行就是一系列消息在各个对象之间传递。

        面向对象:核心在“对象”,分析解决问题需要哪些“人”,然后创造出这些对象,让他们自己去把问题解决。优点是扩展性强

        面向对象三大特点:数据封装,继承和多态

二:对象与类

    对象:是人们要进行研究的任何事物,是特征与行为(功能)的结合体,即包含了数据与对数据的操作

    类(class):用来描述具有相同的属性和方法的对象的集合;它定义了该集合中每个对象所共有的属性和方法

    可以说,对象的抽象是类,类的具体化就是对象,即对象是类的实例

# 在程序中必须先定义类,才能创建对象
# 程序执行到类的定义时,先产生类的名称空间,然后会执行类里面的代码块,并把产生的名字放入该名称空间

class OlyStudent:     # 定义类使用关键字class
    school = 'oly'     # 对象的共有属性
    def learn(self):  # 对象的共有方法;参数self为对象本身,必须得有;被调用时python会自动传入对象参数
        print('%s is learning' %self.name)
    def __init__(self,name,age,sex):  # 此方法为对象创建个性化的属性;调用类时就会触发此方法的执行
        self.name = name
        self.age = age
        self.sex = sex

# 调用类创建类的实例--对象
stu1 = OlyStudent('rock',18,'male')  # 调用类,创建对象名称空间,触发__init__(self,'rock',18,'male'),将产生的名字放入对象名称空间
stu2 = OlyStudent('lula',28,'female')

print(stu1.school)  #调用对象某个属性,会先在该对象的名称空间找,找不到就去对应类的名称空间找

# 查看类与对象名称空间的名字及其对应的值
print(OlyStudent.__dict__)
print(stu1.__dict__)   # {'name': 'rock', 'age': 18, 'sex': 'male'}

# 属性的增删查改
print(stu2.school)    # 使用点号的语法调用对象的属性和方法   查
OlyStudent.school = 'pku'    # 是已有属性则改值,没有该属性则增加此属性    增/改
del stu1.sex         # 删除某属性
print(stu1.__dict__)   # {'name': 'rock', 'age': 18}

    访问限制:

class Foo:
    def __init__(self,name,password):
        self.__name = name   # 将属性名命名为以__开头,这样这个属性就成了对象的私有变量,无法通过外部访问
        self.__password = password
    def ger_name(self):   # 可以通过增加这种方法来方便从外部访问到对象的私有变量
        return self.__name
    def get_pwd(self):
        return self.__password

foo1 = Foo('rock','123')
# print(foo1.__name)   # AttributeError: 'Foo' object has no attribute '__name'
# print(foo1._Foo__name)  # rock   python解释器自动把__name转成了_Foo__name,但不建议这样访问该属性!!!
# print(foo1.__dict__)   # {'_Foo__name': 'rock', '_Foo__password': '123'}
print(foo1.ger_name())  # rock
print(foo1.get_pwd())  # 123

三:类的继承

   新定义一个类,可以继承自某个或某几个已有的类;新的类叫子类(Subclass),被继承的类叫基类、父类或超类(Base class,Super class)

class OlyPeople:     # 父类是对子类的再抽象,提取出各子类共同的属性和方法,这样可以减少重复代码
    school = 'oly'
    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex
    def f1(self):
        print('f1 from OlyPeople')

# 子类继承自父类,最大的好处是子类继承了父类的所有功能,即子类可以使用父类的所有属性和方法
class Teacher(OlyPeople):    # 括号中传入其父类,建立父子类关系;可以传入多个父类,即与多个父类建立父子类关系
    def __init__(self,name,age,sex,level,salary):  # 子类可以定制自己的属性和方法,若与父类发生名字冲突,会覆盖继承而来的
        super().__init__(name,age,sex)    # 得到父类中已定义的属性,避免重复定义,产生冗余代码
        self.level = level
        self.salary = salary
    def teach(self):
        pass
    def f1(self):     
        print('f1 from Teacher')

tea1 = Teacher('rock',18,'male',9,25)  # 调用类创建对象,会自动触发__init__()的执行,若类中没有,会去其父类中找该函数
print(tea1.school)  # 得到继承自父类的属性school
tea1.f1()   # 对象调用一个属性与方法查找顺序:始终先从对象自己的名称空间找,没有再去其对应类中找,还没有再去类的父类中找
# 以上执行结果 oly;f1 from Teacher
'''
对象调用一个属性与方法的查找顺序:
对象自己的名称空间 --> 对应类的名称空间 --> 父类的名称空间 --> 父类的父类的名称空间... --> object
'''
'''
继承自object类的子子孙孙类,都叫新式类;python3中的类全是新式类,没有指定继承类的默认继承自object类
不是继承object类的所有类,都叫经典类;Python2中有经典类
'''
class Foo:   # python3中默认为 class Foo(object):
    pass

'''
新式类与经典类的主要区别在于查找对象的属性和方法(菱形继承结构,即其父类有同一祖先)
新式类:广度优先,一条分支找下去,不找那个共同祖先,然后去下条分支找,最后去共同祖先那找
经典类:深度优先,一条分支找下去,直接找到共同祖先那,然后去下条分支找。。
'''
Foo.mro()   # 可列出对象能调用的名字在类及其父类中的查找路径

    多继承名字查找:(新式类:广度优先)


print(A.mro())  # 查看名字在多继承结构中的查找顺序

#图3:[<class '__main__.A'>, <class '__main__.B'>, <class '__main__.D'>, <class '__main__.C'>, <class '__main__.E'>, <class '__main__.F'>, <class 'object'>]

#图5这种结构会报错
#TypeError: Cannot create a consistent method resolution
#order (MRO) for bases H, E

四:类的数据封装

class Foo:
    def __init__(self,name,age):   # 此处使用构造方法把数据封装到对象中(这就是面向对象的数据封装方式)
        self.name = name
        self.age = age
    def user_info(self):
        print('name:%s  age:%s' %(self.name,self.age))
obj1 = Foo('rock',18) #调用类创建对象,自动执行__init__(),把数据name='rock' age=18 封装到对象obj1中

print(obj1.name,obj1.age)    # 通过对象调用属性的方式直接获取封装的数据
obj1.user_info()    # 通过self参数间接获取封装的数据

五:类的多态

# Python不支持Java和C#这一类强类型语言中多态的写法,但是是原生多态,Python崇尚“鸭子类型”。
# 动态语言的“鸭子类型”:一个对象只要“看起来像鸭子,走起路来像鸭子”,那它就可以被看做是鸭子。
# 多态:多种形态,即多种类型
class Animal:
    def run(self):
        print('Animal is running')

class Dog(Animal):
    def run(self):
        print('Dog is running')

class Duck_like:    # 虽然不属于Animal类,但具有与Animal类相同的方法run(),所以其对象也可以调用run_twice()方法
    def run(self):   # 这就是“鸭子类型”
        print('Duck_like is running')

def run_twice(animal):
    animal.run()
    animal.run()

run_twice(Animal())   # Animal对象属于Animal类,即一种形态
run_twice(Dog())      # Dog对象属于Dog类,也属于Animal类,即具有二种形态
run_twice(Duck_like()) # 从python中的run_twice()方法角度看属于 “鸭子类型”
# run_twice()方法设定的是接收Animal类,但其子类也属于Animal类,所以run_twice()就具备了同时接收其他类型(Animal子类或鸭子类型)的能力
# Animal is running
# Animal is running
# Dog is running
# Dog is running
# Duck_like is running
# Duck_like is running

class Tiger(Animal): # 新增Animal子类
    def run(self):
        print('Tiger is running')

run_twice(Tiger())   # 我们只需知道Tiger对象属于Animal类,就可以调用run_twice()方法,而不用管具体实现细节

# Tiger is running
# Tiger is running

# Python多态符合“开闭”原则
# 对扩展开放:允许新增Animal子类
# 对修改封闭:不需要修改依赖Animal类型的run_twice()等函数。


猜你喜欢

转载自blog.csdn.net/hua1011161696/article/details/79890451