Python第八课----面向对象

来源:转载


一、面向对象

1、封装:

1、组装:将数据和操作(即属性和方法)组装到一起

2、隐藏数据:对外只暴露一些接口,通过接口访问对象

2、继承:

1、多复用,继承的便不用自己写了

2、多继承少修改,OCP-----减少冗余,增加复用

3、多态:

python不太需要了解

二、Python的类

1、定义:

1、必须使用class关键字

2、类名必须是大驼峰

3、类定义完成后就产生了一个类对象,绑定到了ClassName上

class MyClass: #定义一个类

"""A example class"""

x = 'abc' #类属性

def foo(self): #类方法,self自带

return 'My Class'

print(MyClass.x)

print(MyClass.foo)

print(MyClass.__doc__)

三、类对象及类属性

1、类对象,类的定义就会生成一个类对象

2、类的属性,类定义中的变量和类中定义的方法都是类的属性

3、类变量,x是MyClass的变量

MyClass中,x和foo以及__doc__都是类的属性

foo是method方法对象,不是普通的function,它必须至少一个参数,第一个必须是self。

self纸袋当前实例本身

4、实例化:a = MyClass( )

5、__init__方法

Python类实例化后,会自动调用__init__方法,这个方法第一个参数必须是self

MyClass( )实际上调用的是__init__(self)方法,可以不定义,如果没有会在实例化后隐式调用

作用:对实例进行初始化

class MyClass:

def __init__(self):

print('init')

a = MyClass() #这个就会调用__init__

初始化函数可以多个参数,第一个位置必须给self

class Person:

def __init__(self,name,age):

self.name = name

self.age = age

def showage(self):

print('{} is {}'.format(self.name,self.age))

tom = Person('Tom',20) #实例化

jerry = Person('Jerry',25)

print(tom.name,jerry.age)

jerry.age += 1

print(jerry.age)

jerry.showage() #调用方法

__init__()方法不能有返回值,也就是只能是None

6、实例对象instance

类实例化后一定会获得一个对象,就是一个实例对象,tom,jerry都是Person的实例

__init__方法的第一参数self就是指代某一个实例

classMyClass:

def__init__(self):

print('self in init = {}'.format(id(self)))

c=MyClass()

print('c = {}'.format(id(c)))--------->实例化会把c送到self的位置

7、实例变量和类变量

classPerson:

age=3

def__init__(self,name):

self.name=name

tom=Person('Tom')

jerry=Person('Jerry')

print(tom.name,tom.age)

print(jerry.name,jerry.age)

print(Person.age)

Person.age=30

print(Person.age,tom.age,jerry.age)

实例变量是每一个实例自己的变量,是自己独有,类变量是类的变量,是类的所有实例共享的属性和方法

8、

特殊含义

含义

__name__

对象名

__class__

对象的类型

__dict__

对象的属性字典

__qualname__

类的限定名

举例:

classPerson:

age=3

def__init__(self,name):

self.name=name

print(Person.__class__)

print(sorted(Person.__dict__.items()),end='/n/n')

tom=Person('Tom')

print(tom.__class__)

print(tom.__dict__,end='/n')

print(tom.__class__.__name__)

print(tom.__class__.__dict__)

是类的,就是这个类所有实例的,其实例都可以访问,是实例的,就是这个实例自己的,通过类访问不到。

类变量是属于类的变量,这个类的实例可以共享

实例可以动态给自己增加一个属性。实例的.__dict__[变量名]和实例.变量名都可以访问到

实例的同名变量,就是实例自己的,会覆盖类的同名变量,但类的变量不变

classPerson:

age=3

height=170

def__init__(self,name,age=18):

self.name=name

self.age=age

tom=Person('Tom')

jerry=Person('Jerry',20)

Person.age=30

print(Person.age,tom.age,jerry.age)

print(Person.height,tom.height,jerry.height)

tom.height+=10

print(Person.height,tom.height,jerry.height)

Person.height+=15

print(Person.height,tom.height,jerry.height)

Person.weight=70

print(Person.weight,tom.weight,jerry.weight)

print(tom.__dict__['height'])

print(tom.__dict__['weight'])

9、实例属性的查找顺序

tom.__dict__---->tom.__class__---->Person.__dict__

类变量使用全大写来命名

10、装饰一个类

defadd_name(name):

defwrapper(clz):

clz.NAME=name

returnclz

returnwrapper

@add_name('Tom')# add_name = add_name('Tom')(Person)

classPerson:

AGE=3

print(Person.NAME)

11、类方法

classPerson:

@classmethod ----->装饰器,自带的,写法如下

defclass_method(cls):---->必须至少有一个参数,第一个默认cls,即类对象自身

cls.HEIGHT=170

Person.class_method()----->需要运行一下,才能写进去

print(Person.__dict__['HEIGHT'])

cls不能调用类的实例,因为cls是class_method的

12、静态方法:

classPerson:

@classmethod

defclass_method(cls):

cls.HEIGHT=170

@staticmethod

defstatic_method():------>静态方法

print(Person.HEIGHT)

Person.class_method()

Person.static_method()

print(Person.__dict__)

13、方法的调用

classPerson:

defnormal_method():

print('normal')

defmethod(self):

print("{}'s method".format(self))

@classmethod

defclass_method(cls):

print('class = {0.__name__}.({0})'.format(cls))

cls.HEIGHT=170

@staticmethod

defstatic_method():

print(Person.HEIGHT)

print(1,Person.normal_method())

# print(2,Person.method())这个不行

print(3,Person.class_method())

print(4,Person.static_method())

print(Person.__dict__)

tom=Person()

# print(1,tom.normal_method())这个不行,不能给参数

print(2,tom.method())

print(3,tom.class_method())#可以,但是还是Person

print(4,tom.static_method())

类几乎可以调用所有内部定义的方法,但是调用普通方法会报错,因为第一个参数必须是类的实例

实例也几乎可以调用所有的方法,普通函数的调用一般不会出现,不允许这么定义

总结:

类除了普通方法,都可以调用,普通方法需要对象的实例作为第一参数

实例可以调用所有类中定义的方法(包括类方法,静态方法),普通方法传入实例自身,静态和类方法,需要找到实例的类

四、访问控制

1、私有属性Private

classPerson:

def__init__(self,name,age=18):

self.name=name

self.age=age

defgrowup(self,i=1):

ifi>0andi<150:

self.age+=i

p1=Person('Tom')

p1.growup(20)#正常范围

print(p1.age)

p1.age=160#超过范围,还突破了if逻辑

print(p1.age)

私有属性方法:使用双下划线开头的属性名,就是私有属性

classPerson:

def__init__(self,name,age=18):

self.name=name

self.__age=age

defgrowup(self,i=1):

if0<i<150:

self.__age+=i

p1=Person('Tom')

p1.growup(20)

print(p1.__age)#这句不能访问,因为__把它隐藏了

print(p1._Person__age)#不过依然可以访问,只是约定不访问

访问方式:新建一个函数,直接内部返回定义的__age,外部实例调用这个函数即可

classPerson:

def__init__(self,name,age=18):

self.name=name

self.__age=age

defgrowup(self,i=1):

if0<i<150:

self.__age+=i

defgetage(self):

returnself.__age

p1=Person('tom')

print(p1.getage())

p1.growup(20)

print(p1.getage())

2、保护变量

在变量名前使用一个下划线,成为保护变量,就是个约定

classPerson:

def__init__(self,name,age=18):

self.name=name

self._age=age

tom=Person('Tom')

print(tom._age)

print(tom.__dict__)

3、私有方法

classPerson:

def__init__(self,name,age=18):

self.name=name

self._age=age

def_getname(self):#保护变量

returnself.name

def__getage(self):#私有变量

returnself._age

tom=Person('Tom')

print(tom._getname())#下划线只是约定保护,没什么卵用

# print(tom.__getage()) #无此属性

print(tom.__dict__)

print(tom.__class__.__dict__)

print(tom._Person__getage())

五、补丁:可以通过修改或者替换类的成员。使用者调用的方式没有改变,但是类提供的功能可能已经变了

猴子补丁,在运行时,动态替换属性,慎用

test代码:

classPerson:

defget_score(self):

ret={'English':80,'Chinese':99,'History':90}

returnret

test1代码:

defget_score(self):

returndict(name=self.__class__.__name__,English=10,Chinese=20,History=30)

test2代码:

fromtestimportPerson---->导入Person

fromtest1importget_score ---->导入修改模块

defmonkeypatch4Person():---->定义补丁函数

Person.get_score=get_score ---->将原需要修改的地方替换成现在的函数

monkeypatch4Person()---->运行一下

if__name__=="__main__":

print(Person().get_score())---->测试结果

六:属性装饰器

一般设计是:将实例的属性保护起来,不让外部访问,外部使用getter读取和setter设置信息

原理:

classPerson:

def__init__(self,name,age=18):

self.name=name

self.__age=age---->私有起来

defage(self):

returnself.__age ---->外部读取实例属性信息

defset_age(self,age):

self.__age=age ---->外部修改实例属性

tom=Person('Tom')

print(tom.age())

tom.set_age(20)

print(tom.age())

实际应用方法;

property装饰器:后面跟的函数名就是以后的属性名,它就是getter,这个必须有,有了就是只读

setter装饰器:与函数名同名,且接受两个参数,第一个self,第二个要修改的值,有了它,可写

deleter装饰器:可以删除属性,很少用

classPerson:

def__init__(self,name,age=18):

self.name=name

self.__age=age ---->定义一个私有属性

@property---->装饰器私有属性

defage(self): ---->定义函数读取属性

returnself.__age

@age.setter

defage(self,age): ---->定义函数修改属性

self.__age=age

@age.deleter

defage(self):---->定义函数删除属性

delself.__age

tom=Person('Tom')

print(tom.age)

tom.age=20

print(tom.age)

# del tom.age

# print(tom.age)

其他写法:

classPerson:

def__init__(self,name,age=18):

self.name=name

self.__age=age

defgetage(self):

returnself.__age

defsetage(self,age):

self.__age=age

defdelage(self):

delself.__age

age=property(getage,setage,delage,'age property')--->这句写上后面可以直接.age

tom=Person('Tom')

print(tom.age)

tom.age=20

print(tom.age)

deltom.age

或者;

classPerson:

def__init__(self,name,age=18):

self.name=name

self.__age=age

age=property(lambdaself:self.__age)

tom=Person('Tom')

print(tom.age)

七、对象的销毁:

类中可以定义__del__方法,成为析构函数(方法)

作用:销毁类的实例的时候调用,以释放占用的资源

由于python实现了垃圾回收机制,但不能确定何时执行,有必要时,使用del语句删除实例,手动调用

classPerson:

def__init__(self,name,age=18):

self.name=name

self.__age=age

def__del__(self):

print('del')

tom=Person('Tom')

deltom

print(tom.__dict__)

八、类的继承

1、通过继承,不需要写代码就可以继承父类的属性和方法

classAnimal:

def__init__(self,name):

self._name=name

defshout(self):

print('{} shout'.format(self.__class__.__name__))

@property

defname(self):

returnself._name

a=Animal('monster')

a.shout()

classCat(Animal):

pass

cat=Cat('garfield')

cat.shout()

print(cat.name)

classDog(Animal):

pass

dog=Dog('ahuang')

dog.shout()

print(dog.name)

2、特殊属性和方法

特殊属性和方法

含义

示例

__base__

类的基类

__bases__

类的基类元组

__mro__

显示方法查找顺序,基类的元组

mro()

同上

int.mro()

__subclasses__()

类的子类列表

int.subclasses__()

3、继承中的访问控制

classAnimal:

__COUNT=0

HEIGHT=0

def__init__(self,age,weight,height):

self.__COUNT+=1

self.age=age

self.__weight=weight

self.HEIGHT=height

defeat(self):

print('{} eat'.format(self.__class__.__name__))

def__getweight(self):

print(self.__weight)

@classmethod

defshowcount1(cls):

print(cls.__COUNT)

@classmethod

def__showcount2(cls):

print(cls.__COUNT)

classCat(Animal):

NAME='CAT'

c=Cat(3,5,15)

c.eat()

print(c.HEIGHT)

c.showcount1()#类方法,实例无法调用,相当于类调用

print(c.NAME)

print('{}'.format(Animal.__dict__))

print('{}'.format(Cat.__dict__))

print(c.__dict__)

print(c.__class__.mro())

从父类继承,自己没有的,就可以到父类中找

私有的都是不可以访问的,本质上是改了名

4、方法的重写、覆盖override

classAnimal:

defshout(self):

print('Animal shout')

classCat(Animal):

defshout(self):

print('miao')

defshout(self):

print(super())

print(super(Cat,self))

super().shout()

a=Animal()

a.shout()

c=Cat()

c.shout()

print(a.__dict__)

print(c.__dict__)

print(Animal.__dict__)

print(Cat.__dict__)

覆盖自身也是可以的

5、继承中的初始化

classAnimal:

def__init__(self,age):

print('Animal init')

self.age=age

defshow(self):

print(self.age)

classCat(Animal):

def__init__(self,age,weight):

super().__init__(age)

print('Cat init')

self.age=age+1

self.weight=weight

c=Cat(10,5)

c.show()

九、多继承

1、python3都是新式类,继承子object,新式类可以使用super

2、多继承:OCP原则,多继承,少修改,增强基类,实现多态

3、多态:在面向对象中,父类、子类通过继承练习在一起,如果一套方法,可以实现不同表现,就是多态

4、一个类继承自多个类就是多继承,它将具有多个类的特征

5、python使用MRO(method,resolution)


分享给朋友:
您可能感兴趣的文章:
随机阅读: