面向对象
基础
===
- oop
面向对象最重要的概念就是类(Class)和实例(Instance),必须牢记类是抽象的模板,而实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可能不同。
Python类提供了面向对象编程的所有标准功能:类继承机制允许多个基类,派生类可以重写其基类或类的任何方法,并且方法可以调用具有相同名称的基类的方法。对象可以包含任意数量和种类的数据。与模块一样,类也具有Python的动态特性:它们是在运行时创建的,并且可以在创建后进一步修改。 - 定义类
class Employee:
'所有员工的基类'
# empCount 变量是一个类变量,它的值将在这个类的所有实例之间共享。你可以在内部类或外部类使用 Employee.empCount 访问。
empCount = 0
# 方法__init__()方法是一种特殊的方法,被称为类的构造函数或初始化方法,当创建了这个类的实例时就会调用该方法
def __init__(self, name, salary):
self.name = name
self.salary = salary
Employee.empCount += 1
# self 代表类的实例,self 在定义类的方法时是必须有的,虽然在调用时不必传入相应的参数。
def displayCount(self):
print ("Total Employee %d" % Employee.empCount)
print (self.__class__)
def displayEmployee(self):
print("Name : ", self.name, ", Salary: ", self.salary)
ee1= Employee('NICK',100000)
ee2= Employee('ROSE',100000)
ee1.displayCount()
ee2.displayEmployee()
类属性使用 类名.属性名 的方式去访问,对象也可以访问。但是如果对象修改,则只对当前对象适用(因为这是其实是增加对象属性)
- 动态为对象添加、删除属性
只会影响到当前操作的对象
ee1= Employee('NICK',100000)
ee2= Employee('ROSE',888888)
ee1.age=22
print(ee1.age)
# del ee1.name
ee1.displayEmployee()
# print ee2.age #error
print (hasattr(ee1, 'age') ) # 如果存在 'age' 属性返回 True。
print (getattr(ee1, 'age') ) # 返回 'age' 属性的值
setattr(ee2, 'age', 8) # 添加属性 'age' 值为 8
print(ee2.age)
delattr(ee1, 'age') # 删除属性 'age'
- 析构函数
def __del__(self):
class_name = self.__class__.__name__
print(class_name, "销毁")
- 内置属性
print (Employee.__dict__)
print (Employee.__doc__)
# 类的所有父类构成元素(包含了一个由所有父类组成的元组)
print (Employee.__bases__)
ee1=Employee('NICK',200)
dd2=ee1
dd2.name='dog'
# del ee1
# ee1.displayEmployee()
dd2.displayEmployee()
print(isinstance(ee1,Employee))
print(isinstance(ee1,object))
高级
===
6. 继承
类的继承
1:在继承中基类的构造(__init__()方法)不会被自动调用,它需要在其派生类的构造中亲自专门调用。
2:在调用基类的方法时,需要加上基类的类名前缀,且需要带上self参数变量。区别在于类中调用普通函数时并不需要带上self参数
3:Python总是首先查找对应类型的方法,如果它不能在派生类中找到对应的方法,它才开始到基类中逐个查找。(先在本类中查找调用的方法,找不到才去基类中找)。
```
class Boss(Employee):
def __init__(self,name,salary,jiangjin):
super(Boss, self).__init__(name, salary)
self.jiangjin = jiangjin
def displayEmployee(self):
print("Name : ", self.name, ", Salary: ", self.salary,'other jiangjin:',self.jiangjin)
```
>python没有重载,因为函数名知识指向内存地址的变量。
- 多重继承
#-*- coding:UTF-8 -*-
# 多重继承
class A(object):
__scope='a scope'
def __init__(self, a):
print('init A...')
self.a = a
def show(self):
print('i am A')
class B(A):
def __init__(self, a):
super(B, self).__init__(a)
print( 'init B...')
def show(self):
super(B,self).show()
print(' and i am B too')
class C(A):
def __init__(self, a):
super(C, self).__init__(a)
print('init C...')
def show(self):
super(C, self).show()
print(' and i am C too too')
class D(B, C):
def __init__(self, a):
super(D, self).__init__(a)
print('init D...')
def show(self):
super(D, self).show()
print(' and i am D too too...')
d=D(12)
# print B.scope
d.show()
#d多重继承时为了从多个类中提取多个方法
# 查看对象信息
# print(isinstance(d,D))
# print(isinstance(d,A))
#
# print(type(d))
# print(dir(d))
- 使用接口的思想设计多重继承
整体可以分为类型类和功能类两种类,类型类实现主体继承树形结构,功能类作为独立的功能接口存在。
#-*- coding:UTF-8 -*-
# 多重继承
class Animal(object):
def __init__(self,age):
self.age=age
# 大类:
class Mammal(Animal):
def __init__(self,age,foot):
super(Mammal,self).__init__(age)
self.foot=foot
class Bird(Animal):
def __init__(self,age,fly):
super(Bird,self).__init__(age)
self.fly=fly
class RunnableMixIn(object):
def run(self):
print('Running...')
class FlyableMixIn(object):
def fly(self):
print('Flying...')
# 各种动物:
class Dog(Mammal,RunnableMixIn):
def __init__(self,age,foot,gender):
super(Dog,self).__init__(age,foot)
self.gender=gender
def show(self):
print('dog age is:',self.age,'ang have ',self.foot)
class Bat(Mammal):
pass
class Parrot(Bird):
pass
class Ostrich(Bird):
pass
dog=Dog(3,4,'male')
dog.show()
高级
===
- 动态添加属性
- python可以动态为对象绑定属性,但是不会影响到同类的其他对象。
class Person:
pass
p1=Person()
p2=Person()
p1.gender='male'
print(p1.gender)
print(p2.gender) #'Person' object has no attribute 'gender'
- 动态为对象绑定方法
from types import MethodType
class Person:
pass
def displayMe(self):
print('my genderis:', self.gender)
# 给一个实例绑定的方法,对另一个实例是不起作用的:
p1.dispalyMe=MethodType(displayMe,p1)
p1.dispalyMe()
- 通过动态给类增加属性和方法,可以实现所有对象都增加了属性和方法
Person.gender='male'
def displayMe(self):
print('my genderis:', self.gender)
Person.displayMe=displayMe
- 使用__slots__限制实例的属性.比如,只允许对Student实例添加name和age属性。
class Person(object):
__slots__=('name','age')
p1=Person()
print(dir(p1))
# 这是看到p1对象里已经存在name和age属性了
try:
p1.gender = 'female'
except Exception:
print('使用__slots__限制实例的属性')
- 删除属性
class Person:
def __init__(self):
self.age=1
p1=Person()
p2=Person()
p1.gender='male'
Person.nation='china'
del p1.gender
del p1.nation #error nation属于类的,不可以通过对象删除
del Person.nation
del p1.age #这是可以的
类属性也可以通过del动态删除
- 利用函数动态绑定
#该语句只能添加属性,不能添加方法
setattr(ee2, 'age', 8) # 添加属性 'age' 值为 8
getattr(ee1, 'age') # 返回 'age' 属性的值
hasattr(ee1, 'age') # 如果存在 'age' 属性返回 True。
delattr(ee1, 'age') # 删除属性 'age'
- 私有属性
1、 _xx 以单下划线开头的表示的是protected类型的变量。即保护类型只能允许其本身与子类进行访问。若内部变量标示,如: 当使用“from M import”时,不会将以一个下划线开头的对象引入 。
2、 __xx 双下划线的表示的是私有类型的变量。只能允许这个类本身进行访问了,连子类也不可以用于命名一个类属性(类变量),调用时名字被改变(在类FooBar内部,__boo变成_FooBar__boo,如self._FooBar__boo)
3、 __xx__定义的是特列方法。用户控制的命名空间内的变量或是属性,如init , __import__或是file 。只有当文档有说明时使用,不要自己定义这类变量。 (就是说这些是python内部定义的变量名)
python默认的成员函数和成员变量都是公开的,没有像其他类似语言的public,private等关键字修饰.但是可以在变量前面加上两个下划线"",这样的话函数或变量就变成私有的.这是python的私有变量轧压(这个翻译好拗口),英文是(private name mangling.) **情况就是当变量被标记为私有后,在变量的前端插入类名,再类名前添加一个下划线"",即形成了_ClassName__变量名.
class pub():
# protected类型的变量和方法 在类的实例中可以获取和调用
_name = 'protected类型的变量'
__info = '私有类型的变量'
def _func(self):
print("这是一个protected类型的方法")
def __func2(self):
print('这是一个私有类型的方法')
# 如果想要在实例中获取到类的私有类形变量可以通过在类中声明普通方法,返回私有类形变量的方式获取
def get(self):
return(self.__info)
p=pub()
p.__info # error 因为__info是私有变量只有在类内部才可见,所以要用内部方法
复习:
Python内置类属性
__dict__ : 类的属性(包含一个字典,由类的数据属性组成)
__doc__ :类的文档字符串
__module__: 类定义所在的模块(类的全名是'__main__.className',如果类位于一个导入模块mymod中,那么className.__module__ 等于 mymod)
__bases__ : 类的所有父类构成元素(包含了一个由所有父类组成的元组)
- 只读属性
@ property 作用就是采用访问属性的方式访问函数。
class Car:
__wheels=4
@property
def wheels(self):
return self.__wheels
@property可以把方法变为属性,
class Car:
__wheels=4
__voice='didi'
def __init__(self,color):
self.color=color
self.speed=80
@property
def run(self):
print('i can run %d speed'%self.speed)
@run.setter
def run(self,wh):
self.speed=wh
car1=Car('blue')
print(car1.color)
car1.run=120
car1.run
这个属性是不可以通过del car1.run 来删除的。因为他本来就不是一个属性
@run.deleter
def run(self):
del self.speed
print("你的车轮已经被拆除...")
- 静态方法
普通的方法,可以在实例化后直接调用,并且在方法里可以通过self.调用实例变量或类变量,但静态方法是不可以访问实例变量或类变量的,一个不能访问实例变量和类变量的方法,其实相当于跟类本身已经没什么关系了,它与类唯一的关联就是需要通过类名来调用这个方法。
class Car:
__wheels=4
__voice='didi'
def __init__(self,color):
self.color=color
@property
def wheels(self):
return self.__wheels
#静态方法在类中也不需要传入 self参数
@staticmethod
def wash():
print('i am washing')
- 类方法
通过@classmethod装饰器实现,类方法和普通方法的区别是, 类方法只能访问类变量,不能访问实例变量
class Car:
__wheels=4
__voice='didi'
def __init__(self,color):
self.color=color
@property
def wheels(self):
return self.__wheels
@classmethod
def dudu(cls):
print(cls.__voice)
@staticmethod
def wash():
print('i am washing')