第040讲:类和对象:一些相关的BIF
#搬运自FishC论坛,该系列已完结,共有00~96节,本人学习过程中的记录等。
#FishC论坛:http://bbs.fishc.com/forum.php
#小甲鱼课程规划帖:http://bbs.fishc.com/thread-1053-1-1.html 此教程适合完全零基础的朋友学习,
课题笔记
issubclass()函数
issubclass()方法用于判断参数 class 是否是类型参数 classinfo 的子类。issubclass(class, classinfo),如果 class 是 classinfo 的子类返回 True,否则返回 False。
它这种检查是属于非严格的检查,1、一个类,他会被认为是自身的子类;2、classinfo可以是类对象组成的元组,只要class是与其中一个候选类的子类,则返回True,一个一个检索过去,其他类型就会抛出Type Error
>>> class A: pass >>> class B: pass >>> issubclass(B, A) False >>> class B(A): pass >>> issubclass(B, A) True >>> issubclass(B, B) True >>> issubclass(B, object) True >>> #object是所有类的一个基类
isinstance() 函数
isinstance() 函数来判断一个对象是否是一个已知的类型,类似 type()。
isinstance() 与 type() 区别:
type() 不会认为子类是一种父类类型,不考虑继承关系。
isinstance() 会认为子类是一种父类类型,考虑继承关系。
如果要判断两个类型是否相同推荐使用 isinstance()。
用法:isinstance(object, classinfo) object -- 实例对象,classinfo -- 可以是直接或间接类名、基本类型或者由它们组成的元组。
注意:1、如果第一个参数不是对象,则永远返回False;2、如果第二个参数不是由类对象组成的元组,会抛出个TypeError异常。
hasattr() 函数
hasattr() 函数用于判断对象是否包含对应的属性。语法:hasattr(object, name),object -- 对象。name -- 字符串,属性名。如果对象有该属性返回 True,否则返回 False。
getattr() 函数
getattr()函数用于返回一个对象属性值。语法:getattr(object, name[, default]) object -- 对象,name -- 字符串,对象属性,default -- 默认返回值,如果不提供该参数,在没有对应属性时,将触发 AttributeError。返回对象属性值。例子:
>>>class A(object): ... bar = 1 ... >>> a = A() >>> getattr(a, 'bar') # 获取属性 bar 值 1 >>> getattr(a, 'bar2') # 属性 bar2 不存在,触发异常 Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'A' object has no attribute 'bar2' >>> getattr(a, 'bar2', 3) # 属性 bar2 不存在,但设置了默认值 3 >>>
setattr() 函数
setattr() 函数对应函数 getattr(),用于设置属性值,该属性不一定是存在的。语法:setattr(object, name, value) object -- 对象,name -- 字符串,对象属性,value -- 属性值。无返回值。例子:
对已存在的属性进行赋值:
>>>class A(object): ... bar = 1 ... >>> a = A() >>> getattr(a, 'bar') # 获取属性 bar 值 1 >>> setattr(a, 'bar', 5) # 设置属性 bar 值 >>> a.bar 5
如果属性不存在会创建一个新的对象属性,并对属性赋值:
>>>class A(): ... name = "runoob" ... >>> a = A() >>> setattr(a, "age", 28) >>> print(a.age) 28 >>>
delattr() 函数
delattr 函数用于删除属性。delattr(x, 'foobar') 相等于 del x.foobar。语法:delattr(object, name) object -- 对象,name -- 必须是对象的属性。无返回值。例子:
#!/usr/bin/python # -*- coding: UTF-8 -*- class Coordinate: x = 10 y = -5 z = 0 point1 = Coordinate() print('x = ',point1.x) print('y = ',point1.y) print('z = ',point1.z) delattr(Coordinate, 'z') print('--删除 z 属性后--') print('x = ',point1.x) print('y = ',point1.y) # 触发错误 print('z = ',point1.z)
结果:
('x = ', 10) ('y = ', -5) ('z = ', 0) --删除 z 属性后-- ('x = ', 10) ('y = ', -5) Traceback (most recent call last): File "test.py", line 22, in <module> print('z = ',point1.z) AttributeError: Coordinate instance has no attribute 'z'
property() 函数
property() 函数的作用是在新式类中返回属性值。用属性来设置属性。语法:class property([fget[, fset[, fdel[, doc]]]]) or property(fget = None, fset = None, fdel = None, doc = None)
参数:fget -- 获取属性值的函数;fset -- 设置属性值的函数;fdel -- 删除属性值函数;doc -- 属性描述信息
返回新式类属性。
property()这个函数的作用就是设置一个属性,这个属性的作用是去设置定义好的属性。x如何设置属性,你必须传入写好的方法,第一个属性是获取属性的方法,第二个是设置属性的方法,第三是删除属性的方法,第四个就文档。c1.x 就会执行第一个参数的内容,就是获取方法了,c1.x = .. 等于什么的时候就会调用第二个方法。小甲鱼例子:
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.getSize() 10 >>> c1.x 10 >>> c1.x = 18 >>> c1.x 18 >>> c1.size 18 >>> c1.getSize() 18 >>> del c1.x >>> c1.size Traceback (most recent call last): File "<pyshell#19>", line 1, in <module> c1.size AttributeError: 'C' object has no attribute 'size' >>>
菜鸟教程例子:
定义一个可控属性值 x:
class C(object): def __init__(self): self._x = None def getx(self): return self._x def setx(self, value): self._x = value def delx(self): del self._x x = property(getx, setx, delx, "I'm the 'x' property.")
如果 c 是 C 的实例化, c.x 将触发 getter 就是property的第一个参数,第一个参数的方法是getattr;而c.x = value 将触发 setter 就是第二个方法,设置; del c.x 触发 deleter。
如果给定 doc 参数,其将成为这个属性值的 docstring,否则 property 函数就会复制 fget 函数的 docstring(如果有的话)。
这段装饰器的还不会!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
将 property 函数用作装饰器可以很方便的创建只读属性:
class Parrot(object): def __init__(self): self._voltage = 100000 @property def voltage(self): """Get the current voltage.""" return self._voltage
上面的代码将 voltage() 方法转化成同名只读属性的 getter 方法。
property 的 getter,setter 和 deleter 方法同样可以用作装饰器:
class C(object): def __init__(self): self._x = None @property def x(self): """I'm the 'x' property.""" return self._x @x.setter def x(self, value): self._x = value @x.deleter def x(self): del self._x
这个代码和第一个例子完全相同,但要注意这些额外函数的名字和 property 下的一样,例如这里的 x。
课后测试题及答案
测试题:
0. 如何判断一个类是否为另一个类的子类?
使用issubclass()函数,例如issubclass(A, B),A是否是B的子类呢
答:使用 issubclass(class, classinfo) 函数,如果第一个参数(class)是第二个参数(classinfo)的一个子类,则返回 True,否则返回 False。
另外以下这些常识你应该知道:
1、一个类被认为是其自身的子类
2、classinfo 可以是类对象组成的元祖,只要 class 与其中任何一个候选类的子类,则返回 True
3、在其他情况下,会抛出一个 TypeError 异常
1. 如何判断对象 a 是否为 类 A 的实例对象?
使用isinstance()函数
答:使用 isinstance(object, classinfo) 函数,如果第一个参数(object)是第二个参数(classinfo)的实例对象,则返回 True,否则返回 False。
另外以下这些常识你应该知道:
1、如果 objec t是 classinfo 的子类的一个实例,也符合条件
2、如果第一个参数不是对象,则永远返回False
3、classinfo 可以是类对象组成的元祖,只要class与其中任何一个候选类的子类,则返回 True
4、如果第二个参数不是类或者由类对象组成的元祖,会抛出一个 TypeError 异常
2. 如何优雅地避免访问对象不存在的属性(不产生异常)?
使用hasattr()
答:有两种方法可以做到。第一种先使用 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
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 # 此处应该补充一句代码,程序才能正常运行 x = property(getXSize, setXSize, delXSize)#property的参数是字符串,方法名就ok了 # >>> c.x # 10 # >>> c.x = 12 # >>> c.x # 12
答:x = property(getXSize, setXSize, delXSize)
5. 通过自学【扩展阅读】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. 通过自学【扩展阅读】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
作者:Agiroy_70
本博客所有文章仅用于学习、研究和交流目的,欢迎非商业性质转载。
博主的文章主要是记录一些学习笔记、作业等。文章来源也已表明,由于博主的水平不高,不足和错误之处在所难免,希望大家能够批评指出。
博主是利用读书、参考、引用、抄袭、复制和粘贴等多种方式打造成自己的文章,请原谅博主成为一个无耻的文档搬运工!