python之面向对象设计、编程

                                          面向对象

一、编程三个范式

1、面向过程编程

2、函数式编程

数学层面的函数

python中的函数编程

3、面向对象编程

二、面向对象设计

1、类:把一类事物共同的特征和共同的动作整合在一起就是类;

2、对象:基于类而创建的一个具体的事物(具体存在的,也是特征和动作的结合)

def dog(name,type,gender):
    def chi(dog1):
        print("%s 正在嚼骨头!!!" %dog1["name"])
    def jiao():
        print("%s正在汪汪!!" %dog1["name"])
    def  init(name,type,gender):
        dog= {
            "name":name,
            "type":type,
            "gender":gender,
            "chi":chi,
            "jiao":jiao
        }
        return dog
    return init(name,type,gender)

first_dog= dog("alex","中华田园犬","母")
print(first_dog)
first_dog["chi"](first_dog)

三、面向对象编程

1、类:声明类和函数类似,类是用来描述一类事物,类的对象指的是这一类事物中的一个个体

2、属性

(1)、数据属性:就是变量

(2)、函数属性:就是函数,在面向对象里通常称为方法

备注:类和对象都是通过点来访问自己的属性

class Dog:
    name = "alex"
    type = "中华田园犬"
    def chi():
        print("正在嚼骨头")
    def jiao(self):
        print("一直在犬吠")
dog1 =Dog()
print(dir(Dog))
Dog.chi()  

3、实例化

class Dog:
    def __init__(self,name,type):
        self.mingzi = name
        self.leixing = type
    def chi(self):
        print("%s正在嚼骨头" %self.mingzi)
    def jiao(self):
        print("一只%s在犬吠" %self.leixing)
dog1 =Dog("alex","中华田园犬")  ###实例化
print(dir(Dog))
Dog.chi(dog1)
dog1.jiao()

 四、备注

1、静态属性

静态属性的修饰为@property,对方法进行封装,隐藏内部逻辑,将类方法变为类属性

class sch:
    ###初始化参数
    def __init__(self,sch_name,sch_create_time,sch_add,sch_fee,sch_type,sch_level,sch_teach_type,sch_ward,sch_start_edu_time,sch_schedual):
        self.name = sch_name
        self.sch_name = sch_name
        self.sch_create_time = sch_create_time
        self.sch_add = sch_add
        self.sch_fee = sch_fee
        self.sch_type = sch_type
        self.sch_level = sch_level
        self.sch_teach_type = sch_teach_type
        self.sch_ward = sch_ward
        self.sch_start_edu_time = sch_start_edu_time
        self.sch_schedual = sch_schedual
    ###定义方法:这是常规的方法定义
    def sch_catch_fee(self):
        print ("%s本年度学费为%s" %(self.sch_name,self.sch_fee))
    ###对方法加上装饰器property,隐藏方法内部实现逻辑
    @property
    def sch_catch_fee(self):
        return ("%s本年度学费为%s" %(self.sch_name,self.sch_fee))

2、类方法

 使用@classmethod进行修饰,类直接调用,bu用再进行传实例名,跟实例没有任何关系。

class sch:
    ###初始化参数
    def __init__(self,sch_name,sch_create_time,sch_add,sch_fee,sch_type,sch_level,sch_teach_type,sch_ward,sch_start_edu_time,sch_schedual):
        self.name = sch_name
        self.sch_name = sch_name
        self.sch_create_time = sch_create_time
        self.sch_add = sch_add
        self.sch_fee = sch_fee
        self.sch_type = sch_type
        self.sch_level = sch_level
        self.sch_teach_type = sch_teach_type
        self.sch_ward = sch_ward
        self.sch_start_edu_time = sch_start_edu_time
        self.sch_schedual = sch_schedual
    ###classmethod方法修饰的方法的哥参数为cls
    @classmethod
    def sch_edu(cls,x):
        print("这是类的方法,与实例没有任何关系",x)
###类可以直接调用
sch.sch_edu(1) #这是类的方法,与实例没有任何关系 1

3、静态方法

使用staticmethod方法进行修饰,不与类、实例绑定,是类的工具包,只是名义上归类管理

class sch:
    ###初始化参数
    def __init__(self,sch_name,sch_create_time,sch_add,sch_fee,sch_type,sch_level,sch_teach_type,sch_ward,sch_start_edu_time,sch_schedual):
        self.name = sch_name
        self.sch_name = sch_name
        self.sch_create_time = sch_create_time
        self.sch_add = sch_add
        self.sch_fee = sch_fee
        self.sch_type = sch_type
        self.sch_level = sch_level
        self.sch_teach_type = sch_teach_type
        self.sch_ward = sch_ward
        self.sch_start_edu_time = sch_start_edu_time
        self.sch_schedual = sch_schedual
    @staticmethod
    def post_message(message):
        print("本校通知如下:%s" %message)
sch.post_message("本校将于20191207放假")

5、python中关于oop的常用术语

(1)、抽象/实现

抽象指对现实世界问题和实体的本质表现,行为和特征建模,建立一个相关的子集,可以用于 绘程序结构,从而实现这种模型。抽象不仅包括这种模型的数据属性,还定义了这些数据的接口。

对某种抽象的实现就是对此数据及与之相关接口的现实化(realization)。现实化这个过程对于客户 程序应当是透明而且无关的。 

(2)、封装接口

封装描述了对数据/信息进行隐藏的观念,它对数据属性提供接口和访问函数。通过任何客户端直接对数据的访问,无视接口,与封装性都是背道而驰的,除非程序员允许这些操作。作为实现的 一部分,客户端根本就不需要知道在封装之后,数据属性是如何组织的。在Python中,所有的类属性都是公开的,但名字可能被“混淆”了,以阻止未经授权的访问,但仅此而已,再没有其他预防措施了。这就需要在设计时,对数据提供相应的接口,以免客户程序通过不规范的操作来存取封装的数据属性。

注意:封装绝不是等于“把不想让别人看到、以后可能修改的东西用private隐藏起来”

真正的封装是,经过深入的思考,做出良好的抽象,给出“完整且最小”的接口,并使得内部细节可以对外透明

(注意:对外透明的意思是外部调用者可以顺利的得到自己想要的任何功能,完全意识不到内部细节的存在)

python不依赖语言特性去封装数据,而是通过遵循一定的数据属性和函数属性的命名约定来达到封装的效果:

任何以单下划线开头的名字都应该是内部的,私有的,实际上外部还是可以调用的;

class After_sch:
    _school = "tongnan middle school"
    def __init__(self,name,type):
        self.name = name
        self.type = type
    def fangxue(self):
        if self.type == "老师":
            print("下班")
        else:
            print("放学")
class Stu(After_sch):
    pass
class Tea(After_sch):
    pass
stu1 = Stu("小二","学生")
tea1 = Tea("heaton","老师")
print(stu1.__dict__)   ###{'name': '小二', 'type': '学生'}
print(stu1._school)   ###tongnan middle school   单下划线的外部调用成功

以双下划线开头的名字也是内部的,私有的,是python的约定命名,实际上外部也是可以调用的;

class After_sch:
    __school = "tongnan middle school"
    def __init__(self,name,type):
        self.name = name
        self.type = type
    def fangxue(self):
        if self.type == "老师":
            print("下班")
        else:
            print("放学")
class Stu(After_sch):
    pass
class Tea(After_sch):
    pass
stu1 = Stu("小二","学生")
tea1 = Tea("heaton","老师")
print(stu1.__dict__)   ###{'name': '小二', 'type': '学生'}
print(After_sch.__dict__)
# print(stu1.__school)   ###'Stu' object has no attribute '__school' 这样调用会报错
print(stu1._After_sch__school)   ###tongnan middle school 通过"_类名__属性"调用成功

封装有三个层面上的封装

a、第一个层面:类就是麻袋,这本身就是一种封装;

b、第二个层面:类中定义私有的,只有的类的内部可以使用,外部无法访问,该层面的封装就是上面提到的使用单下划线和双下划线实现的,实际上该中层面的封装外部也是可以调用的;

c、第三个层面:明确区分内外,内部的实现逻辑,外部无法知晓,并且为封装到内部的逻辑提供一个访问接口给外部使用,这才是真正的封装;

(3)、合成

合成扩充了对类的 述,使得多个不同的类合成为一个大的类,来解决现实问题。合成 述了 一个异常复杂的系统,比如一个类由其它类组成,更小的组件也可能是其它的类,数据属性及行为, 所有这些合在一起,彼此是“有一个”的关系。合成即组合,组合指的是一个类中以另外一个类作为数据属性,成为类的组合;

>>> class Equip: #武器装备类
...     def fire(self):
...         print('release Fire skill')
... 
>>> class Riven: #英雄Riven的类,一个英雄需要有装备,因而需要组合Equip类
...     camp='Noxus'
...     def __init__(self,nickname):
...         self.nickname=nickname
...         self.equip=Equip() #用Equip类产生一个装备,赋值给实例的equip属性
... 
>>> r1=Riven('锐雯雯')
>>> r1.equip.fire() #可以使用组合的类产生的对象所持有的方法
release Fire skill

 (4)、派生/继承/继承结构

派生描述了子类衍生出新的特性,新类保留已存类类型中所有需要的数据和行为,但允许修改或者其它的自定义操作,都不会修改原类的定义。
继承描述了子类属性从祖先类继承这样一种方式
继承结构表示多“代”派生,可以述成一个“族谱”,连续的子类,与祖先类都有关系。

a、接口继承和归一化设计

  • 继承基类的方法,并且做出自己的改变或者扩展(代码重用):实践中,继承的这种用途意义并不大,甚至常常是有害的,因为她使得子类和基类出现强耦合;
  • 声明某个子类兼容于某个基类,定义一个接口类,接口类中定义了一些接口名(就是函数名),且并未实现接口的功能,子类继承接口类,并且实现接口中的功能;
>>> class Equip: #武器装备类
...     def fire(self):
...         print('release Fire skill')
... 
>>> class Riven: #英雄Riven的类,一个英雄需要有装备,因而需要组合Equip类
...     camp='Noxus'
...     def __init__(self,nickname):
...         self.nickname=nickname
...         self.equip=Equip() #用Equip类产生一个装备,赋值给实例的equip属性
... 
>>> r1=Riven('锐雯雯')
>>> r1.equip.fire() #可以使用组合的类产生的对象所持有的方法
release Fire skill
View Code
  • 接口继承:子类必须继承父类定义的方法,子类必须具体去实现自己的方法。通过abc模块来限定子类必须按照父类定义的方法进行实现。通过abc.abstractmethod的方法装饰类函数;子类未实现父类中的方法则会报错;

  • 子类调用父类的方法
  1. 父类执行函数属性、数据属性

  2.使用supper()方法进行调用

b、继承顺序

  • python的类可以继承多个类,java和c#中则只能继承一个类
  • python的类如果继承了多个类,那么其寻找方法的方式有两种,分别是:深度优先和广度优先;python2中经典类会按照深度优先进行查找,python2中新式类会按照广度优先进行查找;python3中都是新式类,都是按照广度优先的方式进行查找;
  • python3到底是如何实现继承的,对于python3中定义的每个新式类类——广度优先查找方式,python会计算出一个方法解析顺序(MRO)列表,这个MRO列表就是一个简单的所有基类的线性顺序列表;

(5)、泛化/特化

基于继承
泛化表示所有子类与其父类及祖先类有一样的特点。
特化描述所有子类的自定义,也就是,什么属性让它与其祖先类不同。 

(6)、多态与多态性

多态指的是同一种事物的多种状态:水这种事物有多种不同的状态:冰,水蒸气

多态性的概念指出了对象如何通过他们共同的属性和动作来操作及访问,而不需考虑他们具体的类。

class After_sch:
    def __init__(self,name,type):
        self.name = name
        self.type = type
    def fangxue(self):
        if self.type == "老师":
            print("下班")
        else:
            print("放学")
class Stu(After_sch):
    pass
class Tea(After_sch):
    pass
stu1 = Stu("小二","学生")
tea1 = Tea("heaton","老师")   
stu1.fangxue()  ##放学    
tea1.fangxue()   ##放学
####学生类对象stu1和老师类对象tea1调用同一方法呈现不同的结果

 (7)、自省和反射

自省也称作反射,这个性质展示了某对象是如何在运行期取得自身信息的。如果传一个对象给你,你可以查出它有什么能力,这是一项强大的特性。如果Python不支持某种形式的自省功能,dir和type内建函数,将很难正常工作。还有那些特殊属性,像__dict__,__name__及__doc__,

反射主要是指程序可以访问、检测和修改它本身状态或行为的一种能力。

python中面向对象中的反射:通过字符串的形式操作对象相关的属性。有四个系统内置函数可以实现自省

a、hasattr

b、getattr

c、setattr

d、delattr

class After_sch:
    school = "tongnan middle school"
    def __init__(self,name,type):
        self.name = name
        self.type = type
    def fangxue(self):
        if self.type == "老师":
            print("下班")
        else:
            print("放学")
class Stu(After_sch):
    pass
class Tea(After_sch):
    pass
stu1 = Stu("小二","学生")
tea1 = Tea("heaton","老师")
# print(After_sch.__dict__)
# # print(stu1._school)
# print(stu1.__dict__)  ###{'name': '小二', 'type': '学生'}
# stu1.fangxue()
# tea1.fangxue()
print(hasattr(stu1,"school"))   ###判断stu1对象是否有school属性   True
print(getattr(stu1,"school1","没有该条属性"))     ###获取对象的属性,如果没有返回自定义字符串:没有该条属性
setattr(stu1,"年级","一年级")   ###设置对象的属性    {'name': '小三', 'type': '学生', '年级': '一年级'}
delattr(stu1,"type")  ###删除stu1对象的属性
print(stu1.__dict__)   ###{'name': '小二', '年级': '一年级'}

 在编程过程中,通过自省的方式,可以达到可插拔式设计

###这是ftp_client.py文件
class Ftp_client:
    def __init__(self,addr):
        print("正在连接服务器 %s" %addr)
        self.addr = addr
    ###还未实现功能

###这是ftp_call.py文件

from ftp_client import Ftp_client

f1 = Ftp_client("192.168.1.100")
if hasattr(f1,"get"):
    func_get = getattr(f1,"get")
    func_get()
else:
    print("ftp_client还未实现该方法!!!!")


###通过自省的方式可以在ftp_client在未实现的情况下继续后续工作

6、__getattr__,__setattr__,__delattr__

class animal:
    genernal = "冷血动物"
    def __init__(self,name,type):
        self.name = name
        self.type = type
    def cay(self):
        print("%s一直在抽泣" %self.name)
    def __getattr__(self, item):   ####__getattr__调用不存在的属性时运行
        print("你调用的方法不不存在")
    def __setattr__(self, key, value):
        # self.key = value  该种调用的方式会出现无限递归
        self.__dict__[key] = value   ##这种方式直接操作底层字典
    def __delattr__(self, item):    ###__delattr__删除的时候调用该方法
        #del self.item 该种方式也会出现无限递归
        self.__dict__.pop(item)     ##这种方式直接操作底层字典
dog = animal("金毛","dog")
print(dog.__dict__)

dog.addr = "north america"   ###{'name': '金毛', 'type': 'dog', 'addr': 'north america'}
print(dog.gener)   ###你调用的方法不不存在:因为该属性不存在,触发__getattr__方法

7、二次加工标准类型(包装)

包装:python提供了标准数据类型,以及丰富的内助方法,其实在很多场景下我们都需要基于标准数据类型来定制我们自己的数据类型,新增、改写方法,可以通过继承和派生的相关知识;

class List(list):###继承父类list
    def show_middl(self):  ###派生show_middle的方法
        return self[int(len(self)/2)]
    def append(self, object):  ###派生append方法
        if type(object) is not str:
            print(type(object))
            print("添加的类型必须为字符串类型")
        else:
            super().append(object)
l1 = List()
print(l1.__dict__)

res = List("string") ###继承方法
print(res,type(res))   ###['s', 't', 'r', 'i', 'n', 'g'] <class '__main__.List'>
# print(res.show_middl())
res.append("helloworld")
res.append(1234)   ###在调用的append方法是对数据类型对了判断
print(res)   ###  ['s', 't', 'r', 'i', 'n', 'g', 'helloworld']

 授权:授权是包装的一个特性,包装一个类型通常是对已存在的类型的一些定制,这种做法可以是新建、修改或删除原有产品的功能,其他则保持原样。授权的过程,即是所有更新的功能都是有新类的某部分

来处理。

import time
class file_handler:
    def __init__(self,filename,mode="r",encoding="utf-8"):
        # self.filename = filename
        self.file = open(filename,mode,encoding="utf-8") ###获取文件句柄
        self.mode = mode
        self.encoding = encoding
    def write(self,line):
        t = time.strftime("%Y-%m-%d %X")
        self.file.write("%s %s" %(t,line))
    def __getattr__(self, item):
        print(item)
        # self.file.read
        return getattr(self.file,item)

f1 = file_handler("a.text","w+")
    # print(f1.file)
    # print(f1.read)
f1.write("11111111343234
")
time.sleep(1)
f1.write("用户root远程登录服务器
")
time.sleep(2)
f1.write("用户root修改了目录/opt的权限为777
")

  

原文地址:https://www.cnblogs.com/tengjiang/p/11986991.html