首页 > 编程语言 >Python进阶篇04-面向对象编程

Python进阶篇04-面向对象编程

时间:2022-10-26 22:00:30浏览次数:61  
标签:__ mike name Python self 进阶篇 面向对象编程 print 属性

面向对象编程

面向对象编程和面向过程编程的区别:

类和实例

类:抽象的、用于创建实例的基础模板,类里面可以定义这个类所拥有的基础的属性。
实例:根据类而创建的具体的对象,实例拥有类的基础属性和方法(类中的函数),比如 人类 就是一个类,而一个个具体的人,就是根据人类创建出来的具体的对象。
我们使用class关键字来定义类,类名使用驼峰命名法:

class People:    
    def __init__(self, name, age):  
        self.name = name
        self.age = age
        
    def hello(self):
        print('你好 {}'.format(self.name))
        
    def how_old(self):
        print('我{}岁了'.format(self.age))

创建类的实例化对象:

mike = People('mike', 15)  # 根据__init__方法的参数来传参
mike.hello()
  1. __init__() 类的初始化方法,定义该类的实例化对象必须绑定的基础属性,此方法第一个参数必须是self,指创建的实例本身,但在进行实例化时不需要传递此参数,python会自动传递,创建实例时就会将该类的基础属性绑定给实例对象,为通过self变量给实例化对象绑定属性;init方法中无参数时,创建实例不需要传参,有参数时,则创建实例时需要按照参数进行传递。
  2. Python中创建类时默认继承了object类,不需要多余写,若要继承其他类,则需要class People(ObjectName):
  3. 面向对象编程中有个“数据封装”,在类中我们有基础属性,而直接在类中定义访问类中数据的函数,这样根据类实例化对象之后,可以直接通过调用实例的方法(即类中定义的函数)去访问实例对象中的数据,外部不需要知道类及其实例中的细节,这就称为封装(就像一个集装箱,其中有两个窗口,一个可以往外送东西,一个可以往里放东西,我们只需要在窗口输入特定的参数,就可以实现往集装箱放东西、取东西,而不需要关心其中是如何放、取)。
  4. “封装的目的在于保护类内部数据结构的完整性, 因为使用类的用户无法直接看到类中的数据结构,只能使用类允许公开的数据,很好地避免了外部对内部数据的影响,提高了程序的可维护性。用户只能通过暴露出来的方法访问数据时,你可以在这些方法中加入一些控制逻辑,以实现一些特殊的控制”。

访问限制

前面讲到,将类进行封装,可以避免外部随意操作内部的数据,那么如何使外部无法随意操作类及类的实例对象的内部数据呢?
可以看到,之前的写法是可以在外部随意操作内部数据的,这样很容易产生错误,因为我们无法控制外部的操作。

class People:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def hello(self):
        print('你好 {}'.format(self.name))

    def how_old(self):
        print('我{}岁了'.format(self.age))


mike = People('mike', 15)
print(mike.name)
mike.name = 'pika'
print(mike.name)
----------
mike
pika
  1. 在Python中,我们可以在属性前面加上两个下划线__,这样就可以让内部属性无法被外部访问,使之变成了一个私有变量;
class People:
    def __init__(self, name, age):
        self.__name = name
        self.__age = age

    def get_name(self):
        return self.__name

    def set_name(self, n):
        self.__name = n
        return True


mike = People('mike', 15)
print(mike.__name)
----------
Traceback (most recent call last):
  File ".........pythonProject/main.py", line 33, in <module>
    print(mike.__name)
AttributeError: 'People' object has no attribute '__name'
  1. 但这种并非真正的私有变量,在Python内部,是将这样的变量修改为了_ClassName__variable,因此直接通过原来的变量名无法进行访问,这是一种双方默认的私有,即双方自觉遵守规定的私有;
print(mike._People__name)    # 极为不建议,错误的做法
  1. 在Python中,还有一种__variable__的变量,这种是Python的特殊变量,可以直接进行访问,如__name____file__等;
  2. 还有一种以单下划线开头的变量名_variable,这种的含义是,我将其标记为了私有变量,虽然可以进行访问,但请你不要访问它;
  3. 将变量设置为私有变量后,为了外部可以 设置/获取 私有变量的值,就可以给类添加 get方法 与 set方法;
print(mike.get_name())
mike.set_name('kk')
print(mike.get_name())
----------
mike
kk
  1. 外部不可以再操作私有变量,但注意 虽然在表面看来可以对私有变量赋值,实际上那只是给对象新增了一个属性;
mike.name = 'pika'    # 此时的name已经是一个新的属性,相当于给mike对象新增了一个name属性
print(mike.name)

mike.__name = 'test'   # 相当于给mike对象新增了一个__name属性
print(mike.__name)
print(mike.get_name())   # 原来的__name属性,还是原来的值
----------
pika
test
mike

继承和多态

继承
  • 我们定义一个类的时候,可以从现有的类中继承,被继承的类即为父类(或者基类、超类),新定义的类即为子类;
  • 当新类继承某个类后,即拥有了父类的全部功能,继承是实现代码复用的重要方式,可以减少很多重复性代码、使代码更便于维护;
  • 继承某个类后,我们还可以在子类上覆盖重写父类的功能 或者 扩展新的特色功能;
  • Python中,所有的类都默认继承Object类;
  • 继承分为 单继承、多重继承;
单继承

单继承即普通的继承,一个类继承另一个类。

class People:
    def __init__(self, name, age):
        self.__name = name
        self.__age = age

    def get_name(self):
        return '我的名字是{}'.format(self.__name)

    def set_name(self, n):
        self.__name = n
        return True

    def say(self):
        print('我是一个人类')


class Adult(People):
    def say(self):
        print('我是一个成年人')


class Child(People):
    def say(self):
        print('我是一个小孩子')


sky = Adult('sky', 17)
print(sky.get_name())
sky.say()

Adult和Child都继承了People类,拥有People类的所有功能,也可以自己定义新的特色功能

多重继承

在上述例子中,再扩展一下,生活中一般分为工作和读书,那么假如我们有一些类:读书的成年人、读书的孩子、工作的成年人、工作的孩子...,此时我们就可以使用多重继承,可以使一个类同时拥有多种特质(功能)

class Work:
    @staticmethod
    def work():
        print('我在打工,我好累')


class Study:
    @staticmethod
    def study():
        print('我要好好学习')


class ChildLabour(Child, Work):
    pass


class StudyAdult(Adult, Study):
    pass


maria = ChildLabour('maria', 13)
maria.say()
maria.work()
----------
我是一个小孩子
我在打工,我好累

ChildLabour类同时继承了Child和Work,即为工作的孩子-童工类,同时拥有了Child和Work的特质(功能);通过多重继承,我们可以自由对基类进行组合,以创造出合适的新类

多态
  • 多态的概念依赖于继承,因为继承,子类拥有了父类的方法,而子类不仅可以重写父类的方法,还可以自己添加自己特有的方法,最终同一个类型的对象,执行相同的方法时,会出现多种不同的结果,即同一类事物,有多重形态;
  • 当我们调用一个类的实例对象中的方法时,会先从此类本身的定义中寻找此方法,如果没有,则再找父类是否有这个方法,按照此顺序依次向上寻找;
  • 因此,当子类与父类拥有同样的方法时,调用子类的实例化对象的这个方法,那么调用的是子类的方法,这种子类与父类拥有相同方法我们称之为重写,即重新编写父类的方法,使其更“特色”;
  • 在上述例子中,Adult和Child都继承了People类,都重写了People类的say()方法,分别调用Adult.say()、Child.say(),却会出现不同的结果,这就是因为继承而出现的多态;
  • 多态是 发生在父类与子类之间,并且因为子类重写了父类的方法,而产生了调用同一种方法出现不同结果的现象;

如何运用多态呢?如果仅仅是通过继承和重写,在子类中定义相同的方法而使其出现不同的结果,和在子类中定义不同的方法也没什么区别;而假如我们通过其他外部函数,针对某一类对象,统一进行调用并对数据进行处理,这样我们只需要知道传入此类型的对象 或者 拥有此种需要的方法的对象 即可,如果还需要新增新的类去使用这个外部函数来进行处理的话,再定义一个新的子类就可以了,不需要去动这个外部函数的内部功能,这样提高了代码的灵活性、增加了程序的可扩展性。

class People:
    def __init__(self, name, age):
        self.__name = name
        self.__age = age

    def say(self):
        print('我是一个人类')


class Adult(People):
    def say(self):
        print('我是一个成年人')


class Child(People):
    def say(self):
        print('我是一个小孩子')


def say_what(people):
    print('我是一个{}'.format(type(people)))
    people.say()


p = People('kk', 12)
a = Adult('mike', 19)
c = Child('lisa', 10)

say_what(p)
say_what(a)
say_what(c)
----------
我是一个<class '__main__.People'>
我是一个人类
我是一个<class '__main__.Adult'>
我是一个成年人
我是一个<class '__main__.Child'>
我是一个小孩子

我们可以通过一个方法来处理同一类型的对象,再加上多态,从而得到不同的结果,如果我们需要增加其他处理逻辑,直接修改say_what()函数即可;如果我们需要增加新的对象进行处理,再增加新的子类或者拥有say()方法的对象即可。

实例属性和类属性

实例属性:可以通过实例变量直接给实例化对象添加属性,也可以通过定义类时的self变量给实例化对象绑定属性;
类属性:直接在类中绑定在类上的属性,属于类本身,可以通过 classname.name 来进行访问,不过该类的实例化对象也可以访问;

class People:
    count = 0    # 绑定在类的属性,可以通过 People.count访问

    def __init__(self, name):
        self.name = name    # 通过 self 变量给实例化对象绑定属性
        People.count += 1


mike = People('mike')
mike.age = 17    # 通过变量,直接给实例化对象绑定属性,类无此属性
print(mike.age)

print('给mike直接绑定count属性前,打印count属性值:{}'.format(mike.count))    # mike对象本身没有这个属性,会向上查找类的count属性
mike.count = 666
print('给mike直接绑定count属性之后,打印count属性值:{}'.format(mike.count))
print('给mike直接绑定count属性之后,打印People类的count属性值:{}'.format(People.count))
# 给mike对象绑定后,mike对象的有count属性,则会直接打印出mike对象的属性
# 但是People的类属性 count 并未改变,只是通过mike对象无法再访问到这个类属性
----------
给mike直接绑定count属性前,打印count属性值:1
给mike直接绑定count属性之后,打印count属性值:666
给mike直接绑定count属性之后,打印People类的count属性值:1

“注意在实际生活中,不要对实例属性和类属性使用相同的名字,这样实例属性会覆盖掉类属性,而删除掉实例属性后,再使用相同名称访问到的是类属性,这样可能会出现意外的错误。“

标签:__,mike,name,Python,self,进阶篇,面向对象编程,print,属性
From: https://www.cnblogs.com/themoony/p/16807998.html

相关文章

  • python基础之模块
    第三方模块的下载与使用第三方模块:别人写的模块一般情况下功能特别强大想使用第三方模块必须先下载后面才可以反复使用方式1:命令行借助于pip工具pip......
  • OpenCV-Python learning-9.图像阈值处理
    你也可以​​iframe外链​​查看。本节内容包括:常用阈值方法自适应阈值Otsu(大津法)自适应阈值​​github地址​​......
  • OpenCV-Python learning-8.颜色空间
    你也可以​​iframe外链​​查看。本节内容包括:改变色彩空间:cvtColor使用HSV对象跟踪练习......
  • python sklearn中的KNN
    代码fromsklearnimportdatasetsfromsklearn.model_selectionimporttrain_test_splitfromsklearn.neighborsimportKNeighborsClassifierimportnumpyasnpiris=dat......
  • Python调用matlab函数
    参考文章:安装用于Python的MATLAB引擎API环境:MATLABR2022a、Anaconda、python3.9检验配置检查Python版本是否与Matlab版本相匹配安装API打开matlab在命令行中输入......
  • python的一些运算符
    #1.算术运算符print('1.算术运算符')#1.1+求和a=10b=20c=a+bprint(c)print('a+b={}'.format(c))print('a+b=%i'%c)print(f'a+b={c}')#1.2-求......
  • python模块之requents模块及excel操作模块openpyxl
    第三方模块的下载与使用第三方模块:别人写的模块一般情况下功能都特别强大我们如果想使用第三方模块第一次必须先下载后面才可以反复使用(等同于内置模块)下载......
  • Python pandas DataFrame 行列使用常用操作
    Pandas是基于NumPy的一种工具,该工具是为了解决数据分析任务而创建的。Pandas纳入了大量库和一些标准的数据模型,提供了高效地操作大型数据集所需的工具。Pandas提供了大量......
  • Python pip 安装与使用
    简介:​pip是Python包管理工具,该工具提供了对Python包的查找、下载、安装、卸载的功能。1.判断是否安装你可以通过以下命令来判断是否已安装:pip--version......
  • python爬虫练习3
    说明python3.6.132位获取豆瓣电影推荐页电影详情,参考网址​​​https://movie.douban.com/explore#!type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&......