第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.")

如果 cC 的实例化, 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
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

        # 此处应该补充一句代码,程序才能正常运行
    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)
代码A

答案:

 

 

代码B:

class CodeB:
    def foo(cls):
        print("调用类方法 foo()")

        # 将 foo() 方法设置为类方法
        foo = classmethod(foo)
代码B

 

答:其实正是因为设置静态方法和类方法过于讨人吐槽,因此 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

 

posted @ 2020-07-22 16:09  廖海清  阅读(241)  评论(0编辑  收藏  举报