Python面向对象 #4 反射与内置方法


在上一篇文章中我们讲到了继承知道了继承是一种什么“是”什么的关系。

然而类与类之间还有另一种关系,这就是组合

一、组合

组合不是一个新的技术栈,他是对象的另一种说法

什么是组合:组合就是一个对象拥有的属性,该属性的值是另一个对象。

class Aaa():
	def __init__(self,m):
		self.m = m

class Bbb():
	def __init__(self, n):
		self.n = n

obj = Bbb(10)
obj1 = Aaa(20)
"""一个对象拥有一个属性,该属性的值是另外一个对象"""
obj.x = obj1
# 超级对象:通过一个属性可以访问到另一个对象的值
print(obj.x.m)
什么场景下使用继承? 什么场景下使用组合?

继承一般情况用在:什么是什么的情况 is
组合一般用在:什么有什么的情况 has

class People():  # 1. 定义一个父类People,将共同拥有的属性与方法放在一起
    school = "BHYEY"

    def __init__(self, name, age, gender, ):
        self.name = name
        self.age = age
        self.gender = gender


class Course():  # 2.单独方法提取出来做一个课程类,
    def __init__(self, course_name, course_money, course_time):
        self.course_name = course_name
        self.course_money = course_money
        self.course_time = course_time


python = Course('python', 20000, '6month')
linux = Course('linux', 10000, '5month')


class Student(People):  # 建一个子类Student(学生)
    def __init__(self, name, age, gender, course=None):
        super().__init__(name, age, gender)
        if course is None:
            course = []
        self.course = course


stu = Student('jack', 18, 'male')
stu.course.append(python)
stu.course.append(linux)
for i in stu.course:
    print(i.course_name)


class Teacher(People):  # 建一个子类Teacher(老师)
    def __init__(self, name, age, gender, level):
        super().__init__(name, age, gender)
        self.level = level


tea = Teacher('gg', 20, 'male', 10)
tea.course = linux
print(tea.course.course_name)

二、反射

反射:可以用字符串的方式去访问对象的属性,调用对象的方法(但是不能去访问方法),python中一切皆对象,都可以使用反射。

反射有四种方法:

hasattr:hasattr(object,name)判断一个对象是否有name属性或者name方法。有就返回True,没有就返回False

getattr:获取对象的属性或者方法,如果存在则打印出来。hasattr和getattr配套使用

需要注意的是,如果返回的是对象的方法,返回出来的是对象的内存地址,如果需要运行这个方法,可以在后面添加一对()

setattr:给对象的属性赋值,若属性不存在,先创建后赋值

delattr:删除该对象指定的一个属性

1、对象应用反射
class Foo:
    def __init__(self):
        self.name = 'egon'
        self.age = 51
    def func(self):
        print('hello')
egg = Foo()

print(hasattr(egg,'name'))      #先判断name在egg里面存在不存在,结果是True
print(getattr(egg,'name'))      #如果为True它才去得到,结果是egon
print(hasattr(egg,'func'))     #结果是True
print(getattr(egg,'func'))     #得到的是地址<bound method Foo.func of <__main__.Foo object at 0x0000000001DDA2E8>>
getattr(egg,'func')()        #在这里加括号才能得到,因为func是方法,结果是hello

一般用法如下,先判断是否hasattr,然后取getattr
if hasattr(egg,'func'):
    getattr(egg,'func')()   #结果是hello
else:
    print('没找到')
2. 类应用反射
class Foo:
    f = 123
    @classmethod
    def class_method_dome(cls):
        print('class_method_dome')
    @staticmethod
    def static_method_dome():
        print('static_method_dome')
        
print(hasattr(Foo,'class_method_dome'))         #结果是True
method = getattr(Foo,'class_method_dome')
method()                               #结果是class_method_dome

print(hasattr(Foo,'static_method_dome'))         #结果是True
method1 = getattr(Foo,'static_method_dome')
method1()                              #结果是static_method_dome

三 、内置方法之魔术方法

1 .__str__ 和 __repr__
class People():
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        return f'str is {self.name} obj'

    def __repr__(self):
        return f'repr is {self.name} obj'


"""
    1. 打印对象的时候,输出对象的时候会自动触发类中得__str__方法
    2. 返回值必须是字符串形式
    3. 如果它跟__repr__方法同时存在,__str__的优先级更高
"""

peo = People('jack', 20)
print(peo)

"""__str__ 和 __repr__都是返回对象描述信息,当两个同时出现在同一个类中__str__的优先级会比__repr__优先级要高"""
2 .__del__

"""
    1.当你删除对象的时候会触发__del__的执行
    2. 当整个脚本的程序都执行完毕的时候,也会触发__del__的执行
    3. 一般用在用来在对象被删除时自动触发回收系统资源的操作
"""


# 主动删除运行:
class Student():
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender

    def __del__(self):
        print('del运行了')


stu = Student('jack', 20, 'male')

del stu.name


# 程序结束运行:
class Student():
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender

    def __del__(self):
        print('del运行了')


stu = Student('jack', 20, 'male')

print(stu.name)
3.___enter__和__exit__
class Open:
    def __init__(self, name):
        self.name = name

    def __enter__(self):
        print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量')
        # return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('with中代码块执行完毕时执行我啊')

"""with它可以用在很多地方,但是,出现with语句后面的对象中得类必须要声明__enter__和__exit__"""

with Open('a.txt') as f:
    print('=====>执行代码块')
    print('=====>执行代码块')
    print('=====>执行代码块')
    print('=====>执行代码块')
    print('=====>执行代码块')
    # print(f,f.name)
    
简答题:先聊聊with 的用法? 问with上下文管理协议的执行原理? 为什么打开文件只会可以自动关闭?请说出原因


class Open:
    def __init__(self, name):
        self.name = name

    def __enter__(self):
        print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量')
        # return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('with中代码块执行完毕时执行我啊')
        print(exc_type) # 异常类型
        print(exc_val) # 异常值
        print(exc_tb) # 追溯信息
        return True # 如果你在这个方法里面返回了True,with代码块中出现了异常,就相当于没有出现异常

"""with它可以用在很多地方,但是,出现with语句后面的对象中得类必须要声明__enter__和__exit__"""

# with Open('a.txt') as f:
#     print('=====>执行代码块')
#     print('=====>执行代码块')
#     print('=====>执行代码块')
#     print('=====>执行代码块')
#     print('=====>执行代码块')
#     # print(f,f.name)
"""如果with代码块中出现了异常,则with语句之后的代码都不能正常执行"""
with Open('a.txt') as f:
    print('=====>执行代码块')
    raise AttributeError('***着火啦,救火啊***') # 抛出异常,主动报错
print('0'*100) #------------------------------->不会执行
4. __setattr__,__delattr__,__getattr__
点拦截方法

为什么这称为:点拦截方法呢,因为此类魔法方法只有在通过对象.操作属性时才会触发,所以在触发方法时,对给属性赋的值进行一个处理
这个方法有点类似于我们封装里面提到过的property类似效果,那么是否相似接着向下了解吧!!!

__setattr__在对象.属性=值时自动触发,也就是更改属性值时自动触发
__getattr__在对象.属性时自动触发,前提是:当属性不在对象内的时候才会触发,有点鸡肋
__delattr__在del 对象.属性时自动触发,也就是在删除对象属性时自动触发

setattr:
"""当我们通过.增加或修改对象属性的时候,会触发此方法"""
class People():
    def __setattr__(self, key, value): # 默认携带3个参数,属性、属性名、属性值
    	print('修改了对象属性')
    	
    	# 注意:如果我们查找对象的属性,那么则会报错,
    	# 因为对象在增加属性的时候就会执行这个方法
    	# 而那时候属性还没有添加到对象里,所以会报错
    	# print(self.name)
       

p = People()

p.name = 'tom'
> '我们修改了对象属性' # 可以看到,当通过:对象.属性赋值时 触发__setattr__方法的运行
getatter:
"""在我们通过.查询属性的时候且查询的方法不存在才会触发这个方法"""
class People():
    def __init__(self, name, age):
        self.name = name
        self.age = age


    def __getattr__(self, item):
    	# 不可以这样使用:self.属性名,因为涉及到了查询属性,这样也会造成无限递归
        return f'{item}属性不存在'


p = People('jack', 18)

p.name = 'tom'

print(p.name) # 存在,不触发__getattr__方法
> 'tom'

print(p.n) # 查找的属性不存在,触发__getattr__方法
> 'n属性不存在'
delatter:
"""当通过del 对象.属性删除时,才会触发此方法"""
class People():
    def __init__(self, name, age):
        self.name = name
        self.age = age


    def __delattr__(self, item):
        print(f'已经删除{item}属性')
        # 我们这里不可以使用:del self.属性,因为在这里再进行属性删除会造成递归


p = People('jack', 18)

p.name = 'tom'

del p.name
> '已经删除name属性'

del p.s

> '已经删除s属性'
5.__setitem__,__getitem,__delitem__

这三种拦截方法都是通[ ]操作对象时才会触发

setitem:通过中括号向对象设置值时会触发
getitem:通过中括号向对象查询值时会触发
delitem:通过中括号删除对象值时会触发

setitem:
"""操作起来类似于字典赋值"""
class People:
    def __init__(self,name,age):
        self.name = name
        self.age = age
	
	# 当我们通过对象[key] = value时会触发这个方法
    def __setitem__(self, key, value): 
		# 只能将值写入到属性内,因为如果是这样:self[key] = value,
		# 则会继续触发__setitem__这个方法的运行,最终导致递归
        self.__dict__[key] = value
        

p = People('jack',18)

p['sex'] = 'male'

print(p.sex)
> 'male'
getitem:
"""已经可以实现,通过[]向对象赋值,那么我们接下来使用[]进行取值"""
class People:
    def __init__(self,name,age):
        self.name = name
        self.age = age

    def __setitem__(self, key, value):
        self.__dict__[key] = value

    def __getitem__(self, key):
		# 不可以这样返回值,我们并不是一个真正的字典,因为我们的属性还都只是存在于属性字典__dict__内。
		# return self[key]

        return self.__dict__[key] # 返回对象属性字典内对应key值

p = People('jack',18)

p['sex'] = 'male'

print(p['sex'])
> 'male'

print(p.sex)
> 'male'
delitme
"""当我们进行del 属性[key]时,也就是通过key删除对象属性时,触发的方法"""
class People:
    def __init__(self,name,age):
        self.name = name
        self.age = age

    def __setitem__(self, key, value):
        self.__dict__[key] = value

    def __getitem__(self, key):
        return self.__dict__[key]

    def __delitem__(self, key):
        print(f'已经删除{key}属性值')
        del self.__dict__[key] # 删除对象属性字典内对应的key

p = People('jack',18)

p['sex'] = 'male'

del p['sex']
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值