python 类和对象

类和对象

1. 基本概念

1.1 什么是对象?

对于对象而言,其具有属性与行为。在我们进行描述的时候,属性,多体现为名词,而行为,多体现为动词。

1.2 什么是类?

所谓的类,其实指的就是一个类别,即具有相同属性与行为的所有对象构成的一个整体。相同类别的对象之间总会比不同类别的对象之间更加相似。

1.3 类与对象的关系

关于类与对象,我们可以这样总结二者的关系:

类是对象的抽象,而对象是类的具体表现形式。
类是设计的蓝图(模板),而对象就是该蓝图设计出的具体产物。
以下给出具体说明。

2. 类的定义

2.1 类的定义

我们通过class关键字来定义一个类,格式如下:

class 类名:

类体

class  Wwudi(object):   //创建类名,第一个字母必须大写
    def __init__(self,sex,buled):     //创建类的参数名
        self.sex=sex                  //设定参数类型
        self.blued=buled              
    def marry(self):                 //设定行动
        a = input("today is mon")
        return a

jhon = Wwudi("aaa","111")       //传递值
print(jhon)           
print(type(jhon))
print(jhon.marry())             //调用类的定义

2.2 动态增加属性与方法

我们要设计一辆汽车,该汽车具有的功能,就会体现在设计图纸中。当我们使用该图纸创建出真正的汽车之后,该汽车自然也就具有设计图纸中所表明的功能。

同样,我们在类的内部定义属性与方法(设计图纸),当我们使用该类创建具体的对象时,该对象也就自然具有类中定义的属性与方法。

除了在类中预先定义属性与方法外,我们也可以动态的为对象增加属性与方法。

动态为类增加属性与方法

  • 动态增加的方法在调用时,需要显式的传递当前对象。
  • 动态增加的属性与方法仅对当前对象有效,对于其他对象是无效的。

2.3 定义类的属性和方法

对象的行为,我们通过在类内定义方法来实现。所谓方法,其形式与函数非常相似,只不过是定义类的内部,关联了某个对象而已。

一个人的类别,具有走路与跑步两种行为。

self

在两个方法中,都具有一个参数:self。该参数用来表示当前的对象。何为当前对象呢?指的就是调用该方法的时候,所使用的对象。简单来说,就是谁调用了这个方法,当前对象就是谁。

我们知道,如果仅仅定义了类,而没有为类具体化(创建对象),是不能够使用类中定义的功能的,这就正如我们仅有汽车的设计图纸,而没有创建出具体的汽车,就不能够开车出行一样。因此,如果没有创建对象,就不能够调用walk与run方法。而当我们通过对象调用方法时,该对象就会隐式的传递给方法的第一个参数(无需我们显式传递)。

刚才我们在类中定义了方法,来表示对象的行为,但是,对象也是可以具有属性的。例如,人可以具有姓名,年龄等属性。

关于定义属性,我们可以在__init__中进行定义。__init__方法是一个特殊的方法,该方法会在创建对象时自动得到执行。并且,每创建一个对象,该方法都会执行一次。

验证__init__方法(创建时—是两个——)

既然__init__方法具有在创建对象时自动执行的特征,我们就可以在该方法中执行对象的初始化,定义属性就是一件最常用的操作。而__init__方法具有初始化的能力,我们也习惯将其称为构造器或构造方法。

我们在__init__方法中,定义了name与age两个属性。在创建对象时,就能够自动调用该方法,为对象增加这两个属性。同时,我们也修改了walk与run两个方法的实现,在方法中访问name属性,注意,name与age两个属性都是关联当前self对象的,因此也必须要通过对象才能够访问这两个属性。

含有参数的__init__方法

上述的程序,成功在类中定义了属性与方法,并且在创建对象时,也访问了类中定义的属性与方法。不过,这个程序有一个不足,就是无论我们创建多少个对象,对象的属性都是完全一致的。

为了能够更加灵活的创建对象,让对象具有不同的属性值,我们可以在__init__方法中增加参数,然后在创建对象时,动态传递实际参数来初始化对象的属性(不再使用固定值初始化),这样就能够避免创建属性值完全相同的对象了。

通过__init__方法初始化。

3. 类的成员

3.1类属性与实例属性

之前我们定义的属性,都是与类的对象相关联的,这种属性称为实例属性。对于对象,也称为实例,例如,创建类的对象,也可以称为,创建类的实例。

除了实例属性外,我们也可以定义类属性,所谓类属性,就是与当前类进行关联,不属于对象。类属性直接定义在类体中,例如:

class ClassName:

class_property = 1

这样,就定义了一个名称为class_property的类属性,其关联绑定的值为1。

类属性与实例属性的区别在于:

  • 属性的绑定不同
    类属性与类进行绑定,与类的任何一个对象都无关(但是可以共享给所有对象去访问)。实例属性与对象进行绑定,每个对象都有自己的实例属性。如果一个对象改变了实例属性的值,对其他对象没有影响。

  • 访问方式不同
    类属性既可以通过类访问,也可以通过对象访问(类属性会共享给所有对象)。而实例属性只能通过对象访问,而不能通过类访问(实例属性只属于某个类的对象,与类本身无关)。在通过对象访问类属性时,仅限于只读访问,而无法修改类属性的值。因为尝试进行的修改,只不过是动态的为当前对象新增一个实例属性(与类属性同名)而已。

静态属性的使用

  • 类属性与实例属性名称相同
    当类属性与实例属性命名相同时,也不会产生错误。通过类访问的,永远是类属性,而通过对象访问的,可能是类属性,也可能是实例属性。此时要分为读取属性的值,还是修改属性的值。当读取属性值时,首先尝试访问同名的实例属性,如果实例属性不存在,则会访问类属性(如果类属性也不存在则会产生错误)。当修改属性值时,如果实例属性存在,则修改,如果实例属性不存在,则新增该实例属性,即通过对象修改属性时,操作的属性一定是实例属性。

  • 重名的程序。

3.2 类方法与实例方法

属性可以分为类属性与实例属性,同样,方法也可以分为类方法与实例方法。类似的,实例方法与具体的类的某个对象想关联,我们之前所接触的方法,都是实例方法。我们可以使用@classmethod来修饰一个方法,这样的方法称为类方法。例如:

class ClassName:

    @classmethod

    def class_method(cls):

        方法体

按照惯例(并非语法要求),我们将类方法的第一个参数命名为cls(这类似于实例方法的第一个参数self),该参数是有特殊意义的,用来表示当前类,即调用该类方法的那个类。在调用类方法时,cls无需我们显式传递(就像实例方法的self无需我们显式传递一样)。

类方法与实例方法,二者既可以通过类名调用,也可以通过对象来调用。不过,就像通过对象访问类属性一样,通过对象来调用类方法会造成不必要的混淆(类方法与类的对象无关,是绑定当前类的),因此,我们应该总是通过类名来调用类方法。

类方法与实例方法对属性的访问

在类方法中,需要通过参数(cls)访问类属性,而不能直接访问类属性。实例方法没有cls参数,可以通过类名来访问类属性,但是,这是一种硬编码的方式,如果以后类名发生了改变,则我们通过类名访问类属性的语句都需要进行修改。这不利于程序的维护。为了降低耦合性,我们在实例方法中,可以通过__class__来动态获取当前对象所属的类:

self.class # 相当于获取到了cls,也就是self对象所属的类(动态获取)。

更简单一些,如果是在类的内部,我们还可以省略对象的限定,直接使用:

_class_

然后,我们就可以这样去访问类属性:

类的对象.class.类属性

class.类属性 # 必须在类的内部

这种访问的优势在于,以后就算类名发生了改变,访问类属性的语句也无需进行任何修改,利于程序的维护。

对属性的访问

  • 类方法的作用
    类方法与当前类绑定,与类的对象无关,因此,我们通常使用类方法来作为工厂方法,用来创建并返回类的对象,这就相当于提供了另外一种构造器。

  • 使用类方法提供对象的复制。

3.3 静态方法

除了类方法与实例方法外,类中还可以定义静态方法。

静态方法使用@staticmethod修饰,例如:

class ClassName:

    @staticmethod

    def static_method():

        方法体

与类方法不同,静态方法没有cls参数。对于静态方法而言,其既与当前类的对象无关,也与当前类无关,可以说,静态方法只是定义在类的内部,从逻辑结构上,与当前类划分到了一起,从功能的角度讲,我们完全可以将静态方法迁移到类的外部,作为函数来实现同样的功能。

不过,对于当前类来说,静态方法还是有一定的意义的。如果某个函数,其实现的功能与某个类关系紧密,但是又不依赖于当前类(cls)与当前对象(self)时,我们就可以将该函数声明在类的内部,作为静态方法。静态方法既可以通过类名调用,也可以通过对象调用,建议通过类名调用,因为静态方法与对象无关。

静态方法的使用。

3.4 类与实例的选择

我们在类中可以定义类属性,类方法,静态方法,也可以定义实例属性与实例方法。可是,我们在设计一个类的时候,该如何进行选择呢?

4. 魔法方法

在Python语言中,定义了一些特殊的方法,这些方法通常不会显式去调用,而是在特定的场合下隐式调用执行的。这些特殊的方法名称都是以双下划线开头,并且以双下划线结尾,我们将这些方法称为魔法方法。

_new_(cls, ……)
创建cls类的对象。通过参数的cls可知,该方法是一个类方法,但是不需要使用装饰器来修饰(@classmethod),该方法的其他参数由构造器传入。该方法中,通常会调用父类的__new__方法来创建对象,并返回。如果该方法返回值为当前类的对象,则会继续调用初始化方法(init),传入当前创建的对象,否则,初始化方法不会执行。

该方法通常不需要自行实现,当我们实现该方法时,主要用来完成自定义的对象创建。

  • _init_(self)
    初始化方法,在创建对象时,如果__new__方法创建并返回了当前类型的对象,则会调用该方法,对new创建的对象执行初始化。

  • _del_(self)
    当销毁对象时,调用该方法。

  • _str_(self)
    当调用内建函数str,format或print时,就会调用对象的该方法。该方法必须返回字符串(str)类型,用来描述对象的字符串表示。

  • _repr_(self)
    当调用内建函数repr时,就会调用对象的该方法。该方法必须返回字符串(str)类型,用来描述对象的字符串表示。如果类中定义了该方法,但是没有定义__str__方法,则当需要调用__str__方法时,也会调用该方法代替。

  • _bytes_(self)
    当调用内建函数bytes时,会调用该方法,该方法必须返回字节(bytes)类型,用来以字节的形式描述对象。

  • _call_(self)
    当把类的对象作为方法调用时,就会调用该方法。

5. 动态属性操作

Python提供了如下的内建函数,用来操作对象的属性。

  • hasattr(obj, name)
    判断obj对象中是否存在name指定的属性名,存在返回True,否则返回False。

  • setattr(obj, name, value)
    将obj对象的name属性设置为value值。相当于执行如下的操作:

  • obj.name = value
    如果name属性存在,则覆盖,如果不存在,则为对象obj新增name属性。

  • getattr(obj, name[, default])
    返回obj对象的name属性值,相当于执行如下的操作:

  • obj.name
    如果name属性值存在,则返回属性值,如果属性值不存在,返回default参数值,如果属性值不存在,default参数也不存在,则产生AttributeError。

  • delattr(obj, name)
    删除obj对象的name属性。相当于执行如下的操作:
    del obj.name
    如果指定的属性不存在,则会产生AttributeError。

如果使用obj.name的方式访问属性的话,name必须是编写代码时已知的内容,而不能通过字符串来指定。以上函数的优势在于,我们可以通过字符串的形式来操作属性,而无需在编写代码的时候就知道具体的属性名称。因此,这就给我们操作属性带来了一定的灵活性。我们完全可以在运行时以字符串的形式传递属性名,进行操作。

6. 面向对象与面向过程

如今,我们进行的编程往往都是面向对象编程(OOP,Object-Oriented Programming)。在面向对象编程之前,还有一种编程方式,叫做面向过程编程。对于面向过程而言,体现的是一种流程设计,即按部就班的完成每一个环节。为了实现每个环节的可复用性,环节都是通过调用一个个函数来实现的。因此,在面向过程的编程中,通常都是定义大量的函数,按照需求顺序依次进行调用。

而面向对象程序设计则不同,在面向对象中,会根据需求,划分为若干个类,每个类会创建对象,以对象的方式来进行交互。所以,在面向对象中,我们的程序不再是以函数为单位,而是以对象为单位。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值