python OPP面向对象

Python 的所有对象都有三个特性:


身份:每个对象都有一个唯一的身份标识自己,任何对象的身份都可以使用内建函数 id() 来得到,可以简单的认为这个值是该对象的内存地址。
类型:对象的类型决定了对象可以保存什么类型的值,有哪些属性和方法,可以进行哪些操作,遵循怎样的规则。可以使用内建函数 type() 来查看对象的类型。
值:对象所表示的数据

类和实例

python 中创建类和对象

创建类

使用关键字 class
class Foo:
pass
class Foo():
x = 1
def func(self):
pass
class Foo():
x = 1
def __init__(self):
self.x = 100

构造方法


__init__ 是Python中一个特殊的函数名,是一个类实例化对
象的一个初始化方法
self 参数也是python的一个特殊参数的名称,约定俗成的名字
self 实际上指的就是正在被创建的对象本身

class Person(object):
def __init__(self, name):
self.name = name # 属性
# self 可以其他的变量名,但是 self 是业界规范。

实例化对象


类名加上小括号就可创建一个对象了,这个过程也叫实例化对象。
class Person():
def __init__(self, name):
#print(type(self), self)
self.Name = name
# 实例化对象
teacher = Person("yangge")

属性


class Person():
city = "BeiJing" # 类的数据属性
def __init__(self,name,age):
self.Name = name # 实例的数据属性
self.Age = age
def run(self):
print('{} is
running'.format(self.Name))

类属性可以被类和对象调用 , 是所有对象共享的
实例属性只能由对象调用

类的其他属性


# 查看类的名字(这里的类名是字符串类型的 )
Person.__name__, type(Person.__name__)
# 查出的是一个字典, key为属性名,value为属性值
Person.__dict__
Person.__doc__ # 就是把注释显示出来
Person.__class__ # 自己是哪个类

类名称空间
print(Person.__dict__)
print(Person.__dict__['run'])

对象名称空间
print(teacher.__dict__)
print(teacher.__dict__.get('Name'))

对象可以使用类命名空间里的变量
teacher.city
# 局部 ---> 类
# 对象不会去全局找,只会在类的范围找。

总结:
类有数据属性和函数属性
对象只有数据属性

对象的绑定方法


print(Person.run)
print(teacher.run)
print(boss.run)
teacher.run() # Person.run(shark)
boss.run() # Person.run(yangge)
# 对象的绑定方法的特别之处在于,当调用绑定方法时,会自动把对象作为
# 第一个实参传递过去。
# 也就是通常见到的在类里定义的任何函数, self 都是第一个参数,
# 这是 Python的机制所必需的。

面向对象三大特性:继承、多态和封装

继承

 


类的继承就是可以从一个已有的类中衍生出以个新的类,这个新的类可以不需要再做任何代码的复制重写,就可以拥有原有类的所有属性和方法。
并且你也可以对这个新的类进行添加新属性和你需要的新方法;甚至把原来类的方法进行重写,即重写实现,并不改变原来方法的名称,这种重写方法,我们习惯称为覆盖方法

# 先定义一个父类 :车
class Vehicle():
def __init__(self,name,brand,date):
self.name = name self.brand = brand
self.date = date

def run(self):
print('The {} is
running'.format(self.name) )

# 再定义两个子类,对父类车进行继承
class Car(Vehicle): # 汽车类
pass

class Bicycle(Vehicle): # 自行车类
pass

# 现在都继承了父类,但是在子类中什么代码也没写,
# 但是会有服了的所以属性和方法

my_car = Car('x6','bmw','20170106') #
实例化一个汽车对象
my_bicycle =
Bicycle('roam_xr2','giant','20170305') # 实例化一个自行车对象

# 直接通过实例化的对象对其属性和方法进行调用
print(my_car.name)
my_car.run()

print(my_bicycle.name)
my_bicycle.run()

# 输出结果x6
The x6 is running
roam_xr2
The roam_xr2 is running

覆盖方法


class Person():
def __init__(self,name,age):
self.name = name
self.age = age

class MDPerson(Person):
def __init__(self,name,age):
self.name = "Doctor" + name
self.age = age
person = Person('Fudd',23)
doctor = MDPerson('Fudd',23)

print('name:',person.name ,'age
:',person.age)
print('name:',doctor.name ,'age:',doctor.age)
# 输出内容
name: Fudd age : 23
name: DoctorFudd age: 23

添加新方法


class Person():
def __init__(self,name,age):
self.name = name
self.age = age
def run(self):
print('{} is
running'.format(self.name))
class Teacher(Person):
def __init__(self,name,age,level): #添加了新的属性
Person.__init__(self,name,age) # 上面重构了 __init__(),再要使用父类的属性,就需要这样写
self.level = level
def lecture(self): # 添加的新方法
print('%s teacher =>%s teacher is
lecturing' %(self.level,self.name))
t1 = Teacher('shark',23,'Senior ')
print(t1.level)
t1.lecture()
# 输出结果
Senior
Senior teacher =>shark teacher is lecturing

子类里使用 super 调用父类的属性


class Person():
def __init__(self,name,age):
self.name = name
self.age = age
def run(self):
print('{} is
running'.format(self.name))
class Teacher(Person):
def __init__(self,name,age,level):
# 注意这里使用 super() 替代了父类名,并且参数中没有self
super().__init__(name,age)
def lecture(self):
print('%s teacher =>%s teacher is
lecturing' %(self.level,self.name))
t1 = Teacher('shark',23,'Senior ')
print(t1.level)
t1.lecture()

类继承中的名称查找顺序


先在自己的命名空间里找名字,找到则用自己的,找不到时,在去类里的命名空间里找;假如也找不到则不会再继续向全局查找。
当前类或者其父类继承了 object 类,它就是新式类了,否则为经典类

继承顺序


class A(object):
def test(self):
print('from A')

class B(A):
def test(self):
print('from B')

class C(A):
def test(self):
print('from C')

class D(B): # def test(self):
# print('from D')
pass
class E(C):
def test(self):
print('from E')

class F(D,E):
# def test(self):
# print('from F')
pass
f1=F()
f1.test()
print(F.__mro__) #只有新式才有这个属性可以查看线性列表,经典类没有这个属性

#新式类继承顺序:F->D->B->E->C->A
#经典类继承顺序:F->D->B->A->E->C
#python3中统一都是新式类
#pyhon2中才分新式类与经典类

多态


多态就是一类事物有多种形态的表现形式。(一个抽象类有多个子类,因而多态的概念依赖于继承
多态性在面向对象编程( OOP)中指的是不同的对象可以使用相同的函数名,实现了不同的功能,或者说表现出来是形式不一样。
在面向对象方法中一般是这样表述 多态性:向不同的对象发送同一条消息 ,不同的对象在接收时会产生不同的行为(即方法)。

多态性分为:静态多态性和动态多态性


静态多态性:如任何序列类型都可以用运算符 +进行运算
def foo(obj):
print(obj.__len__())
foo('yangge')
foo([1, 2, 3])
foo((1, 2, 3))


# 先定义一个车辆类
class Vehicle():
def __init__(self,name,brand,date):
self.name = name
self.brand = brand
self.date = date
def run(self):
print('The {} is
running'.format(self.name) )
# 定义一个汽车类
class Car(Vehicle): def run(self):
print('{}用四个轮子行驶,速度
80km/h'.format(self.name))
# 定义一个自行车类
class Bicycle(Vehicle):
def run(self):
print('{}用两个轮子行驶,速度
20km/h'.format(self.name))
# 实例化一个汽车对象
my_car = Car('x6','bmw','20170106')
# 实例化一个自行车对象
my_bicycle =
Bicycle('roam_xr2','giant','20170305')

# 为了很好的展示多态性,还有再借助一个函数
def func(obj):
obj.run() #这里明确的调用了一个函数,函数名就是:run
# 再将不同的对象传进这个函数
func(my_car)
func(my_bicycle)
# 输出了不同的结果
x6正在用四个轮子行驶,平均速度是 80km/h
roam_xr2正在用两个轮子行驶,平均速度是 20km/h

通过继承Vehicle类创建了一个新的类,使用者无需更改自己的代码,还是用 func(obj)去调用
# 开发者,修改代码,衍生的新子类:火车
class Train(Vehicle):
def run(self):
print('{}正在用多个轮子行驶,平均速度是
150km/h'.format(self.name))
# 实例化一个新的火车对象 t1
t1 = Train('hexiehao','China CSR','20000706')
# 给使用者的函数代码不变
def func(obj):
obj.run()
# 使用者使用同样的方式去调用
func(t1)

# 输出结果
hexiehao正在用多个轮子行驶,平均速度是 275km/h

组合


class Vehicle(): # 车
def __init__(self,brand):
self.brand = brand

class Wheel(): # 轮子
def __init__(self,num):
self.num = num

class Car(): # 汽车
def __init__(self,car_brand,num_wheel):
self.car_brand = car_brand
self.num_wheel = num _wheel
def run(self):
print('The %s car is running on %s
wheels' %(v1.brand,w1.num))

v1 = Vehicle('BMW')w1 = Wheel(4)
car1 = Car(v1,w1)
car1.run()
# 输出结果
The BMW car is running on 4 wheels

数据封装


封装方法的主要目的是:隔离复杂度,就是把复杂的代码逻辑实现过程封装起来,对于使用者是透明的;给用户用到的只是一个简单的接口。
第一个层面的封装(什么都不用做):
创建类和对象会分别创建二者的名称空间,我们只能用类名 .或者obj.的方式去访问里面的名字,这本身就是一种封装
class Person(object):
def __init__(self, name):
self.name = name

boss = Person("yangge")
boss.name

第二个层面的封装:
类中把某些属性和方法隐藏起来 (或者说定义成私有的),只在类的内部使用、外部无法访问,或者留下少量接口(函数)供外部访问。
在python中用双下划线的方式实现隐藏属性(设置成私有的)

class Duck():
def __init__(self, name):
self.hidden_name = name
def get_name(self):
# print('inside the getter')
return self.hidden_name
name = property(get_name)
fowl = Duck('Howard')
# 当调用 name 属性时,get_name() ⽅方法会自动被调用
fowl.name
# 当然这里可以显式调用
fowl.get_name()
# 下面来使用 Python应有的风格来实现,就是用装饰器器的方式:
# @property, 指 getter 方法
# @name.setter, 指 setter 方法

class Duck(): def __init__(self,input_name):
self.hidden_name = input_name
@property
def name(self):
print('inside the getter')
return self.hidden_name

fowl = Duck('Howard')
print(fowl.name)

在继承中,父类如果不想让子类覆盖自己的方法,也可以将方法定义为私有的
# 把fa定义成私有的,即__fa
>>> class A:
... def __fa(self): #在定义时就变形为_A__fa
... print('from A')
... def test(self):
... self.__fa() #只会与自己所在的类为准 ,即
调用 _A__fa
...
>>> class B(A):
... def __fa(self):
... print('from B')
...
>>> b=B()
>>> b.test()from A

获取对象信息


isinstance()
基本数据类型也可以使用 isinstance() 判断。还可以判断一个变量是否是某些类型中的一种。
In [5]: isinstance([1, 2, 3], list)
Out[5]: True
In [6]: isinstance([1, 2, 3], (list, tuple))
Out[6]: True
In [7]: isinstance((1, 2, 3), (list, tuple))
Out[7]: True
In [8]: isinstance('qf', (list, tuple,str))
Out[8]: True

dir()
如果要获得一个对象的所有属性和方法,可以使用 dir() 函数,它返回一个包含字符串的 list,比如,获得一个 str对象的所有属性和方法。
dir('qf')

猜你喜欢

转载自blog.csdn.net/qq_30429153/article/details/85258474