面向对象2
一、内置类属性
内置类属性:在python中每个类都有内置的类属性
__name__
__doc__
__dict__
__module__
__bases__
class Animal:
"""动物类"""
pass
class Cat(Animal):
"""说明文档:猫类"""
number=0
#对象属性
def __init__(self,name='',color=''):
self.name=name
self.color=color
#对象方法
def run(self):
print('%s在跑'%(self.name))
#静态方法
@staticmethod
def shout():
print('喵')
#类方法
@classmethod
def get_number(cls):
print('猫的数量为:%s'%(cls.number))
if __name__ == '__main__':
cat1=Cat('小花','white')
"""
1.类.__name__
获取类的名字(字符串)
"""
print(Cat.__name__) #Cat
"""
2.类.__doc__
获取类的说明文档
"""
print(Cat.__doc__) #说明文档:猫类
"""
3.
(1)类.__dict__
获取类中所有的类的属性以及对应的值,以键值对的形式存到字典里面
(2)对象.__dict__
将对象的属性和对应的值,转换成字典元素(常用,掌握)
"""
print(Cat.__dict__)
#{'__module__': '__main__', '__doc__': '说明文档:猫类',
# 'number': 0, '__init__': <function Cat.__init__ at 0x02195300>,
# 'run': <function Cat.run at 0x021952B8>, 'shout': <staticmethod object at 0x005DD310>,
# 'get_number': <classmethod object at 0x02193490>,
# '__dict__': <attribute '__dict__' of 'Cat' objects>,
# '__weakref__': <attribute '__weakref__' of 'Cat' objects>}
print(cat1.__dict__) #{'name': '小花', 'color': 'white'}
"""
4.类.__module__
获取当前类所在的模块的名字
"""
print(Cat.__module__) #__main__(正在执行时是__main__,使用外部导入的文件时是文件名)
"""
5.类.__base__
获取当前类的父类
"""
print(Cat.__bases__) #(<class '__main__.Animal'>,)
二、私有化
python中,类中的属性和方法的私有化:直接在属性名或者方法名前加两个下划线(命名时以
__
开头)
属性或者方法私有:在外部不能直接使用,可以在类的内部使用
import random
class Person:
私有的类字段
__number=61
def __init__(self,name='',age=0):
self.name=name
self.__age=age
def show_age(self):
print(self.__age-10)
self.__run() #李四在跑
私有的对象方法只能在类的内部调用
def __run(self):
print('%s在跑'%self.name)
私有的类方法
@classmethod
def __get_number(cls):
print(cls.__number)
静态方法私有化
if __name__ == '__main__':
p1=Person('张三',30)
p1.name='李四'
#print(p1.name,p1.__age) #AttributeError: 'Person' object has no attribute '__age'(age私有化了,外部不能使用)
p1.show_age() #20
(可以在类的内部使用后,再在外面调用)
# Person.__get_number()
**私有化原理:在内部私有化的名字前加前缀'_类名'**
print(p1.__dict__['_Person__age'])
class Student:
def __init__(self,name=''):
self.name=name
self.study_id=''
def __creat_id(self):
'py1805'+str(random.randint(1,50)).rjust(3,'0')
def creat(self,name):
stu= Student(name)
stu.study_id=self.__creat_id()
return stu
三、getter和setter
属性假的私有化:声明对象属性的时候,在属性名前加一个'_',来告诉别人这个属性不可以直接使用要通过getter和setter来获取属性的和修改属性的值
1.getter:获取属性的值
如果在获取对象的某个属性前,需要再干点其他事,就添加getter
@property
def 属性名(去掉下划线)(self):
return 返回值
2.setter:给属性赋值
一个属性必须要要有getter,才能添加setter
如果在给对象的某个属性赋值前,需要再干点儿别的事情,就给属性添加setter
@属性名(去掉下划线).setter
def 属性名去掉下划线(self,变量名):
给带下划线的属性赋值
class Student:
"""学生类"""
def __init__(self):
声明属性的时候,前面加一个"_"是为了告诉别人这些属性不能直接使用
self._name=''
self._score=0
self._age=0
给属性_name添加getter
@property
def name(self):
return self._name
给属性_name添加setter
@name.setter
def name(self,value):
self._name=value
@property
def score(self):
return self._score
@score.setter
def score(self,score):
self.__score=score
@property
def age(self):
return str(self._age) + '岁'
@age.setter
def age(self, age):
if age >= 150 or age < 0:
print('赋值有误,age要求是0-150的值')
# raise 抛出异常: raise 错误类型
# raise ValueError
self._age = None
return
self._age = age
if __name__ == '__main__':
stu1=Student()
不添加getter和setter
stu1._name='李四'
print(stu1._name) #李四
添加getter
stu1._name = '张三'
print(stu1.name) #张三
添加setter
stu1.name='王五'
print(stu1.name) #王五
stu1.age = 20
print(stu1.age)
四、类的继承
子类:继承者
父类(超类):被继承者
1.如何继承
python中类是可以继承的,并且支持多继承
说明:python中所有的类默认继承python的基类:object
class 类名(父类):
'''类的说明文档'''
属性
方法
2.继承哪些内容
继承:直接拥有父类的属性和方法(继承后父类的属性和方法还是存在的)
(1)对象的属性和方法,类的字段和方法,静态方法都可以继承(私有的继承无意义--->不能继承)
(2)slots的值不会被继承
(3)getter和setter会被继承
class Person:
"""人类"""
__slots__ = ('name','age','sex','__lenght','_face')
def __init__(self):
self.name=''
self.age=0
self.sex='男'
self.__lenght=0
self._face=0
@property
def face(self):
return self._face
@face.setter
def face(self, face):
self._face = face
def eat(self):
print('%s在吃饭'%self.name)
类字段
number=61
类方法
@classmethod
def get_number(cls):
print('人类数量:%d'%cls.number)
静态方法
@staticmethod
def hurt_earth():
print('人类破坏环境')
class Student(Person):
"""学生类"""
def study(self):
pass
if __name__ == '__main__':
stu=Student()
stu.name='晓晓'
对象的属性
print(stu.name,stu.age,stu.sex) #晓晓 0 男
对象的方法
print(stu.eat()) #晓晓在吃饭
类的字段
print(Student.number) #61
类的方法
Student.get_number() # 人类数量:61
静态方法
Student.hurt_earth() #人类破坏环境
stu.face = 100
print(stu.face) #100
print(stu.__dict__) #{}
五、练习-获取数据
要求:将width,height的内容变为数字类型,并且将null变为‘无’
image.png
#获取数据
import json
def download_data():
with open('./data.json','r',encoding='utf-8') as f:
content=json.load(f)
return content['data']
class Data:
"""数据类"""
def __init__(self):
self.type=''
self.text=''
self.user_id=''
self.name=''
self.screen_name=''
self._width=0
self._height=0
self._themes=None
#_width的getter和setter
@property
def width(self):
return self._width
@width.setter
def width(self,width):
self._width=int(width)
@property
def height(self):
return self._height
@height.setter
def height(self,height):
self._height=int(height)
@property
def themes(self):
if not self._themes:
return '无'
return self._themes
#根据字典创建对象
@classmethod
def creat_data(cls,dict1):
data=cls()
for key in dict1:
if key=='width':
data.width=dict1[key]
continue
if key=='height':
data.height=dict1[key]
continue
if key=='themes':
data._themes=dict1[key]
continue
data.__setattr__(key,dict1[key])
return data
if __name__ == '__main__':
print(download_data())
datas=[]
for dict1 in download_data():
#通过字典创建对象
data=Data.creat_data(dict1)
#将创建的对象存起来
datas.append(data)
print(datas[0].themes)
六、重写
(1)在子类中可以直接添加其他的方法
(2)重写:
<1>完全重写:重新实现从父类继承下来的方法,重写后,子类再调用这个方法的时候,就调用子类的
<2>保留父类实现的功能,再添加新的功能
对象和类调用方法的过程:先看当前类是否存在这个方法,没有才看父类有没有这个方法,如果父类没有就看父类的父类有没有,直到找到基类(object)为止
class Animal(object):
"""动物类"""
def __init__(self):
self.age=0
self.color=''
def eat(self):
print('吃东西')
def shout(self):
print('叫唤')
@classmethod
def get_number(cls):
return 100
class Dog(Animal):
def look_after(self):
print('看家')
重写父类的shout
def shout(self):
print('汪汪汪')
重写父类的eat方法
def eat(self):
保留父类eat的功能
super().eat()
print('吃骨头')
@classmethod
def get_number(cls):
保留父类的类方法,的功能的时候,还是super().类方法
print(super().get_number())
if __name__ == '__main__':
dog=Dog()
dog.age=3
print(dog.color)
dog.shout() #汪汪汪
dog.look_after() #看家
dog.eat()
'''
吃东西
吃骨头
'''
an=Animal()
继承后,父类不能使用在子类中添加的属性和方法
an.eat() #吃东西
七、添加属性
对象属性的继承:是通过继承init方法来继承的父类方法
给当前类添加对象属性:重写init方法
注意:如果要保留父类的对象属性,需要使用super()调用父类的init方法
多态:同一个事物有多种形态
方法的多态:同一个事物有多重形态,子类继承父类的方法,可以对方法进行重写,一个方法就有多种形态(多态的表现)
类的多:继承产生多态
class Person(object):
"""人类"""
def __init__(self, name, age=0, sex=''):
self.name = name
self.age = age
self.sex = sex
def eat(self):
print('人在吃饭')
class Staff(Person):
(init方法的参数:保证在创建对象的时候就可以给某些属性赋值)
def __init__(self, name='', age=0, salary=0):
super().__init__(name, age)
self.salary = salary
def eat(self):
print('员工在吃饭')
class Scientist(Person):
def eat(self):
print('科学家在吃饭')
if __name__ == '__main__':
p1 = Person('李四',sex='女')
p1.eat()
s1 = Staff(age=18)
s1.sex = '男'
print(s1.name)
s1.salary = 10000
print(s1.salary)
s1.eat()
练习:
声明人类,有属性,名字,年龄,性别,身高,
要求:创建人的对象的时候,可以给名字,性别,年龄赋初值
再创建学生类继承自人类,拥有人类的所有的属性,再添加学号,成绩,电话属性
要求:创建学生对象的时候可以给名字,年龄和电话赋初值
class Person2:
"""人类"""
a = 10
def __init__(self, name, sex, age):
self.name = name
self.age = age
self.sex = sex
self.height = 0
class Student(Person2):
"""学生类"""
b = 100
def __init__(self, name='', age=0, tel='00'):
super().__init__(name, age=age, sex='女')
self.study_id = '00'
self.score = 0
self.tel = tel
stu = Student('李四')
stu.sex = '男'
print(stu.age)
p1 = Person2('张三', '男', 18)
八、运算符的重载
1.重载:一个类中可以有多个名字相同的方法,但是参数(个数)不一样,就叫重载,python中不支持重载
2.运算符重载
(作用:重新定义运算符运算的过程)
(1)> 和 < :大于和小于符号,只需要重载其中一个,另外一个的结果,直接是重载的结果取反
(2)+ 和 - :同上
class Student:
def __init__(self,name='',age=0,height=0):
self.name=name
self.age=age
self.height=height
"""
重载:>
self>other
"""
def __gt__(self, other):
#比较对象1>对象2的时候是比较的他们的height属性
return self.height>other.height
"""
重载:<
"""
def __lt__(self, other):
return self.age<other.age
"""
重载:+
"""
def __add__(self, other):
return self.age+other.age
"""
重载:-
"""
def __sub__(self, other):
return self.height-other.height
#python不支持方法的重载
# def run(self):
# print('人在跑')
def run(self,name):
print('%s再跑'%name)
if __name__ == '__main__':
stu1=Student('AA',18,height=190)
stu2=Student('BB',19,height=180)
if stu1>stu2:
print('学生1大于学生2哦哦哦') #学生1大于学生2哦哦哦
if stu1<stu2:
print('学生1小于学生2')
else:
print('学生2小于学生1') #学生1小于学生2
print(stu1+stu2) #37
print(stu1-stu2) #10
stu=Student()
stu.run('驾考') #驾考再跑
九、python中的内存管理
python内存管理原理
内存中有两个特殊的区域:栈、堆
栈:栈中的内存是系统自动管理(内存的开辟和内存的释放)--->作用域结束,内存就释放
堆:堆中的内存都需要写程序去开辟和释放的(python中这个过程也已经自动化)
堆中的数据到底是什么时候释放的?
看一个值有几个引用,当一个值没有应用的时候,值对应的内存空间就会被释放
(引用计数机制)
引用:存储对象地址的变量
注意:将对象添加到容器中,对象的引用会加1
class Person:
def __init__(self, name):
self.name = name
def run(self):
print(self.name,'人在跑')
if __name__ == '__main__':
# 声明了一个Person对象,存到p中的
p = Person('p')
p.run()
# 删除对象的唯一的引用,对象就会被销毁
del p
# p.run()
# Person对象(0),name='p1' 0+1+1-1-1
p1 = Person('p1')
p2 = p1
del p2
p1.run()
p1 = 'a'
# 注意:将对象添加到容器中,对象的引用会加1
p3 = Person('p3')
lists = [p3, 100]
del p3
lists[0].run()
# del lists[0]
# del lists
lists[0] = None
十、包的使用
封装:
对一个功能的封装--->用函数
对多个功能的封装--->模块和类
对多个数据进行封装--->类,字典
对多个类进行封装--->模块
对多个模块进行封装--->包(文件夹里面有个init.py文件)
导入包
import package1
导入某个包中的某个模块
from package1 import my_math
导入某个包的某个模块中的某个函数和类
from package1.my_math import sum,Math
总结
"""
1.内置属性
__name__:获取当前类的
__doc__:类的说明
类.___dict__:获取类的所有属性
对象.__dict__:获取对象的所有属性
注意:当我们通过__slots__去约束对象属性后,对象__dict__属性不
能使用,如果父类设置了__slots__,子类对象也不能使用__dict__
__module__:获取模块名
__bases__:获取当前类的父类
2.私有化
命名时前加'__',变私有的,不能在类的外面去使用,不能被继承
3.假的私有:getter 和 setter
对象属性
(1)在给对象属性赋值前,或者获取属性前,要干点别的事情,我们就给属性添加getter或者setter
(2)命名属性时,名字前加一个人下划线'_',添加关键字@property
@property
def 属性名去掉下划线(self):
返回值
@属性名去掉下划线.setter
def 属性名去掉下划线(self,value):
给属性赋值
(3)调用
4.继承
让子类直接拥有父类的属性和方法
class 子类(父类):
属性
方法
能继承什么:所有的属性和方法都可以继承,但是除了私有的,__slots__的值不能继承
"""
5.添加属性和方法,以及对方法的重写
重写:(1)完全覆盖 (2)保留父类的功能(super().父类方法)
添加对象属性:
def __init__(self):
super().__init__()
self.属性名=值
6.运算符重载
__add__:+
__sub__:-
__gt__:>
__lt__:<
7.内存管理
一个对象没有引用,内存就释放
引用类型:变量存的是地址
值类型:变量存的是值(数字。字符串)
8.包
封装功能:函数
封装数据:容器类型、对象的属性
多个功能封装:类、模块
多个类封装:模块
多个模块:包
from 包 import 模块
from 包.模块 import 函数、类、变量