python——面向对象——知识汇总一

面向对象技术简介

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

面向对象中,常用术语包括:

  • 类:可以理解是一个模板,通过它可以创建出无数个具体实例。比如,前面编写的 tortoise 表示的只是乌龟这个物种,通过它可以创建出无数个实例来代表各种不同特征的乌龟(这一过程又称为类的实例化)。
  • 对象:类并不能直接使用,通过类创建出的实例(又称对象)才能使用。这有点像汽车图纸和汽车的关系,图纸本身(类)并不能为人们使用,通过图纸创建出的一辆辆车(对象)才能使用。
  • 属性:类中的所有变量称为属性。例如,tortoise 这个类中,bodyColor、footNum、weight、hasShell 都是这个类拥有的属性。
  • 方法:类中的所有函数通常称为方法。不过,和函数所有不同的是,类方法至少要包含一个 self 参数(后续会做详细介绍)。
              例如,tortoise 类中,crawl()、eat()、sleep()、protect() 都是这个类所拥有的方法,类方法无法单独使用,只能和类的对象一起使用。

class tortoise:
    bodyColor = "绿色"
    footNum = 4
    weight = 10
    hasShell = True
    #会爬
    def crawl(self):
        print("乌龟会爬")
    #会吃东西
    def eat(self):
        print("乌龟吃东西")
    #会睡觉
    def sleep(self):
        print("乌龟在睡觉")
    #会缩到壳里
    def protect(self):
        print("乌龟缩进了壳里")

# 实例化类
x = tortoise()

# 访问类的属性和方法
print(x.bodyColor)
print(x.footNum)
print(x.weight)
print(x.hasShell)
print("===================================")
x.crawl()
x.eat()
x.sleep()
x.protect()

============================================================================

定义类

类定义

语法格式如下:

class ClassName:
    <statement-1>
    .
    .
    .
    <statement-N>
class 类名:
    多个(≥0)类属性...
    多个(≥0)类方法...
注意,无论是类属性还是类方法,对于类来说,它们都不是必需的,可以有也可以没有。另外,Python 类中属性和方法所在的位置是任意的,即它们之间并没有固定的前后次序。
和变量名一样,类名本质上就是一个标识符,因此我们在给类起名字时,必须让其符合 Python 的语法。
因此,在给类起名字时,最好使用能代表该类功能的单词,例如用“Student”作为学生类的类名;甚至如果必要,可以使用多个单词组合而成,例如初学者定义的第一个类的类名可以是“TheFirstDemo”。

注意,如果由单词构成类名,建议每个单词的首字母大写,其它字母小写。

给类起好名字之后,其后要跟有冒号(:),表示告诉 Python 解释器,下面要开始设计类的内部功能了,也就是编写类属性和类方法。

其实,类属性指的就是包含在类中的变量;而类方法指的是包含类中的函数。
换句话说,类属性和类方法其实分别是包含类中的变量和函数的别称。
需要注意的一点是,同属一个类的所有类属性和类方法,要保持统一的缩进格式,通常统一缩进 4 个空格。

类实例化后,可以使用其属性,实际上,创建一个类之后,可以通过类名访问其属性。

 =============================================================================

Python的   __init__()   类构造方法

 在创建类时,我们可以手动添加一个 __init__() 方法,该方法是一个特殊的类实例方法,称为构造方法(或构造函数)。

 构造方法用于创建对象时使用,每当创建一个类的实例对象时,Python 解释器都会自动调用它。Python 类中,手动添加构造方法的语法格式如下:

def __init__(self,...):
    代码块

 注意,此方法的方法名中,开头和结尾各有 2 个下划线,且中间不能有空格。Python 中很多这种以双下划线开头、双下划线结尾的方法,都具有特殊的意义

 _init__() 方法可以包含多个参数,但必须包含一个名为 self 的参数,且必须作为第一个参数。

也就是说,类的构造方法最少也要有一个 self 参数。

例如,仍以 TheFirstDemo 类为例,添加构造方法的代码如下所示:

class TheFirstDemo:
    '''这是一个学习Python定义的第一个类'''

    #构造方法
    def __init__(self):
        print("调用构造方法")

    # 下面定义了一个类属性
    add = 'http://c.biancheng.net'


    # 下面定义了一个say方法
    def say(self, content):
        print(content)

 注意,即便不手动为类添加任何构造方法,Python 也会自动为类添加一个仅包含 self 参数的构造方法。

仅包含 self 参数的 __init__() 构造方法,又称为类的默认构造方法。

 显然,在创建 zhangsan 这个对象时,隐式调用了我们手动创建的 __init__() 构造方法。

 不仅如此,在 __init__() 构造方法中,除了 self 参数外,还可以自定义一些参数,参数之间使用逗号“,”进行分割。

例如,下面的代码在创建 __init__() 方法时,额外指定了 2 个参数:

 注意,由于创建对象时会调用类的构造方法,如果构造函数有多个参数时,需要手动传递参数,

可以看到,虽然构造方法中有 self、name、add 3 个参数,但实际需要传参的仅有 name 和 add,也就是说,self 不需要手动传递参数。

Python类的实例化

我们已经学会如何定义一个类,但要想使用它,必须创建该类的对象。创建类对象的过程,又称为类的实例化。

对已定义好的类进行实例化,其语法格式如下:          类名(参数)

定义类时,如果没有手动添加 __init__() 构造方法,又或者添加的 __init__() 中仅有一个 self 参数,则创建类对象时的参数可以省略不写。

在上面的程序中,由于构造方法除 self 参数外,还包含 2 个参数,且这 2 个参数没有设置默认参数,

因此在实例化类对象时,需要传入相应的 name 值和 add 值(self 参数是特殊参数,不需要手动传值,Python 会自动传给它值)。

Python类对象的使用

定义的类只有进行实例化,也就是使用该类创建对象之后,才能得到利用。总的来说,实例化后的类对象可以执行以下操作:

  • 访问或修改类对象具有的实例变量,甚至可以添加新的实例变量或者删除已有的实例变量;
  • 调用类对象的方法,包括调用现有的方法,以及给类对象动态添加方法。
类对象访问变量或方法

使用已创建好的类对象访问类中实例变量的语法格式如下:

类对象名.变量名

使用类对象调用类中方法的语法格式如下:

对象名.方法名(参数)

注意,对象名和变量名以及方法名之间用点 "." 连接。

class CLanguage :

    # 下面定义了2个类变量

    name = "C语言中文网"

    add = "http://c.biancheng.net"

    def __init__(self,name,add):
        #下面定义 2 个实例变量
        self.name = name
        self.add = add
        print(name,"网址为:",add)

    # 下面定义了一个say实例方法
    def say(self, content):
        print(content)


# 将该CLanguage对象赋给clanguage变量
clanguage = CLanguage("C语言中文网","http://c.biancheng.net")


#输出name和add实例变量的值
print(clanguage.name,clanguage.add)


#修改实例变量的值
clanguage.name="Python教程"
clanguage.add="http://c.biancheng.net/python"

#调用clanguage的say()方法
clanguage.say("人生苦短,我用Python")

#再次输出name和add的值
print(clanguage.name,clanguage.add)

Python self用法详解

在定义类的过程中,无论是显式创建类的构造方法,还是向类中添加实例方法,都要求将 self 参数作为方法的第一个参数。

事实上,Python 只是规定,无论是构造方法还是实例方法,最少要包含一个参数,并没有规定该参数的具体名称。

之所以将其命名为 self,只是程序员之间约定俗成的一种习惯,遵守这个约定,可以使我们编写的代码具有更好的可读性(大家一看到 self,就知道它的作用)。


那么,self 参数的具体作用是什么呢?

打个比方,如果把类比作造房子的图纸,那么类实例化后的对象是真正可以住的房子。

根据一张图纸(类),我们可以设计出成千上万的房子(类对象),每个房子长相都是类似的(都有相同的类变量和类方法),但它们都有各自的主人,那么如何对它们进行区分呢?


当然是通过 self 参数,它就相当于每个房子的门钥匙,可以保证每个房子的主人仅能进入自己的房子(每个类对象只能调用自己的类变量和类方法)。

也就是说,同一个类可以产生多个对象,当某个对象调用类方法时,该对象会把自身的引用作为第一个参数自动传给该方法,

换句话说,Python 会自动绑定类方法的第一个参数指向调用该方法的对象。如此,Python解释器就能知道到底要操作哪个对象的方法了。

总之,无论是类中的构造函数还是普通的类方法,实际调用它们的谁,则第一个参数 self 就代表谁。

===================================================================================

Python类变量和实例变量(类属性和实例属性)

无论是类属性还是类方法,都无法像普通变量或者函数那样,在类的外部直接使用它们。

我们可以将类看做一个独立的空间,则类属性其实就是在类体中定义的变量,类方法是在类体中定义的函数。


在类体中,根据变量定义的位置不同,以及定义的方式不同,类属性又可细分为以下 3 种类型:

1、类体中、所有函数之外:此范围定义的变量,称为类属性或类变量;

2、类体中,所有函数内部:以“self.变量名”的方式定义的变量,称为实例属性或实例变量;

3、类体中,所有函数内部:以“变量名=变量值”的方式定义的变量,称为局部变量。

class CLanguage :
    # 下面定义了2个类变量
    name = "C语言中文网"
    add = "http://c.biancheng.net"
    # 下面定义了一个say实例方法
    def say(self, content):
        print(content)




#使用类名直接调用
print(CLanguage.name)
print(CLanguage.add)

print("================================================")

#修改类变量的值
CLanguage.name = "Python教程"
CLanguage.add = "http://c.biancheng.net/python"


print(CLanguage.name)
print(CLanguage.add)

print("+++++++++++++++++++++++++++++++++++++++++++++++++++++++")

print("修改前,各类对象中类变量的值:")
clang1 = CLanguage()
print(clang1.name)
print(clang1.add)
clang2 = CLanguage()
print(clang2.name)
print(clang2.add)


print("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&")

print("修改后,各类对象中类变量的值:")

CLanguage.name = "Python教程"
CLanguage.add = "http://c.biancheng.net/python"

print(clang1.name)
print(clang1.add)

print(clang2.name)
print(clang2.add)

类变量(类属性)

类变量指的是在类中,但在各个类方法外定义的变量。举个例子:

class CLanguage :
    # 下面定义了2个类变量
    name = "C语言中文网"
    add = "http://c.biancheng.net"
    # 下面定义了一个say实例方法
    def say(self, content):
        print(content)

上面程序中,name 和 add 就属于类变量。
类变量的特点是,所有类的实例化对象都同时共享类变量,也就是说,类变量在所有实例化对象中是作为公用资源存在的。

类方法的调用方式有 2 种,既可以使用类名直接调用,也可以使用类的实例化对象调用。

通过类名不仅可以调用类变量,也可以修改它的值。

当然,也可以使用类对象来调用所属类中的类变量(此方式不推荐使用)。

注意,因为类变量为所有实例化对象共有,通过类名修改类变量的值,会影响所有的实例化对象。

注意,通过类对象是无法修改类变量的。通过类对象对类变量赋值,其本质将不再是修改类变量的值,而是在给该对象定义新的实例变量

实例变量(实例属性)

实例变量指的是在任意类方法内部,以“self.变量名”的方式定义的变量,其特点是只作用于调用方法的对象。

另外,实例变量只能通过对象名访问,无法通过类名访问。

通过类对象可以访问类变量,但无法修改类变量的值。

这是因为,通过类对象修改类变量的值,不是在给“类变量赋值”,而是定义新的实例变量。

类中,实例变量和类变量可以同名,但这种情况下使用类对象将无法调用类变量,它会首选实例变量,这也是不推荐“类变量使用对象名调用”的原因。

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

============================================================================================

Python实例方法、静态方法和类方法

和类属性一样,类方法也可以进行更细致的划分,具体可分为类方法、实例方法和静态方法。
和类属性的分类不同,区分这 3 种类方法是非常简单的,即采用

@classmethod 修饰的方法为类方法;

@staticmethod 修饰的方法为静态方法;

不用任何修改的方法为实例方法。

Python类实例方法

通常情况下,在类中定义的方法默认都是实例方法。类的构造方法理论上也属于实例方法,只不过它比较特殊。

实例方法最大的特点就是,它最少也要包含一个 self 参数,用于绑定调用此方法的实例对象(Python 会自动完成绑定)。

实例方法通常会用类对象直接调用。

Python类方法

Python 类方法和实例方法相似,它最少也要包含一个参数,只不过类方法中通常将其命名为 cls,Python 会自动将类本身绑定给 cls 参数(注意,绑定的不是类对象)。

也就是说,我们在调用类方法时,无需显式为 cls 参数传参。

和 self 一样,cls 参数的命名也不是规定的(可以随意命名),只是 Python 程序员约定俗称的习惯而已。

和实例方法最大的不同在于,类方法需要使用@classmethod修饰符进行修饰。

注意,如果没有 @classmethod,则 Python 解释器会将 fly() 方法认定为实例方法,而不是类方法。

类方法推荐使用类名直接调用,当然也可以使用实例对象来调用(不推荐)。

Python类静态方法

静态方法,其实就是我们学过的函数,和函数唯一的区别是,静态方法定义在类这个空间(类命名空间)中,而函数则定义在程序所在的空间(全局命名空间)中。
静态方法没有类似 self、cls 这样的特殊参数,因此 Python 解释器不会对它包含的参数做任何类或对象的绑定。也正因为如此,类的静态方法中无法调用任何类属性和类方法。静态方法需要使用@staticmethod修饰

静态方法的调用,既可以使用类名,也可以使用类对象。

===============================================================================

Python类调用实例方法

实例方法的调用方式其实有 2 种,既可以采用

1、类对象调用;

2、类名调用。

如果想通过类名直接调用实例方法,就必须手动为 self 参数传值。

PS:通过手动将 clang 这个类对象传给了 self 参数,使得程序得以正确执行。实际上,这里调用实例方法的形式完全是等价于 clang.info()

总的来说,Python 中允许使用类名直接调用实例方法,但必须手动为该方法的第一个 self 参数传递参数,这种调用方法的方式被称为“非绑定方法”。

========================================================================================

Python描述符详解

 PS:就是类的封装,类似于java中的getter、setter方法,这样就明白了。

本质上看,描述符就是一个类,只不过它定义了另一个类中属性的访问方式。换句话说,一个类可以将属性管理全权委托给描述符类。

描述符是 Python 中复杂属性访问的基础,它在内部被用于实现 property、方法、类方法、静态方法和 super 类型。

描述符类基于以下 3 个特殊方法,换句话说,这 3 个方法组成了描述符协议:

  • __set__(self, obj, type=None):在设置属性时将调用这一方法(本节后续用 setter 表示);
  • __get__(self, obj, value):在读取属性时将调用这一方法(本节后续用 getter 表示);
  • __delete__(self, obj):对属性调用 del 时将调用这一方法。

其中,实现了 setter 和 getter 方法的描述符类被称为数据描述符;反之,如果只实现了 getter 方法,则称为非数据描述符。


实际上,在每次查找属性时,描述符协议中的方法都由类对象的特殊方法 __getattribute__() 调用(注意不要和 __getattr__() 弄混)。

也就是说,每次使用类对象.属性(或者 getattr(类对象,属性值))的调用方式时,都会隐式地调用 __getattribute__(),它会按照下列顺序查找该属性:

    1. 验证该属性是否为类实例对象的数据描述符;
    2. 如果不是,就查看该属性是否能在类实例对象的 __dict__ 中找到;
    3. 最后,查看该属性是否为类实例对象的非数据描述符。

下面这个调用了 其getter方法:

下面这个调用了setter方法赋值:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值