Python基础19-面向对象基础

目录

面向对象概述

面向对象的一种实现

类的相关知识

对象的相关知识

面向对象属性的查改增删操作

类属性的查改增删

对象属性的查改增删

关于类、对象属性容易混淆额或忽略的地方的说明


面向对象概述

编程发展至今有面向过程编程、函数式编程、面向对象编程三大流派,未来不知道会不会有面向数据的编程。

Python支持面向对象编程,为什么要面向对象呢?面向对象是个啥?我的粗浅理解,就是将一系列相干的数据、方法封装到一起形成实例,并限制实例的数据、方法调用方式,通过对这个实例的控制达到简化编程过程,提高代码可读性的目的。比如,C++怎么实现面向对象的呢,数据用struct结构封装,成员函数其实就是普通的函数但入参多了个this指针,在调用函数的时候this指针取struct实例的地址,再把这个特殊的struct加个关键字class,这样就实现了class类和类的绝大多数功能。这就是面向对象的实现方法。Java也不例外。那么Python呢?

面向对象的一种实现

Python中,属性数据可以用字典封装,函数可以作为对象被封装在字典里面,函数可以嵌套从而限制其不能在作用域外被调用。根据这个思想,我们可以定义一个狗函数dog,嵌套函数定义狗的两个方法bark、wag_tail,再用字典封装狗的属性。这样就实现了面向对象的设计。调用函数的时候,传入自己作为参数,实际上就是类似C++里面的this指针。

def dog(name, type, gender):
    def bark(dog):
        """
        狗会叫
        :return:
        """
        print('%s is wang!wang!' % dog['name'])
        pass

    def wag_tail(dog):
        """
        狗会摇尾巴
        :return:
        """
        print('%s wag tail %s' % (dog['name'], dog['type']))
        pass

    def init():
        """
        初始化狗,名字,品种,公母
        会叫,会摇尾巴
        :return:
        """
        dog_property = {
            'name': name,
            'type': type,
            'gender': gender,
            'bark': bark,  # 将会叫函数作为属性
            'wag_tail': wag_tail,  # 将会摇尾巴函数作为属性
        }
        return dog_property
        pass

    ret = init()
    return ret
    pass


d1 = dog('Snoopy', '哈士奇', 'female')
print(d1)
d1['bark'](d1)
d1['wag_tail'](d1)
# {'name': 'Snoopy', 'type': '哈士奇', 'gender': 'femal', 'bark': <function dog.<locals>.bark at 0x00000000028A50D0>, 'wag_tail': <function dog.<locals>.wag_tail at 0x0000000003BAA620>}
# Snoopy is wang!wang!
# Snoopy wag tail 哈士奇

d2 = dog('旺财', '柴犬', 'male')
print(d2)
d2['bark'](d2)
d2['wag_tail'](d2)
# {'name': '旺财', 'type': '柴犬', 'gender': 'mail', 'bark': <function dog.<locals>.bark at 0x0000000003BAA6A8>, 'wag_tail': <function dog.<locals>.wag_tail at 0x0000000003BAA730>}
# 旺财 is wang!wang!
# 旺财 wag tail 柴犬

类的相关知识

类描述一类事物共有的数据(属性)和动作(方法)。类本身是没有具体信息的,是一个抽象的类型。类可以具体化到对象。

class Dog:
    """
    这是一个狗类
    """
    fur = 'property fur'

    def bark():
        print('from bark')
        pass

    def wag_tail(self):
        print('from wag_tail')
        pass

    pass


print(Dog)
# <class '__main__.Dog'>

# 调用类的方法
Dog.bark()
# from bark
Dog.wag_tail('123')
# from wag_tail

# 比较dir函数的输出和类__dict__的输出
# 特别是自定义的fur、bark、wag_tail
# dir只列出属性的名字
# __dict__累出属性的名字和值
print(dir(Dog))
# ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
# '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
# '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
# '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
# '__str__', '__subclasshook__', '__weakref__', 'bark', 'fur', 'wag_tail']
print(Dog.__dict__)
# {'__module__': '__main__',
# '__doc__': '\n    这是一个狗类\n    ',
# 'fur': 'property fur',
# 'bark': <function Dog.bark at 0x0000000003BBA620>,
# 'wag_tail': <function Dog.wag_tail at 0x0000000003BBA6A8>,
# '__dict__': <attribute '__dict__' of 'Dog' objects>,
# '__weakref__': <attribute '__weakref__' of 'Dog' objects>}


# Dog类里面有fur属性,可以用类名直接调用
print(Dog.fur)
# Dog的__dict__属性,查看类的属性字典
# 上面直接调用Dog.fur实际上也是用属性字典实现的
print(Dog.__dict__['fur'])

print(Dog.__name__)  # 类的名字Dog
print(Dog.__doc__)  # 类的说明文档,也就是类定义后紧跟的说明"""这是一个狗类""""
print(Dog.__bases__)  # Python支持多继承,后面仔细研究,__bases__以元组形式列出了所以父类(<class 'object'>,)

对象的相关知识

我们在面向对象的一种实现那一节用函数实现了面向对象的设计。Python内置了面向对象编程的设计。

我们自己嵌套定义的初始化函数init,Python类里面有内置的__init__方法来初始化,__init__必须有self入参,自动将实例本身传给self。自动进行初始化和返回实例,因此__init__不用return。类创建实例的过程和函数调用类似。

对象只保存数据属性,不保存方法属性。这样,每个对象存自己的数据,共享一份方法。

对象调用方法的时候,将对象本身传给self参数。通过self来访问对象各自的数据。

class Dog:
    """
    这是一个狗类
    """
    fur = 'property fur'

    def __init__(self, name, breed, gender):
        self.name = name
        self.breed = breed  # 品种
        self.gender = gender
        pass

    def bark(self):
        print('%s 汪汪!' % self.name)
        pass

    def wag_tail(self):
        print('%s 摇尾巴' % self.name)
        pass

    pass


d1 = Dog('旺财', '中华田园犬', 'male')
print(d1)
# <__main__.Dog object at 0x00000000026D9BA8>

# __dict__查看对象的属性字典
# 对象只保存数据属性,不保存方法
print(d1.__dict__)
# {'name': '旺财', 'type': '中华田园犬', 'gender': 'male'}

# 调用对象的属性
# 对象有的(__init__)直接调用 name
# 对象没有的,到外面的作用域类里面去找 fur
print(d1.name, d1.fur)

# 对象调用方法是调用类的方法,调用时将对象传给self参数
Dog.bark(d1)
d1.bark()
# 旺财 汪汪!

面向对象属性的查改增删操作

Python的面向对象支持属性的查改增删。类的属性、对象的属性都可以查改增删。

以前用Java知道可以查、改属性,学了Python才知道属性还可以增、删,而且是数据属性和方法属性的查改增删,真牛逼。

类属性的查改增删

我们做查改增删,对比类的属性字典__dict__的内容和调用情况。直接看代码例子……

class Dog:
    """
    这是一个狗类
    """
    fur = 'property fur'

    def __init__(self, name, breed, gender):
        self.name = name
        self.breed = breed  # 品种
        self.gender = gender
        pass

    def bark(self):
        print('%s 汪汪!' % self.name)
        pass

    def wag_tail(self):
        print('%s 摇尾巴' % self.name)
        pass

    def eat_food(self, food):
        print('%s 吃 %s' % (self.name, food))
        pass

    pass


d1 = Dog('旺财', '中华田园犬', 'male')
d2 = Dog('123', '中华田园犬', 'male')

# ========== 类属性的查 ==========

print(Dog.fur)
# property fur

print('查询', Dog.__dict__)
# 查询
# {'__module__': '__main__',
# '__doc__': '\n    这是一个狗类\n    ',
# 'fur': 'property fur',
# '__init__': <function Dog.__init__ at 0x0000000003BAA620>,
# 'bark': <function Dog.bark at 0x0000000003BAA6A8>,
# 'wag_tail': <function Dog.wag_tail at 0x0000000003BAA730>,
# 'eat_food': <function Dog.eat_food at 0x0000000003BAA7B8>,
# '__dict__': <attribute '__dict__' of 'Dog' objects>,
# '__weakref__': <attribute '__weakref__' of 'Dog' objects>}

# ========== 类属性的改 ==========

Dog.fur = 'modify fur'
print(Dog.fur)


# 改方法属性
def test(self):
    print('%s 是 %s 品种' % (self.name, self.breed))
    pass


# 方法属于类,可以在类上改方法属性
# 修改后调用eat_food其实调用的是test
Dog.eat_food = test
d1.eat_food()
# 旺财 是 中华田园犬 品种

# 可以看到eat_food的地址已经发生了变化,变成了test函数的地址
print(test)
# <function test at 0x00000000028950D0>
print('修改', Dog.__dict__)
# 修改
# {'__module__': '__main__',
# '__doc__': '\n    这是一个狗类\n    ',
# 'fur': 'modify fur',
# '__init__': <function Dog.__init__ at 0x0000000003BAA620>,
# 'bark': <function Dog.bark at 0x0000000003BAA6A8>,
# 'wag_tail': <function Dog.wag_tail at 0x0000000003BAA730>,
# 'eat_food': <function test at 0x00000000028B50D0>,
# '__dict__': <attribute '__dict__' of 'Dog' objects>,
# '__weakref__': <attribute '__weakref__' of 'Dog' objects>}

# ========== 类属性的增 ==========

# 增加数据属性——项圈
Dog.ring = 'leather'


# 增加方法属性
def play_ball(self):
    print('%s 玩球' % self.name)
    pass


# 方法属于类,可以在类上增加方法属性play_ball
Dog.play_ball = play_ball
d1.play_ball()
# 旺财 玩球

# 可以看到增加属性以后__dict__里面增加了ring属性、play_ball方法
print('增加', Dog.__dict__)
# 增加
# {'__module__': '__main__',
# '__doc__': '\n    这是一个狗类\n    ',
# 'fur': 'modify fur',
# '__init__': <function Dog.__init__ at 0x0000000003BAA620>,
# 'bark': <function Dog.bark at 0x0000000003BAA6A8>,
# 'wag_tail': <function Dog.wag_tail at 0x0000000003BAA730>,
# 'eat_food': <function test at 0x00000000028C50D0>,
# '__dict__': <attribute '__dict__' of 'Dog' objects>,
# '__weakref__': <attribute '__weakref__' of 'Dog' objects>,
# 'ring': 'leather',
# 'play_ball': <function play_ball at 0x0000000003BAA7B8>}

# ========== 类属性的删 ==========

# 删除数据属性
del Dog.ring

# 删除方法
# 方法属于类,可以在类上删除
del Dog.eat_food

# 注意比较删除前后的属性字典,删除ring以后就没有ring了,删除以后就没有eat_food方法了
print('删除', Dog.__dict__)
# 删除
# {'__module__': '__main__',
# '__doc__': '\n    这是一个狗类\n    ',
# 'fur': 'modify fur',
# '__init__': <function Dog.__init__ at 0x0000000003BAA620>,
# 'bark': <function Dog.bark at 0x0000000003BAA6A8>,
# 'wag_tail': <function Dog.wag_tail at 0x0000000003BAA730>,
# '__dict__': <attribute '__dict__' of 'Dog' objects>,
# '__weakref__': <attribute '__weakref__' of 'Dog' objects>,
# 'play_ball': <function play_ball at 0x0000000003BAA7B8>}

对象属性的查改增删

我们做查改增删,对比对象的属性字典__dict__的内容和调用情况。直接看代码例子……

class Dog:
    """
    这是一个狗类
    """
    fur = 'property fur'

    def __init__(self, name, breed, gender):
        self.name = name
        self.breed = breed  # 品种
        self.gender = gender
        pass

    def bark(self):
        print('%s 汪汪!' % self.name)
        pass

    def wag_tail(self):
        print('%s 摇尾巴' % self.name)
        pass

    def eat_food(self, food):
        print('%s 吃 %s' % (self.name, food))
        pass

    def play_ball(self, ball):
        print('%s 玩 %s' % (self.name, ball))
        pass

    pass


d1 = Dog('旺财', '中华田园犬', 'male')
d2 = Dog('123', '中华田园犬', 'male')

# ========== 对象属性的查 ==========

print(d1.name)
print(d2.name)
# 旺财
# 123

d1.play_ball('篮球')
d2.play_ball('篮球')
print(d1.play_ball)
# 旺财 玩 篮球
# 123 玩 篮球
# <bound method Dog.play_ball of <__main__.Dog object at 0x0000000003B9D8D0>>
# 打印d1.play_ball实际访问的是类Dog.play_ball


print(d1.__dict__)
print(d2.__dict__)
# {'name': '旺财', 'breed': '中华田园犬', 'gender': 'male'}
# {'name': '123', 'breed': '中华田园犬', 'gender': 'male'}

# ========== 对象属性的增 ==========

# 增加数据属性
d1.age = 10
print(d1.__dict__)
print(d2.__dict__)
# {'name': '旺财', 'breed': '中华田园犬', 'gender': 'male', 'age': 10}
# {'name': '123', 'breed': '中华田园犬', 'gender': 'male'}

# 对象可以增加方法属性吗?
# 理论和技术上可以这么做,那么增加的方法就只属于这个对象。
# 这违背了对象实例只有数据属性的原则,不要这么做!!!

# ========== 对冲属性的改 ==========

d1.age = 17
print(d1.age)
# 17

# ========== 对象属性的删 ==========

del d1.age
del d2.name
print(d1.__dict__)
print(d2.__dict__)
# {'name': '旺财', 'breed': '中华田园犬', 'gender': 'male'}
# {'breed': '中华田园犬', 'gender': 'male'}

关于类、对象属性容易混淆额或忽略的地方的说明

挺绕的,直接看代码例子里的注释吧……

fur = 'yellow'


class Dog:
    """
    这是一个狗类
    """
    fur = 'property fur'
    li = ['a', 'b']
    li2 = ['x', 'y']

    def __init__(self, name, breed, gender):
        self.name = name
        self.breed = breed  # 品种
        self.gender = gender
        print('--->', fur)
        pass

    pass


# __init__里面既不是self的也不是作用域内的ring
# 那么就是全局的ring,和类已经没有关系了
d1 = Dog('旺财', '中华田园犬', 'male')
d2 = Dog('123', '中华田园犬', 'male')
# ---> yellow
# ---> yellow

# 数据属性就是属于各自的

Dog.fur = 'yellow'
d1.fur = 'white'
d2.fur = 'gray'
print('类的毛:', Dog.fur)
print('对象d1的毛:', d1.fur)
print('对象d2的毛:', d2.fur)
# 类的毛: yellow
# 对象d1的毛: white
# 对象d2的毛: gray


# 由于li是类的属性
# 通过d1调用li的append并没有给对象新增任何属性
# 所以修改的就是类的li,因此li都是['a','b','c']
d1.li.append('c')
print(Dog.li)
print(d1.li)
print(d2.li)
# ['a', 'b', 'c']
# ['a', 'b', 'c']
# ['a', 'b', 'c']

# 由于li2也是类的属性
# 但是,d2.li2=是给d1对象新增了一个属性,这与上面append不同
# 所以修改的是d2.li2的属性
d1.li2 = [1, 2, 3]
print(Dog.li2)
print(d1.li2)
print(d2.li2)
# ['x', 'y']
# [1, 2, 3]
# ['x', 'y']

# 此时,再对d1和d2的li2操作,已经有本质的不同了
# d1的li2是d1自己的
# d2的li2是类的
# 这一点可以从对象的__dict__可以看出
d1.li2.append('c')
d2.li2.append('z')
print(Dog.li2)
print(d1.li2)
print(d2.li2)
print(d1.__dict__)
print(d2.__dict__)
# ['x', 'y', 'z']
# [1, 2, 3, 'c']
# ['x', 'y', 'z']
# {'name': '旺财', 'breed': '中华田园犬', 'gender': 'male', 'fur': 'white', 'li2': [1, 2, 3, 'c']}
# {'name': '123', 'breed': '中华田园犬', 'gender': 'male', 'fur': 'gray'}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

苦行僧(csdn)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值