您的位置:首页 > 编程语言 > Python开发

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)
  • 点赞
  • 收藏
  • 分享
  • 文章举报
zshzsh2 发布了15 篇原创文章 · 获赞 0 · 访问量 134 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: