第六章 Python面向对象 04-属性方法的动态绑定

属性方法的动态绑定

1. 动态绑定

Python是一个动态的语言,一个类在定义完成之后,在运行的过程中,可以随时动态的给某一个对象绑定新的属性和方法:

class Person:
    def __init__(self, name, age):
        """
        在Person类的构造方法中,只是定义了属性name和age
        :param name:
        :param age:
        """
        self.name = name
        self.age = age


# 实例化Person的对象
xiaoming = Person("xiaobai", 12)
# 为xiaoming绑定一个新的属性
xiaoming.gender = "male"
xiaoming.score = 99
# 可以发现,xiaoming这个对象已经绑定上了新的属性
print(xiaoming.gender)      # male
print(xiaoming.score)       # 99

# 但是,实例化一个新的对象的时候,新的对象是没有这些属性的
xiaobai = Person("xiaobai", 20)
# print(xiaobai.gender)       # AttributeError: 'Person' object has no attribute 'gender'
# print(xiaobai.score)        # AttributeError: 'Person' object has no attribute 'score'

总结来说就是,在构造方法中,定义了属性name和age,是可以被所有的对象所访问的。但是为某一个对象绑定上新的属性的时候,就只有这个对象可以访问,其他的对象都是无法访问的。方法也是这样的

import types


class Person:
    def walk(self):
        print("person walk")


# 在类外定义一个方法
def sleep(self):
    print(f"{id(self)} 睡觉!")


# 实例化Person对象
p = Person()
# 动态绑定新的方法
p.sleep = types.MethodType(sleep, p)
# 调用绑定的新的方法
p.sleep()


# 实例化新的对象
p2 = Person()
# 使用新的对象调用的时候,访问不到这个方法
# p2.sleep()      # AttributeError: 'Person' object has no attribute 'sleep'

2. __slots__

Python是一个动态的语言,对象可以动态的绑定属性,那么这是怎么做到的呢?其实Python会为每一个对象分配一个__dict__属性,这是一个字典,存储的就是每一个对象的属性和值的键值对。

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

    def walk(self):
        pass


# 实例化对象
p1 = Person("tom", 11)
print(p1.__dict__)      # {'name': 'tom', 'age': 11}

# 动态添加属性
p1.gender = "male"
print(p1.__dict__)      # {'name': 'tom', 'age': 11, 'gender': 'male'}

这样做可以保证Python的一个动态的特性,可以随时为每一个对象绑定新的属性,使其更加灵活。但是对于属性在最开始设计类的时候就已经确定的、后续不会再新增的类来说,将会是一个比较大的内存开销。特别是当需要创建大量的这样的类的对象的时候。从内存上来说,每一个对象都会分配一个__dict__字典,而字典底层采用的数据结构是哈希表,是一种以空间换时间的数据结构。因此带来的内存的开销比较大。为了解决这样的问题,我们可以在类中定义__slots__来解决这样的问题!

__slots__是一个不可变的容器,通常我们将需要为这个类设计的属性,以元组的形式表示。在进行空间分配的时候,Python解释器直接会开辟合适的、固定的内存空间来存储每一个属性的值,从而达到节省空间的目的。

注意事项:

  • 如果给一个类设置了_slots_,那么将不会再为每一个属性提供__dict__
  • 设置了__slots__之后,将无法再给这个对象动态绑定其他的属性
# memory_profiler模块可以进行内存占用的分析,需要手动安装这个模块
# pip install memory_profiler
from memory_profiler import profile
import sys

class Person:
    __slots__ = ('name', 'age')

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


@profile
def test():
    l = [Person("p", x) for x in range(1000000)]


if __name__ == '__main__':
    test()
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值