Python面向对象绑定方法、反射与内置方法

2021/12/7 22:17:28

本文主要是介绍Python面向对象绑定方法、反射与内置方法,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

一、绑定方法

类中定义的函数分为两大类:绑定方法非绑定方法

其中绑定方法又分为绑定到对象的对象方法和绑定到类的类方法

在类中正常定义的函数默认是绑定到对象的,而为某个函数加上装饰器@classmethod后,该函数就绑定到了类。

æ‹¿å‰‘æˆ³ä½ - 一组可爱的动图 ​

我在之前的章节中已经介绍过对象方法了,本节我主要介绍类方法。类方法通常用来在__init__的基础上提供额外的初始化实例的方式:

# 类方法的应用
HOST = '127.0.0.1'
PORT = 3306


class MySQL:
    def __init__(self, host, port):
        self.host = host
        self.port = port

    @classmethod
    def from_conf(cls):  # 读取配置进行初始化
        return cls(HOST, PORT)


print(MySQL.from_conf)  # 绑定到类的方法
# <bound method MySQL.from_conf of <class '__main__.MySQL'>>
conn = MySQL.from_conf()  
"""调用类方法,自动将类MySQL当作第一个参数传给cls"""

绑定到类的方法就是专门给类用的,但其实对象也可以调用,只不过自动传入的第一个参数仍然是类,也就是说这种调用是没有意义的,并且容易引起混淆,这也是Python的对象系统与其他面向对象语言对象系统的区别之一,比如Smalltalk和Ruby中,绑定到类的方法与绑定到对象的方法是严格区分开的。

æ— èŠ - 一组可爱的动图 ​

二、非绑定方法

为类中某个函数加上装饰器@staticmethod后,该函数就变成了非绑定方法,也称为静态方法。该方法不与类或对象绑定,类与对象都可以来调用它,但它就是一个普通函数而已,因而没有自动传值那么一说:

import uuid


class MySQL:
    def __init__(self, host, port):
        self.id = self.create_id()
        self.host = host
        self.port = port

    @staticmethod
    def create_id():
        return uuid.uuid1()


conn = MySQL('127.0.0.1', 3306)
print(conn.id)  # 7e402dbe-5756-11ec-8cdc-b0359fd6cd6a

"""类或对象来调用create_id发现都是普通函数,而非绑定到谁的方法"""
print(MySQL.create_id)
# <function MySQL.create_id at 0x000001E6B11741F8>
print(conn.create_id)
# function MySQL.create_id at 0x000001E6B11741F8>

总结绑定方法与非绑定方法的使用:

若类中需要一个功能,该功能的实现代码中需要引用对象则将其定义成对象方法、需要引用类则将其定义成类方法、无需引用类或对象则将其定义成静态方法。

脸红 - 一组可爱的动图 ​

三、反射

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

class Teacher:
    def __init__(self, full_name):
        self.full_name = full_name


t = Teacher('Jason Lin')

# hasattr(object,'name')
hasattr(t, 'full_name')  # 按字符串'full_name'判断有无属性t.full_name

# getattr(object, 'name', default=None)
getattr(t, 'full_name', None)  # 等同于t.full_name,不存在该属性则返回默认值None

# setattr(x, 'y', v)
setattr(t, 'age', 18)  # 等同于t.age = 18

# delattr(x, 'y')
delattr(t, 'age')  # 等同于del t.age

邪恶的微笑 - 一组可爱的动图 ​

基于反射可以十分灵活地操作对象的属性,比如将用户交互的结果反射到具体的功能执行:

class FtpServer:
    def serve_forever(self):
        while True:
            inp = input('input your cmd>>: ').strip()
            cmd, file = inp.split()
            if hasattr(self, cmd):  # 根据用户输入的cmd,判断对象self有无对应的方法属性
                func = getattr(self, cmd)  # 根据字符串cmd,获取对象self对应的方法属性
                func(file)

    def get(self, file):
        print('Downloading %s...' % file)

    def put(self, file):
        print('Uploading %s...' % file)


server = FtpServer()
server.serve_forever()

执行结果为:

input your cmd>>: get a.txt
Downloading a.txt...
input your cmd>>: put b.txt
Uploading b.txt...

撸猫 - 一组可爱的动图 ​

四、内置方法

Python的Class机制内置了很多特殊的方法来帮助使用者高度定制自己的类,这些内置方法都是以双下划线开头和结尾的,会在满足某种条件时自动触发,我们以常用的__str__和__del__及其他了解的几个方法为例来简单介绍它们的使用。

4.1 __str__

__str__方法会在对象被打印时自动触发,print功能打印的就是它的返回值,我们通常基于方法来定制对象的打印信息,该方法必须返回字符串类型:

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

    def __str__(self):
        return '<Name:%s Age:%s>' % (self.name, self.age)  # 返回类型必须是字符串


p = People('lili', 18)
print(p)  # 触发p.__str__(),拿到返回值后进行打印
# <Name:lili Age:18>

4.2 __del__

__del__会在对象被删除时自动触发。由于Python自带的垃圾回收机制会自动清理Python程序的资源,所以当一个对象只占用应用程序级资源时,完全没必要为对象定制__del__方法,但在产生一个对象的同时涉及到申请系统资源(比如系统打开的文件、网络连接等)的情况下,关于系统资源的回收,Python的垃圾回收机制便派不上用场了,需要我们为对象定制该方法,用来在对象被删除时自动触发回收系统资源的操作:

class MySQL:
    def __init__(self, ip, port):
        self.conn = connect(ip, port)  # 这里是伪代码,表示发起网络连接,需要占用系统资源

    def __del__(self):
        self.conn.close()  # 关闭网络连接,回收系统资源


obj = MySQL('127.0.0.1', 3306)  # 在对象obj被删除时,自动触发obj.__del__()

GIF 动图 - 一组可爱的动图 ​

4.3 __call__

__call__方法的触发条件是对象后面加括号,即会触发执行。

注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于__call__方法的执行是由对象后加括号触发的,即:对象() 或者 类()()

class Foo:

    def __init__(self):
        print('__init__')

    def __call__(self, *args, **kwargs):
        print('__call__')


obj = Foo()  # 打印 __init__
obj()  # 打印 __call__

4.4 __enter__和__exit__

我们知道在操作文件对象的时候可以这么写:

with open('a.txt') as f:
  '代码块'

上述叫做上下文管理协议,即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 Open('a.txt') as f:
    print('=====>执行代码块')
    # print(f,f.name)

打印结果为:

出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量
=====>执行代码块
with中代码块执行完毕时执行我啊

__exit__()中的三个参数分别代表异常类型,异常值和追溯信息,with语句中代码块出现异常,则with后的代码都无法执行:

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

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

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


with Open('a.txt') as f:
    print('=====>执行代码块')
    raise AttributeError('***着火啦,救火啊***')
print('0' * 100)  # ------------------------------->不会执行

滑板车 - æ— è„¸ç”·åŠ¨æ€QQ表情包_微信表情包表情

如果__exit__()返回值为True,那么异常会被清空,就好像啥都没发生一样,with后的语句正常执行:

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

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

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


with Open('a.txt') as f:
    print('=====>执行代码块')
    raise AttributeError('***着火啦,救火啊***')
print('0' * 100)  # ------------------------------->会执行

模拟open案例:

class Open:
    def __init__(self, filepath, mode='r', encoding='utf-8'):
        self.filepath = filepath
        self.mode = mode
        self.encoding = encoding

    def __enter__(self):
        # print('enter')
        self.f = open(self.filepath, mode=self.mode, encoding=self.encoding)
        return self.f

    def __exit__(self, exc_type, exc_val, exc_tb):
        # print('exit')
        self.f.close()
        return True

    def __getattr__(self, item):
        return getattr(self.f, item)


with Open('a.txt', 'w') as f:
    print(f)
    f.write('aaaaaa')
    f.wasdf  # 抛出异常,交给__exit__处理

用途或者说好处:

1、使用with语句的目的就是把代码块放入with中执行,with结束后,自动完成清理工作,无须手动干预;

2、在需要管理一些资源比如文件,网络连接和锁的编程环境中,可以在__exit__中定制自动释放资源的机制,你便无须再去关注这个问题,这将大有用处;

小风车 - æ— è„¸ç”·åŠ¨æ€QQ表情包_微信表情包表情



这篇关于Python面向对象绑定方法、反射与内置方法的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程