常见的类的内置方法

__call__方法

### 默认情况下“对象是不可调用的”————后面不能加括号
### __call__方法可以让“对象变的可调用”

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

    def __call__(self, *args, **kwargs):
        print(self.name)
        print(args)
        print(kwargs)

if __name__ == '__main__':
    # 先实例化一个Foo的对象obj
    obj = Foo('HAHA')
    # 有了 __call__方法,obj后面可以“带参数调用”
    obj(1,2,3,a=1,b=2,c=3)
'''
# 调用对象 obj()  会触发 __call__方法。类的调用其实也是一个实例化的过程
HAHA
(1, 2, 3)
{'a': 1, 'b': 2, 'c': 3}
'''
'''
拓展理解:元类的内部也有一个__call__方法,会在调用类Foo的时候触发
'''

__del__析构函数

这个方法是在对象就要被垃圾回收之前调用,但是调用的时间是不可预测的,应该尽量避免使用!

# __del__
### 不调用__del__方法的话,会在程序结束后自动调用
### 自己主动调用的话会在调用的地方执行这个析构方法

class Open:
    print('加载类...')
    def __init__(self,file_name):
        self.file_name = file_name
        print('构造函数...')

    def __del__(self):
        print('析构函数...')

if __name__ == '__main__':
    print('main...')
    f = Open('whw.txt')
    print('do sth else...')
    ### 这里没有调用__del__方法,因为它会在程序执行结束自动执行!
'''
加载类...
main...
构造函数...
do sth else...
析构函数...
'''

__getattr__与__getattribute__方法

1、__getattr__:查找不到属性的时候进入这里(不考虑继承)。

2、__getattribute__:执行查找,无条件进入该魔法函数,即使查找的属性不存在(不考虑继承)。

#__getattr__, __getattribute__
#__getattr__ 就是在查找不到属性的时候调用

class User:
    def __init__(self,info={}):
        self.info = info

    #  查找不到属性的时候进入这里
    def __getattr__(self, item):
        return self.info[item]

    # 执行查找, 无条件进入该魔法函数, 即使所查找的属性不存在
    # def __getattribute__(self, item):
    #     return "火之影"

if __name__ == "__main__":
    user = User(info={"company_name":"china", "name":"whw"})

    ### 如果不注释__getattribute__会打印:
    """
    火之影
    火之影
    """
    print(user.company_name)
    print(user.my_name)

    ### 如果注释掉_getattribute__会:
    """
    1.有company_name会打印china
    2.没有my_name会报错
    """

__getattr__、__getattribute__与继承的关系

结论:优先使用双下划线的方法中的值!

#__getattr__, __getattribute__
#__getattr__ 就是在查找不到属性的时候调用

class UserBase:
    def __init__(self,age):
        self.age = age
        self.my_name = "Base"


class User(UserBase):
    def __init__(self,info={}):
        self.info = info
        super().__init__(info)

    #  查找不到属性的时候进入这里
    def __getattr__(self, item):
        return self.info[item]

    # 执行查找, 无条件进入该魔法函数, 即使所查找的属性不存在
    # def __getattribute__(self, item):
    #     return "火之影"

if __name__ == "__main__":
    user = User(info={"company_name":"china", "name":"whw"})

    ### 如果不注释__getattribute__会打印:———— 优先会调用自己的__getattribute__方法返回的数据!
    """
    火之影
    火之影
    """
    print(user.company_name)
    print(user.my_name)

    ### 如果注释掉__getattribute__会打印:
    """
    china
    Base
    """

__item__系列

# __setitem__   __getitem__  __delitem__

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

    def __getitem__(self, item):
        # return self.__dict__[item]
        return self.__dict__.get(item)

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

    def __delitem__(self, key):
        del self.__dict__[key]

if __name__ == '__main__':
    s1 = Student('whw',22,'male')
    # 可以像操作字典那样操作类的对象了
    print(s1['name'])#whw
    print(s1['age'])#22

    s1['name'] = 'wanghw'
    print(s1['name'])#wanghw

    del s1['age']
    print(s1.__dict__)#{'name': 'wanghw', 'sex': 'male'}

__getitem__与__len__

class Company(object):
    #魔法函数
    def __init__(self, employee_list):
        self.employee = employee_list

    def __getitem__(self, item):
        return self.employee[item]

    def __len__(self):
        return len(self.employee)


company = Company(["tom", "whw", "jane"])
#
# for i in company.employee:
#     print(i)

company1 = company[:2]
# 调用__len__方法
print(len(company)) # 3
# 调用__getitem__方法
for em in company1:
    print(em)
"""
tom
whw
"""

__new__方法1-1

# 在Python中,__new__是用来创造一个类的实例的,而__init__是用来初始化这个实例的

# 既然__new__用来创造实例,也就需要最后返回相应类的实例,那么如果返回的是其他类的实例,结果如何呢?
# 以下代码运行后,首先打印出NoReturn __new__然后打印出other instance,最后通过type(y)可以看到t的类型是<class '__main__.Other'>,
# 可以知道如果__new__中不返回本类的实例的话,是没法调用__init__方法的。

# 想要返回本类的实例,只需要把以下代码中12行的Other()改成super(NoReturn, cls).__new__(cls, *args, **kwargs)即可。
# 见1-2的代码~~

class Other(object):
    def __init__(self):
        print('other instance...')

class Myinstance(object):
    def __init__(self):
        print('my instance...')

    def __new__(cls, *args, **kwargs):
        print('Myinstance__new__...')
        return Other()

if __name__ == '__main__':
    my = Myinstance()
    print(type(my))
    '''
    Myinstance__new__...
    other instance...
    <class '__main__.Other'> ###### 注意这里是Other了!
    '''

__new__方法1-2

class Other(object):
    def __init__(self):
        print('other...')

class Myinstance(object):

    def __init__(self):
        print('my instance...')

    def __new__(cls, *args, **kwargs):
        print('new...')
        ### 下面这三种方法都可以
        # return super(Myinstance,cls).__new__(cls,*args,**kwargs)
        # return super().__new__(cls,*args,**kwargs)
        return object.__new__(cls)

if __name__ == '__main__':
    my = Myinstance()
    print(type(my))
    '''
    new...
    my instance...
    <class '__main__.Myinstance'>
    '''

__new__方法2

class Person(object):
    def __init__(self):
        print('__init__...实例化对象的时候调用')

    def __del__(self):
        print('__del__...程序结束调用')

    def __str__(self):
        return  '__str__...打印对象的时候调用'

    def __new__(cls, *args, **kwargs):
        print('__new__...我最先')
        return object.__new__(cls)
if __name__ == '__main__':
    p = Person()
    print(p)
'''
__new__...我最先
__init__...实例化对象的时候调用
__str__...打印对象的时候调用
__del__...程序结束调用
'''

__str__方法

# __str__方法

class Course:
    def __init__(self,name,price,period):
        self.name = name
        self.price = price
        self.period = period

    def __str__(self):
        return '课程 %s 的价格为:%s,周期为:%s'%(self.name,self.price,self.period)


if __name__ == '__main__':
    python = Course('Python',20000,'6 month')
    print(python.__str__()) # 课程 Python 的价格为:20000,周期为:6 month
    # 打印对象的时候,会自动触发实例化这个对象的类里的__str__方法
    # 一般return的是self.name。
    # 具体问题具体分析
    print(python) # 课程 Python 的价格为:20000,周期为:6 month

__str__方法与__repr__方法

# -*- coding:utf-8 -*-

class Course(object):
    def __init__(self,name,price):
        self.name = name
        self.price = price

    def __repr__(self):
        return f"name:{self.name},price:{self.price}"

    def __str__(self):
        return self.name

if __name__ == '__main__':
    python = Course("Python",2500)
    print(python)
    print(f"{python}")
    print(repr(python))
    print("详情:%r"%python)
    

""" # 如果str存在,repr也存在 # 那么print(obj)和使用字符串格式化format,%s这两种方式 调用的都是__str__ # 而repr(obj)和%r格式化字符串,都会调用__repr__ # 如果str不存在,repr存在 # 那么print(obj),字符串格式化format,%s,%r 和repr(obj)都调用__repr__ # 如果str存在,repr不存在 # 那么print(obj)和使用字符串格式化format,%s这两种方式 调用的都是__str__ # repr(obj)和%r格式化字符串 都会打印出内存地址 """

with上下文管理相关的方法 ***

with上下文管理 

class File:
    def __enter__(self):
        print('start')
return self
def __exit__(self, exc_type, exc_val, exc_tb): print('exit') with File() as f_obj: print('wahaha')

自定义文件操作的类

class myopen:
    def __init__(self,path,mode='r'):
        self.path = path
        self.mode = mode

    def __enter__(self):
        print('start')
        self.f = open(self.path,mode=self.mode)
        return self.f

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

with myopen('userinfo','a') as f:
    f.write('hello,world')

实例:pickle的dump与load的类

import pickle
class MypickleDump:
    def __init__(self,path,mode = 'ab'):
        self.path = path
        self.mode = mode

    def __enter__(self):
        self.f = open(self.path,self.mode)
        return self

    def dump(self,obj):
        pickle.dump(obj,self.f)

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.f.close()

with MypickleDump('pickle_file') as pickle_obj:
    pickle_obj.dump({1,2,3})
   

~~~

import pickle


class MypickelLoad:
    def __init__(self,path,mode='rb'):
        self.path = path
        self.mode = mode

    def __enter__(self):
        self.f = open(self.path,self.mode)
        return self

    def loaditer(self):
        while True:
            try:
                ret = pickle.load(self.f)
                yield ret
            except EOFError:
                break

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.f.close()

with MypickelLoad("pickle_file") as p2:
content = p2.loaditer()
for i in content:
print(i)

在一个函数前后添加功能

 with语句 就是和 __enter__,__exit__
import time
class Timer:
    def __enter__(self):
        self.start = time.time()
    def __exit__(self, exc_type, exc_val, exc_tb):
        print(time.time() - self.start)

def func():
    print('wahaha')
    time.sleep(1)
    print('qqxing')


with Timer():
    func()

~~

posted on 2020-02-11 21:52  江湖乄夜雨  阅读(198)  评论(0编辑  收藏  举报