Python Cookbook学习记录
2020-01-31 21:16
399 查看
8.类与对象
8.1修改实例变量的字符串表示
''' 对于__repr__()标准做法是让他产生的字符串文本能够满足eval(repr(x))=x 若不想这么做,通常让他产生一段有意义的文本,并且以<和>括起来 ''' class Pair(object): def __init__(self, x, y): self.x=x self.y=y def __str__(self): return '({0.x!s}, {0.y!s})'.format(self) #特殊方法__repr__()返回的是实例的代码表示,通常可以用它返回的字符串 #文本来重新创建这个实例既满足obj=eval(repr(obj)) #repr在交互式解释环境时会返回字符串 def __repr__(self): #格式化代码0.x用来指代参数0的x属性因此在下面的函数中0实际代表着self return 'Pair({0.x!r}, {0.y!r})'.format(self) #str print(Pair(3, 4)) p = Pair(3, 4) #特殊的格式化代码!r表示应该使用__repr__()的输出而不是默认的__str__()的输出 print('p is {0!r}'.format(p)) print('p is {0}'.format(p))
8.2自定义字符串的输出格式
''' 要定义字符串的输出格式,可以在类中定义___format__()方法 ''' _formats = { 'ymd': '{d.year}-{d.month}-{d.day}', 'mdy': '{d.month}-{d.day}-{d.year}', 'dmy': '{d.day}-{d.month}-{d.year}' } class Date: def __init__(self, year, month, day): self.year = year self.month = month self.day = day def __format__(self, code): if code == '': code = 'ymd' fmt = _formats[code] return fmt.format(d=self) d = Date(2012, 12, 21) print(format(d)) print(format(d, 'mdy')) print('The date is {:ymd}'.format(d)) print('The date is {:mdy}'.format(d))
8.3让对象支持上下文管理
''' 要让对象能够兼容with语句,需要实现__enter__()和__exit__()方法 当遇到with语句时,__enter__()方法首先被触发执行。__enter__()的返回值被 放置在由as限定的变量中。之后开始执行with代码块中的语句,最后__exit__()方法 被触发执行清理工作 ''' from socket import socket, AF_INET, SOCK_STREAM class LazyConnection: def __init__(self, address, family=AF_INET, type=SOCK_STREAM): self.address = address self.family = AF_INET self.type = SOCK_STREAM self.sock = None def __enter__(self): if self.sock is not None: raise RuntimeError('Already connected') self.sock = socket(self.family, self.type) self.sock.connect(self.address) return self.sock def __exit__(self, exc_type, exc_val, exc_tb): self.sock.close() self.sock = None from functools import partial conn = LazyConnection(('www.python.org', 80)) with conn as s: s.send(b'GET /index.html HTTP/1.0\r\n') s.send(b'Host: www.python.org\r\n') s.send(b'\r\n') resp = b''.join(iter(partial(s.recv, 8192), b''))
8.4当创建大量实例时如何节省内存
''' 在类中添加__slots__属性 当定义了__slots__属性,python不再让每个实例都创建一个__dict__字典, 现在的实例是围绕着一个固定长度的小型数组来构建的,这和一个元祖或列表很相似 在__slots__中列出的属性名会在内部映射到这个数组的特定索引上,副作用是没法再 对实例添加任何型的属性,限制为只允许使用__slots__属性中列出的属性名 ''' class Date: __slots__ = ['year', 'month', 'day'] def __init__(self, year, month, day): self.year = year self.month = month self.day = day
8.5把名称封装到类中
class A: def __init__(self): #以特定的命名规则来限制访问 #内部访问,子类也能访问 self._internal = 0 self.public = 1 def public_method(self): pass def _internal_method(self): pass class B: def __init__(self): #以双下划线打头的名称会导致出现名称重整的行为,具体就是__private #会被重名为_B__private,__private_method会被重命名为_B__private_method #双下划线规定私有,子类也不能访问即不能通过继承而覆盖 self.__private = 0 def __private_method(self): pass def public_method(self): pass class C(B): def __init__(self): super(C, self).__init__() self.__private = 1 #并没有重写B中的__private, 这是_C__private def __private_method(self): pass #定义一个变量,可能会和保留字冲突,应该在变量名后加下划线 lambda_ = 2
8.6创建可管理的属性
#要自定义对属性的访问,一种简单的方式是将定义为property #即把类中的方法当做一种属性来使用 class Person: def __init__(self, first_name): #调用setter方法 #property会在设置属性时进行类型检查,所以下面会调用setter self.first_name = first_name #getter函数,获取属性 @property def first_name(self): return self._first_name #除非first_name已经通过@property方式定义为了property属性 #否则是不能定义@first_name.setter和@first_name.deleter装饰器的 @first_name.setter def first_name(self, value): if not isinstance(value, str): raise TypeError('Expected a string') self._first_name = value @first_name.deleter def first_name(self): raise AttributeError("Can't delete attribute") #property看起来就像一个普通的属性,但是根据访问它的方式不同会自动 #触发getter、setter和deleter方法 a = Person('Guido') print(a.first_name) #a.first_name=43 Error #del a.first_name Error #已经存在的get和set方法,也可以将它们定义为property class Person1: def __init__(self, first_name): self.set_first_name(first_name) def get_first_name(self): return self._first_name def set_first_name(self, value): if not isinstance(value, str): raise TypeError('Expected a string') self._first_name = value def delete_first_name(self): raise AttributeError("Can't delete attribute") name = property(get_first_name, set_first_name, delete_first_name) per = Person1('Guido') print(per.name) per.name = 'James' print(per.name)
- 点赞
- 收藏
- 分享
- 文章举报
相关文章推荐
- Python Cookbook学习记录 ch1_2_2013/10/21
- Python Cookbook学习记录 ch6_3_2013/11/7
- Python Cookbook学习记录 ch1_13_2013/10/24
- Python Cookbook学习记录 ch6_1_2013/11/6
- Python Cookbook学习记录 ch1_1_2013/10/20
- Python Cookbook学习记录 ch1_14_2013/10/25
- Python Cookbook学习记录 ch4_1-5_2013/11/2
- Python Cookbook学习记录 ch4_8-16_2013/11/2
- Python Cookbook学习记录 ch1_4_2013/10/22
- Python Cookbook学习记录 ch2_1_2013/10/27
- Python Cookbook学习记录 ch1_15_2013/10/25
- Python Cookbook学习记录 ch2_6/7/8_2013/10/27
- Python Cookbook学习记录 ch1_17_2013/10/25
- Python Cookbook学习记录 ch4_6/7_2013/11/2
- Python Cookbook学习记录 ch1_3_2013/10/21
- Python Cookbook学习记录 ch3_1/2_2013/10/29
- Python Cookbook学习记录 ch3_5/8_2013/10/30
- Python Cookbook学习记录 ch1_9_2013/10/23
- Python Cookbook学习记录 ch1_12_2013/10/24
- Python Cookbook学习记录 ch1_5_2013/10/22