Java教程

面向对象(4)

本文主要是介绍面向对象(4),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

面向对象(4)

image

1、组合

# 组合
'''
面向对象中组合的概念,其实本质上也是为了减少代码冗余,
核心思想是:对象的属性对应的不再是具体的一个值,而是一个对象,这样
我们在调用的时候就能很大程度的减少重复代码的编写
'''
'''
如果要给一个学生对象传入课程信息,
    1、直接参数传入(太长,每次产生学生对象的话要传入的参数就太多了)代码冗余可读性不高
    2、继承父类,定义一个course类,让学生类继承(学生只属于人类,) 偏离了继承的思想
    3、定义完课程类之后,直接产生课程对象存入课程信息,把课程对象当做学生对象的属性保存——-》组合,减少了代码的冗余,可读性提高
'''

# 示例:以选课系统为例
class School:
    # 初始化学校对象
    def __init__(self, name):
        self.name = name
        self.Class = None

    # 将学校与班级关联起来
    def related_Class(self, Class_obj):
        self.Class = Class_obj.name

    def tell_Class(self):
        print('%s %s' % (self.name, self.Class))


class Class:
    def __init__(self, name):
        self.name = name
        self.course = None

    # 班级与课程关联起来
    def related_course(self, course_obj):
        self.course = course_obj.name

    def tell_course(self):
        print('%s %s' % (self.name, self.course))


class Course:
    def __init__(self, name):
        self.name = name
        self.student = None

    # 将课程和学生关联起来
    def related_student(self, student_obj):
        self.student = student_obj.name

    def tell_student(self):
        print('%s %s' % (self.name, self.student))


class Student:
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender
        self.course = []

    def choose_course(self, course_obj):
        self.course.append(course_obj)

    def tell_course(self):
        print('%s %s' % (self.name, self.course))


# 创建校区
school_obj1 = School('上海老男孩')
school_obj2 = School('北京老男孩')
# 开设班级
class_obj1 = Class('脱产14期')
class_obj2 = Class('脱产19期')
# 开设课程
course_obj1 = Course('python全栈开发')
course_obj2 = Course('linux运维')
# 实例化学生对象
student_obj = Student('jason', 'age', 'male')
# 将学校与班级关联起来
school_obj1.related_Class(class_obj1)
# 查看当前校区开设了哪些班级
school_obj1.tell_Class()

'''
面向对象的基本思想:可扩展性高,代码可读性好,从上面的例子可以很清楚的看出来,
当需要修改某一部分的内容时,只需要针对某一部分进行修改即可,对程序的整体功能影响不大。
'''

image

2、内置方法(魔术方法)

  • 1、什么是内置方法:
    以双下__开头并以__双下结尾的内置方法
  • 特点:在触发了某种条件时,自动执行方法
    内置方法又叫魔术方法简称魔法
  • 2、内置方法是用来干什么的:
    内置方法的本质是为了定制化我们的类或者是对象,
    让我们在使用时的结果能和我们预期的结果一样
# 1、__init__:只要在调用类实例化对象时就会自动执行该方法
class Foo:
    def __init__(self):
        print('哈哈哈')


obj = Foo()  # 哈哈哈


# 2、__str__:
'''
在打印对象时自动触发,并且会打印出return后面的值,且返回的值只能是字符串类型
'''
# 示例:
class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        return '我执行了'


stu1 = Student('jason', 20)
print(stu1)  # 我执行了
# 3、__del__
# 示例一:
class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __del__(self):
        print('我执行了')

stu1 = Student('jason', 20)
del stu1  # 我执行了
# 示例二:
class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __del__(self):
        print('我执行了')

stu1 = Student('jason', 20)
print('========>')
'''
========>
我执行了
'''
'''
从上面的两个例子可以看出来,__del__方法在程序结束前会自动执行,且在删除对象之前执行,
有一点可以确定的是,程序结束时pycharm会进行内存的释放,也就是python里的垃圾回收机制,
由此可以得出__del__方法的定义:
    在执行清除数据之前执行的操作
有一点需要注意的是:我们在pycharm里的程序仅仅只是应用程序里的数据,当我们在后期的使用中,
                 对象里的某个属性涉及到对操作系统的内存空间进行操作时(打开关闭文件),
                 程序结束时是不会自动释放操作系统里占用资源的,这个时候就要利用__del__方法,
                 来达到对操作系统里的资源的释放
'''
# 3、__call__:在对象加括号时自动执行该方法
# 示例:
class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __call__(self, *args, **kwargs):
        print('我执行了')

stu1 = Student('jason', 20)
stu1()  # 我执行了
'''
之前我们说了,python是一门面向对象的语言,即python里的一切皆对象,
下面以我们之前学的int为例
'''
a = int(10) # 这其实就是实例化对象的过程
print(a)  # 10
'''
但是看似违背了我们对对象的认知,我们之前在直接打印对象时,返回的是对象的内存地址,
而不是一个确切的值,这个其实和我们上面说的__str__方法原理一样,python在内部已经为我们
封装好了,所以我们在调用时可以直接查看对应的值,所以可以说,python里一切皆对象
'''
# 再以列表为例
l = [1, 2, 3]
l.append(5)  # 点的方式和我们在用对象调用类里的方法时是一样的,自动将对象传入方法
print(l)  # [1, 2, 3, 5]
list.append(l, 6)
print(l)  # [1, 2, 3, 5, 6]
'''
从上面的例子我们更加验证了’python里一切皆为对象‘这句话,类调用和对象在调用类里的方法时,
和我们自定义的对象和类调用时是一模一样的
'''

'''
基于以上原理,再来看一个例子,我们之前在打开文件时,都是用with...as...语法进行操作的,
但是他的内部原理又是什么,在这里先下个定义:
    with...as...:
      子代码块
    上述语法结构又被称为'上下文管理协议'即with语句,
    为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法'
'''


class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __enter__(self):
        print('enter执行了')

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('exit执行了')

    def read(self):
        print('我也是')


with Student('jason', 18) as self:
    print('执行我以后要就执行exit')

'''
enter执行了
执行我以后要就执行exit
exit执行了
'''

'''
从上面的情况我们可以发现一个很有趣的现象,enter在with语法出现时就自动执行了,
    而exit是在with的子代码块执行结束以后才执行的,这和我们之前执行文件操作时是不是有什么相似之处?
事实上,我们当初在用with语法执行文件时,就是通过enter和exit语法实现对文件的操作时,并且我们
    还知道一点,with语法在打开文件时会自动关闭文件,这是不是exit方法有点类似,也就是说我们只需要在exit方法
    里加入关闭文件的操作就能理解当初为什么我们用with语法打开文件执行完以后会自动关闭文件了,其内部原理其实就是
    利用enter和exit方法实现的
但是,需要补充的是,with语法不仅仅可以对文件操作,还可以对其他的类进行操作,这和我们上面提到的python里一切皆对象又形成了呼应,
    所以我们常说的文件其实也是一个类,而我们所用的with open语法,其实就是调用了open类,而as后面的则是实例化的对象,并且通过
    类调用的方式实例化一个对象,这也就是with语法(上下文管理协议)的内部原理
'''

image

3、反射方法

  • 反射方法
    什么是反射方法:通过字符串操作属性或者方法
    1、getattr
# 1、getattr
class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def read(self):
        print('%s' % self.name)


# 实例化对象
stu1 = Student('jason', 20)
# 利用点的方式查看对象的属性
print(stu1.name)
# 如何通过字符换来操作
# 方法一:
print(stu1.__dict__['name'])
# # 方法二:
print(getattr(stu1, 'name'))
'''
以上的几种方法好像都可以实现查看对象的值,但是有一点要注意,
正常点的方式和用dict方法取值的方式,当对象的属性不存在时会直接报错,
但是getattr方法不一样,getattr方法可以传入第三个参数,
在我们访问的属性不存在时,不会报错,会返回第三个参数,不传参数则报错
'''

# 示例:
print(getattr(stu1, 'name1', '不存在'))  # 不存在

image

2、setaddr

# 2、setattr
# 示例:
class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def read(self):
        print('%s' % self.name)


# 实例化对象
stu1 = Student('jason', 20)
# 正常点的方式修改属性数据
stu1.name = 'jasonNB'
print(stu1.name)  # jasonNB
# 通过字符串的方式修改
# 方式一:
stu1.__dict__['name'] = 'jasonNB'
print(stu1.name)  # jasonNB
# # 方式二:
setattr(stu1, 'name', 'jasonNB')
print(stu1.name)  # jasonNB

image

3、delattr

# 3、delattr
class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def read(self):
        print('%s' % self.name)


# 实例化对象
stu1 = Student('jason', 20)
# 正常点的方式删除属性数据
del stu1.name
print(stu1.__dict__)  # {'age': 20}
# 通过字符串的方式修改
# 方式一:
del stu1.__dict__['name']
print(stu1.__dict__)  # {'age': 20}
# 方式二:
delattr(stu1, 'name')
print(stu1.__dict__)  # {'age': 20}

image

4、hasattr

# 4、hasattr
class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def read(self):
        print('%s' % self.name)


# 实例化对象
stu1 = Student('jason', 20)
# 查看对象是否具有某个属性
print(hasattr(stu1, 'name'))  # True
print(hasattr(stu1, 'name1'))  # False

image

5、延伸

'''
其实对于getattr、delattr、hasattr方法,不仅可以对对象里的属性和方法进行操作,
也可以对类里的属性和方法进行操作
'''
# getattr

class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def read(self):
        print('%s:%s' % (self.name, self.age))


# # 实例化对象
stu1 = Student('jason', 20)
# 获取对象里的方法并调用
getattr(stu1, 'read')()  # jason:20
# 获取类里的方法并调用
getattr(Student, 'read')(stu1)  # jason:20
'''
其实对于我们平时所导入的模块来说,一样可以用getattr方法操作
'''
import time
# 获取时间戳
# 正常获取
print(time.time())  # 1638879367.0702362
# getattr方法获取
print(getattr(time, 'time')())  # 1638879367.0702362
'''
其实对于导入模块来说,我们平常用的都是import 模块名或者from...import...句式导入,
此外我们也可以用字符串的方式导入模块
'''


time = __import__('time')  # 了解即可
print(time.time())  # 1638879518.6852396
hasattr
class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def read(self):
        print('%s:%s' % (self.name, self.age))


# 实例化对象
stu1 = Student('jason', 20)
# 查看类是不是拥有某个属性或者方法
print(hasattr(Student, 'name'))  # False
print(hasattr(Student, 'read'))  # True

image

4、异常

# 异常
'''
1、什么是异常
    异常就是代码运行产生的错误信息
2、异常三要素:
    1、异常出现的位置:Tracback
    2、异常类型:
            1:语法异常
                不被允许的,不能出现语法异常
                    eg:print(
            ps:语法错误根本过不了python解释器检测语法阶段,因此是不被允许的,必须在程序执行前就进行修改
            2:逻辑异常
                可以被允许的,是不可避免的,
                随着我们的代码量越来越多,逻辑异常也会随之增加,也就是我们常说的bug,
    3、异常的详细信息:
        记录了出现异常的详细原因
3、如何处理异常
4、为什么要使用异常处理:
    增强代码的健壮性,减少出现的异常
'''
# 3、如何处理异常
'''
一般语法结构:
    try:
        可能出现异常的代码(被检测的代码尽量不能太多)
    except 异常类型 as e:  # e用来接收异常的详细信息
        检测到异常时采取的相应措施
ps:except数量不限
万能语法结构:
    try:
        可能出现异常的代码(被检测的代码尽量不能太多)
    except BaseException:
        检测到异常时采取的相应措施
'''
# 异常处理包括的其他方法
'''
    try:
        可能出现异常的代码(被检测的代码尽量不能太多)
    except 异常类型 as e:  # e用来接收异常的详细信息
        检测到异常时采取的相应措施
    else:
        不出现异常执行的代码块
    finally:
        不管报不报错都会执行的代码块
'''
# 主动抛出异常
a = int(input('>>>:'))
if a:
    print(a)
else:
    raise '出错啦'

# 断言
assert 1 == 1  # 条件为True正常执行
assert 1 == 2  # 条件为False触发异常AssertionError

image

这篇关于面向对象(4)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!