内容简介:面向对象,绑定方法与异常处理(七)
1.1 继承与派生
1.1.1 什么是继承
<em> </em><em>是一种新建类的方式,新建的类称为子类,子类会遗传父类的属性,可以减少代码冗余</em>
<em> </em><em>在 python 中,子类(派生类)可以继承一个或者多个父类(基类,超类)</em>
<em> </em>
<em>python</em><em>中类的继承分为:单继承和多继承</em>
class Parent1: #定义父类
pass
class Parent2(object): #定义父类
pass
class Sub1(Parent1): ##单继承,基类是Parent1,派生类是Sub1
pass
class Sub2(Parent1,Parent2): #python支持多继承,用逗号分隔开多个继承的类
pass
<strong> </strong>
<strong>查看继承</strong>
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()
<em>属性查找</em>
<em>继承描述的是子类与父类之间的关系,是一种什么是什么的关系。要找出这种关系,必须先抽象再继承</em>
<em> </em>
<em>抽象即抽取类似或者说比较像的部分。</em>
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)
<em>#</em><em>绑定方法:绑定给谁就应该由谁来调用,谁来调用就会把谁当做第一个参数自动传入</em>
<em> </em>
1.11.2 非绑定方法
<em>在类内部用staticmethod装饰的函数即非绑定方法,就是普通函数</em>
<em>statimethod</em><em>不与类或对象绑定,谁都可以调用,没有自动传值效果</em>
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()
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- Golang Echo数据绑定中time.Time类型绑定失败
- 如何在Symfony的表单中添加一个未绑定字段,否则绑定到一个实体?
- js双向绑定
- 延迟静态绑定——static
- 绑定自定义事件
- angular组件双向绑定
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。