python—类的继承——定制类

python中继承一个类

class Person(object):
    def __init__(self, name, gender):
        self.name = name
        self.gender = gender

定义Student类时,只需要把额外的属性加上,例如score:

class Student(Person):
    def __init__(self, name, gender, score):
        super(Student, self).__init__(name, gender)
        self.score = score

一定要用 super(Student, self).__init__(name, gender) 去初始化父类否则,
继承自 PersonStudent 将没有 namegender
函数super(Student, self)将返回当前类继承的父类,即 Person ,然后调用__init__()方法,
注意self参数已在super()中传入,在__init__()中将隐式传递,不需要写出(也不能写)。
 

python中判断类型

函数isinstance()可以判断一个变量的类型,既可以用在Python内置的数据类型如str、list、dict,也可以用在我们自定义的类,它们本质上都是数据类型。

 print isinstance(t,Person)
print isinstance(t,object)
print isinstance(t,Student)
print isinstance(t,Teacher)

一个父类的实例不能是子类类型,因为子类比父类多了一些属性和方法。

一个实例可以看成它本身的类型,也可以看成它父类的类型。

 

python中多态

sStudent类型,它实际上拥有自己的 whoAmI()方法以及从 Person继承的 whoAmI方法,但调用 s.whoAmI()总是先查找它自身的定义,如果没有定义,则顺着继承链向上查找,直到在某个父类中找到为止。

 

Python提供了open()函数来打开一个磁盘文件,并返回 File 对象。File对象有一个read()方法可以读取文件内容:

例如,从文件读取内容并解析为JSON结果:

import json
f = open('/path/to/file.json', 'r')
print json.load(f)

由于Python的动态特性,json.load()并不一定要从一个File对象读取内容。任何对象,只要有read()方法,就称为File-like Object,都可以传给json.load()

请尝试编写一个File-like Object,把一个字符串 r'["Tim", "Bob", "Alice"]'包装成 File-like Object 并由 json.load() 解析:

 

import json
class Students(object):
    def read(self):
        return r'["Tim", "Bob", "Alice"]'
s = Students()
print json.load(s)

 

 

python中多重继承

除了从一个父类继承外,Python允许从多个父类继承,称为多重继承

 
class Person(object):
    pass
class Student(Person):
    pass
class Teacher(Person):
    pass
class SkillMixin(object):
    pass
class BasketballMixin(SkillMixin):
    def skill(self):
        return 'basketball'
class FootballMixin(SkillMixin):
    def skill(self):
        return 'football'
class BStudent(Student,BasketballMixin):
    pass
class FTeacher(Teacher,FootballMixin):
    pass
s = BStudent()
print s.skill()
t = FTeacher()
print t.skill()
 

python中获取对象信息

 

拿到一个变量,除了用 isinstance() 判断它是否是某种类型的实例外,还有没有别的方法获取到更多的信息呢?

 

 可以用 dir() 函数获取变量的所有属性

    class Person(object):
            address = 'Earth'
            def __init__(self,name):
                     self.name=name
     p=Person('test')

     Person.age=25
     print (p.age)

 

     print ("dir:",dir(p))

     

>>> dir(s)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__',
'__hash__', '__init__', '__module__',
'__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__',
'__sizeof__', '__str__', '__subclasshook__', '__weakref__',
'gender', 'name', 'score', 'whoAmI']

     如何去掉`__xxx__`这类的特殊属性,只保留我们自己定义的属性?回顾一下filter()函数的用法

 

   

class Person(object):
    def __init__(self, name, gender, **kw):
        self.name=name
        self.gender=gender
        for k,v in kw.items():
            setattr(self, k, v)
p = Person('Bob', 'Male', age=18, course='Python')
print getattr(p, 'age')
print p.course

 

 python中什么是特殊方法

 

   特殊方法是定义在class中的

   不需要直接去调这些特殊的方法

    python的某些函数或者操作符回去自动调用相应的特殊方法

 

 

python中 __str__和__repr__

如果要把一个类的实例变成 str,就需要实现特殊方法__str__()

 

 
class Person(object):
    def __init__(self, name, gender):
        self.name = name
        self.gender = gender
    def __str__(self):
        return '(Person: %s, %s)' % (self.name, self.gender)

>>> p = Person('Bob', 'male')
>>> print p
(Person: Bob, male)
 

python中 __cmp__

对 intstr 等内置数据类型排序时,Python的 sorted() 按照默认的比较函数 cmp 排序,但是,如果对一组 Student 类的实例排序时,就必须提供我们自己的特殊方法 __cmp__():

 
class Student(object):
    def __init__(self, name, score):
        self.name = name
        self.score = score
    def __str__(self):
        return '(%s: %s)' % (self.name, self.score)
    __repr__ = __str__
    def __cmp__(self, s):
        if self.score <s.score:
            return 1
        elif self.score > s.score:
            return -1
        else:
            if self.name < s.name:
                return -1
            elif self.name > s.name:
                return 1
        return 0
 
 
class Student(object):
    def __init__(self, name, score):
        self.name = name
        self.score = score

    def __str__(self):
        return '(%s: %s)' % (self.name, self.score)

    __repr__ = __str__

    def __cmp__(self, s):
        if self.score == s.score:
            return cmp(self.name, s.name)
        return -cmp(self.score, s.score)
 
 

python中 __len__

如果一个类表现得像一个list,要获取有多少个元素,就得用 len() 函数。

要让 len() 函数工作正常,类必须提供一个特殊方法__len__(),它返回元素的个数。

 

 

 

例如,我们写一个 Students 类,把名字传进去:

class Students(object):
    def __init__(self, *args):
        self.names = args
    def __len__(self):
        return len(self.names)

只要正确实现了__len__()方法,就可以用len()函数返回Students实例的“长度”:

>>> ss = Students('Bob', 'Alice', 'Tim')
>>> print len(ss)
3


需要根据num计算出斐波那契数列的前N个元素
class Fib(object):
    def __init__(self, num):
        self.num = num
        self.L = [0,1]
        for n in range(num-2):
            next_num = self.L[n]+self.L[n+1]
            self.L.append(next_num)
       
    def __str__(self):
        return str(self.L)
       
    def __len__(self):
        return self.num
>>>f = Fib(10)
>>>print f
 
方法二:
     
def __init__(self, num):
        a, b, L = 0, 1, []
        for n in range(num):
            L.append(a)
            a, b = b, a + b
        self.numbers = L



 

python中 @property

 给属性赋值怎么检查分数的有效性:

class Student(object):
    def __init__(self, name, score):
        self.name = name
        self.__score = score
    def get_score(self):
        return self.__score
    def set_score(self, score):
        if score < 0 or score > 100:
            raise ValueError('invalid score')
        self.__score = score

这样, s.set_score(1000) 就会报错。


这种使用 get/set 方法来封装对一个属性的访问在许多面向对象编程的语言中都很常见。

但是写 s.get_score()s.set_score() 没有直接写 s.score 来得直接。

有没有两全其美的方法?----有。

因为Python支持高阶函数,在函数式编程中我们介绍了装饰器函数,可以用装饰器函数把 get/set 方法“装饰”成属性调用:


class Student(object):
    def __init__(self, name, score):
        self.name = name
        self.__score = score
    @property
    def score(self):
        return self.__score
    @score.setter
    def score(self, score):
        if score < 0 or score > 100:
            raise ValueError('invalid score')
        self.__score = score

>>> s = Student('Bob', 59)
>>> s.score = 60
>>> print s.score
60
>>> s.score = 1000
Traceback (most recent call last):
  ...
ValueError: invalid score


如果没有定义set方法,就不能对“属性”赋值,这时,就可以创建一个只读“属性”。
 

python中 __slots__

由于Python是动态语言,任何实例在运行期都可以动态地添加属性。

如果要限制添加的属性,例如,Student类只允许添加 name、genderscore 这3个属性,就可以利用Python的一个特殊的__slots__来实现。

顾名思义,__slots__是指一个类允许的属性列表:

__slots__的目的是限制当前类所能拥有的属性,如果不需要添加任意动态的属性,使用__slots__也能节省内存。

 
class Student(object):
    __slots__ = ('name', 'gender', 'score')
    def __init__(self, name, gender, score):
        self.name = name
        self.gender = gender
        self.score = score


>>> s = Student('Bob', 'male', 59)
>>> s.name = 'Tim' # OK
>>> s.score = 99 # OK
>>> s.grade = 'A'
Traceback (most recent call last):
  ...
AttributeError: 'Student' object has no attribute 'grade'



class Person(object):
    __slots__ = ('name', 'gender')
    def __init__(self, name, gender):
        self.name = name
        self.gender = gender
class Student(Person):
    __slots__ = ('score')
    def __init__(self,score,name,gender):
        super(Student,self).__init__(name, gender)
        self.score=score
s = Student('Bob', 'male', 59)
s.name = 'Tim'
s.score = 99
print s.score


 

python中 __call__

 

在Python中,函数其实是一个对象:

>>> f = abs
>>> f.__name__
'abs'
>>> f(-123)
123

由于 f 可以被调用,所以,f 被称为可调用对象。

所有的函数都是可调用对象。

一个类实例也可以变成一个可调用对象,只需要实现一个特殊方法__call__()

 

我们把 Person 类变成一个可调用对象:

class Person(object):
    def __init__(self, name, gender):
        self.name = name
        self.gender = gender

    def __call__(self, friend):
        print 'My name is %s...' % self.name
        print 'My friend is %s...' % friend

现在可以对 Person 实例直接调用:

>>> p = Person('Bob', 'male')
>>> p('Tim')
My name is Bob...
My friend is Tim...

单看 p('Tim') 你无法确定 p 是一个函数还是一个类实例,所以,在Python中,函数也是对象,对象和函数的区别并不显著。

 

class Fib(object):
    def __call__(self,num):
        a,b,L=0,1,[]
        for n in range(num):
            L.append(a)
            a,b=b,a+b
        return L
f = Fib()
print f(10)
   

 

posted on 2020-05-27 20:08  肉松蛋卷  阅读(233)  评论(0编辑  收藏  举报