【Python基础】07、Python类

2023-01-31 02:01:53 python 基础

一、面向对象编程(OOP)

程序=算法+数据结构=指令+数据


1、代码可以选择以指令为核心或以数据为核心进行编写

两种范型:

       以指令为核心:围绕“正在发生什么”进行编写

              面向过程编程:程序具有一系列线性步骤;主体思想是代码作用于数据

       以数据为核心:围绕“将影响谁”进行编写

               面向对象编程(OOP):围绕数据及为数据严格定义的接口来组织程序, 用数据控制对代码的访问


2、面向对象的核心概念

所有编程语言的最终目的都是提供一种抽象方法

       在机器模型(“解空间”或“方案空间”)与实际解决的问题模型(“问题空间”)之间,程序员必须建立一种联系

                面向过程:程序 = 算法+数据结构

                面向对象:将问题空间中的元素以及它们在解空间中的表示物抽象为对象,并允许通过问题来描述问题而不是方案

                       可以把实例想象成一种新型变量,它保存着数据,但可以对自身的数据执行操作


类型由状态集合(数据)和转换这些状态的操作集合组成

类抽象

      类:定义了被多个同一类型对象共享的结构和行为(数据和代码)

      类的数据和代码:即类的成员

            数据:成员变量或实例变量

            成员方法:简称为方法,是操作数据的代码,用于定义如何使用成员变量;因此一个类的行为和接口是通过方法来定义的

     方法和变量:

            私有:内部使用

            公共:外部可见


3、面向对象的程序设计方法 

所有东西都是对象

程序是一大堆对象的组合

       通过消息传递,各对象知道自己该做什么

       消息:即调用请求,它调用的是从属于目标对象的一个方法

每个对象都有自己的存储空间,并可容纳其它对象

        通过封装现有对象,可以制作成新型对象

每个对象都属于某一类型

        类型,也即类

        对象是类的实例

        类的一个重要特性为“能发什么样的消息给它”    #调用实例的方法就相当于对实例发消息

同一个类的所有对象都能接收相同的消息


4、对象的接口

定义一个类后,可以根据需要实例化出多个对象

如何利用对象完成真正有用的工作?

        必须有一种办法能向对象发出请求,令其做一些事情

        每个对象仅能接受特定的请求

               能向对象发送的请求由其“接口”进行定义

                对象的“类型”或“类”则规定了它的接口形式


5、对上面的概念的总结

类:将同一种具体物事的共同特性抽象出来的表现

       状态和转换这些状态的操作(就是属性和方法)

       数据:

                变量:就是属性

       方法:

                函数:操作变量的代码


6、类间关系

依赖('uses-a')

        一个类的方法操纵另一个类的对象

聚合(‘has-a’)

        类A的对象包含类B的对象

继承(“is-a”)

        描述特殊与一般关系


二、面向对象编程的原则

面向对象的模型机制有3个原则:封装,继承及多态

1、封装(Encapsulation)

       隐藏实现方案细节

       将代码及其处理的数据绑定在一起的一种编程机制,用于保证程序和数据不受外部干扰且不会被误用


2、继承(Inheritance)

一个对象获得另一个对象属性的过程;用于实现按层分类的概念

一个深度继承的子类继承了类层次中它的每个祖先的所有属性

超类、基类、父类

子类、派生类


3、多态性(Polymorphism)

允许一个接口被多个通用的类动作使用的特性,具体使用哪个动作与应用场合相关

“一个接口,多个方法”

         用于为一组相关的动作设计一个通用的接口,以降低程序复杂性


三、Python类和实例

1、python类和实例

类是一种数据结构,可用于创建实例

        一般情况下,类封装了数据和可用于该数据的方法

python类是一个可调用对象,即类对象

Python2.2之后,类是一种自定义类型,而实例则是声明某个自定义类型的变量


2、Python中创建类

Python使用class关键字创建类,语法格式如下:

      class ClassName(bases):

            ‘class documentation string’

                class_suite

超类是一个或多个用于继承的父类的集合

类体可以包含:声明语句、类成员定义、数据属性、方法

注意:

      如果不存在继承关系,ClassName后面的“(bases)”可以不提供

      类文档为可选


class语句的一般形式

class ClassName(bases):

         data = value                       #定义数据属性

         def method(self,…):           #定义方法属性

                 self.member = value


3、实例初始化

通过调用类来创建实例

     instance(自定义的实例名) = ClassName(args…)

类在实例化时可以使用__init__和__del__两个特殊的方法


例子:

Python中,class语句类似def,是可执行代码;直到运行class语句后类才会存在

wKiom1f_UkLjInEIAACf3sllvKA938.png

class语句内,任何赋值语句都会创建类属性

每个实例对象都会继承类的属性并获得自己的名称空间

In [1]: s1="xj"

In [2]: type(s1)
Out[2]: str

In [21]: type(str)
Out[21]: type

In [22]: type(list)
Out[22]: type

In [3]: str.
str.capitalize  str.fORMat      str.isupper     str.rfind       str.startswith
str.center      str.index       str.join        str.rindex      str.strip
str.count       str.isalnum     str.ljust       str.rjust       str.swapcase
str.decode      str.isalpha     str.lower       str.rpartition  str.title
str.encode      str.isdigit     str.lstrip      str.rsplit      str.translate
str.endswith    str.islower     str.mro         str.rstrip      str.upper
str.expandtabs  str.isspace     str.partition   str.split       str.zfill
str.find        str.istitle     str.replace     str.splitlines  

In [3]: s1.
s1.capitalize  s1.find        s1.isspace     s1.partition   s1.rstrip      s1.translate
s1.center      s1.format      s1.istitle     s1.replace     s1.split       s1.upper
s1.count       s1.index       s1.isupper     s1.rfind       s1.splitlines  s1.zfill
s1.decode      s1.isalnum     s1.join        s1.rindex      s1.startswith  
s1.encode      s1.isalpha     s1.ljust       s1.rjust       s1.strip       
s1.endswith    s1.isdigit     s1.lower       s1.rpartition  s1.swapcase    
s1.expandtabs  s1.islower     s1.lstrip      s1.rsplit      s1.title  


In [3]: class FirstClass:
   ...:     spam=30
   ...:     def display(self):
   ...:         print self.spam
   ...:         

In [4]: x=FirstClass

In [5]: type(FirstClass)
Out[5]: classobj                    #自定义类类型

In [6]: type(x)
Out[6]: classobj             

In [9]: x.
x.display  x.spam     

In [9]: x.spam
Out[9]: 30

In [10]: x.display
Out[10]: <unbound method FirstClass.display>

In [11]: x.display()
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-11-ef2c4eba88c5> in <module>()
----> 1 x.display()

TypeError: unbound method display() must be called with FirstClass instance as first argument (Got nothing instead)

In [12]: x.display(self)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-12-0a0d07c21014> in <module>()
----> 1 x.display(self)

NameError: name 'self' is not defined

In [13]: x=FirstClass()

In [14]: type(FirstClass)
Out[14]: classobj

In [15]: type(x)
Out[15]: instance                  #自定义类型的实例(变量)

In [25]: type(FirstClass())
Out[25]: instance

In [16]: x.
x.display  x.spam     

In [17]: x.spam
Out[17]: 30

In [18]: x.display
Out[18]: <bound method FirstClass.display of <__main__.FirstClass instance at 0x1e76998>>

In [19]: x.display()
30


4、Python类方法及调用

实例(对象)通常包含属性

       可调用的属性:方法

              object.method()

       数据属性


在OOP中,实例就像是带有“数据”的记录,而类是处理这些记录的“程序”

      通过实例调用方法相当于调用所属类的方法来处理当前实例

             类似instance.method(args…)会被自动转换为class.method(instance,args…)

                     如前面的例子,x.display()会被自动转换为FirstClass.display(x),即调用类的方法来处理实例x

因此,类中每个方法必须具有self参数,它隐含当前实例之意

在方法内对self属性做赋值运算会产生每个实例自己的属性

Python规定,没有实例,方法不允许被调用,此即为“绑定”

In [38]: l1=[1,2,3]

In [39]: l1.
l1.append   l1.extend   l1.insert   l1.remove   l1.sort     
l1.count    l1.index    l1.pop      l1.reverse  

In [39]: list.
list.append   list.extend   list.insert   list.pop      list.reverse  
list.count    list.index    list.mro      list.remove   list.sort     

In [39]: list.pop
Out[39]: <method 'pop' of 'list' objects>

In [40]: list.pop()
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-40-38a37a7ebeb6> in <module>()
----> 1 list.pop()

TypeError: descriptor 'pop' of 'list' object needs an argument

In [41]: list.pop(l1)
Out[41]: 3

In [42]: l1
Out[42]: [1, 2]


In [55]: class FirstClass():
    spam=30
    def display(self):
        print self.spam
   ....:         

In [56]: x=FirstClass()

In [57]: type(x)
Out[57]: instance

In [58]: x.spam
Out[58]: 30

In [59]: x.display
Out[59]: <bound method FirstClass.display of <__main__.FirstClass instance at 0x1eedb00>>

In [60]: x.display()
30

In [61]: FirstClass.
FirstClass.display  FirstClass.spam     

In [61]: FirstClass.spam
Out[61]: 30

In [62]: FirstClass.display
Out[62]: <unbound method FirstClass.display>

In [63]: FirstClass.display()
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-63-f86eed380e7e> in <module>()
----> 1 FirstClass.display()

TypeError: unbound method display() must be called with FirstClass instance as first argument (got nothing instead)

In [64]: FirstClass.display(x)
30


5、Python类和实例的属性

wKiom1gERg2QlwUrAAGvp-64-ZQ907.png

In [3]: class MyClass():
    gender='Male'
    def setName(self,who):
        self.name=who
   ...:         

In [4]: x=MyClass()

In [5]: x.
x.gender   x.setName  

In [5]: x.gender
Out[5]: 'Male'

In [19]: x.gender()
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-19-30286d5d5900> in <module>()
----> 1 x.gender()

TypeError: 'str' object is not callable

In [20]: x.setName
Out[20]: <bound method MyClass.setName of <__main__.MyClass instance at 0x253ec20>>

In [21]: x.setName()
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-21-6315c358874f> in <module>()
----> 1 x.setName()

TypeError: setName() takes exactly 2 arguments (1 given)


In [23]: x.setName('xj')

In [24]: x.
x.gender   x.name     x.setName  

In [24]: x.setName
Out[24]: <bound method MyClass.setName of <__main__.MyClass instance at 0x253ec20>>

In [25]: x.name
Out[25]: 'xj'

In [26]: x.name()
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-26-efd80cafd8e3> in <module>()
----> 1 x.name()

TypeError: 'str' object is not callable

Python构造器

创建实例时,Python会自动调用类中的__init__方法,以隐性地为实例提供属性

       __init__方法被称为构造器

       如果类中没有定义__init__方法,实例创建之初仅是一个简单的名称空间

wKioL1gEb6-xWw8nAACElj0HO4A053.png

例子:

wKiom1gEcAGiFRK0AAE4gg1bhfU763.png



6、类的特殊属性

      可以使用类的__dict__字典属性或Python内置的dir()函数来获取类的属性

wKiom1gEdRew_LXPAAEo-abYJ98199.png

实例属性

实例仅拥有数据属性(严格意义上来说,方法是类属性)

        通常通过构造器“__init__”为实例提供属性

        这些数据属性独立于其它实例或类

        实例释放时,其属性也将被清除

内建函数dir()或实例的特殊属性__dict__可用于查看实例属性

wKioL1gEdcXAC9ESAAB4zyXCz8E974.png


In [60]: x.
x.gender   x.name     x.setName  

In [60]: MyClass.
MyClass.gender   MyClass.setName 

In [61]: dir(x)
Out[61]: ['__doc__', '__module__', 'gender', 'name', 'setName']

In [62]: x.__dict__
Out[62]: {'name': 'xj'}

In [63]: dir(MyClass)
Out[63]: ['__doc__', '__module__', 'gender', 'setName']

In [64]: MyClass.__dict__
Out[64]: 
{'__doc__': None,
 '__module__': '__main__',
 'gender': 'Male',
 'setName': <function __main__.setName>}
 

  In [71]: help(x)

Help on instance of MyClass in module __main__:

class MyClass
 |  Methods defined here:
 |  
 |  setName(self, who)
 |  
 |  ----------------------------------------------------------------------
 |  Data and other attributes defined here:
 |  
 |  gender = 'Male'
(END) 


In [72]: help(MyClass)

Help on class MyClass in module __main__:

class MyClass
 |  Methods defined here:
 |  
 |  setName(self, who)
 |  
 |  ----------------------------------------------------------------------
 |  Data and other attributes defined here:
 |  
 |  gender = 'Male'
(END)


7、Python类方法中可用的变量

方法的可用变量

       实例变量:指定变量名称及实例自身进行引用

              self.变量名

       局部变量:方法内部创建的变量,可直接使用

       类变量(也称静态变量):通过指定变量名与类名进行引用

              类名.变量名

       全局变量:直接使用


四、继承

1、继承

继承描述了基类的属性如何“遗传”给派生类

       子类可以继承它的基类的任何属性,包括数据属性和方法

        一个未指定基类的类,其默认有一个名为object的基类

        Python允许多重继承


2、创建子类

创建子类时,只需要在类名后跟一个或从其中派生的父类

class SubClassName(ParentClass1[, ParentClass2, …])

    ‘optional class documentation string’

       class_suite


3、Python类的继承和属性搜索

Python中几乎所有属性的获取都可以使用“object.attribute” 的格式

        不过,此表达式会在Python中启动搜索——搜索连续的树

class语句会产生一个类对象,对class的调用会创建实例,实例自动连结至创建了此实例的类

类连结至其超类的方式:

       将超类列在类头部的括号内,其从左至右的顺序会决定树中的次序

       由下至上,由左至右

C1     C2

     C3

      I1

图中所有的对象都是名称空间,而继承就是由下而上搜索此


4、继承方法专用化

继承会先在子类寻找变量名,然后才查找超类,因此,子类可以对超类的属性重新定义来取代继承而来的行为

       子类可以完全取代从超类继承而来的属性

       也可以通过已覆盖的方法回调超类来扩展超类的方法


五、类、实例和其它对象的内建函数

issubclass()

       布尔函数,判断一个类是否由另一个类派生,

语法:

            issubclass(sub, sup)


isinstance()

        布尔函数,判断一个对象是否是给定类的实例,

语法:

            isinstance(obj1, class_obj2)


hasattr()

         布尔函数,判断一个对象是否拥有指定的属性,

语法:

            hasattr(obj, ‘attr’)

同类的函数还有getattr()、setattr()和delattr()


super()

        在子类中找出其父类以便于调用其属性

        一般情况下仅能采用非绑定方式调用祖先类方法

        而super()可用于传入实例或类型对象,

语法:

        super(当前类名[, obj])


调用父类的同名方法

  扩展父类的同名方法

  super方法和super对象 

super(LockableDoor, self).__init__().__init(num,status)      

       #代表父类    调用父类属性


2、运算符重载

运算符重载是指在方法中拦截内置的操作——当类的实例出现在内置操作中,Python会自动调用自定义的方法,并且返回自定义方法的操作结果

      运算符重载让类拦截常规的Python运算

              类可重载所有Python表达式运算符

              类也可重载打印、函数调用、属性点号运算等内置运算

      重载使类实例的行为像内置类型

      重载通过提供特殊名称的类方法实现

运算符重载并非必需,并且通常也不是默认的


3、基于特殊的方法定制类

除了__init__和__del__之外,Python类支持使用许多的特殊方法

      特殊方法都以双下划线开头和结尾,有些特殊方法有默认行为, 没有默认行为的是为了留到需要的时候再实现

       这些特殊方法是Python中用来扩充类的强大工具,它们可以实现

              模拟标准类型

              重载操作符

        特殊方法允许类通过重载标准操作符+,*,甚至包括分段下标及映射操作[]来模拟标准类型


相关文章