一、私有化
1.访问权限
- 私有的:在类的外部不可以使用,也不可以继承
- 保护的:在类的外部不可以使用,可以继承
- 公开的:类的外部可以使用,也可以被继承
2.python的私有化
python中属性和方法的访问权限只有公开,但是提供了另一种私有化的方式
python中在属性或者方法名前加__,就可以将属性或者方法变成私有的(注意:只能__开头,不能两个__结尾)
私有的属性和方法只能在类的内部使用,不能在类的外面使用
3.python私有化的原理
在名字前有__的属性和方法前再加'_类名'去保存属性和方法
class Person:
num = 520
__num2 = 1314
def __init__(self, name='陈儿', age=0):
self.name = name
self.age = age
def eat(self, food):
print(self.name, food)
@classmethod
def show_num(cls):
print('人类的数量%d' % (cls.num, cls.__num))
@staticmethod
def func1():
print('银根哒')
def main():
p1 = Person()
# print(Person.__num) 此处是在类的外部,无法使用。AttributeError: type object 'Person' has no attribute '__num'
print(Person.num)
print(p1.name)
if __name__ == '__main__':
main()
二、getter和setter
1.应用场景
- getter:获取对象属性的值之前想要做点别的事情就给这个属性添加getter
- setter:给对象属性赋值之前想要做点别的事情就给这个属性添加setter
2.getter
- 第一步:声明属性的时候,在属性名前加一个下划线_
- 第二步:声明函数(函数除了self以外没有别的参数,但是要有返回值,返回值就是获取属性拿到的值)
@property
def 去掉下划线后的属性名(self):
做点别的事情
返回属性的值
- 第三步:在类的外部通过(对象.去掉下划线后的属性)去获取相关的属性
3.setter - 想要添加setter必须先要有getter
- 第一步:声明属性的时候在属性名前加下划线_
- 第二步:声明函数(函数除了self以外还需要一个参数,,没有返回值,这儿的参数代表给属性赋的值)
@去掉下划线的属性名.setter
def 去掉下划线的属性名(self,参数):
做点别的事情
给属性赋值
- 第三步:在类的外部,通过(对象.去掉下划线的属性)去给相关属性赋值
class Person:
def __init__(self, name=''):
self.name = name
self._age = 0
self._week = 1 # 属性名前有下划线,使用属性的时候不要直接用
@property
def age(self):
return self._age
# 给age添加setter
@age.setter
def age(self, value):
if not isinstance(value, int):
raise ValueError
if not (0 <= value <= 150):
raise ValueError
self._age = value
# 添加getter
@property
def week(self):
if self._week < 7:
return '星期{}'.format(self._week)
else:
return '星期天'
def main():
p1 = Person('陈儿')
# 通过不带下划线的属性给属性赋值,实质是在调用setter对应的函数
# p1.age = 520
p1.age = 18
print(p1.week) # 这个操作实质是在调用week函数
# 通过不带下划线的属性来获取属性的值实质是在调用getter对应的函数
if __name__ == '__main__':
main()
三、继承
1.什么是继承
一个类继承另外一个类,会产生继承者和被继承者,这儿的继承者叫子类,被继承者叫父类/超类。
继承就是让子类直接拥有父类的方法和属性
2.怎么继承
语法:
class 类名(父类列表):
类的内容
说明:
- a.python中所有的类都是直接或者间接继承自基类object
class 类名: ==> class 类名(object):
- b.python中的继承支持多继承,父类列表中可以有多个类,多个类之间用逗号隔开
3.能继承哪些东西 - 所有的属性和方法都能够继承
注意:
- a.__slots__的值继承后没有效果
- b.在类中给__slots__赋值后,当前类的对象不能使用__dict__,但是这个类的子类对象可以使用__dict__,只是__dict__中没有从父类继承下来的对象属性,只有在子类中添加的对象属性
- c.如果父类没有给__slots__赋值,直接给子类的__slots__赋值,无效!
class Person(object):
num = 520
def __init__(self, name='陈儿', age=0, sex='女'):
self.name = name
self.age = age
self.sex = sex
def eat(self, food):
print('{}在吃{}'.format(self.name, food))
@classmethod
def show_num(cls):
print('人类的数量:{}'.format(cls.num))
class Student(Person):
pass
def main():
Student.num = 1314
print(Student.num)
stu = Student()
print(stu.name)
stu.eat('重庆火锅')
Student.show_num()
if __name__ == '__main__':
main()
四、继承后添加属性和方法
1.添加方法
直接在子类中声明新的方法
2.重写方法
在子类中重新实现父类的方法 - 完全重新
保留父类的功能在子类中添加新的功能 - 部分重写(在子类方法中通过'super().'的方式调用父类方法)
3.类中函数的调用过程
回到函数声明的位置:先看当前类中是否有方法,如果有就直接调用当前类中的方法;没有就去看父类中有没有这个方法,如果父类中也没有就看父类的父类中有没有...直到找到object为止,如果object也没有就报错
======================添加属性=========================
1.类的字段
直接在子类中声明新的字段
class Person(object):
num = 520
def __init__(self, name='陈儿', age=0, sex='女'):
self.name = name
self.age = age
self.sex = sex
def eat(self, food):
print('{}在吃{}'.format(self.name, food))
@classmethod
def show_num(cls):
print('人类的数量:{}'.format(cls.num))
class Student(Person):
num2 = 1314
def study(self):
print('{}在写代码'.format(self.name))
@classmethod
def func2(cls):
print('我是类方法')
@staticmethod
def func1():
print('我是静态方法')
def eat(self, food):
super().eat('零食')
print('吃饱了!')
@classmethod
def show_num(cls):
print('学生数量:{}'.format(cls.num))
def main():
p1 = Person('陈儿')
stu1 = Student('我')
stu1.study()
stu1.func2()
Student.func1()
# 子类可以使用父类的属性和方法,但是父类不能使用子类中添加的属性和方法
# Person.func2()
stu1.eat('fsg')
Person.show_num()
Student.show_num()
if __name__ == '__main__':
main()
五、添加对象属性
添加对象属性:
对象属性其实是通过集成init方法继承下来的
class Animal:
def __init__(self):
self.age = 0
self.type = '爬行类'
class Dog(Animal):
def __init__(self):
# 调用父类的init方法来继承父类的对象属性
self.name = '那傻狗'
super().__init__()
练习:声明人类,属性:名字、年龄、性别;
声明学生类,属性:名字、年龄、性别、学号、分数
要求:创建人的对象的时候名字必须赋值,性别可以赋值也可以不赋值,年龄不能赋值
创建学生对象的时候名字可以赋值可以不赋值,学号必须赋值,分数和性别、年龄不能赋值
class Person(object):
def __init__(self, name, sex='男'):
self.name = name
self.sex = sex
self.age = 0
class Student(Person):
def __init__(self, id, name='一头猪'):
super().__init__(name)
self.id = id
六、运算符重载
1.什么是运算符重载
通过实现类中的相应的魔法方法来让当前类的对象支持相应的运算符
注意:python中所有的数据类型都是类;所有的数据都是对象
class Student(object):
def __init__(self, name='', age=0, score=0):
self.name = name
self.age = age
self.score = score
# 实现'+'对应的魔法方法,让两个学生对象能够进行+操作
# self和other的关系:相当于self + other ==> self.属性 __add__ other.属性
# 返回值就是运算结果
def __add__(self, other):
# 支持Student + Student
return self.age + other.age
def main():
stu1 = Student('陈儿', 18, 90)
stu2 = Student('我', 18, 89)
#所有类的对象都支持'=='和'!='运算
print(stu1 == stu2)
# 注意:大于和小于只需要重载一个,另外一个不需要再重载也可以用
print(stu1 + stu2)
if __name__ == '__main__':
main()
七、内存管理
内存管理
1.数据的存储
内存分为栈区间和堆区间;从底层看,栈区间的内存的开辟和释放是系统自动管理的,堆区间的内存是由程序员通过代码开辟(malloc)和释放的;
从python语言角度看,栈区间的内存的开辟和释放是系统自动管理的,堆区间的内存关键也已经封装好了,程序员也不需要写代码来开辟空间和释放空间
- a.python中变量本身是存在栈区间的,函数调用过程是在栈区间;对象都是存在堆区间的(python中所有数据都是对象)
- b.变量赋值过程:先在堆区间开辟空间将数据存起来,然后将数据对应的地址存到栈区间的变量中
注意:数字和字符串赋值的时候不会直接开辟空间而是先检测之前有没有存储过,如果有就用之前的数据的地址
2.内存的释放(垃圾回收机制)原理:
python中的每个对象都有一个属性,叫'引用计数',表示当前对象的引用的个数。判断一个对象是否销毁,就看对象的引用计数是否为零
为零的就销毁。
getrefcount函数:
getrefcount(对象) --> 获取对象的引用计数
from sys import getrefcount
def main():
# 使用不同的变量村对象地址会增加引用计数
list1 = [1, 2]
print(getrefcount(list1))
if __name__ == '__main__':
main()
网友评论