目录
0. 请写下这一节课你学习到的内容:格式不限,回忆并复述是加强记忆的好方式!
3. Python 的一些 BIF 很奇怪,但却十分有用。请问 property() 函数的作用是什么?
5. 通过自学【Python扩展阅读】Python 函数修饰符(装饰器)的使用,使用修饰符修改以下代码。
6. 你真的理解了修饰符的用法吗?那请你写出以下代码没有用上修饰符的等同形式:
7. 通过自学【Python扩展阅读】property 的详细使用方法,将第 4 题的代码修改为“使用属性修饰符创建描述符”的方式实现。
0. 请写下这一节课你学习到的内容:格式不限,回忆并复述是加强记忆的好方式!
今天我们谈谈和类与对象相关的BIF,也就是内置函数。
(一)issubclass(class, classinfo)
如果第一个参数 class 是第二个参数 classinfo 的子类,就返回 True,关于这个函数有几点需要注意的:
- 一个类被认为是其自身的子类
- classinfo 可以是类对象组成的元组,只要 class 是其中一个候选类的子类,就返回 True
(二)isinstance(object, classinfo)
检查一个实例对象 object 是否属于一个类 classinfo,关于这个函数有几点需要注意的:
- 如果第一个参数不是对象,则永远返回 False
- 如果第二个参数不是类或者由类对象组成的元组,则抛出一个 TypeError 异常
另外,Python 提供了几个BIF让我们访问对象的属性:
(三)hasattr(object, name) attr = attribute:属性。
测试一个对象是否有指定的属性。name 要用引号把属性名引起来。
>>> class C:
def __init__(self, x = 0):
self.x = x
>>> c1 = C()
>>> hasattr(c1, "x")
True
>>> hasattr(c1, x)
Traceback (most recent call last):
File "<pyshell#71>", line 1, in <module>
hasattr(c1, x)
NameError: name 'x' is not defined
(四)getattr(object, name[ , default] )
返回对象指定的属性值。如果指定的属性不存在,如果你有设置 default,它会把这个default 参数打印出来,否则会抛出一个AttributeError异常。
>>> class C:
def __init__(self, x = 0):
self.x = x
>>> c1 = C()
>>> getattr(c1, 'x')
0
>>> getattr(c1, 'y')
Traceback (most recent call last):
File "<pyshell#80>", line 1, in <module>
getattr(c1, 'y')
AttributeError: 'C' object has no attribute 'y'
>>> getattr(c1, 'y', '你所访问的属性不存在')
'你所访问的属性不存在'
(五)setattr(object, name, value)
设定对象中指定属性的值,如果指定的属性不存在,会新建一个新的属性,并给其赋值。
>>> setattr(c1, 'y', '来自江南的你')
>>> getattr(c1, 'y', '你所访问的属性不存在')
'来自江南的你'
(六)delattr(object, name)
删除对象中指定的属性,如果属性不存在,就抛出一个AttributeError异常。
俗话说,条条大路通罗马。Python 其实提供了好几个方式供你选择,property 是一个BIF,作用是通过属性设置属性,
property(fget = None, fset = None, fdel = None, doc = None)
property 函数的作用就是设置一个属性,这个属性就是去设置定义好的属性,它的第一个参数 fget 是获取属性的方法,第一个参数 fset 是设置属性的方法,第一个参数 fdel 是删除属性的方法。举例说明:
>>> class C:
def __init__(self, size = 10):
self.size = size
def getSize(self):
return self.size
def setSize(self, value):
self.size = value
def delSize(self):
del self.size
x = property(getSize, setSize, delSize)
>>> c1 = C()
>>> c1.x
10
>>> c1.getSize()
10
>>> c1.x = 18
>>> c1.getSize()
18
>>> c1.setSize(20)
>>> c1.x
20
>>> del c1.x
>>> c1.getSize()
Traceback (most recent call last):
File "<pyshell#104>", line 1, in <module>
c1.getSize()
File "<pyshell#94>", line 5, in getSize
return self.size
AttributeError: 'C' object has no attribute 'size'
property 的优势:举个例子,在上面这个例子中,这个程序慢慢写的很复杂了,有一天,你想把这个程序进行大改,把函数名进行改写,如果没有 property,那你提供给用户的调用接口就西药修改,就会降低用户体验,但是有了property,问题就不存在了,因为提供给用户的接口都是 x,程序里面无论如何修改,property里面的参数跟着改进行了,用户还是只用调用 x 来设置或者获取 size 属性就可以了。
测试题
0. 如何判断一个类是否为另一个类的子类?
答:使用 issubclass(class, classinfo) 函数,如果第一个参数(class)是第二个参数(classinfo)的一个子类,则返回 True,否则返回 False。
另外以下这些常识你应该知道:
- 一个类被认为是其自身的子类
- classinfo 可以是类对象组成的元祖,只要 class 与其中任何一个候选类的子类,则返回 True
- 在其他情况下,会抛出一个 TypeError 异常
1. 如何判断对象 a 是否为 类 A 的实例对象?
答:使用 isinstance(object, classinfo) 函数,如果第一个参数(object)是第二个参数(classinfo)的实例对象,则返回 True,否则返回 False。
另外以下这些常识你应该知道:
- 如果 objec t是 classinfo 的子类的一个实例,也符合条件
- 如果第一个参数不是对象,则永远返回False
- classinfo 可以是类对象组成的元祖,只要class与其中任何一个候选类的子类,则返回 True
- 如果第二个参数不是类或者由类对象组成的元祖,会抛出一个 TypeError 异常
2. 如何优雅地避免访问对象不存在的属性(不产生异常)?
答:有两种方法可以做到。
第一种先使用 hasattr(object, name) 函数判断属性是否存在,如果存在再访问(第一个参数(object)是对象,第二个参数(name)是属性名的字符串形式);
第二种方法是直接使用 getattr(object, name[, default]) 函数并设置 default 参数(返回对象指定的属性值,如果指定的属性不存在,返回default(可选参数)的值)。
3. Python 的一些 BIF 很奇怪,但却十分有用。请问 property() 函数的作用是什么?
答:property() 函数允许编程人员轻松、有效地管理属性访问。
4. 请补充以下代码,使程序可以正常运行:
class C:
def __init__(self, size=10):
self.size = size
def getXSize(self):
return self.size
def setXSize(self, value):
self.size = value
def delXSize(self):
del self.size
# 此处应该补充一句代码,程序才能正常运行
>>> c.x
10
>>> c.x = 12
>>> c.x
12
答:x = property(getXSize, setXSize, delXSize)
5. 通过自学【Python扩展阅读】Python 函数修饰符(装饰器)的使用,使用修饰符修改以下代码。
代码A:
class CodeA:
def foo():
print("调用静态方法 foo()")
# 将 foo() 方法设置为静态方法
foo = staticmethod(foo)
代码B:
class CodeB:
def foo(cls):
print("调用类方法 foo()")
# 将 foo() 方法设置为类方法
foo = classmethod(foo)
答:其实正是因为设置静态方法和类方法过于讨人吐槽,因此 Python 的作者才开发出了函数修饰符的形式替代。
代码A:
class CodeA:
@staticmethod
def foo():
print("调用静态方法 foo()")
代码B:
class CodeB:
@classmethod
def foo(cls):
print("调用类方法 foo()")
6. 你真的理解了修饰符的用法吗?那请你写出以下代码没有用上修饰符的等同形式:
@something
def f():
print("I love FishC.com!")
答:其实 Python 的修饰符就是一种优雅的封装,但要注意的是只可以在模块或类定义内对函数进行修饰,不允许修饰一个类。
一个修饰符就是一个函数,它将被修饰的函数做为参数,并返回修饰后的同名函数或其它可调用的东西。
@something
def f():
print("I love FishC.com!")
# 相当于
def f():
print("I love FishC.com!")
f = something(f)
7. 通过自学【Python扩展阅读】property 的详细使用方法,将第 4 题的代码修改为“使用属性修饰符创建描述符”的方式实现。
答:可能你还没听说过描述符(这个概念在你学完接下来的几节课自然会了解),但这一点都影响聪明的你修改这个程序。
代码清单:
class C:
def __init__(self, size=10):
self.size = size
@property
def x(self):
return self.size
@x.setter
def x(self, value):
self.size = value
@x.deleter
def x(self):
del self.size