面向对象,绑定方法与异常处理(七)

1.1 继承与派生

1.1.1 什么是继承

    是一种新建类的方式,新建的类称为子类,子类会遗传父类的属性,可以减少代码冗余
    在python中,子类(派生类)可以继承一个或者多个父类(基类,超类)
 
python中类的继承分为:单继承和多继承
class Parent1:    #定义父类

    pass

class Parent2(object): #定义父类

    pass

class Sub1(Parent1):  ##单继承,基类是Parent1,派生类是Sub1

    pass

class Sub2(Parent1,Parent2): #python支持多继承,用逗号分隔开多个继承的类

    pass
 
查看继承
print(Sub1.__bases__)   #__base__只查看从左到右继承的第一个子类,__bases__则是查看所有继承的父类

print(Sub2.__bases__)

提示:如果没有指定基类,python的类会默认继承object类,object是所有python类的基类,它提供了一些常见方法(如__str__)的实现。
print(Parent1.__bases__)

print(Parent2.__bases__)
 
在Python2中类分为两种:
1、经典类:指的就是没有继承object类的类,以及该类的子类
2、新式类:指的就是继承object类的类,以及该类的子类
在Python3中统一都为新式类
class OldboyPeople:

    school = ‘Oldboy‘

    def __init__(self, name, age, sex):

        self.name = name

        self.age = age

        self.sex = sex

    def tell_info(self):

        print(‘<名字:%s 年龄:%s 性别:%s>‘ %(self.name,self.age,self.sex))

class OldboyStudent(OldboyPeople):

    def learn(self):

        print(‘%s is learning‘ %self.name)

    def tell_info(self):

        print(‘我是学生:‘,end=‘‘)

        print(‘<名字:%s 年龄:%s 性别:%s>‘ % (self.name, self.age, self.sex))

class OldboyTeacher(OldboyPeople):

    def teach(self):

        print(‘%s is teaching‘ %self.name)

    def tell_info(self):

        print(‘我是老师:‘,end=‘‘)

        print(‘<名字:%s 年龄:%s 性别:%s>‘ % (self.name, self.age, self.sex))

stu1=OldboyStudent(‘牛榴弹‘,18,‘male‘)

teacher1=OldboyTeacher(‘egon‘,18,‘male‘)

print(stu1.__dict__)

print(stu1.school)

print(stu1.x)

stu1.tell_info()

teacher1.tell_info() 
 
 
属性查找
继承描述的是子类与父类之间的关系,是一种什么是什么的关系。要找出这种关系,必须先抽象再继承
 
抽象即抽取类似或者说比较像的部分。
class Foo:

    def f1(self):

        print(‘Foo.f1‘)

    def f2(self): #self=obj

        print(‘Foo.f2‘)

        self.f1() #obj.f1()

class Bar(Foo):

    def f1(self):

        print(‘Bar.f1‘)

obj=Bar()

print(obj.__dict__)

obj.f2()

1.2 子类重用父类方法part1:

在开发程序的过程中,如果我们定义了一个类A,然后又想新建立另外一个类B,但是类B的大部分内容与类A的相同时

我们不可能从头开始写一个类B,这就用到了类的继承的概念。

通过继承的方式新建类B,让B继承A,B会‘遗传’A的所有属性(数据属性和函数属性),实现代码重用

class OldboyPeople:

    school = ‘Oldboy‘

    def __init__(self, name, age, sex):

        self.name = name

        self.age = age

        self.sex = sex

    def tell_info(self):

        print(‘<名字:%s 年龄:%s 性别:%s>‘ %(self.name,self.age,self.sex))

class OldboyStudent(OldboyPeople):

    def learn(self):

        print(‘%s is learning‘ %self.name)

    def tell_info(self):

        print(‘我是学生:‘,end=‘‘)

        # self.tell_info() #stu1.tell_info()

        OldboyPeople.tell_info(self)

stu1=OldboyStudent(‘牛榴弹‘,18,‘male‘)

stu1.tell_info()
class OldboyPeople:

    school = ‘Oldboy‘

    def __init__(self, name, age, sex):

        self.name = name

        self.age = age

        self.sex = sex

    def tell_info(self):

        print(‘<名字:%s 年龄:%s 性别:%s>‘ %(self.name,self.age,self.sex))

class OldboyStudent(OldboyPeople):

    def __init__(self,name,age,sex,course,stu_id):

        # self.name=name

        # self.age=age

        # self.sex=sex

        OldboyPeople.__init__(self,name,age,sex)

        self.course=course

        self.stu_id=stu_id

    def learn(self):

        print(‘%s is learning‘ %self.name)

    def tell_info(self):

        print(‘我是学生:‘,end=‘‘)

        # self.tell_info() #stu1.tell_info()

        OldboyPeople.tell_info(self)

stu1=OldboyStudent(‘牛榴弹‘,18,‘male‘,‘Python‘,1)

stu1.tell_info()

1.3 组合

组合指的是,在一个类中以另外一个类的对象作为数据属性,称为类的组合

class OldboyPeople:

    school = ‘Oldboy‘

    def __init__(self, name, age, sex):

        self.name = name

        self.age = age

        self.sex = sex

    def tell_info(self):

        print(‘<名字:%s 年龄:%s 性别:%s>‘ %(self.name,self.age,self.sex))

class OldboyStudent(OldboyPeople):

    def __init__(self,name,age,sex,course,stu_id,year,mon,day):

        OldboyPeople.__init__(self,name,age,sex)

        self.course=course

        self.stu_id=stu_id

        self.year=year

        self.mon=mon

        self.day=day

    def learn(self):

        print(‘%s is learning‘ %self.name)

    def tell_info(self):

        print(‘我是学生:‘,end=‘‘)

        # self.tell_info() #stu1.tell_info()

        OldboyPeople.tell_info(self)

    def tell_birth(self):

        print(‘出生日期是:<%s-%s-%s>‘ %(self.year,self.mon,self.day))

class OldboyTeacher(OldboyPeople):

    def __init__(self, name, age, sex, level,salary,year,mon,day):

        OldboyPeople.__init__(self, name, age, sex)

        self.level=level

        self.salary=salary

        self.year=year

        self.mon=mon

        self.day=day

    def tell_birth(self):

        print(‘出生日期是:<%s-%s-%s>‘ %(self.year,self.mon,self.day))

    def teach(self):

        print(‘%s is teaching‘ % self.name)

    def tell_info(self):

        print(‘我是老师:‘, end=‘‘)

        OldboyPeople.tell_info(self)

stu1=OldboyStudent(‘牛榴弹‘,18,‘male‘,‘Python‘,1,1983,3,11)

teacher1=OldboyTeacher(‘啊狗‘,18,‘female‘,10,4000,1990,2,17)

stu1.tell_birth()

teacher1.tell_birth()

组合与继承都是有效地利用已有类的资源的重要方式。但是二者的概念和使用场景皆不同,

1.继承的方式

通过继承建立了派生类与基类之间的关系,它是一种‘是‘的关系,比如白马是马,人是动物。

当类之间有很多相同的功能,提取这些共同的功能做成基类,用继承比较好,比如老师是人,学生是人

2.组合的方式

用组合的方式建立了类与组合的类之间的关系,它是一种‘有’的关系,比如教授有生日,教授教python和linux课程,教授有学生s1、s2、s3...

class OldboyPeople:

    school = ‘Oldboy‘

    def __init__(self, name, age, sex):

        self.name = name

        self.age = age

        self.sex = sex

    def tell_info(self):

        print(‘<名字:%s 年龄:%s 性别:%s>‘ % (self.name, self.age, self.sex))

class OldboyStudent(OldboyPeople):

    def __init__(self, name, age, sex, course, stu_id,):

        OldboyPeople.__init__(self, name, age, sex)

        self.course = course

        self.stu_id = stu_id

    def learn(self):

        print(‘%s is learning‘ % self.name)

    def tell_info(self):

        print(‘我是学生:‘, end=‘‘)

        # self.tell_info() #stu1.tell_info()

        OldboyPeople.tell_info(self)

class OldboyTeacher(OldboyPeople):

    def __init__(self, name, age, sex, level, salary):

        OldboyPeople.__init__(self, name, age, sex)

        self.level = level

        self.salary = salary

    def teach(self):

        print(‘%s is teaching‘ % self.name)

    def tell_info(self):

        print(‘我是老师:‘, end=‘‘)

        OldboyPeople.tell_info(self)

class Date:

    def __init__(self,year,mon,day):

        self.year = year

        self.mon = mon

        self.day = day

    def tell_birth(self):

        print(‘出生日期是:<%s-%s-%s>‘ % (self.year, self.mon, self.day))

stu1 = OldboyStudent(‘牛榴弹‘, 18, ‘male‘, ‘Python‘, 1,)

date_obj1=Date(1983, 3, 11)

stu1.birth=date_obj1

teacher1 = OldboyTeacher(‘啊狗‘, 18, ‘female‘, 10, 4000)

date_obj2=Date( 1990, 2, 17)

teacher1.birth=date_obj2

# print(stu1.birth)

# print(teacher1.birth)

stu1.birth.tell_birth() #date_obj1.tell_birth()

teacher1.birth.tell_birth()
class OldboyPeople:

    school = ‘Oldboy‘

    def __init__(self, name, age, sex,date_obj):

        self.name = name

        self.age = age

        self.sex = sex

        self.birth = date_obj

    def tell_info(self):

        print(‘<名字:%s 年龄:%s 性别:%s>‘ % (self.name, self.age, self.sex))

class OldboyStudent(OldboyPeople):

    def __init__(self, name, age, sex, course, stu_id,date_obj):

        OldboyPeople.__init__(self, name, age, sex,date_obj)

        self.course = course

        self.stu_id = stu_id

    def learn(self):

        print(‘%s is learning‘ % self.name)

    def tell_info(self):

        print(‘我是学生:‘, end=‘‘)

        # self.tell_info() #stu1.tell_info()

        OldboyPeople.tell_info(self)

class OldboyTeacher(OldboyPeople):

    def __init__(self, name, age, sex, level, salary,date_obj):

        OldboyPeople.__init__(self, name, age, sex,date_obj)

        self.level = level

        self.salary = salary

    def teach(self):

        print(‘%s is teaching‘ % self.name)

    def tell_info(self):

        print(‘我是老师:‘, end=‘‘)

        OldboyPeople.tell_info(self)

class OldboySale(OldboyPeople):

    def __init__(self,name,age,sex,kpi,date_obj):

        OldboyPeople.__init__(self,name,age,sex,date_obj)

        self.kpi=kpi

    def tell_info(self):

        print(‘我是销售: ‘,end=‘‘)

        OldboyPeople.tell_info(self)

class Date:

    def __init__(self,year,mon,day):

        self.year = year

        self.mon = mon

        self.day = day

    def tell_birth(self):

        print(‘出生日期是:<%s-%s-%s>‘ % (self.year, self.mon, self.day))

date_obj1=Date(1983, 3, 11)

sale1=OldboySale(‘歪歪‘,38,‘male‘,7.3,date_obj1)

# sale1.birth=date_obj1

# sale1.tell_info()

sale1.birth.tell_birth()
class OldboyPeople:

    school = ‘Oldboy‘

    def __init__(self, name, age, sex,date_obj):

        self.name = name

        self.age = age

        self.sex = sex

        self.birth = date_obj

    def tell_info(self):

        print(‘<名字:%s 年龄:%s 性别:%s>‘ % (self.name, self.age, self.sex))

class OldboyStudent(OldboyPeople):

    def __init__(self, name, age, sex, stu_id,date_obj):

        OldboyPeople.__init__(self, name, age, sex,date_obj)

        self.courses=[]

        self.stu_id = stu_id

    def learn(self):

        print(‘%s is learning‘ % self.name)

    def tell_info(self):

        print(‘我是学生:‘, end=‘‘)

        # self.tell_info() #stu1.tell_info()

        OldboyPeople.tell_info(self)

class OldboyTeacher(OldboyPeople):

    def __init__(self, name, age, sex, level, salary,date_obj):

        OldboyPeople.__init__(self, name, age, sex,date_obj)

        self.level = level

        self.salary = salary

        self.courses=[]

    def teach(self):

        print(‘%s is teaching‘ % self.name)

    def tell_info(self):

        print(‘我是老师:‘, end=‘‘)

        OldboyPeople.tell_info(self)

class OldboySale(OldboyPeople):

    def __init__(self,name,age,sex,kpi,date_obj):

        OldboyPeople.__init__(self,name,age,sex,date_obj)

        self.kpi=kpi

    def tell_info(self):

        print(‘我是销售: ‘,end=‘‘)

        OldboyPeople.tell_info(self)

class Date:

    def __init__(self,year,mon,day):

        self.year = year

        self.mon = mon

        self.day = day

    def tell_birth(self):

        print(‘出生日期是:<%s-%s-%s>‘ % (self.year, self.mon, self.day))

class Course:

    def __init__(self,name,price,period):

        self.name=name

        self.price=price

        self.period=period

    def tell_info(self):

        print(‘课程详细信息:<%s,%s,%s>‘ %(self.name,self.price,self.period))

Python=Course(‘python自动化养猪‘,3000,‘3mon‘)

Linux=Course(‘大数据分析-linux‘,3000,‘3mon‘)

date_obj=Date(1993,3,13)

teacher1=OldboyTeacher(‘egon‘,18,‘male‘,100,3000,date_obj)

teacher1.courses.append(Python)

teacher1.courses.append(Linux)

# print(teacher1.courses)

for course in teacher1.courses:

    course.tell_info()

stu1=OldboyStudent(‘xxxx‘,28,‘female‘,1,date_obj)

# print(stu1.courses)

stu1.courses.append(Python)

stu1.courses.append(Linux)

print(stu1.courses)

1.4 抽象类

1.4.1 什么是抽象类

与java一样,python也有抽象类的概念但是同样需要借助模块实现,抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化

为什么要有抽象类

如果说类是从一堆对象中抽取相同的内容而来的,那么抽象类就是从一堆类中抽取相同的内容而来的,内容包括数据属性和函数属性。

  比如我们有香蕉的类,有苹果的类,有桃子的类,从这些类抽取相同的内容就是水果这个抽象的类,你吃水果时,要么是吃一个具体的香蕉,要么是吃一个具体的桃子。。。。。。你永远无法吃到一个叫做水果的东西。

从设计角度去看,如果类是从现实对象抽象而来的,那么抽象类就是基于类抽象而来的。

  从实现角度来看,抽象类与普通类的不同之处在于:抽象类中只能有抽象方法(没有实现功能),该类不能被实例化,只能被继承,且子类必须实现抽象方法。这一点与接口有点类似,但其实是不同的,即将揭晓答案

import abc

class Animal(metaclass=abc.ABCMeta):

    @abc.abstractmethod

    def eat(self):

        pass

    @abc.abstractmethod

    def run(self):

        pass

class People(Animal):

    def eat(self):

        pass

    def run(self):

        pass

class Pig(Animal):

    def eat(self):

        pass

    def run(self):

        pass

peo1=People()

pig1=Pig()

1.4.2 抽象类与接口

抽象类的本质还是类,指的是一组类的相似性,包括数据属性(如all_type)和函数属性(如read、write),而接口只强调函数属性的相似性。

抽象类是一个介于类和接口直接的一个概念,同时具备类和接口的部分特性,可以用来实现归一化设计

import abc

class File(metaclass=abc.ABCMeta):

    @abc.abstractmethod

    def read(self):

        pass

    @abc.abstractmethod

    def write(self):

        pass

class Disk(File):

    def read(self):

        print(‘disk read‘)

    def write(self):

        print(‘disk write‘)

class Process(File):

    def read(self):

        print(‘Process read‘)

    def write(self):

        print(‘Process write‘)

d=Disk()

p=Process()

d.read()

d.write()

p.read()

p.write()

1.5 继承的实现原理

继承顺序

在Java和C#中子类只能继承一个父类,而Python中子类可以同时继承多个父类,如A(B,C,D)

如果继承关系为非菱形结构,则会按照先找B这一条分支,然后再找C这一条分支,最后找D这一条分支的顺序直到找到我们想要的属性

如果继承关系为菱形结构,那么属性的查找方式有两种,分别是:深度优先和广度优先

图1-1

图1-2

class A(object):

    # def test(self):

    #     print(‘from A‘)

    pass

class B(A):

    # def test(self):

    #     print(‘from B‘)

    pass

class C(A):

    # def test(self):

    #     print(‘from C‘)

    pass

class D(B):

    # def test(self):

    #     print(‘from D‘)

    pass

class E(C):

    # def test(self):

    #     print(‘from E‘)

    pass

class F(D,E):

    # def test(self):

    #     print(‘from F‘)

    pass

f1=F()

print(F.mro())

# f1.test()

1.6 子类重用父类的方法part2

1.6.1 方法一:指名道姓,即父类名.父类方法()

class OldboyPeople:

    school = ‘Oldboy‘

    def __init__(self, name, age, sex):

        self.name = name

        self.age = age

        self.sex = sex

    def tell_info(self):

        print(‘<名字:%s 年龄:%s 性别:%s>‘ %(self.name,self.age,self.sex))

class OldboyStudent(OldboyPeople):

    def __init__(self,name,age,sex,course):

        # OldboyPeople.__init__(self,name,age,sex)

        super(OldboyStudent,self).__init__(name,age,sex)

        self.course=course

    def tell_info(self):

        print(‘我是学生: ‘,end=‘‘)

        # OldboyPeople.tell_info(self)

        super(OldboyStudent,self).tell_info()

stu1=OldboyStudent(‘egon‘,18,‘male‘,‘python‘)

# print(stu1.name,stu1.age,stu1.sex,stu1.course)

stu1.tell_info()

1.6.2 方法二:super()

class Foo:

    def f2(self):

        print(‘====?>‘)

    def f1(self):

        print(‘Foo.f1‘)

        # super().f2()

        Foo.f2(123)

class Bar:

    def f2(self):

        print(‘Bar f2‘)

class Sub(Foo,Bar):

    pass

s=Sub()

# print(Sub.mro())

# [<class ‘__main__.Sub‘>,

# <class ‘__main__.Foo‘>,

# <class ‘__main__.Bar‘>,

#  <class ‘object‘>]

s.f1()

强调:二者使用哪一种都可以,但最好不要混合使用

即使没有直接继承关系,super仍然会按照mro继续往后查找

1.6.3 指名道姓与super()的区别

当你使用super()函数时,Python会在MRO列表上继续搜索下一个类。只要每个重定义的方法统一使用super()并只调用它一次,那么控制流最终会遍历完整个MRO列表,每个方法也只会被调用一次(注意注意注意:使用super调用的所有属性,都是从MRO列表当前的位置往后找,千万不要通过看代码去找继承关系,一定要看MRO列表)

1.7 多态与多态性

1.7.1 多态:同一种事物的多种形态

import abc

class Animal(metaclass=abc.ABCMeta):

    @abc.abstractmethod

    def speak(self):

        pass

class Pig(Animal):

    def speak(self):

        print(‘哼哼‘)

class Dog(Animal):

    def speak(self):

        print(‘汪汪‘)

class People(Animal):

    def speak(self):

        print(‘say hello‘)

people1=People()

dog1=Dog()

pig1=Pig()

1.7.2 多态性:指的是在不考虑对象具体类型的情况下,直接使用对象(对象的方法)

people1.speak()

dog1.speak()

pig1.speak()

def talk(obj):

    obj.speak()

talk(people1) #people1.speak()

talk(dog1)

talk(pig1)

list,str,tuple

l=list([1,2,3])

s=str(‘hello‘)

t=tuple((1,‘a‘,4,‘b‘,‘c‘))

l.__len__()

s.__len__()

t.__len__()

print(len(l))

print(len(s))

print(len(t))

多态性是指在不考虑实例类型的情况下使用实例

多态:同一种事物的多种形态

1.7.3 多态性分为静态多态性和动态多态性

  静态多态性:如任何类型都可以用运算符+进行运算

  动态多态性:

import abc

class Pig:

    def speak(self):

        print(‘哼哼‘)

class Dog:

    def speak(self):

        print(‘汪汪‘)

class People:

    def speak(self):

        print(‘say hello‘)

class Radio:

    def speak(self):

        print(‘radio speak‘)

people1=People()

dog1=Dog()

pig1=Pig()

1.7.4 为什么要用多态性

其实大家从上面多态性的例子可以看出,我们并没有增加什么新的知识,也就是说python本身就是支持多态性的,这么做的好处是什么呢?

1.增加了程序的灵活性

  以不变应万变,不论对象千变万化,使用者都是同一种形式去调用,如func(animal)

2.增加了程序额可扩展性

  通过继承animal类创建了一个新的类,使用者无需更改自己的代码,还是用func(animal)去调用  

import abc

class Disk:

    def read(self):

        print(‘disk read‘)

    def write(self):

        print(‘disk write‘)

class Process:

    def read(self):

        print(‘Process read‘)

    def write(self):

        print(‘Process write‘)

  

1.8 封装之如何隐藏

1.8.1 封装:

1、__开头的属性只是一种语法意义上的变形,并不会真的限制外部的访问

2、这种变形只在类定义阶段发送一次,类定义之后再新增的__开头的属性不会变形

3、这种隐藏只对外不对内,因为类内部定义的属性在类定义阶段统一发生变形

先看如何隐藏

在python中用双下划线开头的方式将属性隐藏起来(设置成私有的)

class Foo:

    __N=1 #_Foo__N=1

    def __init__(self,x,y):

        self.x=x

        self.__y=y #self._Foo__y=y

    def __f1(self): #_Foo__f1

        print(‘f1‘)

    def f2(self):

        print(self.__N,self.__y) #print(self._Foo__N,self._Foo__y)

print(Foo.__N)

print(Foo.__f1)

print(Foo.__dict__)

print(Foo._Foo__N)

print(Foo._Foo__f1)

obj=Foo(1,2)

print(obj.__dict__)

print(obj._Foo__y)

Foo.__M=2

print(Foo.__dict__)

print(Foo.__M)

obj=Foo(1,2)

print(obj.__dict__)

obj.__z=3

print(obj.__dict__)

print(obj.__z)

obj=Foo(1,2)

obj.f2()

print(obj.__N)

这种变形需要注意的问题是:

1.这种机制也并没有真正意义上限制我们从外部直接访问属性,知道了类名和属性名就可以拼出名字:_类名__属性,然后就可以访问了,如a._A__N,即这种操作并不是严格意义上的限制外部访问,仅仅只是一种语法意义上的变形,主要用来限制外部的直接访问。

2.变形的过程只在类的定义时发生一次,在定义后的赋值操作,不会变形

3.继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的

class Foo:

    def __f1(self): #_Foo__f1

        print(‘Foo.f1‘)

    def f2(self):

        print(‘Foo.f2‘)

        self.__f1() #b._Foo__f1()

class Bar(Foo):

    def __f1(self): #_Bar__f1

        print(‘Bar.f1‘)

b=Bar()

b.f2()

1.9 封装之真正意义

封装数据属性的目的:外部无法直接访问数据属性,类内部开放接口,然后可以在接口内严格控制对属性的增删改查操作

class People:

    def __init__(self,name,age):

        # self.__name=name

        # self.__age=age

        self.set_info(name,age)

    def tell_info(self):

        print("姓名:<%s> 年龄:<%s>" %(self.__name,self.__age))

    def set_info(self,name,age):

        if type(name) is not str:

            raise TypeError(‘name must be str‘)

        if type(age) is not int:

            raise TypeError(‘age must be int‘)

        self.__name=name

        self.__age=age

p=People(‘egon‘,18)

# print(p.__name,p.__age)

# p.tell_info()

# p.set_info(‘EGON‘,20)

p.set_info(3537,20)

p.tell_info()

封装方法的目的是:隔离复杂度

class ATM:

    def __card(self):

        print(‘插卡‘)

    def __auth(self):

        print(‘用户认证‘)

    def __input(self):

        print(‘输入取款金额‘)

    def __print_bill(self):

        print(‘打印账单‘)

    def __take_money(self):

        print(‘取款‘)

    def withdraw(self):

        self.__card()

        self.__auth()

        self.__input()

        self.__print_bill()

        self.__take_money()

1.10 封装之property

1.10.1 什么是特性property

property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值

例一:BMI指数(bmi是计算而来的,但很明显它听起来像是一个属性而非方法,如果我们将其做成一个属性,更便于理解)

成人的BMI数值:

过轻:低于18.5

正常:18.5-23.9

过重:24-27

肥胖:28-32

非常肥胖, 高于32

  体质指数(BMI)=体重(kg)÷身高^2(m)

EX:70kg÷(1.75×1.75)=22.86

class People:

    def __init__(self,name,age,height,weight):

        self.name=name

        self.age=age

        self.height=height

        self.weight=weight

    @property

    def bmi(self):

        return self.weight / (self.height ** 2)

egon=People(‘egon‘,18,1.80,75)

egon.height=1.82

# print(egon.bmi())

print(egon.bmi)

1.10.2 为什么要用property

将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,这种特性的使用方式遵循了统一访问的原则

class People:

    def __init__(self,name,):

        self.__name=name

    @property

    def name(self):

        return self.__name

    @name.setter

    def name(self,obj):

        if type(obj) is not str:

            raise TypeError(‘name must be str‘)

        self.__name=obj

    @name.deleter

    def name(self):

        # del self.__name

        raise PermissionError(‘不让删‘)

egon=People(‘egon‘)

# print(egon.name)

# egon.name=‘EGON‘

# egon.name=35357

# print(egon.name)

del egon.name

# print(egon.name)

封装在于明确区分内外,使得类实现者可以修改封装内的东西而不影响外部调用者的代码;而外部使用用者只知道一个接口(函数),只要接口(函数)名、参数不变,使用者的代码永远无需改变。这就提供一个良好的合作基础——或者说,只要接口这个基础约定不变,则代码改变不足为虑。

1.11 绑定方法与非绑定方法

一:绑定方法(绑定给谁,谁来调用就自动将它本身当作第一个参数传入):

    1. 绑定到类的方法:用classmethod装饰器装饰的方法。

为类量身定制

类.boud_method(),自动将类当作第一个参数传入

(其实对象也可调用,但仍将类当作第一个参数传入)

    2. 绑定到对象的方法:没有被任何装饰器装饰的方法。

为对象量身定制

对象.boud_method(),自动将对象当作第一个参数传入

(属于类的函数,类可以调用,但是必须按照函数的规则来,没有自动传值那么一说)

二:非绑定方法:用staticmethod装饰器装饰的方法

        1. 不与类或对象绑定,类和对象都可以调用,但是没有自动传值那么一说。就是一个普通工具而已

    注意:与绑定到对象方法区分开,在类中直接定义的函数,没有被任何装饰器装饰的,都是绑定到对象的方法,可不是普通函数,对象调用该方法会自动传值,而staticmethod装饰的方法,不管谁来调用,都没有自动传值一说

1.11.1 绑定方法

绑定给对象的方法(略)

绑定给类的方法(classmethod)

classmehtod是给类用的,即绑定到类,类在使用时会将类本身当做参数传给类方法的第一个参数(即便是对象来调用也会将类当作第一个参数传入),python为我们内置了函数classmethod来把类中的函数定义成类方法

import settings

import hashlib

import time

class MySQL:

    def __init__(self,host,port):

        self.host=host

        self.port=port

    def func(self):

        print(‘%s 说:你好啊我的天‘ %self.name)

    @classmethod

    def from_conf(cls):

        return cls(settings.HOST,settings.PORT)

    @staticmethod

    def create_id(n):

        m=hashlib.md5()

        m.update(str(time.clock()+n).encode(‘utf-8‘))

        return m.hexdigest()

# conn=MySQL(‘127.0.0.1‘,3306)
#绑定方法:绑定给谁就应该由谁来调用,谁来调用就会把谁当做第一个参数自动传入
 

1.11.2 非绑定方法

在类内部用staticmethod装饰的函数即非绑定方法,就是普通函数
statimethod不与类或对象绑定,谁都可以调用,没有自动传值效果
conn=MySQL.from_conf()

# print(conn.host,conn.port)

print(MySQL.create_id(1))

print(conn.create_id(2))

1.12 内置函数补充

l=list([])

print(type(l) is list)

print(isinstance(l,list))

class Foo:

    pass

class Bar(Foo):

    pass

print(issubclass(Bar,Foo))

1.13 反射

1.13.1 什么是反射

反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。

class Foo:

    def __init__(self,name):

        self.name=name

    def f1(self):

        print(‘===>f1‘)

obj=Foo(‘egon‘)

obj.name #obj.__dict__[‘name‘]

1.13.2 python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)

四个可以实现自省的函数

下列方法适用于类和对象(一切皆对象,类本身也是一个对象)

hasattr

print(hasattr(obj,‘name‘)) #obj.name

print(hasattr(obj,‘f1‘))#obj.f1

getattr

if hasattr(obj,‘f1‘):

    f=getattr(obj,‘f1‘) #f=obj.f1

    f()

print(getattr(obj,‘xxx‘,None))

setattr

obj.x=1

setattr(obj,‘x‘,1)

print(obj.__dict__)

delattr

del obj.name

delattr(obj,‘name‘)

print(obj.__dict__)

导入其他模块,利用反射查找该模块是否存在某个方法

class FtpClient:

    def __init__(self,host,port):

        self.host=host

        self.port=port

        self.conn=‘xxx‘

    def interactie(self):

        while True:

            cmd=input(‘>>: ‘).strip()

            if not cmd:continue

            cmd_l=cmd.split()

            print(cmd_l)

            if hasattr(self,cmd_l[0]):

                func=getattr(self,cmd_l[0])

                func(cmd_l)

    def get(self,cmd_l):

        print(‘geting...‘,cmd_l)

    def put(self,cmd_l):

        print(‘putting....‘,cmd_l)

client=FtpClient(‘1.1.1.1‘,23)

client.interactie()

1.14 类的内置方法

__str__

l=list([1,2,3,4])

print(l)

class People:

    def __init__(self,name,age):

        self.name=name

        self.age=age
    def __str__(self):

        return ‘<name:%s age:%s>‘ %(self.name,self.age)

egon=People(‘egon‘,18)

print(egon) #print(egon.__str__())

注:如果产生的对象仅仅只是python程序级别的(用户级),那么无需定义__del__,如果产生的对象的同时还会向操作系统发起系统调用,即一个对象有用户级与内核级两种资源,比如(打开一个文件,创建一个数据库链接),则必须在清除对象的同时回收系统资源,这就用到了__del__

__del__

f=open(‘a.txt‘,‘w‘,encoding=‘utf-8‘)

f.read()

f.close()
class Foo:

    def __del__(self):

        print(‘del---->‘)

obj=Foo()

del obj

# print(‘主‘)

setting.py

HOST=‘10.10.10.9‘

PORT=3306
class Mysql:

    def __init__(self,host,port):

        self.host=host

        self.port=port

        self.conn=Connect(host,port)

    def __del__(self):

        self.conn.close()

m=Mysql(‘1.1.1.1‘,3306)

m.conn.execute(‘select * from db.user;‘)

1.15 异常处理

1.15.1 什么是异常

异常就是程序运行时发生错误的信号(在程序出现错误时,则会产生一个异常,若程序没有处理它,则会抛出该异常,程序的运行也随之终止),在python中,错误触发的异常如下

而错误分成两种

1.语法错误(这种错误,根本过不了python解释器的语法检测,必须在程序执行前就改正)

2.逻辑错误

# x=

raise TypeError(‘xxxx‘)

为了保证程序的健壮性与容错性,即在遇到错误时程序不会崩溃,我们需要对异常进行处理,

如果错误发生的条件是可预知的,我们需要用if进行处理:在错误发生之前进行预防

#基本语法为

try:

    被检测的代码块

except 异常类型:

    try中一旦检测到异常,就执行这个位置的逻辑

#举例

try:

    f=open(‘a.txt‘)

    g=(line.strip() for line in f)

    print(next(g))

    print(next(g))

    print(next(g))

    print(next(g))

    print(next(g))

except StopIteration:

    f.close()

原文地址:https://www.cnblogs.com/x-y-j/p/8342779.html

时间: 2024-11-09 13:57:47

面向对象,绑定方法与异常处理(七)的相关文章

面向对象——绑定方法与非绑定方法

1 在类内部定义的函数,分为两大类 2 一:绑定方法:绑定给谁,就应该由谁来调用,谁来调用就会把调用者当做第一个参数自动传入 3 绑定到对象的方法:在类内定义的没有被任何装饰器修饰的 4 绑定到类的方法:在类内定义的被装饰器classmethod修饰的方法 5 二:非绑定方法(staticmethod):没有自动传值这么一说,就是类中定义的一个普通函数,对象和类都能使用 6 非绑定方法:不与类或者对象绑定,谁都可以调用,参数该怎么传就怎么传 1 class Foo: 2 def __init__

面向对象——绑定方法和非绑定方法

类中的绑定方法分为两类: 1.绑定方法 特殊之处:绑定给谁就应该由谁调用,谁调用就会将谁当做第一参数自动传入. 绑定对象的方法:在类中定义函数没有任何装饰器修饰的情况下,默认就是绑定对象的 绑定给类的方法:为类中定义函数添加一个装饰器classmethod,绑定给类的. 2.非绑定方法 特殊之处:非绑定方法就是一个普通函数,即不与类绑定也不与对象绑定,以为着类与对象都可以调用,但是无论谁调用都是普通函数的,没有自动传值的功能 三种方法的定义方式 class foo: #绑定对象的方法 def f

Python基础(17)_面向对象程序设计(抽象类、继承原理、封装、多态,绑定方法)

一.抽象类 抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化 1.在python中实现抽象类 import abc #利用abc模块实现抽象类 class All_file(metaclass=abc.ABCMeta): all_type='file' @abc.abstractmethod #定义抽象方法,无需实现功能 def read(self): '子类必须定义读功能' pass @abc.abstractmethod #定义抽象方法,无需实现功能 def write(sel

第七课:类、抽象类、绑定方法、反射

上节回顾 面向过程与面向对象 面向过程:核心的就是过程,过程就是解决问题的步骤,就是实现确定先干什么后干什么,面向对象的设计程序就好比是在设计一条流水,是一种机械思维方式. 优点:复杂的问题简单化 缺点:可扩展性差(牵一发而动全身) 用到的一些经典案例:Linux内核,httpd,git 面向对象:核心是对象,要理解对象应该把自己当成上帝.把一切存在的事物都当成对象,不存在的也可以创建出来.对象可以理解为特征(变量)与技能(函数)的结合体. 优点就是可扩展性强. 缺点是无法像面向过程一样准确的知

三 面向对象之绑定方法与非绑定方法

一 绑定方法 二 非绑定方法 三 classmethod和staticmethod的区别 一 绑定方法 绑定方法(绑定给谁,谁来调用就自动将它本身当作第一个参数传入): 1. 绑定到类的方法:用classmethod装饰器装饰的方法.                 为类量身定制                 类.boud_method(),自动将类当作第一个参数传入               (其实对象也可调用,但仍将类当作第一个参数传入) 2. 绑定到对象的方法:没有被任何装饰器装饰的方

面向对象,封装,反射,绑定方法

封装就是对内可访问外部不可访问,不过可以通过给定的接口进行访问 可以通过__语法定义私有属性私有方法  同时可以在父类这样定义使得子类不能继承父类私有属性 def__stu(self)  __n='ii' 内部可以通过设置 def study(self): self.__stu() 进行访问   同时可以通过 ._类名__属性  的方法进行访问 可以隔离复杂度提高数据安全度 issubclass(,)判断是否是父子关系 将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察

python24 面向对象的绑定方法 类与类之间的继承

## 类属性与对象属性 类中应该仅存储所有对象共有的内容 ? 如所有人的国籍相同那就放到类中 对象中存储每个对象独有的内容 ? 如每个人的名字都不同 ## __init__方法的作用 init 是初始化的缩写 用于为对象的属性设置初始值 特点: ```# 执行时机:当实例化产生对象时会自动执行该函数# 会自动传入需要初始化的对象# 初始化必须包含至少一个参数 用于表示对象本身# 该函数不允许有返回值 必须为None``` ## 绑定方法 绑定即两个东西绑在一起 方法就是函数 那就是说绑定方法 =

面向对象 --- 类的绑定方法,面向对象高阶

昨日回顾 类的绑定方法 classmethod(类的绑定方法) 翻译过来是一个类方法,是一个装饰器,可以装饰给类内部的方法,使该方法绑定给类来使用. --- 对象的绑定方法的特殊之处:由对象来调用,会将对象当作第一个参数传给该方法 --- 类的绑定方法的特殊之处:由类来调用,会将类仿作第一个参数传给该方法 通过对象也可以调用,只是默认传递的第一个参数还是这个对象对应的类 staticmethod(非绑定方法) 是一个装饰器,可以装饰类内部的方法,使该方法即不绑定给对象,也不绑定给类.谁都可以调用

面向对象二次整理(基础,属性引用,方法引用.绑定方法)

概念之类的去百度一下... 基础 类 属性 实例变量 类变量(默认共享) 私有属性(__var) 方法 构造方法 析构方法或析构函数 私有方法 对象: 实例化一个类之后得到的对象 封装 把一些功能的实现细节不对外暴露 类的初始化(__init__): 就是给对象定义一些自己的特征,不能有返回值 继承 代码的重用 单继承 多继承 2.7的经典类-->深度优先,新式类-->广度优先 3.x 均是广度优先 class Foo() 多态 接口重用,一种接口,多种实现 高级属性: 静态方法 与类无关,不