私有化
.属性和方法访问权限
私有的:在类的外部不可以被使用,,也不可以被继承
保护的:在类的外部不可以被使用,也可以被使用
公开的:在类的外部可以被使用,也可以被继承-
python的私有化
python属性和方法访问权限只有一种,但是提供了另一中私有化的方式python中在属性或者方法名前加__(只能两个下划线开头,不能结尾),就可以将属性和方法私有化
私有的属性和方法只能在类的内部使用,不能在类的外部使用 -
python私有化的原理
在名字前是_的属性和方法前加'类名'去保存属性和方法class Person: num = 61 __num2 = 62 def __init__(self, name='郭锐',age=18): self.name = name self.age = age self.__sex = '男' def eat(self, food): print('%s正在吃%s' % (self.name, food)) self.__run() def show_sex(self): print(self.__sex) def __run(self): print('正在跑步') @classmethod def show_num(cls): print('人类的数量是%d %d' % (cls.num, cls.__num2)) @staticmethod def func1(): print('郭锐 别吃屎了') def main(): p1 = Person() print(Person.num) # print(Person.__num2) print(p1.name) p1.eat('屎') Person.show_num() p1.show_sex() print(p1.__dict__) if __name__ == '__main__': main()
getter 和 setter的用法
应用场景
getter: 获取对象属性的值之前,想要做点别的事情,就给这个属性添加getter
setter:在给对象属性赋值之前,想要做点别的事情,就给这个属性添加settergetter
第一步:声明属性的时候,在属性明前加一个下划线
第二部:声明一个函数
@property
def 去掉下划线的属性名(self):没有除了self以外的参数,但是要有返回值,返回值就是获取属性拿到的值
做点别的事情
返回属性的值
第三步:在类的外部通过对象.去掉下划线的属性去获取相关的属性-
setter - 想要添加setter,必须先要有getter
第一步:声明属性的时候在属性名前加_
第二步:声明函数(函数除了self以外还需要一个参数,没有返回值,这的参数代表给属性赋的值)
@属性名(去掉下划线).setter
def 去掉下划线的属性名(self,参数):
做点别的事情
给属性赋值
第三步:通过对象.去掉下划线属性给相关属性赋值class Person: def __init__(self, name=''): self.name = name self._week = 7 # 属性名前不要直接用 self._age = 18 # 给age添加getter @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 '星期%d' % self._week else: return '星期天' @week.setter def week(self, value): self._week = value def main(): p1 = Person() # 通过不带_的属性 给属性赋值 实质是在调用setter对应的函数 p1.age = 23 p1.age = 150 # 这个操作实质是在调用week函数 # 通过不带_属性来 获取属性 的实质是在调用getter对应的函数 p1.week = 5 print(p1.week) if __name__ == '__main__': main()
继承(inherit)
什么是继承
一个类继承另外一个类,其中会产生继承者和被继承者,这个的继承者叫做子类,被继承者叫做父类或者超类
继承就是让子类直接拥有父类的方法和属性-
怎么继承
语法:
class 类名(父类列表):
类的内容说明:
a.python中所有的类都是直接或者间接继承自基类Object
class 类名 <===> class 类名(Object)
b.python中的继承 支持多继承,父类列表中可以有多个类,多个类之间用逗号隔开 -
能继承哪些东西:所有的属性和方法都可以
slots的值继承后没有效果
在类中给slots赋值后,当前对象不能使用dict,但是这个类的子类对象可以使用dict
只是dict中取不到从父类继承的属性,只有在子类中添加的对象
如果父类没有给slots 赋值,直接给子类的slots赋值,slots无效class Person(object): num = 61 __slots__ = ('name', 'sex', 'age', '__face') def __init__(self, name='', age=0, sex='男'): self.name = name self.age = age self.sex = sex self.__face = 'very good' def eat(self, food): print('%s 正在吃 %s' % (self.name, food)) @classmethod def show_person_num(cls): print('人类的数量是%d亿' % cls.num) class Student(Person): pass def main(): p1 = Person() # print(p1.__dict__) 会报错 # 类的字段可以继承 Student.num = 20 print(Student.num) stu1 = Student('郭锐') print(stu1.name) print(stu1.age) print(stu1.sex) print(stu1._Person__face) print(stu1.__dict__) stu1.eat('海底捞') Student.show_person_num() if __name__ == '__main__': main()
继承后添加属性和方法
添加方法
添加方法
直接在子类中声明新的方法
子类可以使用父类的属性和方法,但是父类不能使用子类中添加的属性和方法重写方法
在子类重新实现父类中的方法 - 完全重写
保留父类的功能在子类中添加新的功能 - 部分重写 在子类方法中通过super().的方式来调用父类的方法
super() -> 先实现父类的功能-
类中函数调用的过程
回到函数声明的位置,先看当前类中是否有方法,如果有就直接用,没有就去看父类中有没有,没有的话,再找父类的父类直到Object,
如果Object中也没有 ,就会报错添加属性
直接在子类中声明新的字段
class Person(object): num = 61 __slots__ = ('name', 'sex', 'age', '__face') def __init__(self, name='', age=0, sex='男'): self.name = name self.age = age self.sex = sex self.__face = 'very good' def eat(self, food): print('%s 正在吃 %s' % (self.name, food)) @classmethod def show_person_num(cls): print('人类的数量是%d亿' % cls.num) class Student(Person): num2 = 20 # 添加方法 def study(self): print('%s 正在学习' % self.name) @classmethod def show_person_num(cls): print('学生数量%d' % cls.num2) def eat(self, food): super().eat(food) print('吃饱了') def main(): p1 = Person('张三') stu1 = Student('李四') stu1.study() stu1.show_person_num() stu1.eat('是') if __name__ == '__main__': main()
添加对象属性
添加对象属性:
对象属性其实是通过继承init方法继承下来的class Animal: def __init__(self, age): self.age = age self.color = '灰色' class Dog(Animal): def __init__(self, name, age): # 调用父类的init方法来继承父类的对象属性 super().__init__(age) self.name = name # 练习: 声明一个类,人类有属性名字,年龄,性别 # 学生类:有属性 名字 性别 年龄 学号 分数 # 要求 创建人的对象的时候名字必须赋值,年龄不能复制,性别可以赋值 也可以不赋值 # 创建学生对象的时候名字可以赋值 可以不赋值,学号必须赋值,分数、性别、年龄,并不能赋值 class Person(object): def __init__(self, name, sex='女'): self.name = name self.age = 18 self.sex = sex class Student(Person): def __init__(self, stu_num, name='小小'): super().__init__(name) self.stu_num = stu_num self.score = 98 def main(): # dog1 = Dog('菜菜') # print(dog1.age) dog2 = Dog('阿黄', 3) print(dog2.name) print(dog2.age) girl = Student(stu_num='001') print(girl.name) print(girl.age) print(girl.sex) print(girl.score) print(girl.stu_num) if __name__ == '__main__': main()
多继承
-
多继承:
class 类名(父类, 父类2,····)
类的内容多继承的时候,多个父类中的所有方法和字段可以继承,只是对象属性只能继承第一个父类的
class Animal: def __init__(self, name=''): self.name = name self.age = 1 self.color = 'black' def func1(self): print('动物中的对象方法') class Fly: def __init__(self): self.height = 1000 def func2(self): print('飞行类的对象方法') class Bird(Animal, Fly): pass def main(): b1 = Bird() b1.func1() b1.func2() print(b1.name, b1.age) # print(b1.height) AttributeError:'Bird'对象没有属性'height' if __name__ == '__main__': main()
运算符重载
-
什么是运算符重载
通过实现类中相应的魔法方法来让当前类的对象支持相应的运算符注意:pyhton中所有的数据类型都是类;所有的数据都是对象
class Student: 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 # 支持Student + int return self.age + other def __mul__(self, other): return self.name * other # self other 都是学生对象 # 大于 或者小于运算符 只需要重载一个就行 def __gt__(self, other): return self.score > other.score def __repr__(self): return str(self.__dict__)[1:-1] def main(): stu1 = Student('小花', age=20, score=89) stu2 = Student('小明', age=18, score=98) # 所有类的对象都支持 == != 运算 # print(stu1 > stu2) “学生”和“学生”实例之间不支持'>' print(stu1 == stu2) print(stu1 + 3.3) print(stu1 * 2) print(stu1 < stu2) print(stu1 > stu2) print(stu1.__repr__()) if __name__ == '__main__': main()
内存管理机制
-
数据的存储
内存分为 栈区间和堆区间:从底层看来,栈区间的内存的开辟和释放是系统自动管理的。堆区间的内存是由程序员通过代码开辟和释放的
从python角度来看,栈区间的内存的开辟和释放是系统自动管理的,堆区间的内存管理也已经封装好了,程序员不需要
写代码来开辟空间和释放空间- python中变量本身是存在栈区间的,函数调用过程是在栈区间,对象都是存在堆区间(python中所有数据都是对象)
- 变量赋值过程:先在堆区间开辟空间将数据存起来,然后将数据对应的地址存在栈区间的变量里
- 数字和字符串比较特殊,赋值的时候不会直接开辟空间,而是先检测之前有没有存储过这个数据,如果有则直接调用
内存释放(垃圾回收机制)原理
python每个对象都有一个属性叫做'引用计数',表示当前对象的引用的个数,判断一个对象是否销毁,就看对象的引用计数是否为0;
为0的就销毁,不为0的就不销毁