Python学习笔记——类(面向对象)

Python中使用类(class〕来实现面向对象编程。Python中的类, 具有面向对象编程的所有基本特征:允许多继承、派生类可以重写它父类的任何方法、方法可以调用父类中同名的方法, 对象可以包含任意数量和类型的数据成员。

创建类

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

类定义会创建一个新的命名空间作为一个局部的作用域。在该作用域中的变量被叫作成员变量。在该类作用域下的函数就被叫作成员函数, 也叫作该类的方法。当一个类定义结束后, 系统就会创建一个类对象(ClassObject)。

创建类属性

1、定义类属性

需要注意的是, 在定义类方法时, 需要有一个默认的形参一self。而在调用类方法时, 却不需要传入形参self所对应的实参。因为这个形参self是由类的内部机制调用的。

class  MyClass :
    """ A  simple  example  class """
    i  =  12345
    def f(self):
        return  ' I  love  Python ' 

2、使用类

创建好的类可以实例化成一个对象, 井通过调用对象的方法来实现具体功能。

myc  = MyClass()
print(myc.i)
print(myc.f())

3、类的内置属性

Python中的类有一些相同的内置属性。这些内置属性用于维护类的基本信息。

  • __name__:类名称。

  • __doc__:类的文档字符串。

  • __module__:类定义所在的模块。如果是直接运行当前文件, 该值为__main__

  • __base__:该类所有的父类<class『object'>列表, 是一个阳ple类型的对象。

  • __diet__:该类的所有属性(由类的数据属性组成), 是一个diet类型的对象。

定义类的动态属性

Python中的类, 在使用时能够根据需要随时添加动态属性。

添加动态属性

为类添加动态属性的方法是:在实例化对象的后面加一个点, 在点后跟上属性名称。

如果该对象己经有这个属性, 系统就会读取其内容;否则, 系统会自动为该对象加上这个属。

class  Record :
    pass

Anna  =  Record()                #实例化一个对象
Anna.name  ='Anna '              #为对象添加属性并赋值
Anna.age  =  42
print(Anna.name, Anna.age)

删除动态属性

虽然可以动态地添加属性, 但总不能无止境地增加很多属性。在有时还需将不用的属性删除。用de!加上对象属性, 即可删除属性。

del  Anna.age
print(Anna.age)

限制类属性(__slots__)

__slots__是一个特殊的变量, 其值可以是元组的形式, 元组的元素为该类所允许添加的属性名称。在一个类中, 一旦为_slots_赋值, 则该类的实例化对象就只能添加__slots__中所规定的属性。

class  Record :
   __slots__ = ('name','age')

Anna  =  Record()                #实例化一个对象
Anna.name  ='Anna '              #为对象添加属性并赋值
Anna.age2  =  42                 #系统报错

实例化类对象

带有初始值的实例化

实例化类,可以使用类的名字加括号来实现。对于复杂功能的类,实例化的同时需要为其初始化一些必须的成员变量,即带有初始值的实例化。

类的初始化方法(__init__)

要想实现带有初始值的实例化, 需要在定义类时, 在类里面实现一个__init__方法。__init__方法的定义与函数几乎一样, 也需要形参, 并且支持形参默认值等规则。

class MyClass:                          #定义一个类
    def __init__(self,name,age):        #定义该类的初始化函数
        self:name=name
        self.age=age
    def getrecode(self):              #定义一个成员函数
        return self.name,self.age
myc=MyClass("Anna",42)
print(myc.getrecode())                #调用对象的成员函数, 并将返回值打印。输出元纽类型:(Anna’,42)

隐藏调用类的初始化方法

每个类实例化时,都会调用内部默认的__init__方法,如果在类中实现了__init__方法,则会优先调用自己的__init__方法。即使没有初始值也会调用。

注意:如果类中的__init__函数, 有除self以外的参数。实例化该类时, 就必须输入与__init__函数应的参数, 否则就会错。

class中的self

在类中,可以使用self关键字指定本身。类中的成员函数必须第一个参数是self,以保证实例化的对象能调用自己的成员函数。

1、直接调用类的成员函数:类名.方法

从函数传值的角度来看, 直接使用该类的成员函数并传入实例化对象, 与通过“类对象.成员函数”的调用方法效果一样。

2、将成员函数定义在外面

如果将类中的成员函数(即方法)看成一个函数, 则完全可以把类的成员函数定义在类外面。但是, 第一个参数是self这个规则还要必须保留。例如:

def fun(self):                           #在类的外面定义方法
    return 'IlovePython'

class MyClass:
    i=12345
    f=fun                                #在类的内部指定成员函数

myc=MyClass()                            #实例化类对象, 并赋位给myc
print(myc.f())                    #调用类实例myc的成员函数f, 并打印返回值。输出:I love Python

3、类内的成员互相访问

想在类中使用该类的其它的成员变量或方法,需要使用self加点的方式调用

在Python中, 每个值都是一个对象, 可以通过object.__class__来获取对象的class(即类型), 其作用与type()相同。

类方法(@classmethod)与静态方法(@staticmethod)

类方法

在一个类的定义中,如某个方法使用了装饰器@classmethod进行装饰,则说明该方法是一个类方法。

类方法与默认成员方法的区别是:类方法属于类;而默认成员方法属于类实例化对象。具体表现为:

  • 类方法的第一个参数必须是cls(用来指代该类), 而默认成员方法的第一个参数必须是self(用来指代该类的实例对象)。在调用类方法, 需要使用“类名.类方法名”的方式。

  • 在调用默认成员方法时, 则是使用“该类的实例化对象.类方法名”的方式。

class MyClass:
    def f(self):                         #默认的成员方法
        return 'I love Python'

    @classmethod
    def fcls(cls):                        #定义类方法
        return '类方法:I love Python'

myc=MyClass()
print(myc.f())
print(MyClass.fcls())

静态方法

静态方法的定义是使用装饰器@staticmethod进行装饰的。静态方法的特点是:第一个参数没有任何要求, 与普通的函数参数一样。其调用方式更加宽松, 使用类名或是类实例化对象都可以对其进行调用。代码如下:

class  MyClass :
    @staticmethod
    def fstatic(  ) :
        return '静态方法:Ilove  Python '

类变量与实例变量

变量与实例变量的区别:

  • 类变量:是指类的属性和方法, 类似于一种静态数据。类变量是在定义类时所定义的, 类的所有实例都会共享类变量;

  • 实例变量:更像是一种动态数据。只有在实例化时, 系统才会为该实例指定它特有的数据, 有别于该类中的其他个体。

通过修改一个类的类变量, 可以将这个类的所有实例化对象的属性统一修改。但是, 当实例变量与类变量同名时, 系统会以实例变量优先。这会导致类变量失效, 从而无法批量修改实例化后的类属性。

销毁类实例化对象

调用__del__方法可以销毁类对象。在销毁对象时,会自动调用__del__方法。

类变量的私有化属性

以两个下划线开头的成员对象为私有化成员

私有化的实现方式是:给类变量加上一个私有化(private)权限。被私有化的属性不能被该类的实例化对象直接访问, 但是类的内部成员函数是可以访问的。如果类的实例化对象想要取得该类的私有化属性, 可以通过调用该类中的get函数来完成。

与私有化(private)对应的是公有化(public)。公有化是Python中的默认权限, 即, 所有的对象都可以访问。

使用装饰器技术实现私有化(@property)

私有化属性的应用提高了程序的健壮性。但必须为私有化变量封装get方法, 通过调用get方法才可以取值。

1、装饰器实现私有化变量的get函数

在get函数上方使用@property修饰后,可以把改get函数当成属性来用,即:对象.get函数名

2、装饰器实现私有化变量的set函数

函数Occupation是私有变量__Occupation的set函数。通过@Occupation.setter装饰之后, 就可以当作属性被调用了

子类继承

类的继承分为单继承和多继承。

  • 单继承是指派生类只有一个父类。即, 只继承了一个父类的属性及方法。

  • 多继承是指, 派生类有多个父类。即, 子类继承了多个父类的属性及方法。

单继承的实现

单继承的实现非常简单定义类时, 在类名后面加一个括号, 在括号里指定父类的类名。

访问派生类的属性时, 首先会在当前的派生类中搜索, 如果没有找到, 则会递归地去基类中寻找。

当子类的方法与父类的方法同名时, 父类的方法将失效。即, 子类方法覆写(override)了父类的方法。

多重继承的实现

多重继承与单继承类似, 只不过是在类名后的括号里多加几个父类, 间用逗号分割。

多重继承下, 若要访问派生类的属性, 默认的搜索的规则是:深度优先, 从左到右。即:

(1)如果一个属性在当前类中没有被找到, 它就会搜寻FatherClassNamel。

(2)如果FatherClassName1中没找到, 就会递归地搜寻Fath巳rClassNamel的父类。

(3)如果FatherClassName1的所有父类没找到, 就会搜索FatherClassName2。

(4)循环(2)、(3)两步, 依次类推, 直到找到为止。

(5)如果都没找到就会报错。

super函数

用于在有类继承关系且有方法覆盖的子类中,调用父类中被覆盖的方法。
通过super函数进行调用的父类方法, 会保证只执行一次。

注意:使用super函数时, 对父类的方法调用会自动传入self。无需再传入self, 否则会报错误。

类相关的内置函数

判断实例(isinstance)

函数isinstance的作用, 判断某个实例对象是否是某个类或其派生类的实例。

定义:isinstance(object, class_name)

  • object:实例对象

  • class_name:类名

如果object(object.__class__)是类class_name或其派生类的实例, 则返回True。

判断子类(issubclass)

函数issubclass的作用是, 判断类是否是另一个类的子类。

定义:issubclass(classl,class2)

如果类classl是class2的派生类, 则返回True。例如issubclass(bool,int)会返回True, 因为booI是int的派生类。

判断类实例中是否含有某个属性(hasattr)

函数hasattr的作用是, 判断类实例中是否含有某个属性。

定义:hasattr(obj, name, /)

如果类实例。bj中含有name属性, 则返回True:否则返回False。

获得类实例中的某个属性(getattr)

函数getattr的作用是, 获得类实例中的某个属性。

定义:getattr(obj, name[, default])

如果类实例obj中含有name属性, 则返回该属性的值:否则看是否有default, 如果有, 则将该default的值返回:否则会产生一个AttributeError的异常。

设置类实例中的某个属性值(setattr)

函数setattr的作用是, 设置类实例中的某个属性。

定义:setattr(obj , name , value , /)

为实例obj中的name赋上value的值, 如果obj中没有name, 则新建一个。

其存在的价值在于, 与getattr函数混合使用, 如:getattr(obj,name,setattr(obj,name,value,/))

该语句的作用是, 先为o句中的name赋值value(如果obj中没有name, 就创建一个, 再赋值), 接着再取obj中的name属性。

包装与代理

包装就是将某个对象(或类), 进行重新打包, 转换成另外一种更适合当前使用场合的对外接口。被包装后的对象(或类〉, 自身的内部逻辑并没有改变, 只是变化了对外的接口而己。这么做的初衷, 是为了让对象(或类〉更能适应当前的调用环境。

在Python中包装的具体做法是:

(1)创建一个类, 将其要包装的目标类的对象, 作为新创建类的成员对象。即, 包装类包含被包装类的实例。

(2)为包装类实现各种与外部调用相吻合的接口。通过接口将调用关系传递到被包装类对象中, 以实现真正的包装效果。

class WrapMe(object):
    def __init__(self, obj) :            #初始化函数, 将被包装对象传入
        self.__data  =  obj               #__data为包装类的成员对象
    def get(self ) :
        return  self.__data               #返回被包装类中的数据, 这里是返回整个对象了
    def __str__(self)  :                 #重载str函数
        return "data =" + str (self.__data)
mynum  = WrapMe(888)                #对一个整型类的实例888进行包装, 并实例化成mynum对象
print(str(mynum))                   #调用了包装类对象的str。输出:data=888

还可以使用代理的方式来实现类的包装。具体做法是, 将包装类变成一个属性的“代理。这使得访问包装类的属性等同于访问被包装类的属性。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值