Python——什么是面向对象?类的定义、self和继承详解

创作不易,来了的客官点点关注,收藏,订阅一键三连❤😜 

往期系列

Python——函数大全及使用方法! lambda?global?

Python——流程控制,pass?break?continue?这些你弄清楚了吗?

目录

常见的三种编程范式

函数式编程

面向过程编程

面向对象编程 (OOP-Object Oriented Programming)

面向过程VS面向对象

面向对象的基本概念

类(class申明)

类:用来描述具有相同属性和方法的对象的集合,分为基类、子类。

对象

类的实例化

类的定义与使用

类空间和实例空间

类的基本特点

类的定义与使用

__init__方法

__new__方法

__init__与__new__总结

小练习:创建类,实现计算学生的总成绩与平均分

类的self方法

类-self

练习:用面向对象实现斐波那契数列

类的继承

面向对象的好处

继承

使用继承的好处

python的多态

练习:利用类自定义异常类


 

常见的三种编程范式

函数式编程

• 函数可以作为参数传递、修改,或作为返回值

• 函数内不修改外部变量的状态

面向过程编程

• 根据操作数据的语句块来实现功能。

def login(username,passwd):

    if username == "root" and passwd == "123456":

        return True

    else:

        return False

面向对象编程 (OOP-Object Oriented Programming)

• 把数据和功能结合起来,用称为对象的东西包裹起来组织程序的方法。

class LoginCheck():

    # 登陆数据

    username = "root"

    passwd = "123456"

    # 登录功能

    def login(self,username,passwd):

        if username == "root" and passwd == "123456":

            return True

        else:

            return False

面向过程VS面向对象

• 面向过程是一件事"该怎么做", 着重于做什么。

面向过程 = 分析问题 + 逻辑

优点:性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗资源;比如单片机、嵌入式开发、 Linux/Unix等一般采用面向过程开发,性能是最重要的因素。

缺点:没有面向对象易维护、易复用、易扩展

面向对象是一件事"该让谁来做",着重于谁去做

优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统 更加灵活、更加易于维护

缺点:性能比面向过程低


面向对象的基本概念

• 对象:通过类定义的数据结构实例。

• 对象包括两个数据成员(类变量和实例变量)和方法。

• python一切皆对象,类是对象,实例也是对象

示例代码:

class Bus317(object):

    # 类属性

    line = "317"

    # 方法-->行为

    def run(self,flag):

        print("bus317 is run")

        if flag == 0:

            print("从农大到长华小区")

        else:

            print("从长华小区到农大")

实例化:创建了一个对象

bus01 = Bus317()

bus02 = Bus317()

类(class申明)

类:用来描述具有相同属性和方法的对象的集合,分为基类、子类。

什么是类?

生活例子:车可以理解为一个类,特征:有车轮、车牌,方法:会跑

基类/子类

车-->基类;摩托车,大卡车-->子类

对象

实例:具体的某一个事务,某个类型实实在在的一个例子

类的实例化

通过类创建的一个具体的实例,类的具体对象;

类就是一个生产实例的工厂,类就是一个模型图

实例化

lg1 = LoginCheck()

lg1就是一个对象,实例去干活

print(lg1.login("root1","21323"))


类的定义与使用

类空间和实例空间

创建类的时候就会创建类空间

实例化对象时就会生成实例空间,不同的实例有单独的空间

实例查找属性方法时,会现在实例空间查找,找不到就去类空间查找,类空间找不到就去父空间查找

eg:bus01.xx --> 查找xx属性

先在他自己的实例空间查找--找不到就去Bus317里找--再找不到再去object找--最后找不到就报错

类的基本特点

封装(Encapsulation)

  在类中对数据的赋值、内部调用对外部用户是透明的

  把一些功能的实现细节不对外暴露

  将数据和函数做了一层封装,封装成类,使用者不需要管具体实现的代码

• 继承(Inheritance)

  继承:即一个派生类(derived class)继承基类(base class)的字段和方法。

  目的:为实现代码的重用, 一个类可以派生出子类

  继承也允许把一个派生类的对象作为一个基类对象对待。

• 多态(Polymorphism)

  接口重用, 一个接口,多种实现(重写)

类的定义与使用

• 类名的规范

  一般首字母大写(大驼峰)

  Person, GoodsInfo

• 函数的命名

  由小写字母和下划线组成

  scan_book, drink

• 类的定义方式(关键字:class)

python2 => 经典类和新式类

python3 => 新式类

继承了object类的类都属于新式类,没有继承的属于经典类

class A():

    pass

class B:

    pass

class C(object):

    pass

python3中以上三种定义没有区别,默认会继承object类

class Bus317(object):

    # 类属性

    line = "317"

    # 方法-->行为

    def run(self,flag):

        print("bus317 is run")

        if flag == 0:

            print("从农大到长华小区")

        else:

            print("从长华小区到农大")

#实例化:创建了一个对象

bus01 = Bus317()

bus02 = Bus317()



#打印类和实例的内存:类和实例化都有单独的命名空间

print(id(Bus317),id(bus01),id(bus02))



#查看对象的属性或方法

print(dir(bus01))

print(bus01.line)

bus01.run(0)

bus02.run(1)



#直接用类访问属性

print(Bus317.line)

__init__方法

实例化对象的构造方法,实例化对象的时候会自动调用__init__方法

用来初始化属性

__new__方法

创建实例化,一般情况下不需要重写,静态方法

class Bus317(object):

    # 类属性

    # line-->公共属性

    line = "317"

    def __init__(self,pro):

        print("this is __init__")

        self.pro1 = pro

    # cls接收到的参数就是当前类(Bus317)

    def __new__(cls, *args, **kwargs):

        print("this is new method")

        return "new"

        # return object.__new__(cls)

        # 返回父类object.__new__方法通过当前类创建的对象

    # *args和 ** kwargs主要用于函数定义。你可以将不定数量的参数传递给一个函数。

    # 这里的不定的意思是: 预先并不知道, 函数使用者会传递多少个参数给你, 所以在这个场景下使用这两个关键字。

    def run(self,flag):

        print("bus317 is run")

        if flag == 0:

            print("从农大到长华小区")

        else:

            print("从长华小区到农大")

# 创建实例

bus01 = Bus317("benci","chao")

bus02 = Bus317("futian")

print(bus01)

# print(dir(bus01))

# print(bus01.pro1,bus02.pro1)

# 查看类空间有什么东西

# print(Bus317.__dict__)

# 查看实例空间有什么内容

# print(bus01.__dict__)

__init__与__new__总结

__init__是对创建好的实例,进行初始化工作的方法

__new__是创建实例的方法

1.__new__方法必须传入一个参数(cls),代表当前类

2.__new__必须返回一个实例化的对象

3、__init__的self就表示__new__返回的实例,__init__对这个实例进行初始化工作

4、子类没有__new__,会去找父类的__new__

5、新式类才有__new__

6、如果实例化对象和本身class不一致,__init__不会执行

小练习:创建类,实现计算学生的总成绩与平均分

创建一个学生类

• 类名:Student

• 属性:姓名,年龄,学校,成绩(字典)

{'yuwen':100, 'suxue':100, 'yinyu':100}

• 方法:求总分、求平均值

class Student(object):

    school = "hunau"

    def __init__(self,name,age,scores):

        # 初始化函数,self-->实例本身

        self.name = name

        self.age = age

        self.school = Student.school # 使用类属性

        self.scores = scores



    def sum(self):

        # sum1 = 0

        # for i in self.scores.values():

        #     sum1 += i

        # return sum1

        # 方法二

        return sum(self.scores.values())

    def avg(self):

        # avg1 = self.sum()/len(self.scores)

        # return avg1

        # 方法二

        return self.sum()/len(self.scores)





lzc = Student("lzc", 20,{"math":100,"Chinese":90})

lzw = Student("lzw", 20,{"math":98,"Chinese":92})

llf = Student("llf", 20,{"math":97,"Chinese":91})

print(lzc.sum())

print(lzc.avg())

类的self方法

类-self

类的实例方法与普通的函数只有一个特别的区别——它们必须有一个额外的第一个参数名称

在调用这个方法的时候你不为这个参数赋值,Python会提供这个值

这个特别的变量指对象本身,按照惯例它的名称是self

class A:

    name = "sc"

    age = 4



    def info(self,sex):

        print(f"我是:{self.name},今年{self.age}岁,性别{sex}")

        print(self)

        print(id(self))

    def info2(chao):

        print(f"this is {chao}")



#self 表示实例本身

a = A()

print(id(a))

a.info("man")

print("***")

A.info(a,"man") # 实际上运行

#输出结果:

1889166028752

我是:sc,今年4岁,性别man

<__main__.A object at 0x000001B7DB11EFD0>

1889166028752

self 不必非写成self,self的名字不是强制规定的(可以理解为不一定要命名为self)

最好还是尊重约定俗成的习惯,使用self

b = A()

b.info2()

#输出结果:

this is <__main__.A object at 0x00000278DEEEEFD0>

方法中可以不传入self,如果不写的话就不能使用对象调用

实例调用方法的时候,默认就会把当前的实例传给self,不需要手动传入

示例:

class Parent:

    def pprt(self):

        print(self)

 

class Child(Parent):

    def cprt(self):

        print(self)

       

c = Child()

c.cprt()

c.pprt()

#输出结果:

<__main__.Child object at 0x00000278DEEEEFA0>

<__main__.Child object at 0x00000278DEEEEFA0>

练习:用面向对象实现斐波那契数列

用类实现斐波那契数列的运算(编写自定义迭代器)

斐波那契数列: 0 1 1 2 3 5

码如下

class Fib_list:

    def __init__(self):

        self.before = 0

        self.now = 1

 

    def __iter__(self):

        return self

 

    def __next__(self):

        result = self.now

        self.before,self.now=self.now,self.before+self.now

        return result

 

a = Fib_list()

 

print([next(a) for i in range(11)])

类的继承

面向对象的好处

面向对象的编程带来的主要好处之一是代码的重用,实现这种重用的方法之一是通过继承机制

继承完全可以理解成类之间的类型和子类型关系。

• 可以节省很多的代码,不需要写,直接使用

• 衍生出不同的子类,大部分代码一样,部分代码不一样

继承

• 继承父类的属性和方法

• 对象属性查找

先在实例空间查找,没有就去类空间

再没有就去父类空间找,层层往上递归查找

class Animal():

    species = "Animal"

    count = 0

    def __init__(self):

        self.name = "animal"

        Animal.count += 1

        print("初始化animal......")



    def breath(self):

        print("i can breath")



    def eat(self):

        print("i can eat")



# 继承Animal类

class Person(Animal):

    species = "Person" #重写父类属性



class Dog(Animal):

    species = "Dog"



    def __init__(self):  #重写父类的__init__

        print("i am dog")



    def eat(self): #重写父类的eat()

        print("dog is eatting......")



class Pig(Animal):

    count = 0 #重写父类属性



    def __init__(self):  #重写父类__init__

        self.name = "pig"

        Pig.count += 1

        print("初始化Pig......")

        super().__init__() #去执行父类的__init__,子类访问父类属性的方法属性



print(Animal.count)

# 输出结果

0



# 实例化Animal

animal = Animal()

print(Animal.count,animal.count)

# 输出结果

初始化animal......

1 1



# 实例化Person

person = Person()

print(person.species,person.count,Person.count)

#输出结果

初始化animal......

Person 2 2



# 实例化Dog

dog = Dog()

print(dog.count)

print("*"*5)

# 输出结果

i am dog

2



# 实例化Pig

pig = Pig()

print(pig.count,pig.name)

# 输出结果

初始化Pig......

初始化animal......

1 animal



# 类与实例的关系

print("类与实例的关系".center(30,"*"))

print(type(dog))

print(isinstance(dog,Dog), isinstance(dog, Animal))

# 输出结果

***********类与实例的关系************

<class '__main__.Dog'>

True True

使用继承的好处

增加了代码的利用率,如果需要给Pig/Person同时增加新的功能时,只需要在Animal中添加即可

便于更新迭代,如果你的父类方法的功能不能满足你的需求,你可以在子类重写你父类的方法父类里的方法

python的多态

python不支持多态,语法上的多态,不需要额外实现多态代码

python里处处都是多态,python是一个多态类型语言,本身就实现了多态,崇尚鸭子类型

在鸭子类型中,关注的不是对象的类型本身,而是它是如何使用的。

多态的好处

• 增加了程序的灵活性

• 以不变应万变,不论对象千变万化,使用者都是同一种形式去调用,如func(animal)

• 增加了程序额可扩展性

• 通过继承animal类创建了一个新的类,使用者无需更改自己的代码,还是用func(animal)去调用

• 多态:同一种事物的多种形态,动物分为人类,猪类(在定义角度)

• 多态性:一种调用方式,不同的执行效果(多态性)

• 实现接口重用

练习:利用类自定义异常类

自定义异常类

• 自定义异常能让异常更精准

• 自定义异常类:当list内元素长度超过10的时候抛出异常

• 自定义异常类:消息小于8时抛出异常

 方法一

class List_Error(Exception):

    pass

lst1 = [1,2,3]

if not 8<len(lst1)<10:

    raise List_Error("列表长度小于8或超出10")

else:

    print("No Problem")

方法二:

class List_Error(Exception):# 注:继承Exception的基类

    def __init__(self,lst,message):

        self.lst = lst

        self.message = message



    def __str__(self):

        str1 = "list is " + str(self.lst)

        str1 = str1 +"\n" + self.message

        return str1



try:

    lst = [1,2,3,4,5,6]

    if not 8 < len(lst) < 10:

        raise List_Error(lst,"列表长度小于8或超出10!")



except List_Error as e:

    print("listError error:",e)

创作不易,客官点个赞吧!评论一下!一起加油❤😜   

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

chaochao️

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值