Python面向对象之十:函数和方法及双下方法

本文介绍了Python中的函数与方法概念,区分了普通函数与类方法,并深入探讨了双下划线方法(如len、hash、str__和__repr__等)的工作原理。通过实例解析,展示了这些特殊方法在实际应用中的行为和作用。
摘要由CSDN通过智能技术生成

Python面向对象之十:函数和方法及双下方法

一、函数与方法

1 、定义

1、函数:函数是封装了一些独立的功能,可以直接调用,能将一些数据(参数)传递进去进行处理,然后返回一些数据(返回值),也可以没有返回值。可以直接在模块中进行定义使用。所有传递给函数的数据都是显式传递的。与类和实例无绑定关系的function都属于函数(function)。

2、方法:方法和函数类似,同样封装了独立的功能,但是方法是只能依靠类或者对象来调用的,表示针对性的操作。方法中的数据self和cls是隐式传递的,即方法的调用者;方法可以操作类内部的数据。与类和实例有绑定关系的function都属于方法(method)。

2 、函数与方法的确定方式
2.1 通过打印函数(方法)名确定
class Person(object):

    def func(self):
        pass

def func():
    pass

per = Person()

print(Person.func)   #<function Person.func at 0x00000206ECF47CA0>
print(per.func)      #<bound method Person.func of <__main__.Person object at 0x000002D599FE9400>>
print(func)          #<function func at 0x00000206ECF47C10>

分析:打印结果含有 function 的是函数,打印结果含有 method 的是方法

2.2 通过types模块验证
from types import FunctionType
from types import MethodType

class Person(object):

    def func(self):
        pass

def func():
    pass

per = Person()

print(isinstance(func, FunctionType))          #True
print(isinstance(Person.func, FunctionType))   #True
print(isinstance(per.func, FunctionType))      #False
print(isinstance(per.func, MethodType))        #True
2.3 静态方法和类方法的确定
from types import FunctionType
from types import MethodType

class Person(object):

    @staticmethod
    def func1(self):
        pass

    @classmethod
    def func2(cls):
        pass

per = Person()

print(isinstance(Person.func1, FunctionType))     #True
print(isinstance(Person.func2, FunctionType))     #False
print(isinstance(Person.func2, MethodType))       #True
print(isinstance(per.func1, FunctionType))        #True
print(isinstance(per.func2, MethodType))          #True

分析:@classmethod下定义的func属于方法,@staticmethod下定义的func属于函数。

总结:

1、与类和实例无绑定关系的 func 都属于函数(function); —> 如:静态函数和类调用的普通func()。
2、与类和实例有绑定关系的 func 都属于方法(method). —> 如:类方法和类对象调用的普通func()。

3、函数和方法的作用域

1、函数的作用域:从函数调用开始至函数执行完成,返回给调用者后,在执行过程中开辟的空间会自动释放,也就是说函数执行完成后,函数体内部通过赋值等方式修改变量的值不会保留,会随着返回给调用者后,开辟的空间会自动释放。

2、方法的作用域:通过实例化的对象进行方法的调用,调用后开辟的空间不会释放,也就是说调用方法中对变量的修改值会一直保留。

二、双下方法

双下方法是特殊方法,他是解释器提供的 由爽下划线加方法名加双下划线 __方法名__的具有特殊意义的方法,双下方法主要是python源码程序员使用的,我们在开发中尽量不要使用双下方法,但是深入研究双下方法,更有益于我们阅读源码。

1 、len
class B:
    def __len__(self): # 必须有一个int类型的返回值 否则会报错,但仍会执行此方法
        print(999)
        return 666
b = B()
print(len(b))   # len 一个对象就会触发 __len__方法
# 999
# 666
2、hash
class A:
    def __init__(self):
        self.a = 1
        self.b = 2

    def __hash__(self):
        return hash(str(self.a)+str(self.b))
a = A()
print(hash(a))   #会调用a这个对象的类(基类)的__hash__方法
3、 str__和__repr
class Student:
    def __init__(self,name,age):
        self.name = name
        self.age = age
        
    def __str__(self):  # 优先级要高
        return f'姓名:{self.name},年龄:{self.age}'
    
    def __repr__(self):
        return f'姓名:{self.name},年龄:{self.age}'
        
obj1 = Student('a',18)
obj2 = Student('b',18)

print(str(obj1)) # 会触发 __str__
print(str(obj2)) # 会触发 __repr__

print(obj1)
print(obj2)  # 打印输出实例会触发__str__ 和 __repr__

print('此对象为%s' % obj1)  # 格式化输出会触发__str__
print('此对象为%r' % obj2)  # 格式化输出会触发__str__
4、call

调用一个对象去执行,就是触发对象所在类中的__call__方法的执行。

class Foo:
    def __call__(self, *args, **kwargs):
        print(self)
        print(args)
        print(kwargs)

obj = Foo()

res = obj(1, 2, 3, x=1, y=2) #只有写了这行代码,__call__才会运行
5、eq

对一个类的两个对象进行比较操作,就会触发__eq__方法

class A:
    def __init__(self):
        self.a = 1
        self.b = 2

    def __eq__(self,obj):
        print(111)
        return True
        # if self.a == obj.a and self.b == obj.b:
        #     return True
a = A()
b = A()
print(a == b)
6、del

析构方法,当对象在内存中被释放时,自动触发执行。

注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。

class A:

    def __del__(self):
        print(111)

obj = A()
del obj    # 打印111
l1 = [1,2,3]
dic = {1:2}
del l1
del dic  # 主动删除
print(dic) # 已经被删除,访问会报错
print(111)
print(222)
7、new

创建一个对象,首先会运行__new__方法创建一个空对象,然后再运行__init__方法装备名称空间。

class A(object):

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

    # 这里的__new__不能创造空间,必须引用父类的__new__创造空间
    def __new__(cls, *args, **kwargs): # 传一个类给cls,确定给哪个类创建空间
        print('in __new__')
        object1 = object.__new__(cls)
        return object1
obj = A()  # 类名() 先触发__new__ 并且将类名自动传给cls
print(obj)
8、__item__系列

只有在通过字典key操作才会触发,而通过点的方式来操作,则触发attr相关方法。

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

    def __getitem__(self, item):
        print('执行getitem')
        return self.__dict__[item]

    def __setitem__(self, key, value):
        print('执行setitem')
        self.__dict__[key] = value

    def __delitem__(self, key):
        print('执行delitem')
        self.__dict__.pop(key)

f = Foo('Jerry', 18)

#获取属性,通过字典key的形式,其实是操作底层__dict__[key]来获取相应的值
print(f['name'])   #执行getitem    Jerry

#设置(修改)属性,也是通过字典key的形式,其实是操作底层__dict__[key] = value 来设置(修改)相应的值
f['name'] = 'Meanwey'   #执行setitem
print(f.__dict__)       #{'name': 'Meanwey', 'age': 18}

#删除属性,通过字典key的形式,其实是操作底层__dict__.pop(key)来删除相应的属性和值
del f['age']            #执行delitem
print(f.__dict__)       #{'name': 'Meanwey'}
9、上下文管理器相关

在python中实现了__enter__和__exit__方法,即支持上下文管理器协议。上下文管理器就是支持上下文管理器协议的对象,它是为了with而生。

当with语句在开始运行时,会在上下文管理器对象上调用 enter 方法。with语句运行结束后,会在上下文管理器对象上调用 exit 方法。

class A:

    def __init__(self, text):
        self.text = text

    def __enter__(self):  # 开启上下文管理器对象时触发此方法
        print('触发__enter__')
        self.text = self.text + '您来啦'
        return self  # 将实例化的对象返回f1

    def __exit__(self, exc_type, exc_val, exc_tb):  # 执行完上下文管理器对象f1时触发此方法
        print('触发__exit__')
        self.text = self.text + '这就走啦'


with A('大爷') as f1:
    print(f1.text)
print(f1.text)
#运行结果:
# 触发__enter__
# 大爷您来啦
# 触发__exit__
# 大爷您来啦这就走啦
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值