本节中,我们将更深入地学习 Python 对面向对象的支持,学习很多可以减少必须编写的代码的总量、拓展程序的威力与功能的技术。下面以一个简单的类开始:
# 简单类定义
class Point:
__slots__ = ("x", "y")
def __init__(self, x=0, y=0):
self.x = x
self.y = y
__slots__
限制了 Point 能添加的属性只有 x 和 y 。下面测试一下:
pt = Point()
pt.x = 1
pt.y = 2
pt.z = 3
[out]
Traceback (most recent call last):
File "<ipython-input-1-88952c59b8ad>", line 11, in <module>
pt.z = 3
AttributeError: 'Point' object has no attribute 'z'
可以看出不能给 pt 中没有定义的属性赋值,下面去掉 __slots__
所在行:
class Point2:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
pt = Point2()
pt.x = 1
pt.y = 2
pt.z = 3
上面这段程序可以正常运行。
01.控制属性存取
控制属性存取
Python中定义了一些用于属性存取的特殊方法:
方法名称 | 使用 | 描述 |
---|---|---|
__delattr__(self, name) | del x.n | 删除对象x的属性 |
__dir__(self) | dir(x) | 返回x的属性名列表 |
__getattr__(self, name) | v = x.n | 返回对象x的n属性值 |
__getattribute__(self, name) | v = x.n | 返回对象x的n属性值 |
__setattr__(self, name) | x.n = v | 将对象x的n属性名值设为v |
__getattr__
与 __getattribute__
的主要区别:
__getattrobute__()
只要涉及到实例属性的访问就会调用该方法,如果属性不存在会抛出AttributeError
异常。__getattr__()
在以下情况下调用:dict
中;dict
中;AttributeError
异常时(不仅仅是get_attribute()
引发的异常,property中定义的get()
方法抛出的异常也会调用该方法。 3.当__getattr__
和__getattribute__
同时被定义时,要么显示在__getattribute__
中调用,要么抛出AttributeError
异常,否则__getattr__
永远不会被调用。
下面定义了一个简单的 “常数” 类,可以正常的设置任意属性,但如果想要去改变或者删除该属性,则会产生异常。
class Const:
def __setattr__(self, name, value):
if name in self.__dict__:
raise ValueError("cannot change a const attribute")
self.__dict__[name] = value
def __delattr__(self, name):
if name in self.__dict__:
raise ValueError("cannot delete a const attribute")
raise AttributeError("'{0}' object has no attribute '{1}'"
.format(self.__class__.__name__, name))
测试1:
# 尝试改变属性
const = Const()
const.limit = 51
const.limit = 20
[out]
Traceback (most recent call last):
File "<ipython-input-6-16721df7d195>", line 3, in <module>
const.limit = 20
File "<ipython-input-4-92afbeaa4fd4>", line 4, in __setattr__
raise ValueError("cannot change a const attribute")
ValueError: cannot change a const attribute
测试2:
# 尝试删除属性
del const.limit
[out]
Traceback (most recent call last):
File "<ipython-input-7-c88698f71e6c>", line 1, in <module>
del const.limit
File "<ipython-input-4-92afbeaa4fd4>", line 9, in __delattr__
raise ValueError("cannot delete a const attribute")
ValueError: cannot delete a const attribute
02.函子
在计算机科学中,函子是指一个对象,该对象可以向函数一样进行调用,在 Python 中,函子就是另一种类型的函数对象。任何包含了特殊方法 __call__()
的类都是一个函子。函子可以提供的关键好处是可以维护一些状态信息。
下面定义一个去除字符串末尾符号的函子:
# 函子
class Strip:
def __init__(self, characters):
self.characters = characters
def __call__(self, string):
return string.strip(self.characters)
使用示例:
st = Strip(',;:.!?')
result = st('Hello Python!')
print(result)
[out]
Hello Python
03.上下文管理器
前面的文件操作部分,已经见过 with open()
了,with 就是上下文管理器的标志。使用上下文管理器可以简化代码,这是通过确保某些操作在特定代码块执行前与执行后再进行来实现的。之所以可以做到这样,是因为上下文管理器提供了两个特殊方法 :__enter__()
和 __exit__()
。在 with 语句内创建上下文管理器时,其 __enter__()
方法会自动被调用,在 with 语句后、上下文管理器作用范围之外时,其__exit__()
方法会自动被调用。使用上下文管理器的语法如下:
with expression as variable:
suite
expression 部分必须是或者必须可以生成一个上下文管理器。
下面两个代码片段实现的功能一致,来体验一些上下文管理器的魅力吧:
filename = 'd:/open.txt'
# open 正常使用
content = ''
fh = None
try:
fh = open(filename)
for line in fh:
content += line
except EnvironmentError as err:
print(err)
finally:
if fh is not None:
fh.close()
# open 上下文管理器用法
content = ''
try:
with open(filename) as fh:
for line in fh:
content += line
except EnvironmentError as err:
print(err)
系列文章推荐
┣ Python指南:Python的8个关键要素
┣ Python指南:数据类型
┣ Python指南:组合数据类型
┣ Python指南:控制结构与函数
┣ Python指南:面向对象程序设计
┣ Python指南:文件处理
┣ Python指南:高级程序设计之过程型程序设计进阶