19--面向对象01:介绍、类定义、属性查找、绑定与非绑定方法

一 对象的概念

# “面向对象”的核心是“对象”二字,而对象的精髓在于“整合“,什么意思?
  所有的程序都是由”数据”与“功能“组成
  因而编写程序的本质就是定义出一系列的数据
  然后定义出一系列的功能来对数据进行操作。
    
  "对象"是把数据与功能整合到一起的产物,或者说”对象“就是一个盛放数据与功能的容器/箱子/盒子。


面向过程:
    核心是"过程"二字
    
    过程的终极奥义就是将程序流程化
    过程是"流水线",用来分步骤解决问题的
    
    优点是:复杂度的问题流程化,进而简单化
    缺点是:一套流水线或者流程就是用来解决一个问题,改动很麻烦

    应用场景:
      一旦完成基本很少改变的场景,著名的例子有Linux內核,git,以及Apache HTTP Server等。
    
       
面向对象:
    核心是"对象"二字
    
    对象的终极奥义就是将程序"整合"
    对象是"容器",用来盛放数据与功能的  
    类也是"容器",该容器用来存放同类对象共有的数据与功能
    
    
    缺点:编程的复杂度高
    优点:扩展性强,可维护性强
    应用场景:
      需求经常变化的软件,一般需求的变化都集中在用户层,
      互联网应用,企业内部软件,游戏等都是面向对象的程序设计大显身手的好地方。如:微信、qq
    
    
# 需要强调的是,面向对象解决的仅仅只是扩展性问题
  软件质量属性包含很多方面:安全性、可拓展性、可维护性、可移植性、可伸缩性、可靠性、成本、性能

二 类与对象

# 类即类别/种类
  是面向对象分析和设计的基石
  如果多个对象有相似的数据与功能,那么该多个对象就属于同一种类


# 对象是"容器",用来盛放数据与功能的  
# 类也是"容器",该容器用来存放同类对象共有的数据与功能


# 强调:
  1.在程序中,必须要事先定义类,然后再调用类产生对象(调用类拿到的返回值就是对象)
    
  2.产生对象的类与对象之间存在关联
    对象可以访问到类中共有的数据与功能
    所以类中的内容仍然是属于对象的,类只不过是一种节省空间、减少代码冗余的机制
    面向对象编程最终的核心仍然是去使用对象

三 面向对象编程

3.1 类的定义与实例化

# 一:类的定义
  类是对象相似数据与功能的集合体
  所以类体中最常见的是变量与函数的定义,但是类体其实是可以包含任意其他代码的

  # 注意:
    1.类体代码是在类定义阶段就会立即执行,会产生类的名称空间 (局部名称空间)
      定义完类,可在类.__dict__查看名称空间
    
    
class Student:
    # 1.共有数据属性的定义
    stu_school='oldboy'
	
    # 2.对象独有数据的定义 (通过类实例化时自动调用的初始化方法)
	  该方法会在对象产生之后自动执行,专门为对象进行初始化操作
      可以有任意代码,但一定不能返回非None的值
    
    def __init__(self,name,sex,age):
        self.name=name
        self.sex=sex
        self.age=age
    
    # 3.共有功能属性的定义
     def tell_stu_info(self):
        print('学生信息:名字:%s 年龄:%s 性别:%s' %(
            self.stu_name,
            self.stu_age,
            self.stu_gender
        ))

    def set_info(self,x,y,z):
        self.stu_name=x
        self.stu_age=y
        self.stu_gender=z

    def choose(self,x):
        print('正在选课')
        self.course=x
        
        
# 二:类的实例化  调用类产生对象

调用类的过程又称之为实例化,发生了三件事:
  1.先产生一个空对象  通过类.__new__()
  2.python会自动调用类中的__init__方法,
    然后将空对象以及调用类时括号内传入的参数,一同传给__init__方法
  3.返回初始完的对象
    
stu1_obj=Student('egon',18,'male')  # 本质:Student.__init__(空对象,'egon',18,'male')
stu2_obj=Student('lili',19,'female')
stu3_obj=Student('jack',20,'male')


# 总结__init__方法:
    1.会在调用类时自动触发执行,用来为对象初始化自己独有的数据
    2.__init__内应该存放是为对象初始化属性的功能
      但是可以存放任意其他代码,想要在类调用时就立刻执行的代码都可以放到该方法内
        
    3.__init__方法必须返回None

    
# 注意:
  1.类的名字使用驼峰体,变量命名使用下划线
    
  2.类与函数的区别:
    1.类的名称空间在类定义时产生;函数的名称空间是在函数调用阶段才会产生 
    2.调用类的过程称为将类实例化,拿到的返回值就是程序中的对象,或称为一个实例。
      但并不会执行类中的代码体,因为类中代码体在定义阶段已经执行了
      而函数中的代码体在调用阶段执行。(函数在定义时,只是声明了函数名的名称空间)

3.2 属性访问

3.2.1 类属性与对象属性

# 类中存放的是对象共有的数据与功能

# 一.类属性是共享的
# 1.类可以访问:
    1.类的数据属性
    print(Student.stu_school)  # 等同于Student.__dict__['stu_school']
    2.类的函数属性
    print(Student.tell_stu_info)
    print(Student.set_info)
    
    # 除了查看属性
      Student.attrib=value  # 修改或新增属性
      del Student.attrib  # 删除属性
   
# 2.对象也可以访问:
    stu1_obj.name  # 查看 等同于stu1_obj.__dict__[‘name']
    stu1_obj.course='python'  # 新增 等同于stu1_obj.__dict__['course']='python'
    stu1_obj.age=38  # 修改  等同于stu1_obj.__dict__['age']=38
    del stu1_obj.course  # 删除 等同于del stu1_obj.__dict__['course']
    
    
# 二.类属性与对象属性
# 1.类中定义的变量是类的数据属性,是共享给所有对象用的,大家访问的地址都一样
print(id(Student.stu_school))  # 4301108704
print(id(stu1_obj.stu_school))  # 4301108704
print(id(stu2_obj.stu_school))  # 4301108704

# 若修改类的数据属性,则所有对象包括类的数据属性都会修改
Student.stu_school='OLDBOY'
print(Student.stu_school)   # 'OLDBOY'
print(stu1_obj.stu_school)  # 'OLDBOY'
print(stu2_obj.stu_school)  # 'OLDBOY'

# 若修改对象的数据属性,则只有对象本身数据属性会修改  
原理:赋值操作,会从自身对象中,查找是否有该属性;若是有直接修改,若是没有直接新建;
     新建后,自身该数据属性已存在,就不会访问类共有的该数据属性(或者说是覆盖了类的共有该数据) 

stu1_obj.stu_school='OLDBOY'
print(stu1_obj.stu_school)  # 'OLDBOY'
print(Student.stu_school)   # 'oldboy'
print(stu2_obj.stu_school)  # 'oldboy'


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

# 类可以使用,但必须遵循函数的用法,有几个参数需要传几个参数
Student.tell_stu_info(stu1_obj)  # 第一个参数:对象 就不能省略!
Student.set_info(stu1_obj,'EGON',19,'MALE')

# 绑定方法的特殊之处在于:绑定给谁就应该由谁来调用,就会将’谁’本身当做第一个参数自动传入

stu1_obj.tell_stu_info()   # tell_stu_info(stu1_obj)
stu2_obj.tell_stu_info()   # tell_stu_info(stu2_obj)

stu1_obj.choose('python全栈开发')
stu2_obj.choose('linux运维')

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

3.2.2 属性查找顺序

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

3.3 绑定方法

# 一、绑定方法
  绑定方法:特殊之处在于将调用者本身当做第一个参数自动传入
    
# 1.绑定给对象的方法:调用者是对象,自动传入的是对象 (类也可以调用)
  在类中书写方法,默认绑定给对象使用的  参数名称:self
    
# 2.绑定给类的方法:调用者类,自动传入的是类
  classmethod :将下面的函数装饰成,绑定给类的方法    参数名称:cls

class Mysql:
    def __init__(self,ip,port):
        self.ip=ip
        self.port=port

    def func(self):  # 类中不加任何装饰器的函数,都是绑定给对象的方法
        print('%s:%s' %(self.ip,self.port))

    @classmethod  # 将下面的函数装饰成,绑定给类的方法
    def from_conf(cls):
        print(cls)
        return cls(settings.IP, settings.PORT)

obj2=Mysql.from_conf()
print(obj2.__dict__)  # {'ip':'127.0.0.1', 'port':3306}


# 二、非绑定方法  (静态方法)
  没有绑定给任何人:调用者可以是类、对象,没有自动传参的效果,就是普通函数

class Mysql:
    def __init__(self,ip,port):
        self.nid=self.create_id()
        self.ip=ip
        self.port=port

    @staticmethod  # 将下述函数装饰成一个静态方法
    def create_id():
        import uuid
        return uuid.uuid4()

obj=Mysql('1.1.1.1', 3306)
print(Mysql.create_id)  # 类可以调用  <function Mysql.create_id at 0x0000018367B8AAE8>
print(obj1.create_id)   # 对象也可以调用  <function Mysql.create_id at 0x0000018367B8AAE8>

print(Mysql.create_id)
print(Mysql.f1)   # <bound method Mysql.f1 of <class '__main__.Mysql'>>  类方法
print(obj1.f2)  # <bound method Mysql.f2 of <__main__.Mysql object at 0x0000028DE0E59A90>> 对象方法

3.4 总结

# Python中一切皆为对象,且Python3中类与类型是一个概念!

在上述介绍类与对象的使用过程中,我们更多的是站在底层原理的角度去介绍类与对象之间的关联关系
如果只是站在使用的角度,我们无需考虑语法"对象.属性"中 "属性"到底源自于哪里
只需要知道是通过对象获取到的就可以了。

对象是一个高度整合的产物,有了对象
只需要使用”对象.xxx“的语法就可以得到跟这个对象相关的所有数据与功能
十分方便且解耦合程度极高
posted @ 2022-06-24 13:13  Edmond辉仔  阅读(50)  评论(0编辑  收藏  举报