本专题主要是解决Pytorch框架下项目的数据预处理工作
Table of Contents:
1. HDF5文件简介
2. Python中的_, __, __xx__区别
3. Dataset类
4. DataLoader类
1. _xx 单下划线开头
Python中没有真正的私有属性或方法,可以在你想声明为私有的方法和属性前加上单下划线,以提示该属性和方法不应在外部调用。如果真的调用了也不会出错,但不符合规范。
2. __xx 双下划线开头
双下划线开头,有两个用处:
- 为了不让 子类 重写 父类 的属性或方法
- 不允许外部调用(即a.__method()是错误的)
class A:
def __method(self):
print('This is a method from class A')
def method(self):
return self.__method()
class B(A):
def __method(self):
print('This is a method from calss B')
a = A()
b = B()
a.method()
b.method()
请先独立思考一下为什么会是这样的输出?
- 由于class B 没有方法 method(),因此会继承 class A 中的 method()。
- 由于__开头的方法子类无法重写,所以子类仍然调用class A 中的 __method()。
如何实现子类仍然调用class A 中的 __method() 的呢?通过类的实例化时自动转换,在类中的双下划线开头的属性方法前加上”_类名”实现。
如果在 class B 中重写方法 method() 呢?会出现什么结果?
3. __xx__ 双下划线开头且结尾
__xx__ 经常是操作符或本地函数调用的magic methods(魔法方法),通常提供了一种重写类的操作符的功能。比如遍历迭代器对象,得根据数据本身重写迭代器对象来适配遍历函数。
在Python中,常见的对象类型有: number,string,tuple,dict,list,set,None。其中 tuple,string 是不可变容器,dict,list 是可变容器。
可变容器和不可变容器的区别在于,不可变容器一旦赋值后,不可对其中的某个元素进行修改。比如定义了 list1 = [1, 2, 3] 和 tuple1 = (1, 2, 3) 后, 执行 list1[0] = 0 是可以的,但执行 tuple1[0] = 0则会报错。
如果我们要自定义一些数据结构,使之能够跟以上的容器类型表现一样,那就需要去实现某些协议。这里的协议跟其他语言中所谓的"接口"概念很像,一样的需要你去实现才行,只不过没那么正式而已。
如果要自定义不可变容器类型,只需要定义__len__ 和 __getitem__方法;
如果要自定义可变容器类型,还需要在不可变容器类型的基础上增加定义__setitem__ 和 __delitem__;
如果你希望你的自定义数据结构还支持"可迭代", 那就还需要定义__iter__。
魔法方法说明:
- __len__(self):返回数值类型的结果,以表示容器的长度。该方法在可变容器和不可变容器中必须实现。
- __getitem__(self, key):当你执行 container[key] 的时候,调用的就是该方法。该方法在可变容器和不可变容器中也都必须实现。调用的时候,如果 key 的类型错误,该方法应该抛出TypeError;如果没法返回 key 对应的数值时,该方法应该抛出ValueError。注:key 可以是索引(index)
- __setitem__(self, key, value):当你执行 self[key] = value 时,调用的是该方法。
- __delitem__(self, key):当你执行 del self[key] 的时候,调用的是该方法。
- __iter__(self):该方法需要返回一个迭代器(iterator)。当你执行 for x in container: 或者使用iter(container) 时,该方法被调用。
- __reversed__(self):如果想要该数据结构被內建函数 reversed() 支持,就还需要实现该方法。
- __contains__(self, item):如果定义了该方法,那么在执行 item in container 或者 item not in container 时该方法就会被调用。如果没有定义,那么Python会迭代容器中的元素来一个一个比较,从而决定返回True或者False。
- __missing__(self, key):dict字典类型会有该方法,它定义了 key 如果在容器中找不到时触发的行为。比如d = {‘a’: 1}, 当你执行 d[notexist] 时,d.__missing__(‘notexist’)就会被调用。
现以构造自定义类型对象(即容器container)为例:
enumerate(container)返回索引与数值, 即 index 与 container[index], 所以你得在你的__getitem__(self, key):中定义好 container[index] 的返回值,其中 key(index) 可以是参数。
class Con:
def __init__(self, values=None):
if values is None:
self.values = []
else:
self.values = values
def __len__(self):
return len(self.values)
def __getitem__(self, key):
return self.values[key]
def __setitem__(self, key, value):
self.values[key] = value
def __delitem__(self, key):
del self.values[key]
def __iter__(self):
return iter(self.values)
c = Con([0, 1, 2, 3,4])
for i, data in enumerate(c):
print(data)
注:之所以没实现 __iter__(self):方法是因为 enumerate( c ) 中的 c 是一个可遍历对象,如果要想把 c 变成一个可迭代对象,还得实现 __iter__(self):方法。
在特殊的情况下,它只是python调用的hook。例如,__init__()函数是当对象被创建初始化时调用的;__new__()是用来创建实例。
推荐阅读: