Python面向对象总结一

还记得第一次接触Python是在刚刚进入大学的第一个学期,之后就没有再使用过python。虽然基本语法,内置函数等没有忘记,但最近的学习中,一直在用python、matlab混合编程,零零散散的知识点、模模糊糊的记忆,有时候令我眼花缭乱。现在趁着闲暇,系统的温习一下python的基础知识。


目录

一、初识对象

二、self参数详解

三、变量的划分(类变量、实例变量、局部变量)

四、实例方法、静态方法、类方法


一、初识对象

我依稀记得,大一上python的某堂课,任课老师让我们用一段python程序描述班级中学生的信息。

A同学回答:我的程序是这样的

student_1={
"姓名":sun,
"性别":男,
"籍贯":河南,
年龄:18
}

A同学选择使用字典来描述信息。

B同学回答:我的程序是这样的

student_2=["王五","南京","男",19]

他使用列表描述学生信息。

C同学回答道:我选择使用字符串描述信息

student_3="张柳来自福建省,他是男生,今年19岁"

 不难看出,由于不同的同学采用不同数据类型的变量来描述学生信息,使得数据很乱。我们有没有什么其他办法来统一数据格式,使得学生信息看起来整齐有序呢?

我们发现要描述一个学生的信息,形式是多样的(比如使用列表,字典等),但是无论是什么形式都需要包含姓名,年龄,性别,籍贯几个要素。不同的学生的姓名、年龄等个不相同,但是要描述清楚这个学生的信息,总得有这几个要素。如果我们使用一个“模板”,这个“模板”中包含姓名、性别、年龄、籍贯这几个要素,那么这个“模板”肯定能描述清楚任何一个特定学生的信息。因为任何一个特定的学生信息都是从这个“模板”中得来的,数据格式就变得整齐有序了。

上面这个过程其实就是使用对象来组织数据,其形式如下:

class Student:
    name:None
    age:None
    sex:None
    birthPalce:None

 那么A、B、C三位同学的程序就可以统一为:

stu_1=Student()
stu_1.name="sun"
stu_1.age=18
stu_1.sex="男"
stu_1.birthPalce="河南"

stu_2=Student();
stu_2.name="王五"
stu_2.age=19
stu_2.sex="男"
stu_2.birthPalce="南京"

stu_3=Student();
stu_3.name="张柳"
stu_3.age=19
stu_3.sex="男"
stu_3.birthPalce="福建"

 在上面的几段程序中

class Student:
    name:None
    age:None
    sex:None
    birthPalce:None 

称为设计类。其中name,age,sex等称为类的属性,它是用来描述类的特征。比如,一个学生年龄19岁,籍贯河南,姓名李华,这里的年龄、籍贯、姓名就是这个学生的特征(或者称为属性),而19岁、河南,李华就是对应属性的值。又比如,丽丽长的很漂亮,这里丽丽的属性就是“外貌’,而对应的属性值是“漂亮”。其实,要全面描述清楚一个学生,单凭使用“年龄”“姓名”“外貌”等属性是描述不清的,一个学生还可以学习、社交、考试等等,我们无法使用属性来解释学生的这些行为。这时候就要使用“方法”来描述了,现在我们来拓展一下上面的学生类,在类中添加学生的“行为”:

class Student:
    name:None
    age:None
    sex:None
    birthPalce:None 

    def study(self):

            print(f"大家好,我是{self.name},我非常擅长数学,如果有数学难题,欢迎一起探讨") 

 我们在类中定义了一个函数"study"来描述学生的学习行为,这里在类中定义的函数就称为类的成员方法,它是用来描述类的功能。在方法定义的参数列表中,有一个self关键字,它是用来表示类对象自身的意思当我们使用类对象调用方法的是,self会自动被python传入。关于self参数,在本篇文章的下一个章节会详细介绍。

在上面的程序段中:

stu_1=Student()

stu_2=Student();

stu_3=Student();

称为创建对象。为什么非要创建对象才能使用呢?类是程序中的“设计图纸”,而对象是基于图纸生产的具体实体,只要创建出对象,才能用实体去实现类的功能。

类只是一种程序内的“设计图纸”,需要基于图纸生产实体(对象),才能正常工作这种套路,称之为:面向对象编程。面向对象编程就是根据实体抽象出共性,设计出类,基于类创建对象,由对象做具体的工作。

我们继续看上面的程序段:

stu_1.name="sun"

stu_1.age=18

stu_1.sex="男"

stu_1.birthPalce="河南"

stu_2.name="王五"

stu_2.age=19

stu_2.sex="男"

stu_2.birthPalce="南京"

stu_3.name="张柳"

stu_3.age=19

stu_3.sex="男"

stu_3.birthPalce="福建"

 称为对象属性赋值。但是在这段对象属性赋值代码中,为对象的属性赋值需要依次进行,略显繁琐。有没有更加高效的方式就完成呢?

答案是肯定的,我们完全可以使用构造方法对成员变量进行赋值。

class Student:
    def __init__(self,name,age,sex,birthPlace):
        self.name=name
        self.age=age
        self.sex=sex
        self.birthPlace=birthPlace

Python类可以使用:__init__()方法,称之为构造方法。
它可以实现:
在创建类对象(构造类)的时候,会自动执行。
在创建类对象(构造类)的时候,将传入参数自动传递给__init__方法使用。借此特性可以给成员变量赋值
值得注意的是:构造方法名称:__init__ 千万不要忘记init前后都有2个下划线,构造方法也是成员方法,不要忘记在参数列表中提供:self

二、self参数详解

self 参数的具体作用是什么呢?举一个例子,如果把类比作造房子的图纸,那么类实例化后的对象是真正可以住的房子。根据一张图纸(类),我们可以设计出成千上万的房子(类对象),每个房子长相都是类似的(都有相同的类变量和类方法),但它们都有各自的主人,那么如何对它们进行区分呢?当然是通过 self 参数,它就相当于每个房子的门钥匙,可以保证每个房子的主人仅能进入自己的房子(每个类对象只能调用自己的类变量和类方法)。也就是说,同一个类可以产生多个对象,当某个对象调用类方法时,该对象会把自身的引用作为第一个参数自动传给该方法。

在上面这段代码中,我们使用Person类创建了两个不同的对象,打印构造方法中的self发现也不同,这一点也恰好印证了:无论是类中的构造函数还是普通的类方法,实际调用它们的谁,则第一个参数 self 就代表谁。

在上面的章节中我们通过生活中的例子,初步认识了对象,学到了如何定义一个类,知道了类中可以包含属性(变量)与方法(函数)。下面我们继续学习在类中定义的变量与函数,加深对python类的认识。

三、变量的划分(类变量、实例变量、局部变量)

类变量是定义在类内,但在函数外部的变量。

实例变量是定义在类的函数体内,并且是以“self.变量名”定义的变量。

局部变量是定义在类的函数体内,但不是以“self.变量名”定义的变量。

3.1类变量


class Person:
    name = "sun"  # 这是一个类变量

    def __init__(self, age):
        self.age = age  # 这是一个实例变量

    def talk(word):
        words = "Hi"+word  # 这是一个局部变量
        print(words)

p1 = Person(12)
p2=Person(18)

#类变量的调用方式
print(Person.name)#调用类变量的第一种方式:类名.变量名
print(p1.name)#调用类变量的第二种方式:对象名.变量名

#类变量为所有实例共享
print(p1.name)
print(p2.name)

#类变量的修改方式
Person.name="张三"#通过类名.变量名的方式对类变量重新赋值
print(Person.name)#类变量的值变为"张三"
print(p1.name)#用对象p1调用类变量发现值变为"张三"
print(p2.name)#用对象p2调用类变量发现值也变为“张三”

在上面的这段代码中name为类变量。并且类变量具有两种调用方式:(1)类名.变量名(2)对象名.变量名。我们还可以通过类名.变量名的方式对类变量的属性值进行重新赋值修改。但是由于类变量为所有实例对象共享,修改类变量后,通过两个不同的实例对象重新调用name类变量,发现变量值也发生改变。

还有一点需要注意的是,通过类对象是无法修改类变量的。通过类对象对类变量赋值,其本质将不再是修改类变量的值,而是在给该对象定义新的实例变量。看如下代码:

class Student:
    name="王同学"
    def __init__(self,age):
        self.age=age
s1=Student(16)
s1.name="王五"
print(s1.name)
print(Student.name)

王五
王同学

不仅可以通过类名.变量名的方式修改类中已有的类变量,还可以动态添加没有的类变量。

在上段代码中添加以下代码:

class Person:
    name = "sun" 
    def __init__(self, age):
        self.age = age  
p1 = Person(12)
p2=Person(18)
Person.sex="男"
print(Person.sex)
print(p1.sex)
print(p2.sex)

 运行结果



3.2 实例变量 

下面的代码中age,name为实例变量,其中,由于 __init__() 函数在创建类对象时会自动调用,而 learn() 方法需要类对象手动调用。因此,Person类的类对象都会包含 age实例变量,而只有调用了 learn() 方法的类对象,才包含 name实例变量。它们都可以通过对象名.变量名的方式调用

class Person:
    def __init__(self, age):
        self.age = age  # 这是一个实例变量
    def learn(self):
        self.name="sun"#这也是一个实例变量
#实例变量调用方式:对象名.变量名
p1=Person(18)
p2=Person(19)
print(p1.age)
print(p2.age)
#p2对象调用learn方法后再调用name属性
p2.learn()
print(p2.name)
#p1对象在没有调用learn方法时直接调用name
print(p1.name)#直接报错

18
19
sun
Traceback (most recent call last):
  File "e:\VsCodeWorkSpace\PythonProjects\PythonDemo\vari.py", line 76, in <module>
    print(p1.name)#直接报错
AttributeError: 'Person' object has no attribute 'name' 

值得注意的是,如果类变量与实例变量同名,它会首选实例变量。看下面的例子

class Student:
    name="王同学"
    def __init__(self,name):
        self.name=name
s1=Student("王五")
print(s1.name)
print(Student.name)

王五
王同学

另外,和类变量不同,通过某个对象修改实例变量的值,不会影响类的其它实例化对象,更不会影响同名的类变量。例如:

class Person:
    def __init__(self, age):
        self.age = age  # 这是一个实例变量
p1=Person(18)
p2=Person(19)
print(p1.age)#18
print(p2.age)#19
#修改p1的age值
p1.age=20
print(p1.age)#20
print(p2.age)#19

 可以看出,对p1对象的age修改值,并不会影响到p2的age

3.3 局部变量

下面的代码段中c就是一个定义在函数内部的局部变量

class add:
    def sum(self,a,b):
        c=a+b
        print(c)
s=add()
s.sum(1,2)

需要注意的一点是,局部变量只能用于所在函数中,函数执行完成后,局部变量也会被销毁。

在这一章节,我们对python类中的属性(变量)进行了比较深入的分析,和类属性一样,类方法也可以进行更细致的划分,下面我们按照这个思路继续分析类中的方法(函数)

四、实例方法、静态方法、类方法

 采用 @classmethod 修饰的方法为类方法;采用 @staticmethod 修饰的方法为静态方法;不用任何修改的方法为实例方法

4.1 实例方法

class math:
    def sum(self,var1,var2):
        return var1+var2

上面这段代码中的sum方法就是一个实例方法,实例方法最大的特点就是,它最少也要包含一个 self 参数,用于绑定调用此方法的实例对象。实例方法通常可以用对象直接调用,也可以使用类名调用(但此方式需要手动给 self 参数传值)

class Math:
    def sum(self,var1,var2):
        return var1+var2
m=Math()
print(m.sum(2,3))#使用对象调用实例方法
print(Math.sum(m,2,6))#使用类名调用实例方法,但是必须传入对象本身

值得注意的是,类的构造方法也是一种实例方法。

4.2 类方法
与实例方法相似,类方法最少也要包含一个参数,只不过类方法中通常将其命名为 cls,Python 会自动将类本身绑定给 cls 参数(注意,绑定的不是类对象)。也就是说,我们在调用类方法时,无需显式为 cls 参数传参。

调用类方法的方式也有两种:(1)使用类名.方法名(2)使用对象名.方法名

class Math:
    @classmethod
    def sum(cls,var1,var2):
        return var1+var2

print(Math.sum(2,6))#使用类名调用类方法,但是不必显式传入类本身

#也可以使用对象调用类方法
m = Math()
print(m.sum(2,3))

值得注意的是,类方法需要使用@classmethod修饰符进行修饰,上面的sum方法如果不加@classmethod,python会将该方法认定为实例方法

4.3 静态方法

静态方法需要使用@staticmethod修饰,它没有类似 self、cls 这样的特殊参数,因此 Python 解释器不会对它包含的参数做任何类或对象的绑定。也正因为如此,类的静态方法中无法调用任何类属性和类方法。

class Math:
    @staticmethod
    def sum(var1,var2):
        return var1+var2

print(Math.sum(2,6))#使用类名调用静态方法

#也可以使用对象调用静态方法
m = Math()
print(m.sum(2,3))

 到此,通过以上所有的章节我们系统地认识了python对象、类、类的属性、类的方法,有了这些基础,接下来我们继续探讨python封装继承与多态,由于篇幅有限,后续章节会在下一篇博客中介绍。

  • 2
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

城南皮卡丘

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

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

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

打赏作者

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

抵扣说明:

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

余额充值