一、私有化
1.属性和方法访问权限
私有的:在类的外部不可以使用,也不可以继承
保护的:在类的外部不可以使用,可以继承
公开的:类的外部可以使用,可以被继承
2.python中属性和方法的访问权限
只有公开,但是提供了另一种私有化的方式
2.如何私有化
定义:在属性或者方法前加__,属性或者方法就会变为私有化
特点:私有的属性和方法只能在类的内部使用,不能在类的外面使用
注意:
输入时,只能在前面加__,不能在后面加__
类的字段:可以在内部用,不能在外部用
对象属性:可以在内部用,不能在外部用
对象方法:可以在内部用,不能在外部用
类方法:可以在内部用,不能在外部用
静态方法:可以在内部用,不能在外部用
3.python私有化原理
在私有化的属性和方法前再加"_类名"去保存属性和方法
外部想调用可以通过"_类名__(属性或者方法)"
class Person:
num = 61
__num2 = 62
def __init__(self, name='张三', age=0):
self.name = name
self.age = age
self.__sex = '男'
def eat(self, food):
print(self.__sex)
print(self.name, food)
self.__run()
def __run(self):
print('%s在跑步' % self.name)
@classmethod
def show_num(cls):
print('人类的数量:%d, %d' % (cls.num, cls.__num2))
@staticmethod
def func1():
print('人类要保护大自然!')
p1 = Person()
print(Person.num) # 61
# print(Person.__num2) # AttributeError: type object 'Person' has no attribute '__num2'
print(p1.name) # 61
# print(p1.__sex) # AttributeError: 'Person' object has no attribute '__sex'
print(p1._Person__sex) # 男
p1.eat('面条') # 张三 面条
# p1.run() # AttributeError: 'Person' object has no attribute 'run'
Person.show_num() # 人类的数量:61, 62
Person.func1() # 人类要保护大自然!
print(p1.__dict__) # {'name': '张三', 'age': 0, '_Person__sex': '男'}
二、getter和setter
1.应用场景
getter:获取对象属性的值(调用时)之前想要做点别的事情,就给这个属性添加getter
setter:给对象属性赋值(传参时)之前想要做点别的事情,就给这个属性添加setter
2.getter
第一步:声明属性的时候,在属性名前加_
第二步:声明一个函数,函数名前加@property
要求:只有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 = 7 # 属性名前有_,使用属性的时候不要直接用
@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
# 给week添加getter
@property
def week(self):
if self._week < 7:
return '星期%d' % self._week
else:
return '星期天'
@week.setter
def week(self, value):
self._week = value
def main():
p1 = Person('小明')
# 通过不带_的属性给属性赋值实质是在调用setter对应的函数
p1.age = 45
p1.age = 3
# 这个操作实质是在调用week函数
# 通过不带_的属性来获取属性的值实质是在调用getter对应的函数
print(p1.week)
p1.week = 4
三、继承
1.什么是继承
定义:一个类继承另外一个类,其中会产生继承者和被继承者,这里的继承者叫子类,被继承者叫父类/超类
2.怎么继承
class 类名(父类列表):
类的内容
说明:
a.python中所有的类都是直接或者间接继承基类object
class 类名: ==> class 类名(object):
b.python中的继承支持多继承, 父类列表中可以有多个类,多个类之间用逗号隔开
3.继承哪些东西:
所有的属性和方法
注意:a.__slots__的值继承后没有约束效果
b.在类中给__slots__赋值后,当前类的对象不能使用__dict__,但是子类可以使用,只是__dict__中没有从父类继承下来的对象属性,只有子类中添加的对象属性
c.如果父类没有给__slots__赋值,直接给子类的__slots__,无效
class Person(object):
num = 61
# __slots__ = ('name', 'age', 'sex', '__face')
def __init__(self,name='zhangsan', age=0, sex='男'):
self.name = name
self.age = age
self.sex = sex
self.__face = 60
def eat(self, food):
print('%s在吃%s' % (self.name, food))
@classmethod
def show_num(cls):
print('人类的数量:%d' % cls.num)
print(Student.num) # 61
stu = Student()
print(stu.name) # zhangsan
# print(stu.__dict__)
# print(stu.__face)
stu.eat('海底捞') # zhangsan
Student.show_num() # 人类的数量:61
p1 = Person()
# print(p1.__dict__)
# p1.score = 100
stu.score = 100
print(stu.score) # 100
print(stu.__dict__) # {'name': 'zhangsan', 'age': 0, 'sex': '男', '_Person__face': 60, 'score': 100}
四、添加方法
1.添加新的方法
怎么声明:直接在子类中声明新的方法
2.重写方法
完全重写:在子类中重新声明实现父类的方法
部分重写:保留父类的功能,在子类中添加新的功能
如何操作:在子类方法中通过"super()."的方式调用父类方法
3.类中函数的调用过程
回到函数声明的位置:先看当前类中是否有方法,如果有,就直接调用当前类中的方法,没有就去看父类中是否有方法,如果父类也没有,就去找父类的父类,直到找到object类,如果还没有,就报错
- 会一直往上找,不会往下找
class Person(object):
num = 61
def __init__(self,name='zhangsan', age=0, sex='男'):
self.name = name
self.age = age
self.sex = sex
self.__face = 60
def eat(self, food):
print('%s在吃%s' % (self.name, food))
@classmethod
def show_num(cls):
print('人类的数量:%d' % cls.num)
class Student(Person):
num2 = 100
# 添加方法
def study(self):
print('%s在写代码' % self.name)
@classmethod
def func1(cls):
print('我是学生类的类方法')
@staticmethod
def func2():
print('我是学生类的静态方法')
@classmethod
def show_num(cls):
print('学生数量:%d' % cls.num)
def eat(self, food):
super().eat(food)
print('吃饱了')
p1 = Person('张三')
stu1 = Student('李四')
stu1.study() # 李四在写代码
Student.func1() # 我是学生类的类方法
# 子类可以使用父类的属性和方法,但是父类不能使用子类中添加的属性和方法
# Person.func2()
Person.show_num() # 61
Student.show_num() # 61
stu1.eat('包子') # 李四在吃包子 吃饱了
print(Student.num2) # 100
五、添加属性
1.添加类的字段
如何声明:直接在子类中声明新的字段
2.添加对象属性
本质:对象属性是通过继承init方法继承下来的
class Animal:
def __init__(self, age):
self.age = age
self.color = '灰色'
class Dog(Animal):
def __init__(self, name, age):
# 调用父类的init方法来继承父类的对象属性
# 父类的init方法需要传参的话,需要在init加参数
super().__init__(age)
self.name = name
# 情景1:直接继承不添加
# dog1 = Dog()
# print(dog1.age)
dog2 = Dog('才次', 18)
print(dog2.name) # 才次
# print(dog2.age) # AttributeError: 'Dog' object has no attribute 'age'
p1 = Student(23)
print(p1.sex) # 男
补充:多继承
多继承:
class 类名(父类1, 父类2,....):
类的内容
特点:
1.方法:多个父类都可以继承
2.属性:类的字段都可以继承,对象属性只能继承第一个父类
class Animal:
def __init__(self, name=''):
self.name = name
self.age = 0
self.color = '黑色'
def fun1(self):
print('动物中的对象方法')
class Fly:
def __init__(self):
self.height = 1000
def func2(self):
print('飞行类的对象方法')
class Bird(Animal, Fly):
pass
def main():
b1 = Bird()
b1.fun1() # 动物中的对象方法
b1.func2() # 动物中的对象方法
print(b1.name, b1.age)
# print(b1.height) # 'Bird' object has no attribute 'height'
六、运算符重载
1.什么是运算符重载
目的:通过实现类中相应的魔法方法来让当前类的对象支持相应的运算符
注意:python中所有的数据类型都是类,所有的数据都是对象
步骤:
第一步:找到运算符相应的魔法方法
如何找:通过一个能支持的表达式,按ctrl键来查看
第二步:在类中重新声明,重写相应的魔法方法
class Student(object):
def __init__(self, name='', age=0, score=0):
self.name = name
self.age = age
self.score = score
def __repr__(self):
return '<' + str(self.__dict__)[1:-1] + '>'
# 实现'+'对应的魔法方法,让两个学生对象能够进行+操作
# self和other的关系: self+other ==> self.__add__(other)
# 返回值就是运算结果
def __add__(self, other):
# a.支持Student+Student:
return self.age + other.age
# b.支持Student+数字
# return self.age + other
# self * other
# 将other当成数字
def __mul__(self, other):
return self.name * other
# self和other都是学生对象
# 注意:大于和小于运算符是需要重载一个就行
def __gt__(self, other):
return self.score > other.score
stu1 = Student('小花', 18, 90)
stu2 = Student('夏明', 20, 78)
stu3 = Student('小红', 17, 99)
# 所有类的对象都支持'=='和'!='运算
print(stu1 == stu2) # False
print(stu1 + stu2) # print(stu1.__add__(stu2)) # 38
# print(stu1 > stu2)
# print(stu1 < stu2)
print(stu1 * 2) # print(stu1.__mul__(2)) # 小花小花
students = [stu1, stu2, stu3]
print(students)
students.sort()
print(students)
七、python内存管理机制
1.数据的存储
内存分为栈区间和堆区间
底层:
栈区间内存:系统自动释放和开辟
堆区间内存:由程序员通过代码开辟和释放
代码:手写函数melloc
python:
栈区间内存:系统自动开辟和释放
堆区间内存:内存管理也已封装好,无需程序员在写代码手动释放
python:
栈区间:变量本身,函数调用过程(压栈)
堆区间:所有的对象(python中一切数据皆对象)
变量赋值过程:
堆区间:开辟空间储存数据,产生一个地址
栈区间:变量储存数据的地址
特殊情况:数字和字符串
堆区间:赋值前先检测之前是否存过这个数据
如果有,直接使用之前的地址,反之,开辟空间
2.内存释放(垃圾回收机制)
引用计数:每个对象都有一个属性叫引用计数,用来表示当前对象的引用计数
如何判断一个对象是否销毁
依据:看一个对象的引用计数是否为0,为0就
销毁,不为0就不销毁
getrefcount函数
用法:getrefcount(对象)
目的:获取对象的引用计数
如何增加引用计数:
使用不同变量存地址(让多个变量指向一个地址)
如何减少引用计数:
1.让变量指向其他地址(重新赋值)
2.直接删除变量
网友评论