Python-6-Python面向对象

6-1 面向过程与面向对象

1. 面向过程
面向过程,核心在过程二字,面向过程设计思维,就好比精心设计一条流水线,考虑周全,相应时候处理相应问题。
优点:将复杂问题流程化,进而简单化。
缺点:扩展性差。若更改需求,可能整个代码都需要重写,牵一发而动全身。

若解决不需要经常迭代更新的程序时,面向过程是比较好的,当解决需要频繁迭代更新维护的,使用面向对象比较好。

2. 面向对象
面向对象,是对现实世界的模拟。
面向对象编程的特点:可以编写表示真实世界中事务和情景的类,并基于这些类来创建对象。这可以使程序的维护和扩展变得简单,可大大提高开发效率。

面向对象三大特点:
封装性:使对象的特征与行为保存起来。
继承性:通过继承,子类可快速获取父类的特征与行为。
多态性:不同的子类对象,调用相同的父类方法,产生不同的执行结果。


6-2 创建一个简单的类

类:是描述具有相同特征和行为的对象的集合。格式如下

class 类名():
    变量  #刻画类的特征
    def 相关方法(self, 相关参数):  #描述类的行为
        pass

定义一个简单类:

class Man():
    gender = 'male'
    avg_height = 1.7
    
    def think(self): #实例方法
        print('thinking')
    def sleep(self):
        prnt('sleeping')

 

6-3 self 与实例方法

1. 实例方法
man = Man() #实例化一个对象

2. self
self名称是约定成俗的(虽然也可以传其它名字字符串);self是指向类实例化的对象本身;self只会在类的方法中才会有,函数是不必带有self的;self在定义类的方法(实例方法)时是必须的;self在调用时不必传入相应的参数,python会为我们自动传入

例子:

class Man():
    gender = 'male'
    avg_height = 1.7
    
    def think(self):
        print('thinking')
    def sleep(self):
        print('sleeping')
man = Man()
man.sleep()
print(man.gender)
-----------------------
sleeping
male

 

6-4 __init__ 构造函数

使用构造函数,可以让模板生成不同特征的对象。

构造函数格式:

def __init__(self):
    pass

例子:

class Man():
    gender = 'male' #类变量(描述类的通俗特征,只与类有关)######
    avg_height = 1.7

    def __init__(self, name, age):
        print('this is __init__()')
        self.name = name  #实例变量(保存对象的具体特征)
        self.age = age    #成员变量也不需要事先定义

    def think(self):
        print('thinking')
    def sleep(self):
        print('sleeping')
man = Man('xiaohei', 18)
man.sleep()
print(man.gender)
print(man.name)
print(man.age)
-----------------------
this is __init__()
sleeping
male
xiaohei
18

查看对象:

man.__dict__ #{'name': 'xiaohei', 'age': 18} 查看对象,对象以字典的形式展示,只显示实例变量,不显示类变量
Man.__dict__ #类也可以使用 __dict__方法,会展示很多东西

 

6-5 通过实例方法访问实例变量与类变量

例子

class Man():
    gender = 'male'
    avg_height = 1.7

    def __init__(self, name, age):
        print('this is __init__()')
        self.name = name
        self.age = age

    def think(self):
        print('thinking')
    def sleep(self):
        print('sleeping')
    def find(self):
        print('this is ' + str(self.name)) #访问实例变量
        print(self.__class__.gender) #访问类变量,法一
        print(Man.gender)            #访问类变量,法二
        print(self.gender)           #访问类变量,法三 它会先在构造方法中找,若找不到向上找

man = Man('xiaohei', 18)
man.sleep()
man.find()
print(man.name)
-----------------------
this is __init__()
sleeping
this is xiaohei
male
male
male
xiaohei

 

6-6 类方法

1. 开闭原则:对于扩展是开放的,对于修改是关闭的。

比如要将上面的 avg_height 改为 1.75

man.avg_height = 1.75 #相当于在构造函数中加了一个 self.avg_height = 1.75, 类的 avg_height 还是1.7
man.__dict__
-----------------------
{'name': 'xiaohei', 'age': 18, 'gender': 'renyao', 'avg_height': 1.75}


2. 可以使用类方法来操作类的特征

例子:

class Man():
    gender = 'male'
    avg_height = 1.7

    def __init__(self, name, age):
        print('this is __init__()')
        self.name = name
        self.age = age

    def think(self):
        print('thinking')
    def sleep(self):
        print('sleeping')
    @classmethod                    #声明定义的是类方法
    def modify_height(cls, height): #cls类似self,为了区分写成cls, 表示当前类,也不用传参
        cls.avg_height += height
        print('Now the avg_height is ' + str(cls.avg_height))

Man.modify_height(0.05)
Man.__dict__
-----------------------
Now the avg_height is 1.75
...
'avg_height': 1.75, #类属性已经改过来了

 

6-7 静态方法

静态方法与普通函数基本上没有什么区别。静态方法与类、对象没有太大关系的时候可以使用该方法。

例子:

class Man():
    gender = 'male'
    avg_height = 1.7

    def __init__(self, name, age):
        print('this is __init__()')
        self.name = name
        self.age = age

    def think(self):
        print('thinking')
    def sleep(self):
        print('sleeping')
    @classmethod
    def modify_height(cls, height): #cls类似self,为了区分写成cls, 表示当前类,也不用传参
        cls.avg_height += height
        print('Now the avg_height is ' + str(cls.avg_height))
    @staticmethod  #声明类的静态方法
    def plus_num(x, y):
        print(str(x) + ' + ' + str(y) + ' = ' + str(x+y)) #注意这个打印
        return x+y

Man.plus_num(2, 3)
man = Man('xiaohei', 12)
man.plus_num(4, 5)
-----------------------
2 + 3 = 5
this is __init__()
4 + 5 = 9
9

 

6-8 成员可见性

public: 公开性,外部可以访问相关变量和方法
private:私有性,外部不可以访问相关变量和方法

设置成private的:成员变量或成员方法名前加'__'

例子:

class Man():
    gender = 'male'
    avg_height = 1.7

    def __init__(self, name, age):
        self.__name = name #私有成员变量__name
        self.age = age

    def __sleep(self): #私有方法
        print('sleeping')

    def get_message(self):
        print('name= ' + self.__name) #私有成员变量还可以爱成员方法中访问
        #__sleep() 加这个也报错,私有成员方法在成员方法内也无法访问吗? TODO:

man = Man('xiaohei', 10)
# man.__name 私有变量,对外部不可见,包没有属性__name
# man.__sleep() 私有方法,对外部不可见
man.get_message()
-----------------------
name= xiaohei

 

6-9 python 没有什么是不能访问的

例子:

man.__dict__ #{'_Man__name': 'xiaohei', 'age': 10} 可以看到多出来了 _Man__name 成员变量,外部可以通过它来访问私有成员变量
man._Man__name #'xiaohei' 外部访问私有成员变量
man._Man__sleep() #sleeping 外部访问私有成员方法

python私有机制做的不是很好,但为了代码规范性,最好还是遵从,Python没有任何机制阻止你访问其私有成员变量和私有成员方法。


6-10 继承

例子:

class Man():
    gender = 'male'
    avg_height = 1.7

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

    def think(self):
        print('thinking')
    def sleep(self):
        print('sleeping')

class ChinesMan(Man): #继承,ChinesMan 继承 Man
    pass

cman = ChinesMan('xiaobai', 24)
cman.think()

继承后重写成员函数:

class Man():
    gender = 'male'
    avg_height = 1.7

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

    def think(self):
        print('thinking')
    def sleep(self):
        print('sleeping')

class ChinesMan(Man):
    def __init__(self, name, age, height):
        self.name = name  # 这两行也可以改为调用父类的,使用 Man.__init__(self, name, age); 调用父类方法需要手动传入self
        self.age = age
        self.height = height
    def think(self): # 这里也可以通过 Man.think(self) 调用父类的think()
        print(self.name + ' is thinking')

cman = ChinesMan('xiaobai', 24, 1.8)
cman.think()
-----------------------
xiaobai is thinking

cman.__dict__ # {'name': 'xiaobai', 'age': 24, 'height': 1.8} 可以看到类成员已经变化了

但是 类.构造方法 的调用格式来调用父类的构造方法并不好。其次若这样调用若父类名变了,子类都要进行修改。


6-11 super关键字调用父类方法

super 不仅可以调用父类的构造函数,也可以调用父类的成员方法,可以解决父类名变化带来的影响。

例子:

class Man():
    gender = 'male'
    avg_height = 1.7

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

    def think(self):
        print('thinking')
    def sleep(self):
        print('sleeping')

class ChinesMan(Man):
    def __init__(self, name, age, height):
        super(ChinesMan, self).__init__(name, age); # super(子类名, self).父类构造方法 调用父类构造方法
        self.height = height
    def think(self):
        super(ChinesMan, self).think() #使用super后就不需要再传self参数了 调用父类成员函数
        print(self.name + ' is thinking')

cman = ChinesMan('xiaobai', 24, 1.8)
cman.think()
-----------------------
thinking
xiaobai is thinking

注意:父类必须在子类前面定义,子类可继承一个或多个父类(那此时super调用的是哪个父类的?

 

posted on 2023-08-01 15:07  Hello-World3  阅读(8)  评论(0编辑  收藏  举报

导航