python学习之路-day6-面向对象

一、面向对象学习

1、面向对象介绍

2、创建一个类

3、实例变量和类变量

4、析构函数

5.私有属性&私有方法

6、继承

7、多态

8、类的特殊方法

9、反射

面向对象编程

OOP编程是利用“类”和“对象”来创建各种模型来实现对真实世界的描述,使用面向对象编程的原因一方面是因为它可以使程序的维护和扩展变得更简单,并且可以大大提高程序开发效率 ,另外,基于面向对象的程序可以使它人更加容易理解你的代码逻辑,从而使团队开发变得更从容。

初识class类

一个类即是对一类拥有相同属性的对象的抽象、蓝图。原型。在类中定义了这些对象的都具备的属性、共同的方法。

面向过程编程和面向对象编程:

面向过程编程:使用一系列的指令告诉计算机怎么一步步执行
基本设计思路就是程序一开始是着手解决一个大的问题,然后把一个大的问题分解成很多小问题或子过程
面向对象编程:
OOP编程是利用“类”和“对象”来创建各种模型来实现对真实世界的描述
世界万物皆对象。
只要是对象,就肯定属于某种类
只要是对象,就肯有属性

objiect对象:

一个对象即是一个类的实例化后的实例,一个类可以实例化多个对象,每个对象亦可以有不同的属性

特性:

  封装

  继承

  多态

encapsulation封装:

  在类中对数据的赋值、内部调用对外部用户是透明的,这使类变成了一个胶囊或容器,里面包含着类的数据和方法,封装可以隐藏实现细节,使得代码模块化,就是用户不需要知道类的内部是怎样做的,只需要知道它的功能。

inheritance继承:

  一个类可以派生出子类,在这个父类里面定义的属性、方法自动被子类继承

名词术语:

  • 类(Class):

  用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。

  • 类变量

  类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。

  • 对象

  一个对象即是一个类的实例化后的实例,一个类必须经过实例化后方可在程序中调用,一个类可以实例化多个对象,每个对象亦可以有不同的属性

  • 实例变量

  定义在方法中的变量,只作用于当前实例的类

  • 方法

   类中定义的函数。(动态属性)

  • 属性

  类变量、实例变量、方法都是属性,变量是静态属性,方法是动态属性

  • 实例化

  创建一个类的实例,类的具体对象。

类的语法:

  用class语句来创建一个新类,class之后为类的名称并以冒号结尾

class liangwei:
print("我是一个类")

术语讲解

1、构造方法

class Role(object):  #定义一个类
def __init__(self): #初始化,构造方法,调用类的时候自动执行的函数
pass

上面的这个__init__()叫做初始化方法(或构造方法), 在类被调用时,这个方法(虽然它是函数形式,但在类中就不叫函数了,叫方法)会自动执行,进行一些初始化的动作。

属性

__author__ = 'lw'

class Role(object):
def __init__(self,name,role,weapon,life_value=100,money=15000): ##定义一个类, class是定义类的语法,Role是类名,(object)是新式类的写法
self.name = name              ##初始化函数,在生成一个角色时要初始化的一些属性就填写在这里
self.role = role              ####self.name = r1.name
self.weapon = weapon
self.life_value = life_value
self.money = money def shot(self):
print("shooting...") def got_shot(self):
print("ah...,I got shot...") def buy_gun(self,gun_name):
print("just bought %s" %gun_name) r1 = Role('Alex','police','AK47') #生成一个角色,也即是生成一个实例(对象)
r2 = Role('Jack','terrorist','B22') #生成一个角色,生成一个实例(对象)
我们看到,上面的创建角色时,我们并没有给__init__传值,程序也没未报错,是因为,类在调用它自己的__init__(…)时自己帮你给self参数赋值了,
r1 = Role('Alex','police','AK47’) #此时self 相当于 r1 ,  Role(r1,'Alex','police','AK47’)
r2 = Role('Jack','terrorist','B22’)#此时self 相当于 r2, Role(r2,'Jack','terrorist','B22’)
 
   

例2:

  

#!/usr/bin/env python
#_*_ coding:utf-8 _*_
#_*_coding:utf-8_*_
class Dog:
n = 123   #类变量,公用的属性
  def __init__(self,name): #构造函数    

  #self代表d1,self就是为了接受d1,d1(self)其实就是接收的变量值的内存地址,下面函数调用(self)的时候就是把变量传进去(内存地址) 

  #self:谁调用就是指谁(d1或者d2或者d3) #d1 = Dog(“al”)---->Dog(“d1”,”al”), 
    self.name = name #实例变量(静态属性),赋值给实例,作用域就是实例本身
    
  def bulk(self): #self接收d1(Dog)
    “””” Bulk:类的方法(动态属性) ”””     print("%s 汪~汪~汪" %(self.name)) #self.name ===d1.name
d1 = Dog("旺旺") #只是生成一个dog,并没有动作,旺旺是传给了类里面init函数里的变量
d1.name = “旺旺2” #可以改名
d1.fafagagag = “test” #可以添加一个新的属性
del d1.name 删除d1的name属性,下面就不能调用了
d2 = Dog("小黑")
d3 = Dog("豆豆")
d1.bulk() #动作 d2.bulk() #执行输出: # 旺旺 汪~汪~汪 # 小黑 汪~汪~汪 #注:变量的顺序,现找实例变量,后找类变量,如果有实例变量就用实例变量,如果没有实例变量,就用类变量

2、析构函数(方法)

  在实例释放、销毁的时候自动执行的,通常用于做一些收尾工作, 如关闭一些数据库连接,关闭打开的临时文件

def __del__(self):    #析构函数,收尾工作,自动执行
pass

例1:

 #_*_ coding:utf-8 _*_
class Role(object):
def __init__(self,name,role,weapon,life_value=100,money=15000):
#构造函数
#在实例化时做一些类的初始化的工作
self.name = name
self.role = role
self.weapon = weapon
self.life_value = life_value
self.money = money
def __del__(self): #析构函数,收尾工作,自动执行
print("%s 死了"%self.name)
def shot(self):
print("shooting...") def got_shot(self):
print("%s: ah...,I got shot..."%self.name) def buy_gun(self,gun_name):
print("just bought %s" %gun_name) r1 = Role('Alex','police','AK47') #生成一个角色
r1.buy_gun("AAA")
r1.got_shot()
r2 = Role('Jack','terrorist','B22') #生成一个角色
r2.got_shot() 执行结果:
just bought AAA
Alex: ah...,I got shot... #在这析构函数并没有执行,因为程序还在执行,r1实例还在内存中,没有释放! 如果想中枪就死,需要在r1执行完后(r1.got_shot()后面)加上del r1
Jack: ah...,I got shot...
Alex 死了
Jack 死了

私有属性&&私有方法

  私有属性:只能内部(类的内部)调用,外面调用不了(r1调用不了)

  私有方法:和私有方法是一样的。

 # _*_ coding:utf-8 _*_
__author__ = 'XS'
#_*_ coding:utf-8 _*_
class Role(object):
def __init__(self,name,role,weapon,life_value=100,money=15000):
#构造函数
#在实例化时做一些类的初始化的工作
self.name = name
self.role = role
self.weapon = weapon
self.__life_value = life_value #私有属性
self.money = money
def __shot(self): #私有方法
print("shooting...")
def show_status(self): #只能这样调用
print("%s:life_vale"%self.__life_value)
def got_shot(self):
self.__shot() #调用私有方法
r1 = Role('A','police','AK47') #生成一个角色)
r1.got_shot()
#r1._Role__shot()
print(r1.show_status())
r2 = Role('Jack','terrorist','B22') #生成一个角色
r2.got_shot()

3、静态方法

 # _*_ coding:utf-8 _*_
__author__ = 'XS'
class Dog(object):
def __init__(self,name,food):
self.name = name
self.food = food
# @staticmethod
#静态方法,使下面的类的方法变成一个单纯的函数(使函数跟类没什么关系了,只是还是需要这个类调用)
#下面的函数不能调用类的变量,也不能调用self。
# @classmethod #类方法
def eat(self):
print("%s is eating %s"%(self.name,self.food))
# def eat():
# print("%s is eating %s"%("A","food"))
d = Dog("A","B")
d.eat()
# d = Dog("A","B")
# d.eat()

4、类方法:只能访问类变量,不能访问实例变量

 # _*_ coding:utf-8 _*_
__author__ = 'XS'
class Dog(object):
# name = "zs"
# food = "qiezi"
def __init__(self,name,food):
self.name = name
self.food = food
# @classmethod #类方法,只能访问类变量,不能访问实例变量
def eat(self):
print("%s is eating %s"%(self.name,self.food))
d = Dog("A","B")
d.eat()

5、属性方法

  把一个方法变成一个静态属性,(成为一个属性后不能通过加括号调用)

 # _*_ coding:utf-8 _*_
__author__ = 'XS'
class Dog(object):
def __init__(self,name):
self.name = name
# self.__food = None
def eat(self):
print("%s is eating %s"%(self.name,""))
# @property # 属性方法,变成一个属性后就不能通过括号传参数了
# def eat(self):
# print("%s is eating %s"%(self.name,self.__food))
# @eat.setter #和属性方法对应,用于给属性方法传参数
# def eat(self,food):
# print "set to food:",food
# self.__food = food
# @eat.deleter
# def eat(self):
# del self.__food
# print("delete") d = Dog("A")
d.eat()
# d.eat
# d.eat = "baozi"
# d.eat
#
# del d.eat #属性方法默认不能删除,需要@eat.deleter
# d.eat

继承

例1:

class  People:
def __init__(self,name,age):
self.name = name
self.age = age
def eat(self):
print("%s is eating...."%self.name)
def talk(self):
print("%s is talking..."%self.name)
def sleep(self):
print("%s is sleeping...."%self.name)
class Man(People): #继承People类
pass
m1 = Man("A","") #因为Man是继承People,所以调用Man的时候需要传和People一样的参数
m1.eat()

例2:

#_*_ coding:utf-8 _*_
class People(object):
def __init__(self,name,age):
self.name = name
self.age = age
def eat(self):
print("%s is eating...."%self.name)
def talk(self):
print("%s is talking..."%self.name)
def sleep(self):
print("%s is sleeping...."%self.name)
class Man(People):
def __init__(self,name,age,money): #重构父类方法
#因为继承的父类People,父类里面有name和age属性,所以这里也要加
#实例化的时候传的参数先到这里
# People.__init__(self,name,age) #把父类的执行一遍(调用父类),经典类写法
super(Man,self).__init__(name,age) #调用父类,和上面的一样,新式类写法
self.money = money #name和age 都在父类里面定义了,这里只需要money
print("%s 一出生就有%s money"%(self.name,self.money))
def piao(self):
print("%s is piaoing....."%self.name)
class Woman(People):
def get_birth(self):
print("%s is born a baby...."%self.name)
m1 = Man("A","","")
m1.eat()
m1.piao() w1 = Woman("B",26)
w1.get_birth()

多继承

例1:

 #_*_ coding:utf-8 _*_
class People(object):
def __init__(self,name,age):
self.name = name
self.age = age
def eat(self):
print("%s is eating...."%self.name)
def talk(self):
print("%s is talking..."%self.name)
def sleep(self):
print("%s is sleeping...."%self.name)
class Relation(object):
def make_friends(self,obj):
print("%s is making friends with %s" %(self.name,obj.name)) #name在下面类里面继承父类的时候传进去
class Man(People,Relation): #在Man构造的时候生成了name,下面调用的时候先执行的Man,然后在执行父类的方法
#子类有构造函数(__init__),所以继承的顺序没有关系,如果子类没有构造函数,继承的顺序是有关系的,因为没有构造函数变量就会传到父类里面,一个父类里面没有就去另一个父类里面找
def __init__(self,name,age,money): #重构父类方法
#因为继承的父类People,父类里面有name和age属性,所以这里也要加
#实例化的时候传的参数先到这里
# People.__init__(self,name,age) #把父类的执行一遍(调用父类),经典类写法
super(Man,self).__init__(name,age) #调用父类,和上面的一样,新式类写法
self.money = money #name和age 都在父类里面定义了,这里只需要money
print("%s 一出生就有%s money"%(self.name,self.money))
def piao(self):
print("%s is piaoing....."%self.name)
class Woman(People,Relation):
def get_birth(self):
print("%s is born a baby...."%self.name)
m1 = Man("A","","")
w1 = Woman("B","") #Woman继承的People,所以需要传2个参数
m1.make_friends(w1) #obj = w1 --》0bj.name == w1.name

经典类和新式类的区别

广度优先:先找D,D没有就找B,B没有找C,C没有找A

深度优先:先找D,D没有就找A,A没有在去找C

 #_*_ coding:utf-8 _*_

 class A:

     def __init__(self):

         print("A")

 class B(A):    #B继承A

     pass

     # def __init__(self):

     #     print("B")

 class C(A):  #C继承A

     pass

     # def __init__(self):

     #     print("C")

 class D(B,C): #D继承B,C

     pass

     # def __init__(self):

     #     print("D")

 obj = D()

Python2:经典类是按深度优先查询,新式类是按广度优先继承的

pythony3: 经典类和新式类都是统一按广度优先来继承的

继承实例(学校)

实例功能,教师教学,学生缴费

 # _*_ coding:utf-8 _*_
__author__ = 'XS'
class School(object):
def __init__(self,name,addr):
self.name = name
self.addr = addr
self.students = []
self.teachers = []
self.staffs = []
def enroll(self,stu_obj):
print("为学员%s办理注册手续"%stu_obj.name) #stu_obj是个实例,学员需要实例化,实例化后就可以得到名字
self.students.append(stu_obj) #添加到列表中的都是实例,打引:print(stu_obj[0].name)
def hire(self,staff_obj):
self.staffs.append(staff_obj) #添加到列表中的都是实例,打引列表中的值:print(staff_obj[0].name==staff_obj.name)
print("雇佣新员工%s" %staff_obj.name)
class SchoolMember(object):
def __init__(self,name,age,sex):
#学生和老师类都需要继承schoolMember类,老师和学生都有name、age。。。
#下面老师和学生类继承schoolMember类,就可以少写属性了(self.name = name)
self.name = name
self.age = age
self.sex = sex
def tell(self):
pass
class Teacher(SchoolMember):
def __init__(self,name,age,sex,salary,course): #重构父方法,教师除了name等,还有salary和course(课程)
super(Teacher,self).__init__(name,age,sex) #继承父类已经实现了的(变量/属性)
self.salary = salary #自己的变量(属性)
self.course = course
def tell(self): #重构tell方法
print('''
---- info of Teacher:%s ----
name:%s
Age:%s
Sex:%s
Salary:%s
Course:%s
'''%(self.name,self.name,self.age,self.sex,self.salary,self.course)) def teach(self): #教师的特性方法
print("%s is teaching course [%s]"%(self.name,self.course)) class Student(SchoolMember):
def __init__(self,name,age,sex,stu_id,grade):
super(Student,self).__init__(name,age,sex) ##继承父类已经实现了的(变量),
self.stu_id = stu_id #自己的变量(属性)
self.grade = grade
def tell(self): #重构tell方法
print('''
---- info of Student:%s ----
name:%s
Age:%s
Sex:%s
Stu_id:%s
Grade:%s
'''%(self.name,self.name,self.age,self.sex,self.stu_id,self.grade))
def pay_tuition(self,amount): #定义学生自己的方法
print("%s has paid tuition for $ %s"%(self.name,amount)) #开始实例化
#先实例化一个学校
school = School("清华","中关村") #School类里面构造函数的时候需要2个参数 t1 = Teacher("Oldboy",56,"Man",20000,"Linux")
t2 = Teacher("Alex",22,"Man",3000,"Python") s1 = Student("A",30,"MF",1001,"Python")
s2 = Student("B",20,"Woman",1002,"Linux") t1.tell()
s1.tell()
school.hire(t1)
school.enroll(s1)
school.enroll(s2) print(school.students)
print(school.staffs) school.staffs[0].teach() for stu in school.students:
stu.pay_tuition(5000)

多态

一种接口,多种实现

例:

# _*_ coding:utf-8 _*_
__author__ = 'XS'
class Animal: #定义一个动物类
def __init__(self,name):
self.name = name
# def talk(self):
# pass
# @staticmethod #静态方法
# def duotai(obj):
# obj.talk()
class Cat(Animal):
def talk(self):
print("%s is miao"%self.name)
class Dog(Animal):
def talk(self):
print("%s is wang"%self.name) # def duotai(obj): #定义一个多态接口,传一个obj参数
# obj.talk()
d = Dog("A")
d.talk() c = Cat("B")
c.talk() #
# duotai(d)
# duotai(c) # Animal.duotai(d)
# Animal.duotai(c)

类的特殊方法

1. __doc__  表示类的描述信息

 # _*_ coding:utf-8 _*_
__author__ = 'XS'
class Foo:
"""类的描述信息,就是__doc__"""
def func(self):
pass
print Foo.__doc__

2. __module__ 和  __class__ 

 __author__ = 'XS'
class C:
def __init__(self):
pass
############
from lw.tete import C A = C()
print(A.__module__) #输出C这个模块是在哪个路径导入的
print(A.__class__) #输出A是哪个类实例化的

3. __init__ 构造方法,通过类创建对象时,自动触发执行。

4.__del__

5. __call__ 对象后面加括号,触发执行

 #__call__
# 注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
class Dog:
def __init__(self,name):
self.name = name
def bulk(self):
print("%s 汪~汪~汪" %(self.name))
def __call__(self, *args, **kwargs):
print "I am call",args,kwargs
d1 = Dog("旺旺")
d1("aaa","bbb","cccc")

6. __dict__ 查看类或对象中的所有成员

# _*_ coding:utf-8 _*_
__author__ = 'XS'
class Province:
country = 'China'
def __init__(self, name, count):
self.name = name
self.count = count
def func(self, *args, **kwargs):
print 'func'
# 获取类的成员,即:静态字段、方法、
print Province.__dict__
# obj1 = Province('HeBei',10000)
# print obj1.__dict__
# 获取 对象obj1 的成员
obj2 = Province('HeNan', 3888)
# print obj2.__dict__
# 获取 对象obj1 的成员

7.__str__ 如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值。

python3中使用,python建议使用__unicode__

 # _*_ coding:utf-8 _*_
__author__ = 'XS'
# _*_ coding:utf-8 _*_
__author__ = 'XS'
#_*_ coding:utf-8 _*_
class Role(object):
def __init__(self,name,role,weapon,life_value=100,money=15000):
self.name = name
self.role = role
self.weapon = weapon
self.life_value = life_value
self.money = money
def shot(self):
print("shooting...")
def got_shot(self):
print("%s: ah...,I got shot..."%self.name)
def buy_gun(self,gun_name):
print("just bought %s" %gun_name)
# def __str__(self):
# print("name is %s"%self.name)
# return "name is %s"%self.name r1 = Role("A","P","Ak47")
print(r1)

8.__getitem__、__setitem__、__delitem__

用于索引操作,如字典。以上分别表示获取、设置、删除数据

 # _*_ coding:utf-8 _*_
__author__ = 'XS'
#把这个实例变成字典
class Foo(object):
def __init__(self):
self.data = {}
def __getitem__(self, key):
print('__getitem__',key) #('__getitem__', 'name')
return self.data.get(key)
def __setitem__(self, key, value):
print('__setitem__',key,value)
self.data[key] = value
def __delitem__(self, key):
print('__delitem__',key) obj = Foo() #实例化后,就成了字典
obj["name"] = "lw" #可以像字典一样赋值,自动触发执行 __setitem__
result = obj['name'] # 自动触发执行 __getitem__
print(result)
print(obj.data) #打印这个字典
del obj['name'] #只是触发__delitem__,并没有真的删除,要想删除在__delitem__这个函数下面删除,如果不想让用户删除某些key,可以加判断
print(obj.data)
# del obj['k1']

9. __new__ \ __metaclass__

# _*_ coding:utf-8 _*_
__author__ = 'XS'
class Foo(object):
def __init__(self,name):
self.name = name f = Foo("lw")

上述代码中,obj 是通过 Foo 类实例化的对象,其实,不仅 obj 是一个对象,Foo类本身也是一个对象,因为在Python中一切事物都是对象

如果按照一切事物都是对象的理论:obj对象是通过执行Foo类的构造方法创建,那么Foo类对象应该也是通过执行某个类的 构造方法 创建。

print type(f) # 输出:<class '__main__.Foo'>     表示,obj 对象由Foo类创建
print type(Foo) # 输出:<type 'type'> 表示,Foo类对象由 type 类创建

那么创建类就有两种方式

a)普通方式:

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

b)特殊方式:


def func(self):
print("hello xs")
Foo = type('Foo',(object),{'fc':func}) #Foo:类名,object:新式类,fc:key,func函数 print(type(Foo)) f = Foo()
f.fc()
#type第一个参数:类名 #type第二个参数:当前类的基类 #type第三个参数:类的成员

SO,类是由type类实例化产生的
#类的起源,类的底层----------一切皆对象,类也是对象
 def func(self):
print("hello xs %s"%self.name)
def __init__(self,name,age):
self.name = name
self.age = age
Foo = type('Foo',(),{'fc':func,'__init__':__init__})
f = Foo("A","")
f.fc()

反射

通过字符串映射或修改程序运行时的状态、属性、方法, 有以下4个方法

hasattr:判断object中有没有一个name字符串对应的方法或属性

getattr:根据字符串去获取对象里的方法对应的内存地址

setattr :s equivalent to ``x.y = v''

 # _*_ coding:utf-8 _*_
__author__ = 'XS'
def bulk(self): #这里会将函数设置成类里面的方法
print("%s is bulking"%self.name)
class Dog(object): def __init__(self,name):
self.name = name
def eat(self,age): print("%s is eating.."%self.name) d = Dog("金毛")
# d.eat()
choice = raw_input(">>>:").strip()
# d.choice 想实现这种调用,根据用户输入调用方法,但是不能这么写,因为choic是个字符串
print(hasattr(d,choice)) #查看类中是否有用户输入的方法或者属性,有打印True,没有打印False
# print(getattr(d,choice)) #这样会打印这个方法的内存地址,加上()就调用了
# getattr(d,choice)() #调用
#------------------------------
# print(d.name)
# setattr(d,"name",choice)
# print(d.name)
#-------------------------------
# setattr(d,choice,"22")
# print(getattr(d,choice))
# print(hasattr(d,choice))
#------------------------------
#动态添加变量
# if hasattr(d,choice):
# getattr(d,choice)
# else:
# setattr(d,choice,"ccc")
# V = getattr(d,choice)
# print(V)
#---------------------------
#动态设置方法,无论用户输入什么,都不会报错,都可以调用方法
# if hasattr(d,choice):
# getattr(d,choice)
# else:
# setattr(d,choice,bulk) #d.talk == bulk
# func = getattr(d,choice) #获取choic的内存地址
# func(d) # ----------------------
# print(hasattr(d,choice))
# getattr(d,choice)()
# print(d.name)
# if hasattr(d,choice):
# delattr(d,choice)
# else:
# print("dont")
# print(d.name)
# delattr(d,choice)
# if hasattr(d,choice):
# getattr(d,choice)()
#
# else:
# # print("没有这个方法")

练习

角色:学校、学员、课程、讲师
要求:
1. 创建北京、上海 2 所学校
2. 创建linux , python , go 3个课程 , linux\py 在北京开, go 在上海开
3. 课程包含,周期,价格,通过学校创建课程 
4. 通过学校创建班级, 班级关联课程、讲师
5. 创建学员时,选择学校,关联班级
5. 创建讲师角色时要关联学校, 
6. 提供两个角色接口
6.1 学员视图, 可以注册, 交学费, 选择班级,
6.2 讲师视图, 讲师可管理自己的班级, 上课时选择班级, 查看班级学员列表 , 修改所管理的学员的成绩 
6.3 管理视图,创建讲师, 创建班级,创建课程

上一篇:hdu3282 链表或者对顶堆


下一篇:(后端)Mybatis中#{}和${}传参的区别及#和$的区别小结(转)