2.4python中继承

继承中不要忘了调用super().__init__

def __init__(self,args)
super(subclass,self).__init___(args) #初始化父类
pass
例:

定义一个person类

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
定义一个teacher类,添加额外属性course

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

t = Teacher('Alice', 'Female', 'English')
print t.name
print t.course

>>>Alice
English

2.5判断类型

函数isinstance()可以判断一个变量的类型,如内置的数据类型:str、list、dict,也可以用我们自定义的类。

例:person、student、teacher的定义和继承关系如下

class Person(object):
def __init__(self, name, gender):
self.name = name
self.gender = gender
class student(person):
def __init__(self,name,gender,score):
super(student,self).__init__(name,gender)
self.score=score
class Teacher(Person):
def __init__(self, name, gender, course):
super(Teacher, self).__init__(name, gender)
self.course = course
p = Person('Tim', 'Male')
s = Student('Bob', 'Male', 88)
t = Teacher('Alice', 'Female', 'English')

>>> isinstance(p, Person)
True # p是Person类型
>>> isinstance(p, Student)
False # p不是Student类型
>>> isinstance(p, Teacher)
False # p不是Teacher类型

>>> isinstance(s, Person)
True # s是Person类型
>>> isinstance(s, Student)
True # s是Student类型
>>> isinstance(s, Teacher)
False # s不是Teacher类型

总结:一个父类的实例不能是子类类型,所以子类比父类多一些属性和方法;一个实例可以看成它本身的类型,也可以看成它父类的类型

2.6多态

例:

class Person(object):
def __init__(self, name, gender):
self.name = name
self.gender = gender
def whoAmI(self):
return 'I am a Person, my name is %s' % self.name

class Student(Person):
def __init__(self, name, gender, score):
super(Student, self).__init__(name, gender)
self.score = score
def whoAmI(self):
return 'I am a Student, my name is %s' % self.name

class Teacher(Person):
def __init__(self, name, gender, course):
super(Teacher, self).__init__(name, gender)
self.course = course
def whoAmI(self):
return 'I am a Teacher, my name is %s' % self.name

def who_am_i(x):
print x.whoAmI()

p = Person('Tim', 'Male')
s = Student('Bob', 'Male', 88)
t = Teacher('Alice', 'Female', 'English')

who_am_i(p)
who_am_i(s)
who_am_i(t)

>>>I am a Person, my name is Tim
I am a Student, my name is Bob
I am a Teacher, my name is Alice
说明:s 是Student类型,它实际上拥有自己的 whoAmI()方法以及从 Person继承的 whoAmI方法,但调用 s.whoAmI()总是先查找它自身的定义,如果没有定义,则顺着继承链向上查找,直到在某个父类中找到为止。

python是动态语言,所以传递给who_ami(x)的参数不一定是person或person的子类型。任何数据类型的实例都可以。只要它有who_ami()的方法即可。

class Book(object):
def whoAmI(self):
return 'I am a book'

2.7多重继承

python允许从多个父类继承,为多重继承

例:

class A(object):
def __init__(self, a):
print 'init A...'
self.a = a

class B(A):
def __init__(self, a):
super(B, self).__init__(a)
print 'init B...'

class C(A):
def __init__(self, a):
super(C, self).__init__(a)
print 'init C...'

class D(B, C):
def __init__(self, a):
super(D, self).__init__(a)
print 'init D...'

>>>d = D('d')
init A...
init C...
init B...
init D...

说明:D 同时继承自 B 和 C,也就是 D 拥有了 A、B、C 的全部功能。多重继承通过 super()调用__init__()方法时,A 虽然被继承了两次,但__init__()只调用一次

多重继承的目的:从两种继承树中分别选择并继承出子类,以便组合功能使用

2.8获取对象信息

例:

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

class Student(Person):
def __init__(self, name, gender, score):
super(Student, self).__init__(name, gender)
self.score = score
def whoAmI(self):
return 'I am a Student, my name is %s' % self.name
>>> type(123) #用 type() 函数获取变量的类型返回一个 Type 对象
<type 'int'>
>>> s = Student('Bob', 'Male', 88)
>>> type(s) #用 type() 函数获取变量的类型返回一个 Type 对象
<class '__main__.Student'>
 dir() 函数获取变量的所有属性

>>> dir(123) # 整数也有很多属性...
['__abs__', '__add__', '__and__', '__class__', '__cmp__', ...]

>>> 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__`这类的特殊属性,只保留我们自己定义的属性

>>> getattr(s, 'name') # 获取name属性
'Bob'

>>> setattr(s, 'name', 'Adam') # 设置新的name属性

>>> s.name
'Adam'

>>> getattr(s, 'age') # 获取age属性,但是属性不存在,报错:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute 'age'

>>> getattr(s, 'age', 20) # 获取age属性,如果属性不存在,就返回默认值20:
20

2.9特殊方法

特殊方法的特点:特殊方法定义在class中;不需要直接调用;python的某些函数或操作符会自动调用对应的特殊方法

正确实现特殊方法:只需要编写用到的特殊方法;有关联性的特殊方法都必须实现(__getattr__,setattr__,delattr__)

3.0 __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)
>>> p
<main.Person object at 0x10c941890>
Python 定义了__str__()和__repr__()两种方法,__str__()用于显示给用户,而__repr__()用于显示给开发人员。

例:定义__repr__

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)
__repr__ = __str__

3.1 __cmp__

对于int、str等内置数据类型排序,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.name < s.name:
return -1
elif self.name > s.name:
return 1
else:
return 0
说明: Student 类实现了__cmp__()方法,__cmp__用实例自身self和传入的实例 s 进行比较,如果 self 应该排在前面,就返回 -1,如果 s 应该排在前面,就返回1,如果两者相当,返回 0。

>>> L = [Student('Tim', 99), Student('Bob', 88), Student('Alice', 77)]
>>> print sorted(L)
[(Alice: 77), (Bob: 88), (Tim: 99)]
注意: 如果list不仅仅包含 Student 类,则 __cmp__ 可能会报错:

L = [Student('Tim', 99), Student('Bob', 88), 100, 'Hello']
print sorted(L)
例:修改 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 cmp(self.name, s.name) #cmp()函数默认是由低到高
    return -cmp(self.score, s.score)

L = [Student('Tim', 99), Student('Bob', 88), Student('Alice', 99)]
print sorted(L)
>>>[(Alice: 99), (Tim: 99), (Bob: 88)]

3.2 __len__

如果一个类表现得像一个list,要获取有多少个元素,就得用 len() 函数。类必须提供一个特殊方法__len__(),它返回元素的个数。

例:

class Students(object):
def __init__(self, *args):
self.names = args
def __len__(self):
return len(self.names)
>>> ss = Students('Bob', 'Alice', 'Tim')
>>> print len(ss)
3

3.3数学运算

python提供基本数据类型int、float可以做整数和浮点的四则运算和乘方运算。还包括有理数和矩阵的四则运算

表示有理数,可以用rational类来表示

例:

class Rational(object):
def __init__(self, p, q): #p、q 都是整数,表示有理数 p/q
self.p = p
self.q = q
要让Rational进行+运算,需要正确实现__add__

class Rational(object):
def __init__(self, p, q):
self.p = p
self.q = q
def __add__(self, r):
return Rational(self.p * r.q + self.q * r.p, self.q * r.q)
def __str__(self):
return '%s/%s' % (self.p, self.q)
__repr__ = __str__

>>> r1 = Rational(1, 3)
>>> r2 = Rational(1, 2)
>>> print r1 + r2
5/6
rational类做剑法、乘方、除法运算:

def gcd(a, b):
  if b == 0:
    return a
  return gcd(b, a % b)

class Rational(object):
  def __init__(self, p, q):
    self.p = p
    self.q = q
  def __add__(self, r):
    return Rational(self.p * r.q + self.q * r.p, self.q * r.q)
  def __sub__(self, r):
    return Rational(self.p * r.q - self.q * r.p, self.q * r.q)
  def __mul__(self, r):
    return Rational(self.p * r.p, self.q * r.q)
  def __div__(self, r):
    return Rational(self.p * r.q, self.q * r.p)
  def __str__(self):
    g = gcd(self.p, self.q)
    return '%s/%s' % (self.p / g, self.q / g)
  __repr__ = __str__

r1 = Rational(1, 2)
r2 = Rational(1, 4)
print r1 + r2
print r1 - r2
print r1 * r2
print r1 / r2

>>>3/4
1/4
1/8
2/1

3.4类型转换

如果要把 Rational 转为 int,只需要实现特殊方法__int__()

例:

class Rational(object):
def __init__(self, p, q):
self.p = p
self.q = q
def __int__(self):
return self.p // self.q
>>> print int(Rational(7, 2))
3
>>> print int(Rational(1, 3))
0

3.5 @property

例:

class Student(object):
def __init__(self, name, score):
self.name = name
self.score = score
s = Student('Bob', 59)
s.score = 60 #修改一个student的score属性
s.score = 1000
说明:直接给属性赋值无法检查分数的有效性。

利用两个方法:使用 get/set 方法来封装对一个属性的访问

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.get_score() 和 s.set_score() 没有直接写 s.score 来得直接。

所以可以用装饰器函数把 get/set 方法“装饰”成属性调用

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

@property---这是关键字,固定格式,能让方法当“属性”用。

@score.setter---前面的"score"是@property紧跟的下面定义的那个方法的名字,"setter"是关键字,这种“@+方法名字+点+setter”是个固定格式与@property搭配使用。

3.6 __slots__

python是动态语言,可以在运行期间动态的添加属性,利用__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'
__slots__的目的:限制当前类所能拥有的属性,如果不需要添加任意动态的属性,使用__slots__也能节省内存。

例:Person类通过__slots__定义了name和gender,请在派生类Student中通过__slots__继续添加score的定义,使Student类可以实现name、gender和score 3个属性。

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, name, gender, score):
super(Student, self).__init__(name, gender)
self.score = score

s = Student('Bob', 'male', 59)
s.name = 'Tim'
s.score = 99
print s.score

3.7 __call__

在python中,函数其实就是一个对象,所有的函数都是可调用对象。

>>> f = abs
>>> f.__name__
'abs'
>>> f(-123) # f 可以被调用,所以,f 被称为可调用对象。
123
一个类实例也可以变成一个可调用对象,只需要实现一个特殊方法__call__()。

例:

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
>>> p = Person('Bob', 'male')
>>> p('Tim') #对person实例直接调用
My name is Bob...
My friend is Tim...
说明:单看 p('Tim') 你无法确定 p 是一个函数还是一个类实例,所以,在Python中,函数也是对象,对象和函数的区别并不显著。
---------------------
版权声明:本文为CSDN博主「jh993627471」的原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/jh993627471/article/details/79515422

python中继承、定制类的更多相关文章

  1. Python中的元类(metaclass)

    推荐+收藏:深刻理解Python中的元类(metaclass) 做一些笔记学习学习: 在大多数编程语言中,类就是用来描述如何生成一个对象的代码段,在Python中类也是一个对象,这个(类)对象自身拥有 ...

  2. [转]深刻理解Python中的元类(metaclass)以及元类实现单例模式

    使用元类 深刻理解Python中的元类(metaclass)以及元类实现单例模式 在看一些框架源代码的过程中碰到很多元类的实例,看起来很吃力很晦涩:在看python cookbook中关于元类创建单例 ...

  3. Python中的元类(译)

    add by zhj: 这是大stackoverflow上一位小白提出的问题,好吧,我承认我也是小白,元类这块我也是好多次想搞明白, 但终究因为太难懂而败下阵来.看了这篇文章明白了许多,再加下啄木鸟社 ...

  4. Python中如何获取类属性的列表

    这篇文章主要给大家介绍了在Python中如何获取类属性的列表,文中通过示例代码介绍的很详细,相信对大家的学习或者工作具有一定的参考借鉴价值,有需要的朋友可以参考借鉴,下面来一起看看吧. 前言 最近工作 ...

  5. Python中的动态类

    Python中的动态类 有这样一个需求,我有SegmentReader.PostagReader.ConllReader这三个Reader,他们都继承于一个Reader类.在程序运行中,由用户通过se ...

  6. Python 中的经典类新式类

    Python 中的经典类新式类 要知道经典类和新式类的区别,首先要掌握类的继承 类的继承的一个优点就是减少代码冗余 广度优先和深度优先,这主要是在多类继承的时候会使用到 经典类和新式类的主要区别就是类 ...

  7. Python中面向对象和类

    目录 面向对象 类的定义 类的访问 类的属性和方法 继承和多态 面向对象 Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对象是很容易的. 面向对象: 类(C ...

  8. python中的嵌套类

    python中的嵌套类 在.NET和JAVA语言中看到过嵌套类的实现,作为外部类一个局部工具还是很有用的,今天在python也看到了很不错支持一下.动态语言中很好的嵌套类的实现,应该说嵌套类解决设计问 ...

  9. Python中的元类

    从前面"Python对象"文章中了解到,在Python中一切都是对象,类可以创建实例对象,但是类本身也是对象. class C(object): pass c = C() prin ...

随机推荐

  1. 小记-----一些linux操作小操作

    lrzsz工具 window系统与linux系统 文件互传      1.在linux系统命令行:sudo yum install lrzsz  或者  yum install lrzsz (输入一个 ...

  2. MyBatis Mapper XML 详解

    MyBatis Mapper XML 详解 MyBatis 真正的力量是在映射语句中.这里是奇迹发生的地方.对于所有的力量,SQL 映射的 XML 文件是相当的简单.当然如果你将它们和对等功能的 JD ...

  3. 并发之AQS原理(二) CLH队列与Node解析

    并发之AQS原理(二) CLH队列与Node解析 1.CLH队列与Node节点 就像通常医院看病排队一样,医生一次能看的病人数量有限,那么超出医生看病速度之外的病人就要排队. 一条队列是队列中每一个人 ...

  4. java按值传递?

    原文链接:https://blog.csdn.net/scholar_man/article/details/80900212 在Java中,参数都是按值传递的.被传递到方法中的拷贝值,要不就是一个引 ...

  5. springboot基于CORS处理跨域问题

    1. 为什么有跨域问题 跨域不一定都会有跨域问题. 因为跨域问题是浏览器对于ajax请求的一种安全限制:一个页面发起的ajax请求,只能是与当前页域名相同的路径,这能有效的阻止跨站攻击. 因此:跨域问 ...

  6. RabbitMQ入门教程(八):远程过程调用RPC

    原文:RabbitMQ入门教程(八):远程过程调用RPC 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.cs ...

  7. laravel5.8 Models

    <?php namespace App\Models; use Illuminate\Notifications\Notifiable;use Illuminate\Contracts\Auth ...

  8. ConditionalOnProperty的使用

    时间  2018-02-23 标签 ConditionalOnPropert SpringBoot 栏目 Spring 原文   http://blog.csdn.net/u010002184/art ...

  9. Mac下开发环境的配置

    新安装的mac系统往往要配置各种环境,总是记不住,暂时保存在这,以备后需------- Mac下的包管理工具使用的是brew,首先安装它 官方站:https://brew.sh/ 安装命令: /usr ...

  10. @ResponseBody 注解是什么意思?

    1. @ResponseBody注解的作用是将Controller的方法返回的对象通过适当的转换器转换为指定的格式之后,写入到response对象的body区,通常用来返回JSON数据或者是XML数据 ...