面向对象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__': ,
    #  'run': , 'shout': ,
    #  'get_number': ,
    # '__dict__': ,
    # '__weakref__': }

    print(cat1.__dict__)   #{'name': '小花', 'color': 'white'}

    """
    4.类.__module__
    获取当前类所在的模块的名字
    """
    print(Cat.__module__)   #__main__(正在执行时是__main__,使用外部导入的文件时是文件名)


    """
    5.类.__base__
    获取当前类的父类
    """
    print(Cat.__bases__)   #(,)

二、私有化

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.agestu2:
        print('学生1大于学生2哦哦哦')   #学生1大于学生2哦哦哦

    if stu1

九、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 函数、类、变量

你可能感兴趣的:(面向对象2)