持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的22天,点击查看活动详情
👨🎓作者:Java学术趴
💌公众号:Java学术趴
🚫特别声明:原创不易,未经授权不得转载或抄袭,如需转载可联系小编授权。
🙏版权声明:文章里的部分文字或者图片来自于互联网以及百度百科,如有侵权请尽快联系小编。微信搜索公众号Java学术趴联系小编。
☠️每日毒鸡汤:这个社会是存在不公平的,不要抱怨,因为没有用!人总是在反省中进步的!
👋大家好!我是你们的老朋友Java学术趴。
第二十章 动态添加属性和方法
20.1 概念
- 动态语言:运行时可以改变其结构的语言,例如新的函数、对象、甚至代码可以被引入,已有的函数可以被删除或是其他结构上的变化。如php、js、python都是动态语言,C、C#、Java都是静态语言。所以python可以在程序运行过程中添加属性和方法。
20.2 动态添加属性
给类的实例对象添加额外属性
# 动态添加属性和方法
class Student(object):
def __init__(self, name, age):
self.name = name
self.age = age
pass
def __str__(self):
return '姓名:{},年龄:{}'.format(self.name, self.age)
pass
# 创建一个类实例对象
student = Student('小明', 30)
# 使用类实例对象原有的属性
print(student.name)
# 动态添加实例对象属性。此时并不是给类添加了这个room属性
# 此时只是给这个对象添加了额外的room属性,其他的实例对象不会有这个room属性
student.room = 'python二班'
print(student.room)
# python二班
student2 = Student('小王', 40)
# student2没有room属性,student只是给自己添加了额外的room属性
# print(student2.room) 报错
给类添加额外属性
# 动态添加属性和方法
class Student(object):
def __init__(self, name, age):
self.name = name
self.age = age
pass
def __str__(self):
return '姓名:{},年龄:{}'.format(self.name, self.age)
pass
# 给类添加属性。通过类进行点
Student.height = '175'
# 实例对象可以访问类属性。
# 实例对象可以访问类属性以及实例属性
# 类只能访问类属性,不可以访问实例属性
student = Student('张三', 30)
print(student.height)
# 175
20.3 动态添加方法
动态添加实例方法:需要使用types
# 动态添加属性和方法
# 导入添加方法的库
import types
# 定义动态添加的实例对象方法
# 定义的实例对象的方法必须存在 self 这个参数,否则在绑定的时候会报错
# 即使方法体中用不到这个 self 参数,这里也不可以省略
def show(self):
print('{}的身高是:{}kg,班级是:{}'.format(self.name, self.height, Student.room))
print(1)
pass
class Student(object):
def __init__(self, name, age):
self.name = name
self.age = age
pass
def __str__(self):
return '姓名:{},年龄:{}'.format(self.name, self.age)
pass
student = Student('小明', 20)
# 动态添加实例对象属性
student.height = '175'
# 动态添加类属性
Student.room = 'python一班'
# 给实例对象动态添加方法。
# 首先需要通过types.MethodType绑定方法,第一个参数是绑定的方法名,第二个是实例对象名
student.showInfo = types.MethodType(show, student)
# 调用动态绑定的实例方法
student.showInfo()
# 小明的身高是:175kg,班级是:python一班
# 1
student1 = Student('小王', 30)
# 此时给实例对象添加额外的方法,只是给student进行了添加,student1需要再次进行绑定
# student1.showInfo() 报错
动态添加类方法和静态方法:类名.方法名 = xxx 形式绑定类方法
# 动态添加属性和方法
# 导入添加方法的库
import types
# 定义一个类方法
# 这个类方法必须存在 cls 这个参数,不论方法体有没有用到,都必须给定这个参数
# 否则在绑定方法的时候会报错
@classmethod
def eat(cls):
print('吃饭')
pass
# 定义一个静态方法
# 静态方法,这个 cls 参数可有可无
@staticmethod
def drink():
print('喝水')
pass
class Student(object):
def __init__(self, name, age):
self.name = name
self.age = age
pass
def __str__(self):
return '姓名:{},年龄:{}'.format(self.name, self.age)
pass
student = Student('小明', 30)
# 给Student类绑定类方法eat()
Student.eat = eat
# 调用额外添加的类方法
# 这里的参数不能传递,如果给了会报错
Student.eat()
# 吃饭
# 给Student类绑定额外的静态方法
Student.drink = drink
Student.drink()
# 喝水
# 实例对象可以访问到额外添加的类方法和类静态方法
student.eat()
student.drink()
第二十一章 _ _slots__属性
21.1 概念
- python是动态语言,在运行的时候可以动态添加属性。如果是限制在运行时候给类添加属性,Python允许在定义class的时候,定义一个特殊的_ _slots__变量,来限制该class实例能添加的属性。
- 只有在_ _slots__变量中的属性才能添加,没有在slots变量中的属性添加失败。可以防止其他人在调用类的时候胡乱添加啊属性或方法。只有子类声明 slots 的时候,才会继承父类的slots。如果子类不声明slots变量则不会进行继承
使用方式
# 通过 __slots__ 控制添加的额外实例属性还有类属性
class Student(object):
def __init__(self, name, age):
self.name = name
self.age = age
pass
def __str__(self):
return '姓名:{},年龄:{}'.format(self.name, self.age)
# 如果不把name以及age属性添加到这个 __slots__,那么此时name和age为只读属性,不可以从新赋值
# 在创建对象的时候就无法给name和age赋值,所以这里必须把这两个参数写上
__slots__ = ('sex', 'room', 'name', 'age')
pass
student = Student('小明', 20)
print(student.name)
print(student.age)
# 添加额外的实例属性并且是__slots__中存在的
student.sex = '男'
print(student.sex)
# 男
# 添加额外的实例属性,是__slots__中不存在的
# student.height = '186' 报错
# 给类添加额外的属性并且是 __slots__ 中存在的
Student.sex = '男'
print(Student.sex)
# 男
# 添加额外的实例属性,是__slots__中不存在的
# student.height = '186' 报错
# 如果不存在 __slots__ ,那么所有的实例属性都会存储在一个字典中。字典是非常占用内存空间的
# 当存在 __slots__ 的时候,所有的实例属性就不会存储到这个字典中,而是把属性存储到 __slots__ 变量中
print(student.__dict__)
# {'name': '小明', 'age': 20, 'sex': '男'}
slots变量在父子类之间的继承
子类必须声明 slots 变量才会继承父类的,否则不会继承
# 通过 __slots__ 控制添加的额外实例属性还有类属性
class People(object):
def __init__(self, name, age):
self.name = name
self.age = age
pass
def __str__(self):
return '姓名:{},年龄:{}'.format(self.name, self.age)
# 如果不把name以及age属性添加到这个 __slots__,那么此时name和age为只读属性,不可以从新赋值
# 在创建对象的时候就无法给name和age赋值,所以这里必须把这两个参数写上
__slots__ = ('sex', 'room', 'name', 'age')
pass
class Student(People):
pass
student = Student('小李', 18)
# 当子类没有声明 slots 变量的时候不会继承父类的 slots 变量
# 此时可以给子类随意动态添加属性值
student.height = '165'
print(student.height)
# 165
class Teacher(People):
# 子类声明 slots 变量,此时会继承父类的并且可以添加额外的属性
# 子类尽量不要去重写父类已经存在的属性。重复声明会占用内存空间
__slots__ = 'weight'
pass
teacher = Teacher('王老师', 40)
# 继承父类中 slots变量 中的属性
print('教师的姓名:{},教师的年龄:{}'.format(teacher.name, teacher.age))
# 教师的姓名:王老师,教师的年龄:40
# 此时子类继承了父类的 slots 变量,就不可以随意的添加属性了
# teacher.height = '175' 报错,因为slots中不存在height属性
# 可以添加 slots 中存在的属性值
teacher.weight = '50'
print(teacher.weight)
# 50