代码改变世界

python 类和oop

2022-04-05 17:00  jym蒟蒻  阅读(74)  评论(0编辑  收藏  举报

文章目录

    • oop:面向对象程序设计
    • python类的特点:
    • oop基本概念:
      • 1.属性继承搜索:
      • 2.类和实例:
      • 3.类方法调用
      • 4.编写类树
      • 5.代码重用

 

oop:面向对象程序设计

1.类:一些函数的包,这些函数大量使用并处理内置对象类型。

2.类的设计是为了创建和管理新的对象。类是定义新种类东西的方式。

3.通过类来实现一个对象,也就意味着建立对象实际结构和关系的模型。

4.继承:学生属于人,学生拥有一般人的属性,在oop术语里面,学生继承了人的通用属性,这些通用属性只需实现一次,就能在我们创建所有种类人的时候使用。

5.组合:组合就是组件的集合。学生是一个组合的实例,学生类里面还包含其他对象,比如学习。每个组件都可以写成类,定义自己的行为和关系,学习可以写成一个学习类。

6.对于GUI系统:写成图形组件的集合(按钮,标签)可以称为接口,绘制图形组件的容器时,图形组件也跟着绘制,这是一种组合。我们编写定制的图形组件(有独特颜色形状的按钮或标签),可以通过接口的继承机制实现。

python类的特点:

1多重实例:类是产生对象的工厂,每调用一个类,就产生一个独有命名空间的新对象。这个对象能够读取类的属性,并可以用自己的命名空间来存储数据,而且不同对象数据也不同。

2通过继承进行定制:在类的外部重新定义其属性从而扩充这个类。

3运算符重载:类可以定义对象来响应在内置类型上的几种运算。

oop基本概念:

1.属性继承搜索:

object.attribute(对象.属性)

这个表达式,会在python中启动搜索,去搜索一个种种对象连接的树,寻找attribute首次出现的对象,找到之后停止搜索。先搜索object,然后是该对象之上的所有类,从下到上,从左到右。

下面这个例子:c1c2c3为类对象,l1,l2为实例对象。

1.就搜索树来看,实例从他的类继承属性,类是从搜索树中所有比他更上层的类中继承属性。

2.超类提供了所有子类共享的行为,但因为搜索由下而上,子类可能在树中较低位置重新定义超类变量名,覆盖超类的定义。

3.比如l2.w的搜索顺序:l2,c1,c2,c3,也就是说,l2从c3继承了属性w

l1.x搜索顺序:l1,c1

l1.name搜索顺序:l1

如果说找不到某一属性,比如:l1.k,此时发生错误。

2.类和实例:

类通常都有函数,而实例有一些数据项,类的函数使用了这些数据。实例像是带有数据的记录,类是处理这些记录的数据。

3.类方法调用

调用类函数的时候,总会有一个主体对象,这个主体就是类的实例。python把隐含的实例传进方法中。方法能够通过实例或类进行调用。jack.givemoney()同于employee.givemoney(jack)。

l2.w()的意思是调用c3.w处理l2,l2.w()同于c3.w(l2)

4.编写类树

每个class对象会生成一个新对象。

每次类调用时,会生成新的实例对象。

实例自动连接至创建这些实例的类。

类连接至其超类的方式,将超类列在类头部的括号内,其从左至右的顺序会决定树中的次序。(在类树中,class语句小括号内有一个以上超类,他们从左至右的次序决定超类搜索的顺序)

上面的图可以表示成:

#创建三个类对象
class C2:#省略具体内容
class c3: #省略
class C1(c2,c3):#省略
#创建两个实例对象
l1=c1()
l2=c2()

附加在实例上的属性只属于那些实例,而附加在类上的属性,由所有子类及其实例共享。如c1和l1

python把隐含的实例传进方法中第一个特殊的参数,习惯称之为self。

class c1(c2,c3):
    def setname(self,who):
        self.name=who
l1=c1()
l1.setname('jack')
print(l1.name)

类通过函数为实例提供行为,上面例子,l1传入self里,指明了类处理的实例是l1,然后通过类里面的函数def对self做赋值运算,把属性添加到类对象之中。self用来存储实例内部变量名。

对于类来说:属性通常是在class语句中通过赋值语句添加在类中,而不是通过def函数。

对于实例来说:属性通常是在类内,对传给def函数的特殊参数(self),做赋值运算,而添加在实例中。

通过构造函数,创建实例时初始化实例。

上述代码,在setname方法调用前,c1不会把name属性附加在实例上,那么在调用l1.setname前引用l1.name会产生未定义变量名的错误。如果类要确保name变量名一定会在实例中被设置,通常在构造时就填好这个属性。

class c1(c2,c3):
    def _init_(self,who):
        self.name=who
l1=c1('jack')
print(l1.name)

每次从类产生实例时,python会自动调用名为_init_的方法,它也称之为构造函数。新实例传入self参数,类调用小括号内的任何值成为第二个及以后的参数。

5.代码重用

通过类,我们可以定制现有的软件来编写代码,而不是对现有代码进行原处修改,或者每个项目都从头开始。自动属性继承搜索,软件定制,这些是通过模块和函数做不到的。

方法只有特殊第一参数self的函数,我门可以把要处理的对象传给简单函数,模拟其行为。方法参与了类的继承,我们可以通过定义新方法编写子类,而不用原处修改代码。

class employee:
    def computesalary(self):#省略内容
    def giveraise(self):#省略
    def promote(self):#省略
    def retire(self):#省略

employee是一个通用的超类,定义所有员工默认的通用行为。

class engineer(employee):
    def computesalary(self):#省略

这里engineer继承了employee,是他的一个子类,这里我们重载了computesalary方法,实现了定制的目的。这个engineer类型的员工的其他行为会继承employee里面的行为。

之所以说定制,是因为这里的computesalary在employee的下面。所以类树搜索时搜到他就截止。

jack=employee()
kk=engineer()

我们可以对树中任何类创建实例,创建的实例所用的类,会决定其属性搜索从哪个层次开始。

company=[jack,kk]
for emp in company:
    print(emp.computesalary())

两个实例对象,可以嵌入到一个更大的容器对象里,从而可以代表一个部门

这个for里面也用到了多态,隐藏了接口的差异性。

多态还可以用到下面:

处理数据流的程序,可以写成预期有输入和输出方法的对象,而不用关心那些方法实际做的是什么

def processor(reader,converter,writer):
    while 1:
        data = reader.read()
        if not data:break
    data=converter(data)
    writer.write(data)
class reader:
    def read(self):#省略
    def other(self):#省略
class filereader(reader):
    def read(self):#省略
class socketreader(reader):
	def read(self):#省略
#...省略...
       
    
processor(filereader(...),converter,filewriter(...))
processor(ftpreader(...),converter,xmlwriter(...))

所谓框架,就是把常见程序设计成类,让你可以编写一些子类,写一两个方法,树中较高位置的框架类会替你做大多数工作。