Python-面向对象编程思想

一、面向对象简单解析

我们之前学过面向过程实现,它的核心即是过程两字,即就是先干啥后干啥,最后在干啥,基于这个思想编程就像是设计流水线,将复杂的流程问题流程化进而简单化,缺点就是拓展性较差牵一动则全身;
而面向对象编程思想核心则是对象两字,对象可以把它当成一个盛放数据和功能的容器,基于这个思想写程序就像在整合工具\程序,优点数据等分开存放,拓展行性强,缺点也很明细,会较大的提升编程的复杂度。

二、类与对象

1、类与对象解析

类也就是类别/种类,是面向对象分析和设计的基石,如果多个对象有相似的数据与功能,那么该多个对象就属于同一种类。有了类的好处是:我们可以把同一类对象相同的数据与功能存放到类里,而无需每个对象都重复存一份,这样每个对象里只需存自己独有的数据即可,极大地节省了内存空间。如果说对象是用来存放数据与功能的容器,那么类则是用来存放多个对象相同的数据与功能的容器。
虽然我们这是先介绍对象后介绍类,但需要强调:在程序中,必须要事先定义类,然后再调用类产生对象(调用类拿到的返回值就是对象)。产生对象的类与对象之间存在关联,这种关联指的是:对象可以访问到类中共有的数据与功能,所以类中的内容仍然是属于对象的,类只不过是一种节省空间、减少代码冗余的机制,面向对象编程最终的核心仍然是去使用对象。

在现实世界中:先有对象,再有类;
世界上肯定是先出现各种各样的实际存在的物体,然后随着人类文明的发展,人类站在不同的角度总结出了不同的种类,如人类、动物类、植物类等概念
也就说,对象是具体的存在,而类仅仅只是一个概念,并不真实存在

在程序中:务必保证先定义类,后产生对象;
这与函数的使用是类似的,先定义函数,后调用函数,类也是一样的,在程序中需要先定义类,后调用类;

不一样的是,调用函数会执行函数体代码返回的是函数体执行的结果,而调用类会产生对象,返回的是对象;

2、案例解析

# 站在现实世界,学校的角度:现有对象后有类
'''
学生对象1
    数据:

        名字 = "小龙女"
        年龄 = 200
        性别 = "female"


学生对象2
    数据:

        名字 = "尹志平"
        年龄 = 19
        性别 = "male"


学生对象3
    数据:
        名字 = "杨过"
        年龄 = 18
        性别 = "male"


学生的类
    相同的数据
        学校 = "oldboy"
    相同的功能
        选课


'''
# 在程序中,务必保证:先定义(类),后使用(产生对象)
# 类体代码会在类定义阶段立刻执行,然后将产生的名字都丢到类的名称空间中
class Student:
    # 相同的数据
    school = "oldboy"

    # 相同的功能
    def choose(self):
        print("正在选课")

类体最常见的是变量的定义和函数的定义,但其实类体可以包含任意Python代码,类体的代码在类定义阶段就会执行,因而会产生新的名称空间用来存放类中定义的名字,可以打印Student.__dict__来查看类这个容器内盛放的东西

print(Student.__dict__)
# {'__module__': '__main__', 'school': 'oldboy', 'choose': <function Student.choose at 0x033AA220>, '__dict__': <attribute '__dict__' of 'Student' objects>, '__weakref__': <attribute '__weakref__' of 'Student' objects>, '__doc__': None}

注意:

  1. 类中可以有任意python代码,这些代码在类定义阶段便会执行
  2. 因而会产生新的名称空间,用来存放类的变量名与函数名,可以通过OldboyStudent.__dict__查看
  3. 对于经典类来说我们可以通过该字典操作类名称空间的名字(新式类有限制),但python为我们提供专门的.语法
  4. 点是访问属性的语法,类中定义的名字,都是类的属性
# 程序中的对象
# 调用类,或称为实例化,得到对象
stu_obj1=Student()
stu_obj2=Student()
stu_obj3=Student()

如此stu1、stu2、stu3全都一样了(只有类中共有的内容,而没有各自独有的数据),要在实例化的过程中就为三位学生定制各自独有的数据:姓名,性别,年龄,需要我们在类内部新增一个py内置的__init__方法,如下

class Student:
    school='清华大学'

    #该方法会在对象产生之后自动执行,专门为对象进行初始化操作,可以有任意代码,但一定不能返回非None的值
    def __init__(self,name,sex,age):
        self.name=name
        self.sex=sex
        self.age=age

    def choose(self): 
        print('%s is choosing a course' %self.name)然后我们重新实例出三位学生>>> stu1=Student('李建刚','男',28)
>>> stu2=Student('王大力','女',18)
>>> stu3=Student('牛嗷嗷','男',38)

# 单拿stu1的产生过程来分析,调用类会先产生一个空对象stu1,然后将stu1连同调用类时括号内的参数一起传给Student.__init__(stu1,’李建刚’,’男’,28)

def __init__(self, name, sex, age):
    self.name = name  # stu1.name = '李建刚'
    self.sex = sex    # stu1.sex = '男'
    self.age = age    # stu1.age = 28会产生对象的名称空间,同样可以用__dict__查看>>> stu1.__dict__
{
    
    'name': '李建刚', 'sex': '男', 'age': 28}

三、属性访问

1、类属性与对象属性

在类中定义的名字,都是类的属性,细说的话,类有两种属性:数据属性和函数属性,可以通过__dict__访问属性的值,比如Student.dict[‘school’],但Python提供了专门的属性访问语法

>>> Student.school # 访问数据属性,等同于Student.__dict__['school']
'清华大学'
>>> Student.choose # 访问函数属性,等同于Student.__dict__['choose']
<function Student.choose at 0x1018a2950>
# 除了查看属性外,我们还可以使用Student.attrib=value(修改或新增属性),用del Student.attrib删除属性。

# 操作对象的属性也是一样
>>> stu1.name # 查看,等同于obj1.__dict__[‘name']
'李建刚'
>>> stu1.course=’python’ # 新增,等同于obj1.__dict__[‘course']='python'
>>> stu1.age=38 # 修改,等同于obj1.__dict__[‘age']=38
>>> del obj1.course # 删除,等同于del obj1.__dict__['course']

2、属性查找顺序与绑定方法

对象的名称空间里只存放着对象独有的属性,而对象们相似的属性是存放于类中的。对象在访问属性时,会优先从对象本身的__dict__中查找,未找到,则去类的__dict__中查找;

类中定义的变量是类的数据属性,是共享给所有对象用的,指向相同的内存地址

# id都一样
print(id(Student.school)) # 4301108704

print(id(stu1.school)) # 4301108704
print(id(stu2.school)) # 4301108704
print(id(stu3.school)) # 4301108704

类中定义的函数是类的函数属性,类可以使用,但必须遵循函数的参数规则,有几个参数需要传几个参数

Student.choose(stu1) # 李建刚 is choosing a course
Student.choose(stu2) # 王大力 is choosing a course
Student.choose(stu3) # 牛嗷嗷 is choosing a course

但其实类中定义的函数主要是给对象使用的,而且是绑定给对象的,虽然所有对象指向的都是相同的功能,但是绑定到不同的对象就是不同的绑定方法,内存地址各不相同

print(id(Student.choose)) # 4335426280

print(id(stu1.choose)) # 4300433608
print(id(stu2.choose)) # 4300433608
print(id(stu3.choose)) # 4300433608

绑定到对象的方法特殊之处在于,绑定给谁就应该由谁来调用,谁来调用,就会将’谁’本身当做第一个参数自动传入(方法__init__也是一样的道理)

stu1.choose()  # 等同于Student.choose(stu1)
stu2.choose()  # 等同于Student.choose(stu2)
stu3.choose()  # 等同于Student.choose(stu3)

绑定到不同对象的choose技能,虽然都是选课,但李建刚选的课,不会选给王大力,这正是”绑定“二字的精髓所在。

注意:绑定到对象方法的这种自动传值的特征,决定了在类中定义的函数都要默认写一个参数self,self可以是任意名字,但命名为self是约定俗成的。

猜你喜欢

转载自blog.csdn.net/msmso/article/details/107790232