Python组合,反射,内置魔术方法

1 组合

1.1 什么是组合?


        组合就是,一个对象拥有一个属性,该属性的值是另外一个对象

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

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

"""一个对象拥有一个属性,该属性的值是另外一个对象."""
obj=Bar(10)
obj1 = Foo(20)
# 超级对象,通过一个属性可以访问到另外一个对象的值
obj.x=obj1

print(obj.x.m)    

        在一个类中以另外一个类的对象作为数据属性,称为类的组合

        组合与继承都是用来解决代码的重用性问题

不同的是:继承是一种“是”的关系,比如老师是人、学生是人,当类之间有很多相同的之处,应该使用继承;而组合则是一种“有”的关系,比如老师有生日,老师有多门课程,当类之间有显著不同,并且较小的类是较大的类所需要的组件时,应该使用组合,如下示例:

class Course:
    def __init__(self,name,period,price):
        self.name=name
        self.period=period
        self.price=price
    def tell_info(self):
        print('<%s %s %s>' %(self.name,self.period,self.price))

class Date:
    def __init__(self,year,mon,day):
        self.year=year
        self.mon=mon
        self.day=day
    def tell_birth(self):
       print('<%s-%s-%s>' %(self.year,self.mon,self.day))

class People:
    school='清华大学'
    def __init__(self,name,sex,age):
        self.name=name
        self.sex=sex
        self.age=age

#Teacher类基于继承来重用People的代码,基于组合来重用Date类和Course类的代码
class Teacher(People): #老师是人
    def __init__(self,name,sex,age,title,year,mon,day):
        super().__init__(name,age,sex)
        self.birth=Date(year,mon,day) #老师有生日
        self.courses=[] #老师有课程,可以在实例化后,往该列表中添加Course类的对象
    def teach(self):
        print('%s is teaching' %self.name)


python=Course('python','3mons',3000.0)
linux=Course('linux','5mons',5000.0)
teacher1=Teacher('lili','female',28,'博士生导师',1990,3,23)

# teacher1有两门课程
teacher1.courses.append(python)
teacher1.courses.append(linux)

# 重用Date类的功能
teacher1.birth.tell_birth()

# 重用Course类的功能
for obj in teacher1.courses: 
    obj.tell_info()

1.2 什么场景下使用继承? 什么场景下使用组合?

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

#  大类集合people
class People():
    school = 'SH'

    def __init__(self, name, age, gender, course_name=None, course_price=None, course_period=None):
        self.name = name
        self.age = age
        self.gender = gender
        self.course_name = course_name
        self.course_price = course_price
        self.course_period = course_period
#  管理员
class Admin(People):
    def __init__(self, name, age, gender):
        super().__init__(name, age, gender)
#  课程
class Course():
    def __init__(self, name, price, period):
        self.name = name
        self.price = price
        self.period = period


python=Course('python', 10000, '6mon')
linux=Course('linux', 20000, '5mon')
# print(python.name)
# print(python.price)
# print(python.period)

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

#  输入学生信息
stu = Student('kevin', 20, 'male')
stu.course.append(python.name)
stu.course.append(linux.name)
print(stu.course) # [<__main__.Course object at 0x000001F258F86B80>, <__main__.Course object at 0x000001F258F511C0>]
# stu.course: []
for i in stu.course:
    print(i)
    
#  教师类
class Teacher(People):
    def __init__(self, name, age, gender, level):
        super().__init__(name, age, gender)
        self.level = level

#  教师输入信息
tea = Teacher('ly', 19, 'female', 10)
print(tea.course_name)
tea.course=linux

print(tea.course.name)
print(tea.course.price)

2 反射

 在Python中,反射指的是通过字符串来操作对象的属性,涉及到四个内置函数的使用(Python中一切皆对象,类和对象都可以用下述四个方法)

四个内置函数:
    getattr: 获取属性(用的最多)
    setattr:设置属性
    hasattr:判断是否有某个属性
    delattr:删除

Python反射是指在运行时动态地访问、检查和修改对象的特性和方法。当在运行时需要根据某些条件动态地调用对象的属性和方法时,可以使用反射机制。

反射可以用来完成以下几个任务:

  1. 获取对象的属性:可以通过对象的属性名来获取属性值。

  2. 获取对象的方法:可以通过对象的方法名来获取方法,并对其进行调用。

  3. 动态修改对象的属性和方法:可以在运行时动态地添加、删除和修改对象的属性和方法。

Python中的反射机制主要是通过内置函数getattr()hasattr()setattr()delattr()来实现的。

getattr(object, name[, default]):获取对象的属性,如果属性不存在,返回默认值或抛出AttributeError异常

hasattr(object, name):检查对象是否存在指定的属性,返回TrueFalse

setattr(object, name, value):设置对象的属性,如果属性不存在,会创建该属性。

delattr(object, name):删除对象的指定属性,如果属性不存在,会抛出AttributeError异常。

下面是一个例子:

class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age
        
    def study(self):
        print('{} is studying'.format(self.name))
        
s = Student('Tom', 18)
# 获取对象的属性
print(getattr(s, 'name'))  # Tom
# 获取对象的方法并调用
fun = getattr(s, 'study')
fun()
# 检查对象是否存在指定属性
print(hasattr(s, 'age'))  # True
# 设置对象的属性
setattr(s, 'gender', 'male')
print(s.gender)  # male
# 删除对象的属性
delattr(s, 'gender')
print(hasattr(s, 'gender'))  # False

输出:

Tom
Tom is studying
True
male
False

3 魔术方法(内置方法之一)

        Python中有一些特殊的方法,称为魔术方法(magic methods),也叫做特殊方法(special methods)。这些方法的名称以双下划线开头和结尾(例如__init__,__add__等),它们用于重载操作符、实现类的特殊行为等。(巨重要)

Python中有一些特殊的方法,称为魔术方法(magic methods),也叫做特殊方法(special methods)。这些方法的名称以双下划线开头和结尾(例如__init__,__add__等),它们用于重载操作符、实现类的特殊行为等。

以下是一些常见的魔术方法:

1. __init__(self, ...):初始化方法,创建一个类的实例时调用。

2. __str__(self):返回一个对象的字符串表示形式,可以通过print()函数输出。

3. __repr__(self):返回一个对象的可打印字符串表示形式,通常用于调试和开发中。

4. __add__(self, other):重载加法运算符(+)。

5. __sub__(self, other):重载减法运算符(-)。

6. __eq__(self, other):重载等于运算符(==)。

7. __lt__(self, other):重载小于运算符(<)。

8. __gt__(self, other):重载大于运算符(>)。

9. __len__(self):返回对象的长度。

10. __getattr__(self, name):获取一个不存在的属性时调用。

11. __setattr__(self, name, value):设置属性值时调用。

12. __delattr__(self, name):删除属性时调用。

13. __call__(self, ...):使一个实例变成可调用的,可以像函数一样调用。

14. __getitem__(self, key):重载索引运算符([]),可以通过操作一个对象的索引或键来访问其元素。

15. __setitem__(self, key, value):设置对象的索引或键值。

16. __delitem__(self, key):删除对象的索引或键值。

这些魔术方法使得Python编程变得更加灵活和方便。

3.1 魔术方法之__init__ 和 __str__和__repr__

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

    """
        1. 打印对象的时候,输出对象的时候会自动触发类中得__str__方法
        2. 返回值必须是字符串形式
        3. 如果它跟__repr__方法同时存在,__str__的优先级更高
    """
    def __str__(self): # 这个用的是最多的
        print('str')
        return 'from str'

    def __repr__(self):
        print('repr')
        return 'from repr'

stu = Student('ly', 20)
# print(stu) # <__main__.Student object at 0x00000226AC4F5A60>

# print('repr:', repr(stu))
print('str:', str(stu))

class MySQL:
    def __init__(self, ip, port):
        self.ip = ip
        self.port = port
        self.f = open('a.txt', 'w')
    """
    1.当你删除对象的时候会触发__del__的执行
    2. 当整个脚本的程序都执行完毕的时候,也会触发__del__的执行
    3. 一般用在用来在对象被删除时自动触发回收系统资源的操作
    """
    def __del__(self):
        print('from _del')
        self.f.close()

 3.2 魔术方法之__doc__和__del__

class MySQL:
    def __init__(self, ip, port):
        self.ip = ip
        self.port = port
        self.f = open('a.txt', 'w')
    """
    1.当你删除对象的时候会触发__del__的执行
    2. 当整个脚本的程序都执行完毕的时候,也会触发__del__的执行
    3. 一般用在用来在对象被删除时自动触发回收系统资源的操作
    """
    def __del__(self):
        print('from _del')
        self.f.close()


mysql = MySQL('127.0.0.1', 3306)

print('1223')
print('1223')

print(isinstance(123, str))
print(type(123) is int)


class Foo:
    pass
class Bar(Foo):
    pass
class Bar1():
    pass
print(issubclass(Bar1, Foo))


class Foo:
    """
    '我是描述信息asdasd'
    '我是描述信息asdasd'
    '我是描述信息asdasd'
    """

    pass
class Bar(Foo):
    pass
print(Bar.__doc__)

3.3 魔术方法之__enter__和__exit__

with语句 (上下文管理器) 它可以用在很多地方

但是,出现with语句后面的对象中得类必须要声明__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)
3.3.1 with简答题

        先聊聊 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) #------------------------------->不会执行

3.4 魔术方法之 __setattr__和__delattr__和__getattr__

__setattr__,__delattr__,__getattr__

class Foo:
    x=1
    def __init__(self,y):
        self.y=y

    """当你找的属性不存在的时候,会触发__getattr__,但是必须是点语法的时候才会"""
    def __getattr__(self, item):
        print('----> from getattr:你找的属性不存在')


    def __setattr__(self, key, value):
        print('----> from setattr')
        # self.key=value # self.a=20
        # self.key=value #这就无限递归了,你好好想想
        self.__dict__[key]=value #应该使用它


    def __delattr__(self, item):
        print('----> from delattr')
        # del self.item #无限递归了
        self.__dict__.pop(item)

obj=Foo(10)
# obj.z
obj.a=20
print(obj.a)

del obj.a

3.5 魔术方法之__setitem__和__getitem__和__delitem__

__setitem__,__getitem,__delitem__

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

    """当你通过中括号获取对象的属性的时候,会自动触发__getitem__"""
    def __getitem__(self, item):
        print('__getitem__')
        print(self.__dict__[item])

    def __setitem__(self, key, value):
        # key:age
        # value:18
        print('__setitem__')
        self.__dict__[key] = value
        #  self.__dict__['age'] = 18

    def __delitem__(self, key):
        print('del obj[key]时,我执行')
        self.__dict__.pop(key)
        pass

    # def __delattr__(self, item):
    #     print('del obj.key时,我执行')
    #     self.__dict__.pop(item)
obj=Foo('tom')
# print(obj.name)

# obj['name']
obj['age'] = 18
# obj.age=18
print(obj.age)

del obj['age']

3.6 魔术方法之__call__

class Foo:

    def __init__(self):
        pass
    #### 当对象加括号的时候会触发__call__的执行
    def __call__(self, *args, **kwargs):
        print('__call__')


obj=Foo()
print(obj)
obj()

END 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值