Python基础 day12--面向对象(2)

面向对象介绍

  • 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
  • 类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
  • 数据成员:类变量或者实例变量, 用于处理类及其实例对象的相关的数据。
  • 方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
  • 局部变量:定义在方法中的变量,只作用于当前实例的类。
  • 实例变量:在类的声明中,属性是用变量来表示的。这种变量就称为实例变量,是在类声明的内部但是在类的其他成员方法之外声明的。
  • 继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。
  • 实例化:创建一个类的实例,类的具体对象。
  • 方法:类中定义的函数。
  • 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。

创建类

使用 class 语句来创建一个新类,class 之后为类的名称并以冒号结尾:

class ClassName:
   '类的帮助信息'   #类文档字符串
   class_suite  #类体

举个栗子

class Student:
    '''
     这是一个学生类

     '''
    class_num = "18511"
    # 初始化方法:属性初始化
    def __init__(self,name,age,ID):
        self.name = name
        self.age = age
        self.ID = ID

    # 实例方法
    def study(self):
        print("%s正在学习"%self.name)

# 实例化
s1 = Student("张飞",23,10010)
print(s1.class_num)    
# 输出张飞的班级
18511
print(s1.study())
# 输出
张飞正在学习
  • class_num:是学生班级信息,他的值将在这个类的所有实例之间共享。
  • __init__()方法是一种特殊的方法,我们称他为魔法方法,也被称为类的构造函数或者初始化函数,当创建了这个类的实例就会调用该方法
  • self:代表类实例的本身,self在定义类的方法时必须有的,虽然在调用时不传入相应的参数。

面向对象特性之继承

基本继承语法

面向对象的编程(OOP:Object Oriented Programming )带来的主要好处之一是代码的重复利用,实现这种重复利用的方法直以就是通过继承机制;继承是指:它可以使用现有类的所有功能和属性,并在无需重新编写原来类的情况下对着功能进行扩展。

通过继承创建的新类称之为子类或者派生类,被继承的类称为基类、父类或者超类,继承的过程,就是从一般到特殊的过程。在某些面向对象编程语言中,一个子类可以继承多个基类(父类)。但是一本情况下,一个子类只能有一个基类(父类),要实现多重继承,可以通过多级继承来实现。

继承的定义

class Person(object):  # 定义一个父类

    def talk(self):  # 父类中的方法
        print("人类可以说话...")


class Chinese(Person):  # 定义一个子类, 继承Person类

    def walk(self):  # 在子类中定义其自身的方法
        print('人类可以跑步...')


c = Chinese()
c.talk()  # 调用继承的Person类的方法
c.walk()  # 调用本身的方法

# 输出结果
"""
人类可以说话...
人类可以跑步...
"""

面试题:

class Base:
    def __init__(self):
        self.func()
    def func(self):
        print('他是爸爸')

class Son(Base):
    def func(self):
        print('他是儿子')

s = Son()
# 输出结果为:
他是儿子

这里一定药注意查找变量(我们把函数也当作变量)顺序!

多重继承

简单的来说,就是一个类拥有多个父类,,可以在类名的()后边添加多个类,来实现多重继承;多重继承,会使子类同时拥有多个父类,并且会获取得到所有父类中的方法和属性

语法:

class SubClassName (ParentClass1, ParentClass2, ...):

多重继承有什么意义呢?举个例子,鹰和麻雀都拥有飞的功能,飞的功能就可以写在父类中,由鹰和麻雀来继承,这样鹰和麻雀都有了自己的功能还继承了鸟类的功能,还省了代码。

单继承栗子:

class Birds:
    """ 定义一个鸟类"""
    def run(self):
        print("运动。。。")

    def fly(self):
        print("飞行。。。")

    def sleep(self):
        print("睡觉。。。")


class Eagle(Birds):
    """定义一个老鹰类"""
    def catch(self):
        print("捕捉!@!")


class Sparrow(Birds):
    """定义一个麻雀类"""
    def seeds(self):
        print("吃种子!@!")

p1 = Eagle()
p2 = Sparrow()
print(p1.fly())
# 输出
飞行。。。
print(p2.sleep())
# 输出
睡觉。。。

多重继承的栗子:

class A(object):
    def test(self):
        print('AAA')

class B(object):
    def test(self):
        print('B中的test()方法')
        
    def test2(self):
        print('BBB')

class C(A,B):
    pass

c = C()

c.test()

# 类名.__bases__  这个属性可以用来获取当前类的所有父类    
print(C.__bases__)

补充

说到多重继承,就不得不提一下c3算法了。mro即 method resolution order (方法解释顺序),主要用于在多继承时判断属性的路径(来自于哪个类)。

在python2.2版本中,算法基本思想是根据每个祖先类的继承结构,编译出一张列表,包括搜索到的类,按策略删除重复的。但是,在维护单调性方面失败过(顺序保存),所以从2.3版本,采用了新算法C3。

为什么采用C3算法

C3算法最早被提出是用于Lisp的,应用在Python中是为了解决原来基于深度优先搜索算法不满足本地优先级,和单调性的问题。

  • 本地优先级:指声明时父类的顺序,比如C(A,B),如果访问C类对象属性时,应该根据声明顺序,优先查找A类,然后再查找B类。
  • 单调性:如果在C的解析顺序中,A排在B的前面,那么在C的所有子类里,也必须满足这个顺序。

私有化变量

在Class内部,可以有属性和方法,而外部代码可以通过直接调用实例变量的方法来操作数据,这样,就隐藏了内部的复杂逻辑。

但是,从前面Student类的定义来看,外部代码还是可以自由地修改一个实例的namescore属性:

class Student(object):

    def __init__(self, name, score):
        self.name = name
        self.age = score

zhangfei = Student("张飞",22)
caocao = Student("曹操",34)


zhangfei.age=1000
print(zhangfei.age)

如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__,在Python中,实例的变量名如果以__开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问,所以,我们把Student类改一改:

class Student(object):

    def __init__(self, name, score):
        self.__name = name
        self.__age = score

zhangfei = Student("张飞",12)
caocao = Student("曹操",34)

print(zhangfei.__age)

改完后,对于外部代码来说,没什么变动,但是已经无法从外部访问实例变量.__name实例变量.__score了。

这样就确保了外部代码不能随意修改对象内部的状态,这样通过访问限制的保护,代码更加健壮。

但是如果外部代码要获取name和score怎么办?可以给Student类增加get_nameget_score这样的方法:

class Student(object):

    def __init__(self, name, score):
        self.__name = name
        self.__age = score

    def get_name(self):
        return self.__name

    def get_age(self):
        return self.__age

zokey = Student("家宁",18)
kong = Student("悟空",28)

print(zokey.get_name())
print(zokey.get_age())

如果又要允许外部代码修改age怎么办?可以再给Student类增加set_age方法:

class Student(object):

    def __init__(self, name, score):
        self.__name = name
        self.__age = score

    def get_name(self):
        return self.__name

    def get_age(self):
        return self.__age

    def set_age(self,age):
        self.__age=age

zokey = Student("家宁",18)
print(zokey.get_age())
zokey.set_age(1000)
print(zokey.get_age())

你也许会问,原先那种直接通过bart.score = 99也可以修改啊,为什么要定义一个方法大费周折?因为在方法中,可以对参数做检查,避免传入无效的参数:

class Student(object):
    ...
    def set_age(self,age):
        if isinstance(age,int) and 0 <= age <= 100:
            self.__age = age
        else:
            raise ValueError('bad age!')

需要注意的是,在Python中,变量名类似__xxx__的,也就是以双下划线开头,并且以双下划线结尾的,是特殊变量,特殊变量是可以直接访问的,不是private变量,所以,不能用__name____score__这样的变量名。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值