Python面向对象编程

01.基本理论

一、对象的概念

1.万物皆对象

2.对象是一个具体的物体

拥有的属性、拥有的行为、零散的封装成一个整体。例如:王小二(属性:姓名、年龄、身高...行为:走路、吃饭、放羊...)

3.对象在python中的体现

python是一门特别彻底的面向对象编程(OOP)的语言( 其它语言包括基本数据类型与对象类型)

二、面向过程与面向对象的区别

1.面向过程与面向对象的编程思想

他们都是属于一种解决问题的思路。

面向过程:在解决问题的时候,关注的是解决问题的每一个过程(步骤)

面向对象:在解决问题的时候,关注的是解决问题所需要的对象

例如:吃完饭之后洗碗(面向过程:放水、放碗、倒洗洁精、刷、擦干;面向对象:你的技能、你对象的技能...)

2.面向过程与面向对象的对比

1)面向对象和面向过程都是解决问题的一种方式(思想),面向对象是面向过程的一种封

2)面向过程编程最重要的是:把一个任务分解成具体的步骤。

3)面向对象编程最重要的是:按照对象的功能进行划分,找到对象确定对象的属性和行为。

3.从面向过程编程的思想过渡到面向对象编程的步骤

1)列举出一个任务具体的实现步骤;

2)试图分离这些实现步骤中的功能代码;

3)将这些功能代码块,划分都某一个对象中;

4)根据这个对象以及对应的行为,抽象出对应的类;

三、类的简介

1.什么是类

某一个具体对象特征的抽象

2.类的作用

根据抽象的类,生产出具体的对象

例如:(类:不良青年 属性:年龄、身高、体重... 行为:吃喝嫖赌...对象:张三、李四、王五...都满足以上的属性和行为)

3.类的组成

名称、属性(静态的特征值)、方法(动态的动作)

注意:1)以上属性和方法,都是抽象的概念

           2)在产生对象之后,对象才拥有具体的属性值和方法实现

4.生活中常用的类

1)类:钱                    对象:具体的一块、两块、一百块...

2)类:汽车                对象:奥迪、宝马、奔驰...

5.对象和类的区别

对象——>抽象——>类——>实例化——>对象

02.面向对象编程在python中的实践

一、定义一个类(经典类、新式类)

class Money:		#class类名:(类名的首字母需要大写,不要加小括号)
    pass
class renminbi(money):		#括号内部表示继承关系

二、根据类创建一个对象

one =Money()		#one就是一个对象(通过*类名+一个括号*即可创建一个对象)
print(one)

三、创建对象时的底层运作

ProcessOn在线绘图(可以绘制流程图)

Python面向对象编程

四、属性相关

1.属性和变量的区别及判定依据

1)区别:变量是“可以改变的量值”,根据不同的位置存在不同的访问权限(全局变量、局部变量)

                 属性是“属于某个对象的特性”,只能通过一个对象进行访问

2)判定依据:是否存在宿主

2.对象属性

1)添加操作:直接通过对象动态添加——>对象.属性=值

                       通过类的初始化方法(构造方法)——>int方法

2)查询操作

3)修改操作

4)删除操作

#定义一个类
class Person:
    pass
#根据这个类创建一个对象
p=Person()
#给对象p增加属性
p.age=18
p.height=180
#查找当前对象所有的属性(返回一个字典)
p.__dict__
#删除一个属性
del p.age

5)注意事项:不同对象之间不能访问其唯一的属性。

3.类属性

1)添加操作:类名.属性=值     ;在类里面写变量名=值

2)查询属性:既可以通过类进行查询,也可以通过对象进行查询

(python对象查找机制:优先到对象自身去查找属性,如果没有找到,则根据class找到对应的类,再在这个类里面进行查找)

3)修改属性:只能通过类名进行修改,不能通过对象进行修改

4)删除操作:只能通过类名进行删除,不能通过对象进行删除

5) 注意事项:类属性的内存存储问题;类属性被各个对象所共享

#在类里面添加属性
class Money:
    age=18
    count=1
    pass
class Text:
    sex=male
#更改对象所属的类
one=Money()
one.__class__=Text
#对类的属性的修改
Money.age=22
#删除类的属性
del Money.age

五、方法相关

1.方法的概念

1)方法的概念:描述一个目标的行为动作(比如描述一个人怎么吃、怎么喝...)和函数非常的类似

——>都封装了一系列行为动作

——>都可以被调用之后执行一系列行为动作

——>最主要的区别就是调用的方式不同

#函数
def eat():
    print(1)
    print(2)
    print(3)
eat()
#方法
class Person:
    def eat2(self):
        print(1)
        print(2)
p=Person()
p.eat2()

2.方法的划分

1)类、对象、实例、实例对象、实例化

Python面向对象编程

2)方法的划分依据

实例方法:默认第一个参数需要接收到一个实例;

类方法:默认第一个参数需要接收到一个类;

静态方法:静静的看着前面两个在装逼,第一个参数啥也不默认接收;

注意:

—>划分的依据是第一个参数必须接收到的数据类型

—>不管是哪一种类型的方法,都是存储在类当中,没有在实例当中的

—>不同类型的调用方式不同

—>重点关注方法的使用层面:语法、不同类型方法的规则、不同类型的方法调用、根据不同的问题设计不同的方法解决问题

3)方法的存储问题

Python面向对象编程

3.实例方法

1)标准形式

2)标准调用:使用实例调用实例方法(不用手动传,解释器会自动被调用对象本身传递过来)

             注意:如果实例方法没有接收到任何参数,则会报错。

#创建一个类+实例方法
class Person:
    def eat(self,food):
        print("在吃饭",food)
#标准调用
p=Person()
p.eat("土豆")
#————>输出:在吃饭,土豆

4.类方法

1)标准形式

2)标准调用:既可以通过类调用,也可以通过实例调用

#创建一个类+类方法
class Person:
    @classmethod		#类方法装饰器
    def leifangfa(cls,a):
        print("这是一个类方法",cls,a)
#标准调用(既可以通过类调用,也可以通过实例调用)
Person.leifangfa(123)
#—————>输出:这是一个类方法,<class'__main__.Person>123

5.静态方法

1)标准形式

2)标准调用:既可以通过类调用,也可以通过实例调用

#创建一个类+静态方法
class Person:
    @staticmethod
    def jingtai():
        print("这是一个静态方法")
#标准调用(既可以通过类调用,也可以通过实例调用)

6.不同类型的方法中访问不同类型属性的权限问题

class person:
    age=0
    def shilifangfa(self):
        print(self.age)
        print(self.num)
    @classmethod
    def leifangfa(cls):
        print(cls.age)
        print(cls.num)

p=Person()
p.num=10

p.shilifangfa()		#age和num属性全部能够输出
p.leifangfa()		#age属性能够输出,num属性会报错

六、补充

1.类相关补充

1)元类:创建类对象的类

2)类的描述:(用于规范编程)

  • 目的:方便自己理清逻辑思路、方便多人合作开发时的沟通、方便生成项目文档

  • 描述方式:在定义类、属性、方法下面一行写注释,使用双引号对(标明效果、 参数、参数含义、参数类型[动态语言参数不确定],是否有默认值, 返回值)

  • 生成项目文档:(不需要把源码全部给别人,先使用help()生成项目)

              方式一,使用python内置模块pydoc(参考课程,现学现用)

              方式二,使用第三方模块Sphinx、epydoc、doxygen(参考课程,现学现用)

2.属性相关补充

1)私有化属性(对访问范围较大的属性设置一个范围,使其访问范围较小)

                可用于数据保护以及数据过滤

  • 注意:python中并没有真正的私有化支持(只是通过名字重整规则加密了),但是可以使用下划线完成伪私有效果(使用其他的手段进行访问); 类属性(方法)和实例属性(方法)遵循相同的规则

  • 公有属性(x):类内部访问——>可以

                               子类内部访问——>可以

                               模块内其他位置访问 类访问——>警告

                                                                 实例访问——>警告

                                跨模块访问 import——>可以

                                                   from 模块 import *——>可以

Python面向对象编程

  • 受保护的属性(_y):类内部访问——>可以

                                           子类内部访问——>可以

                                           模块内其他位置访问 类访问——>可以

                                                                             实例访问——>可以

                                           跨模块访问 import——>报错

                                                              from 模块 import *——>报错

#file1
_a=6
#file2
from file1 import *
print(_a)			#受保护会报错
###########################################################################################
#file1
_a=6
__all__=['_a']		#内置属性__all__可用来传输受保护参数
#file2
from file1 import *
print(_a)		#可以正常访问
  • 私有属性(__z):   类内部访问——>可以

                                       子类内部访问——>报错

                                       模块内其他位置访问 类访问——>报错

                                                                          实例访问——>报错

                                        跨模块访问 import——>报错

                                                           from 模块 import *——>报错

                          注意:也可以使用__all__=['']使其他模块进行访问

  • 补充: x_       与系统内置的关键字做区分

                 _ _x__   系统内置的特殊属性(例如:__dict__、__count__)

2)只读属性(一个属性【一般指实例属性】只能读取不能写入)

有些属性只限于内部根据不同场景进行修改,而对外界来说不能修改,只能读取。

 例如:电脑类的网速属性、网络状态属性。

  • 设置只读属性(方案一):全部隐藏,部分公开【这里就会用到@property修饰器】

                首先通过“属性前置双下划线”实现,再通过公开的方法进行部分公开。

class Person(object):
    def __init__(self):
#全部隐藏
        self.__age=18

#部分公开
    @property        #主要作用就是可以使用属性的方式来使用这个方法
    def age(self):
        return self.__age

p=Person()
print(p.age)


'''
经典类与新式类(建议使用新式类)
经典类:没有继承(object)
新式类:有继承(object)
        可以通过'__bases__'查询继承类
python2.x 如果定义一个类,没有显示继承自object,那么这个类就是一个经典类。
python3.x 无论有没有显示继承,默认都是一个新式类
'''
'''
@property 装饰器讲解 
1.主要作用:将一个些“属性的相关方法(删、改、查)”关联到某一个属性中。常用于定义或管理__X
2.property在新式类中的使用:(代码1)
3.property在经典类中的使用:(代码2)(一般不使用,随用随听)
'''

#代码1
class Person(object):
    def __init_(self):
        self.__age=18
    @property        ##########装饰器1:(查)
    def age(self):
        return self.__age
    @age.setter        #########装饰器2:(改)
    def age(self,value)
        self.__age=value
    @age.deleter       #########装饰器3:(删)
    def x(self):
        del self.__age                      
                             
p=Person()
print(p.age)
print(p.age=90)
  • 设置只读属性(方案二)
class Person:
    def __setattr__(self,key,value):
    #当我们通过 实例.属性=值 时,给一个实例增加一个属性或者说修改一个属性值的时候,都会调用这个方法
    #在这个方法内部,才会真正把这个属性以及对应的数据存储到__dict__字典里面。
        print(key,value)
        #第一步:判定key是否是我们要设定的只读属性的名称。
        if key=='age' and key in self.__dict__.keys():
            print('这个属性是只读属性,不能设置数据')
        #第二部:如果不是只读属性的名称,则真正的给它添加到这个实例里面去。
        else:
            self.__dict__[key]=value

3)内置特殊属性(当定义好一个类或通过这个类创造了一个实例,系统自动的分配了一些可以直接使用的属性,以完成一些小的测试操作或某些应用场景)

  • 类属性:__dict__:类的属性

                      __bases__:类的所有父类元组(python是多继承,java是单继承)

                      __doc__:类的文档字符串

                      __name__:类名

                      __module__:类定义所在的模块

  • 实例属性:__dict__:实例的属性

                         __class__:实例对应的类

class Person:
    age=19                        #类属性
    def __init__(self):
        self.name='sz'            #利用初始化方法定义一个实例属性
    def run(self):
        print("run")
print(Person.__dict__)
print(Person.__bases__)
print(Person.__doc__)
print(Person.__name__)
print(Person.__module__)


P=Person()
print(P.__dict__)
print(P.__class__)

 2.方法相关补充

1)私有化方法(同于私有化属性:名称重整机制)

                当类的内部才使用的方法,且不暴露给外界使用。

2)内置特殊方法

  • 生命周期方法(下一节单独介绍)
  • 信息格式化操作:__str__方法:面向用户

                                    __repr__方法:面向开发人员、python解释器

class Person:
    def __init__(self,n,a):
        self.name=n
        self.age=a
    def __str__(self):
        return "这个人的姓名是:%s,这个人的年龄是:%s"%(self.name,self.age)

p1=Person("sz",18)
p2=Person("zs",19)

print(p1)        #此时打印的就不再是模块名+类名+内存地址,而是__str__方法,return的返回值
print(p2)
print(repr(p1))        #当有__str__方法时,用此方法可打印模块名+类名+内存地址
print(repr(p2))
  • 调用操作:__call__方法                使得实例化的对象具有被调用的能力
class Person:
    def __call__(self,*args,**kwargs):
'''
    使用用__call__方法,使得实例化的对象具有被调用的能力。
    *args  为元组的形式
    **kwargs  为字典形式
    这两个参数保证了可以传输任何形式
'''
        print("xxx",args,kwarge)
    pass
p=Person
p(123,456,name='sz')    #若类中没有__call__方法,则会报错;若有__call__方法,则会调用__call__的方法。
  • 索引操作
  • 切片操作
  • 迭代器
  • 描述器

03.面向对象编程——综合案例

#任务:做一个计算器,实现一些基本操作,加减乘除以及打印结果
#面向过程编程,对于连续运算极其复杂,不安全

#设计以及优化思路:包装——>安全性——>能否满足多个同时运算——>是否容错(健壮性)
class Cacular:
    def __int__(self,num):		#用于初始化一个类,num是初始化的属性值
        if not isinstance(num,int):	  #Python中的 isinstance() 函数,是Python中的一个内置函数,用来判断一个函数是否是一个已知的类型,类似 type()。
            raise TypeError("当前这个数据类型有问题,应该是一个整型数据。") 
    #当程序出现错误,python会自动引发异常,也可以通过raise显示引发异常,并通过TypeError()给出提示语。一旦执行了raise语句,raise后面的语句将不能执行。
        self.__result=num		#“__”是私密化处理,实例只能调用、查询,不能修改
    def jia(self,n):
         if not isinstance(num,int):
            raise TypeError("当前这个数据类型有问题,应该是一个整型数据。")
        self.__result+=n
    def jian(self,n):
         if not isinstance(num,int):
            raise TypeError("当前这个数据类型有问题,应该是一个整型数据。")
        self.__result-=n
    def cheng(self,n)
     if not isinstance(num,int):
            raise TypeError("当前这个数据类型有问题,应该是一个整型数据。")
        self.__result*=n
    def show(self):
        print("计算的结果是:%d"%self.__result)
c1=Cacular(2)
c1.jia(6)
c1.jian(4)
c1.cheng(5)
c1.show()
—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
#进一步优化思路:以上代码太过冗余,需要简化————>装饰器(不改变原来的代码基础)————>装饰器私有方法
class Cacular:
    def __check_num_zsq(func):		#私有方法的装饰器
        def inner(self,n):
            if not isinstance(num,int):
            	raise TypeError("当前这个数据类型有问题,应该是一个整型数据。")
            return func(self,n)		######################################################不太明白!!!
        return inner
    @__check_num_zsq		#装饰器
    def __int__(self,num):
        self.__result=num
    @__check_num_zsq
    def jia(self,n):
        self.__result+=n
    @__check_num_zsq
    def jian(self,n):
        self.__result-=n
    @__check_num_zsq
    def cheng(self,n)
        self.__result*=n
    def show(self):
        print("计算的结果是:%d"%self.__result)
—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
#增加一个新任务:每一步都实现语音播报功能(类似与开启声音的计算器)
#既可以通过安装第三方库实现,也可以通过调用Windows操作系统的接口
#设计以及优化思路:在哪里插入代码——>简化代码————>采用装饰器,不破坏原有的结构(嵌套装饰)
import win32com.client
class Cacular:
    def __check_num_zsq(func):		#私有方法的装饰器
        def inner(self,n):
            if not isinstance(num,int):
            	raise TypeError("当前这个数据类型有问题,应该是一个整型数据。")
            return func(self,n)		######################################################不太明白!!!
        return inner
    def __say(self,word):
        spearker=win32com.client.Dispatch("SAPI.ApVoice")		#创建一个播报对象
        speaker.Speak(word)			#通过这个播报器对象,直接播放对应的语音字符串即可
    def __creat_say_zsq(word=""):
        def __say_zsq(func):
            def inner(self,n):
                self.__say(word+str(n))
                return func(self,n)
            return inner
        return __say__zsq
    @__check_num_zsq		#装饰器
    @__creat_say_zsq()
    def __int__(self,num):
        self.__result=num
    @__check_num_zsq
    @__creat_say_zsq("加")
    def jia(self,n):
        self.__result+=n
    @__check_num_zsq
    @__creat_say_zsq("减去")
    def jian(self,n):
        self.__result-=n
    @__check_num_zsq
    @__creat_say_zsq("乘以")
    def cheng(self,n)
        self.__result*=n
    def show(self):
        self.__say("计算的结果是:%d"%self.__result)
        print("计算的结果是:%d"%self.__result)

c1=Caculator(10)
c1.jia(6)
c1.jian(4)
c1.cheng(5)
c1.show

上一篇:Android强行进阶,自定义控件—LayoutManager,android开发视频


下一篇:C# LINQ简单使用