面向对象 - 类与对象、属性查找、一切皆对象

面向对象编程

核心是对象二字,对象就是盛放相关数据与功能的容器,也可以说是把数据与功能整合到一起的产物

基于该思想编写程序就是在创造一个个的容器

  • 优点:扩展性强()

  • 缺点:编程的复杂度提升

    应用场景:需要经常变化的软件,一般需求的变化都集中在用户层,互联网应用,企业内部软件,游戏等都是面向对象的程序设计大显身手的好地方

    面向对象的程序设计并不是全部。对于一个软件质量来说,面向对象的程序设计只是用来解决扩展性

一个学生的数据信息:name,age,gender

name = 'jack'
age = 18
gender = 'male'


def tell_info():
    print('my name is %s my age is %s my gender is %s' % (name, age, gender))


tell_info()  # my name is jack my age is 18 my gender is male

'''
此时若想执行查看个人信息的功能,需要同时拿来两样东西,
一类是功能,另外一类则是数据,然后才能执行,非常麻烦
'''

把数据和功能整合放到一个容器中,在增加多个学生信息

def tell_info(student):
    print('my name is %s my age is %s my gender is %s' % (student["name"], student["age"], student["gender"]))


student = {
    "school": "华中科技大学",
    "name": "jack",
    "age": 18,
    "gender": "male",
    "tell_info": tell_info
}

student["tell_info"](student)  # my name is jack my age is 18 my gender is male

student1 = {
    "school": "华中科技大学",
    "name": "mary",
    "age": 19,
    "gender": "female",
    "tell_info": tell_info
}

student1["tell_info"](student1)  # my name is mary my age is 19 my gender is female

"""可以看出两个容器有相同的地方,只有是同一类才能总结出相似的东西"""


类与对象

类即类别、种类,是面向对象设计最重要的概念,对象是数据与功能的容器,而类则是一系列对象相似的数据与功能的容器

那么问题来了,先有的一个个具体存在的对象(比如一个具体存在的人),还是先有的人类这个概念,这个问题需要分两种情况去看

  • 在现实世界中:先有对象,再有类

  • 在程序中:务必保证先定义类,后产生对象

    这与函数的使用是类似的,先定义函数,后调用函数,类也是一样的,在程序中需要先定义类,后调用类

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

定义类发生的事

  • 1、会立刻运行类体代码

  • 2、将运行过程中产生的名字都丢到类的名称空间中

class Student:  # 类的命名应该使用“驼峰体”
    school = "华中科技大学"  # 数据

    def tell_info(student):  # 功能
        print('my name is %s my age is %s my gender is %s' % (student["name"], student["age"], student["gender"]))
'''
类体最常见的是变量的定义和函数的定义,但其实类体可以包含任意Python代码,
类体的代码在类定义阶段就会执行,因而会产生新的名称空间用来存放类中定义的名字,
可以打印 Student.__dict__ 来查看类这个容器内盛放的东西
'''
print(Student.__dict__)  # 类.__dict__查看属性

# 打印结果
'''
{'__module__': '__main__', 'school': '华中科技大学',
'__dict__': <attribute '__dict__' of 'Student' objects>,
 '__weakref__': <attribute '__weakref__' of 'Student' objects>, 
 '__doc__': None}
'''

调用类发生的事情

  • 1、创造一个对象的字典,用来存放对象独有的数据

  • 2、将对象与类建立好关联

class Student:
    school = "华中科技大学"  # 共有数据
    
  def tell_info(student):  # 功能
      print('my name is %s my age is %s my gender is %s' % (student["name"], student["age"], student["gender"]))
      
      
obj1 = Student()  # 类加括号实例化创建一个对象
obj2 = Student()  # 每实例化一次Student类就得到一个学生对象

print(obj1)  # <__main__.Student object at 0x7fc61be99f40>
print(obj2)  # <__main__.Student object at 0x7fc61e900130>

print(obj1.__dict__)  # {} 对象.__dict__查看属性,先从对象找,找不到会去类中找,没有传所以是个空字典
print(obj1.__dict__)  # {}


# 推导一:给对象添加属性
# 学生1
obj1.name = 'jack'  # obj1.__dict__['name'] = 'jack  # 本质就是在操作字典
obj1.age = '18'  # obj1.__dict__['age'] = 18
obj1.gender = 'male'  # obj1.__dict__['gender'] = 'male'
print(obj1.__dict__)  # {'name': 'jack', 'age': '18', 'gender': 'male'}

# 学生2
obj2.name = 'mary'  # obj2.__dict__['name'] = 'mary'
obj2.age = '19'  # obj2.__dict__['age'] = 19
obj2.gender = 'female'  # obj2.__dict__['gender'] = 'female'

print(obj2.__dict__)  # {'name': 'mary', 'age': '19', 'gender': 'female'}

"""
如果做到上面这种程度会发现仍然比较麻烦,依旧在写重复代码,唯一不同的是简化了一丢丢
"""


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

init(obj1, "jack", 18, "male")  # 重新实例学生
init(obj2, "mary", 19, "female")

# 至此,我们造出了两个对象与一个类,对象存放各自独有的数据,类中存放对象们共有的内容

print(obj1.__dict__)  # {'name': 'geng', 'age': 18, 'gender': 'male'}

print(obj2.__dict__)  # {'name': 'yang', 'age': 19, 'gender': 'female'}


"""推导二比推导一有所升级,但感觉还是有问题,依旧不够好,那么往下看最终版本"""

调用类的过程

  • 1、先创造一个空对象

  • 2、自动触发类内的__init__函数的运行,将空对象当做第一个参数自动传入

  • 3、返回一个初始化好的对象给obj1或obj2

class Student:
    school = "华中科技大学"
    # 空对象, "jack",  18,  "male"
    def __init__(self,  x,  y,  z):  # 该方法在类调用时会自动执行
        self.name = x  # 空对象.name = "jack"
        self.age = y  # 空对象.age = 18
        self.gender = z  # 空对象.gender = "male"

    def tell_info(self):
        print('my name is %s my age is %s my gender is %s' % (student["name"], student["age"], student["gender"]))

# obj1 = Student()  # 这时候直接调用类会报错,空对象传入了,但缺少参数x,y,z

# 重新定义调类的过程
obj1 = Student("jack", 18, "male")  # Student.__init__(空对象, "jack", 18,"male")
obj2 = Student("mary", 19, "female")
"""
需要注意:返回一个初始化好的对象,并不是__init__返回的结果,__init__不能有返回值
其实是Student()背后干的事情
"""

print(obj1.__dict__)  # {'name': 'jack', 'age': 18, 'gender': 'male'}
print(obj2.__dict__)  # {'name': 'mary', 'age': 19, 'gender': 'female'}
print(Student.__dict__)
'''
{'__module__': '__main__', 'school': '华中科技大学',
'__init__': <function Student.__init__ at 0x7ff043e07550>,
'tell_info': <function Student.tell_info at 0x7ff043e079d0>, 
'__dict__': <attribute '__dict__' of 'Student' objects>, 
'__weakref__': <attribute '__weakref__' of 'Student' objects>,
'__doc__': None}
'''

属性查找

  • 对象的名称空间里只存放着对象独有的属性,而对象们相似的属性是存放于类中的。对象在访问属性时,会优先从对象本身的__dict__中查找,未找到,则去类的__dict__中查找
class Student:
    school = "华中科技大学"
    
    def __init__(self,  x,  y,  z):
        self.name = x  # 空对象.name = "jack"
        self.age = y  # 空对象.age = 18
        self.gender = z  # 空对象.gender = "male"

    def tell_info(self):
        print('my name is %s my age is %s my gender is %s' % (self.name, self.age, self.gender))


obj1 = Student("jack", 18, "male")
obj2 = Student("mary", 19, "female")

# 对象.属性的查找顺序: 先从对象的字典里找,再从类的字典里找

print(obj1.name)  # jack  # obj1.__dict__["name"]
print(obj1.school)  # 华中科技大学
print(obj1.tell_info)  # <bound method Student.tell_info of <__main__.Student object at 0x7fd087d86850>>

obj1.school = "武汉大学"
print(obj1.school)  # 武汉大学  --说明优先从对象字典里找


# 类.属性:从类自己的字典里找(类中属性之所以可以自己调,其实是因为类的属性是为对象准备的)
print(Student.school)  # 华中科技大学
print(Student.__init__)  # <function Student.__init__ at 0x7fa16bd08550>
print(Student.tell_info)  # <function Student.tell_info at 0x7fa16bd089d0>


"""类中的数据属性是直接共享给所有对象用的,指向相同的内存地址"""
Student.school = 'XXXXX'
obj1.school = 'YYYYY'
print(Student.school, id(Student.school))  # XXXXX 140639098147632
print(obj1.school, id(Student.school))  # YYYYY 140639098147632
print(obj2.school, id(Student.school))  # XXXXX 140639098147632


"""
总结:
类中的数据属性:直接给所有对象共享,类只要一变,所有对象都变,某一对象变不影响其他对象

类中的函数属性:
类中的函数类可以用,如果类来调用就是一个普通函数,该怎么传参就怎么传参,不能少
但其实类中的函数是给对象用的,对象来调用就是一个绑定方法,绑定方法的特点是会将调用者当做第一个参数自动传入
"""
# 类调用就是一个普通函数
print(Student.tell_info)  # <function Student.tell_info at 0x7f8d510089d0>
Student.tell_info(obj1)  # my name is jack my age is 18 my gender is male
Student.tell_info(obj2)  # my name is mary my age is 19 my gender is female

# 对象调用就是一个绑定方法
print(obj1.tell_info)  # <bound method Student.tell_info of <__main__.Student object at 0x7f95c797e850>>
obj1.tell_info()  # my name is jack my age is 18 my gender is male
obj2.tell_info()  # my name is mary my age is 19 my gender is female

一切皆对象(补充概念)

  • 说python中一切皆对象,所有的东西全都是对象。在python3当中统一了类型与类的概念,如整型、浮点型、列表、字典、元组等这都是类型,一个类型可以称之为一个类,类就等同于类型
# 自定义类型:Student

class Student:
    n = 0

    def __init__(self, name, age, gender):
        Student.n += 1
        self.name = name
        self.age = age
        self.gender = gender

    def choose(self):  # self = obj1
        print('hello %s' %self.name)  # obj1.name


obj1 = Student("jack1", 18, "male")
# 查看对象的类型
print(type(obj1))  # <class '__main__.Student'>

# 查看类跟对象类型一样,说明类等同于类型
print(Student)  # <class '__main__.Student'>
print(list)  # <class 'list'>

obj1.choose()  # hello jack1
Student.choose(obj1)  # hello jack1

# 内置类型:list
l1 = list([1, 2, 3])
# print(l1)

# l1.append(4)
list.append(l1, 4)
print(l1)
posted @ 2021-01-08 19:26  山风有耳  阅读(141)  评论(0编辑  收藏  举报