python 复习 day21-day23

上节课复习

  面向过程编程:

    核心是过程二字:过程指的是解决问题的步骤,即想干什么在干什么后干什么

    基于该思想编程序就好比在设计一条流水线,以一种机械式的思维方式

    优点:复杂的问题流程化,简单化

    确定:扩展性差

  面向对象编程:

    核心是对象二字,对象是特征与技能的结合体

    基于该思想在编写程序就好比在创造一个世界,世界万物都是对象,你就是这个世界的上帝

对象是特征与技能的结合体,类就是一些列对象相似的特征与技能的结合体

站在不同的角度,总结出的类是截然不同

在现实世界中给一定是要现有一个个对象,然后才有的不同的类

在程序中务必保证先定义类,然后调用类来产生对象

现实世界中总结对象--->抽取相似之处,得到现实世界中的类---》定义为程序为的类—----》调用类,场所程序中的对象

站在老男孩选课系统的角度

  

现实世界中的老男孩学生对象:
对象1:
特征:
学校='oldboy'
姓名='耗哥'
年龄=18
性别='male'
技能:
选课

对象2:
特征:
学校='oldboy'
姓名='猪哥'
年龄=17
性别='male'
技能:
选课

对象3:
特征:
学校='oldboy'
姓名='帅翔'
年龄=19
性别='female'
技能:
选课

站在老男孩选课系统的角度,先总结现实世界中的老男孩学生类
老男孩学生类:
相似的特征:
学校='oldboy'
相似的技能
选课




#1、先定义类
class OldboyStudent:
school='oldboy'

def choose_course(self):
print('is choosing course')


强调:类定义阶段会立刻执行类体代码,会产生类的名称空间,将类体代码执行过程中产生的名字都丢进去

print(OldbodyStudent.__dict___)
类本质就是一个名称空间/容器,从类的名称空间中,增加、删除、该、查名字
python 为我们提供专门访问属性 (名称空间中的名字)的语法,点后的都是属性
# OldboyStudent.school #OldboyStudent.__dict__['school']
# OldboyStudent.x=1 #OldboyStudent.__dict__['x']=1
# OldboyStudent.school='Oldboy' #OldboyStudent.__dict__['school']='Oldboy'
# del OldboyStudent.x #del OldboyStudent.__dict__['x']

类中定义的函数是类的函数属性,类可以使用,但使用的就是一个普通的函数而已,意味着需要完全遵循函数的参数规则,该传几个值就传几个
# OldboyStudent.choose_course(123)
后调用类产生对象,调用类的过程称之为实例化,实例化的结果成为类的一个实例或者对象
stu1=OldboyStudent()
stu2=OldboyStudent()
stu3=OldboyStudent()
# print(stu1)
# print(stu2)
# print(stu3)

# print(OldboyStudent.school)
# OldboyStudent.school='OLDBOY'
# print(stu1.school)
# print(stu2.school)
# print(stu3.school)

为对象定制自己独有的属性
class OldboyStudent:
  school='oldboy'
  def choose_course(self):
      print('is choosing course')

对象的本质也就是一个名称空间而已,对象名称空间是用来存放对象自己
独有的名字、属性,
而类中存放的是对象们共有的属性

# print(stu1.__dict__)
# print(stu2.__dict__)
# print(stu3.__dict__)

stu1.name='耗哥'
stu1.age=18
stu1.sex='male'
# print(stu1.name,stu1.age,stu1.sex)
# print(stu1.__dict__)

stu2.name='猪哥'
stu2.age=17
stu2.sex='male'

stu3.name='帅翔'
stu3.age=19
stu3.sex='female'


# 例2
class OldboyStudent:
school='oldboy'

def choose_course(self):
print('is choosing course')

stu1=OldboyStudent()
stu2=OldboyStudent()
stu3=OldboyStudent()

def init(obj,x,y,z):
obj.name=x
obj.age=y
obj.sex=z

# stu1.name='耗哥'
# stu1.age=18
# stu1.sex='male'
init(stu1,'耗哥',18,'male')

# stu2.name='猪哥'
# stu2.age=17
# stu2.sex='male'
init(stu2,'诸哥',17,'male')

# stu3.name='帅翔'
# stu3.age=19
# stu3.sex='female'
init(stu3,'帅翔',19,'female')


print(stu1.__dict__)
print(stu2.__dict__)
print(stu3.__dict__)
'''


class OldboyStudent:
school='oldboy'


def __init__(obj, x, y, z): #会在调用类时自动触发
obj.name = x #stu1.name='耗哥'
obj.age = y #stu1.age=18
obj.sex = z #stu1.sex='male'

def choose_course(self):
print('is choosing course')

调用类时发生的两件事
  1.创建一个空对象
  2.自动触发类中 __init__()构造函数,的执行。将对象以及调用类括号内的参数一同传入
stu1=OldboyStudent('耗哥',18,'male') #OldboyStudent.__init__(stu1,'耗哥',18,'male')
stu2=OldboyStudent('猪哥',17,'male')
stu3=OldboyStudent('帅翔',19,'female')


print(stu1.__dict__)
print(stu2.__dict__)
print(stu3.__dict__)


绑定方法
class OldboyStudent:
school='oldboy'


def __init__(self, x, y, z): #会在调用类时自动触发
self.name = x #stu1.name='耗哥'
self.age = y #stu1.age=18
self.sex = z #stu1.sex='male'

def choose_course(self,x):
print('%s is choosing course' %self.name)

def func():
pass


类名称空间中定义的数据属性和函数属性都是共享给所有对象用的
对象名称空间中定义的只有数据属性,而且是对象所独有的数据属性

stu1=OldboyStudent('耗哥',18,'male')
stu2=OldboyStudent('猪哥',17,'male')
stu3=OldboyStudent('帅翔',19,'female')

# print(stu1.name)
# print(stu1.school)

类中定义的函数是类的函数属性,类可以使用,但使用的就是一个普通的函数而已
意味着需要完完全全遵循函数的参数规则,该传几个值就传几个
# print(OldboyStudent.choose_course)
# OldboyStudent.choose_course(123)
类中定义的函数是共享给对象的,对象也可以使用,而且是绑定给对象的
绑定效果:绑定给谁,就应该由谁来调用,谁来调用就是将谁当作第一个参数自动传入
# print(id(stu1.choose_course))
# print(id(stu2.choose_course))
# print(id(stu3.choose_course))
# print(id(OldboyStudent.choose_course))

# print(id(stu1.school))
# print(id(stu2.school))
# print(id(stu3.school))
#
# print(id(stu1.name),id(stu2.name),id(stu3.name))


# stu1.choose_course(1)
# stu2.choose_course(2)
# stu3.choose_course(3)
sut1.func()


补充:类中定义的函数,类确定可以使用,但其实类定义的函数大多数情况下都是绑定给对象用的,所以在类中定义的函数都应该自带一个参数self


类即类型

#在python3 总统一了类与类型的概念,类就是类型
class OldboyStudent:
school='oldboy'

def __init__(self, x, y, z): #会在调用类时自动触发
self.name = x #stu1.name='耗哥'
self.age = y #stu1.age=18
self.sex = z #stu1.sex='male'

def choose_course(self,x):
print('%s is choosing course' %self.name)

stu1=OldboyStudent('耗哥',18,'male')
# stu1.choose_course(1) #OldboyStudent.choose_course(stu1,1)
# OldboyStudent.choose_course(stu1,1)


l=[1,2,3] #l=list([1,2,3])
# print(type(l))
# l.append(4) #list.append(l,4)
list.append(l,4)
print(l)

对象是一个高度整合的产物,整合数据与专门操作该数据的方法(绑定方法)

class Foo:
def __init__(self,host,port,db,chartset):
self.host=host
self.port=port
self.db=db
self.charset=charset

def exc1(self,sql):
conn = connect(self.host, self.port, self.db, self.charset)
conn.execute(sql)
return xxx

def exc2(self,proc_name)
conn = connect(self.host, self.port, self.db, self.charsett)
conn.call_proc(sql)
return xxx

class Bar:
def __init__(self,x,y,z,a,b,c):
self.x=x
self.y=y
self.z=z
self.a=a
self.b=b
self.c=c

def exc3(self,xxx):
pass

def exc4(self,yyy)
pass

obj1=Foo('1.1.1.1',3306,'db1','utf-8')
obj1.exc1('select * from t1')
obj1.exc1('select * from t2')
obj1.exc1('select * from t3')
obj1.exc1('select * from t4')

obj2=Foo('1.1.1.2',3306,'db1','utf-8')
obj2.exc1('select * from t4')

继承与派生

什么是继承
  继承是一种新建类的方式,新建类的称为子类,被继承的类称为父类
  继承的特性:子类会遗传父类的属性
  强调:继承是类与类之间的关系

为什么用继承
  继承:可以减少代码冗余

如何用继承
    python 中支持一个类同时继承多个父类
    在python3中
      如果一类没有继承任何类,拿默认继承object类
    在pytone2中
      如果一个类没有继承任何类,不会继承object类

  新式类:
      但凡继承了object 的类以及该类的子类,都是新式类
  经典类:
      没有继承object 的类以及该类的子类,都是经典类
在python3 中都是新式类,只有在python2中才区别新式类与经典类


派生:子类中新定义的属性,子类在使用时始终以自己为准


class OldboyPeople:
school = 'oldboy'
def __init__(self,name,age,sex):
self.name = name #tea1.name='egon'
self.age = age #tea1.age=18
self.sex = sex #tea1.sex='male'



class OldboyStudent(OldboyPeople):
def choose_course(self):
print('%s is choosing course' %self.name)


class OldboyTeacher(OldboyPeople):
# tea1,'egon',18,'male',10
def __init__(self,name,age,sex,level):
# self.name=name
# self.age=age
# self.sex=sex
OldboyPeople.__init__(self,name,age,sex)
self.level=level

def score(self,stu_obj,num):
print('%s is scoring' %self.name)
stu_obj.score=num

stu1=OldboyStudent('耗哥',18,'male')
tea1=OldboyTeacher('egon',18,'male',10)

#对象查找属性的顺序:对象自己-》对象的类-》父类-》父类。。。
# print(stu1.school)
# print(tea1.school)
# print(stu1.__dict__)
# print(tea1.__dict__)

tea1.score(stu1,99)

print(stu1.__dict__)


# 在子类派生出的新功能中重用父类功能的方式有两种:
#1、指名道姓访问某一个类的函数:该方式与继承无关


# class Foo:
# def f1(self):
# print('Foo.f1')
#
# def f2(self):
# print('Foo.f2')
# self.f1()
#
# class Bar(Foo):
# def f1(self):
# print('Bar.f1')
#
# #对象查找属性的顺序:对象自己-》对象的类-》父类-》父类。。。
# obj=Bar()
# obj.f2()
# '''
# Foo.f2
# Bar.f1
# '''

什么是封装:
  封:属性对外是隐藏的,但对内是开发的
  装:申请一个名称空间,往里面装入一些列名字/属性

为什么要封装
  封装数据属性的目的
    首先定义属性的目的就是为了给类外部的使用使用的
    隐藏之后是为了不让外部使用直接使用,需要类内部开辟一个接口
    然后让类外部的使用通过接口来间接地操作隐藏的属性
    精髓在与:我们可以在接口之上附加任意逻辑,从而严格控制使用者对属性的操作
封装函数属性:
  首先定义属性的目的就是为给类外部的使用的
  隐藏函数属性是为了不让外直接使用,需要类内部开辟一个接口
  然后在接口内去调用隐藏的功能
  精髓在:隔离了复杂度
如何封装
  如何隐藏:在属性前 加上 _ _ 开头

这种隐藏仅仅只是一种语法上的变形操作
这种语法上的变形只在类定义阶段发生一次
因为类体代码仅仅只在类定义阶段检测一次
这种隐藏是对外不对内的,即在类的内部可以直接访问,而在类的外侧无法直接访问,原因是
在类的定义阶段,类体内代码统一发生了一次变形

如果不想让子类的方法覆盖父类的,可以将方法名加一个 _ _ 开头

# class People:
# __country='China' #_People__country='China'
# __n=100 #_People__n=100
# def __init__(self,name,age,sex):
# self.__name=name #self._People__name=name
# self.age=age
# self.sex=sex
#
# def eat(self):
# print('eat.....')
# print(People.__country) #People._People__country
# print(self.__name) #self._People__name

# People.eat(123)
# print(People.__country)

# peo1=People('egon',18,'male')
# peo1.eat()
# print(peo1.__name)

# print(People.__dict__)
# print(People.__country)
# print(People._People__country)

# People.__x=11
# print(People.__dict__)


# peo1=People('egon',18,'male')
# print(peo1.__dict__)
# peo1.__x=111
# print(peo1.__dict__)

# class Foo:
# def __f1(self): #_Foo__f1
# print('Foo.f1')
#
# def f2(self):
# print('Foo.f2')
# self.__f1() #self._Foo__f1
#
# class Bar(Foo):
# def __f1(self): #_Bar__f1
# print('Bar.f1')
#
# obj=Bar()
# obj.f2()




class People:
def __init__(self,name,age):
self.__name=name
self.__age=age

def tell_info(self):
print('%s:%s' %(self.__name,self.__age))

def set_info(self,name,age):
if type(name) is not str:
# print('用户名必须为str类型')
# return
raise TypeError('用户名必须为str类型')

if type(age) is not int:
# print('年龄必须为int类型')
# return
raise TypeError('年龄必须为int类型')
self.__name=name
self.__age=age

peo1=People('egon',18)
# peo1.name=123
# peo1.age
# peo1.tell_info()

peo1.set_info('egon',19)
# peo1.tell_info()



特性
  property装饰器用于被装饰的方法伪装成一个数据属性,在使用时可以不用加括号而直接引用

绑定方法:
  特性:绑定给谁就应该由谁来调用,谁来调用就会将谁当做第一个参数自动传入
    《精髓在与自动传值》
  
绑定方法分为两类:
    绑定给对象方法
      在类内部定义的函数(没有被任何装饰器修饰的),默认就是绑定给对象用的
    绑定给类的方法
      在类内部定义的函数如果被装饰器@classmethod装饰
      那么则是绑定给类使用的,应该由类来调用,类来调用就自动
      将类当做第一个参数传入

非绑定方法:
    类中定义的函数如果被装饰器@staticmethod装饰,那么该函数就变成非绑定方法
    既不与类绑定,又不与对象绑定,意味着类与对象都可以来调用
    但是无论谁来调用,都没有任何自动传值的效果,就是一个普通的函数

应用:
  如果函数体代码需要用外部传入的类,则应该将该函数定义成绑定给类的方法
  如果函数体代码需要用外部传入的对象,则应该将该函数定义为绑定给对象的方法
  如果函数体代码既不需要外部传入类,也不需要传入对象,则应该将该函数定义为非绑定方法/就是普通函数



# class Foo:
# @classmethod
# def f1(cls):
# print(cls)
#
# def f2(self):
# print(self)
#
#
# obj=Foo()
# print(obj.f2)
# print(Foo.f1)

# Foo.f1()
# print(Foo)


#1、f1绑定给类的
# 了解:绑定给类的应该由类来调用,但对象其实也可以使用,只不过自动传入的仍然是类
# print(Foo.f1)
# print(obj.f1)
# Foo.f1()
# obj.f1()

#2、f2是绑定给对象的
# obj.f2()
# Foo.f2(obj)

import settings
import uuid

class Mysql:
def __init__(self,ip,port):
self.uid=self.create_uid()
self.ip=ip
self.port=port

def tell_info(self):
print('%s:%s' %(self.ip,self.port))

@classmethod
def from_conf(cls):
return cls(settings.IP, settings.PORT)

@staticmethod
def func(x,y):
print('不与任何人绑定')

@staticmethod
def create_uid():
return uuid.uuid1()

# 默认的实例化方式:类名(..)
obj=Mysql('10.10.0.9',3307)

# 一种新的实例化方式:从配置文件中读取配置完成实例化
# obj1=Mysql.from_conf()
# obj1.tell_info()

# obj.func(1,2)
# Mysql.func(3,4)
# print(obj.func)
# print(Mysql.func)

print(obj.uid)

上节课复习
  什么是组合?一个类的对象具备某一个属性
  该属性的值是指向另外一个类的对象的

    class Foo:
pass

class Bar:
pass

obj_of_foo=Foo()
obj_of_bar=Bar()
obj_of_foo.attrib=obj_of_bar

obj_of_foo.attrib.xxx

为何用组合?
是为了减少类与类之间的代码冗余

菱形继承问题之新式类与经典的区别
A(B,C,D)
在属性查找方面
新式类:广度优先查找
经典类:深度优先查找

继承的实现原理
基于c3算法,mro 列表
在子类派生的新方法中重用父类功能的两种方式
  指名道姓(与继承类无关):类名.函数名(该传几个传几个)
  super(自己的类名,self).父类的属性:
    严格依赖继承, super()得到一个特殊的对象
      该对象专门从当前的父类开始往后查找

多态
  多态值的是一种事物的多种形态,
  多态性:
      指的是继承同一个父类的子类,具有相同的方法名
      在使用的时候,子类的对象可以在不用考虑其具体数据类的前提下
      而直接调用方法
import abc
class Foo(metaclass=abc.ABCMeta):
@abc.abstractmethod
def func1(self):
pass

class Bar(Foo):
def func1(self):
pass


强调:父类不能实例化,子类要想实例化则必须实现与父类同名的方法
python 崇尚 鸭子类型

猜你喜欢

转载自www.cnblogs.com/yanxiatingyu/p/9314453.html