当前位置: 移动技术网 > IT编程>脚本编程>Python > python面向对象编程实例讲解

python面向对象编程实例讲解

2017年12月23日  | 移动技术网IT编程  | 我要评论

楼上楼下广播剧,淘宝网店注册,太空宝箱攻略

python面向对象编程全解。

面向对象技术简介

一个类占有一个独立的空间,类中的属性(函数外)叫做类变量,类中的函数,叫做类的方法。类中的方法第一个参数self,表示的是实例对象,不是类。

类(Class):用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个实例对象所共有的属性和方法。对象是类的实例(对象是类实例化之后的结果)。

类变量:定义在类中且在函数体之外。类变量通常不作为实例变量使用。实例对象无法修改类变量,不过可以读取类变量,只能添加同名属性覆盖类变量

数据成员:类变量和实例变量统称为数据成员。用于处理类及其实例对象的相关的数据。

方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。

实例变量:定义在方法中的变量,只庸作为当前实例的属性。

继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟”是一个(is-a)”关系(例图,Dog是一个Animal)。

实例化:浅复制类的空间到一个独立的空间。创建一个类的实例,类的具体对象。

方法:类中定义的函数。包含实例方法,类方法,静态方法。

对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。

这里写图片描述

类中的类方法中self表示类本身,实例方法无法调用。

实例对象中的类方法中self表示类本身,实例方法中的self表示实例对象本身

实例化,复制类到一个独立的空间(会复制类中的公共类变量和实例方法、类方法、静态方法到实例对象的独立空间)。实例化的对象可以访问这个独立空间的所有属性和方法。在调用实例方法时将自身传递到函数中。函数的第一个参数self表示的是实例对象本身,self.name表示访问实例对象的属性,如果实例对象不存在就会访问实例空间的类变量,如果类变量也不存在或者不能访问(私有),则就会为实例对象创建这个属性。

创建类
#!/usr/bin/python
# -*- coding: UTF-8 -*-
class Employee:
    '所有员工的基类'
    empCount = 0

    def __init__(self, name, salary):
        self.name = name
        self.salary = salary
        Employee.empCount += 1

    def displayCount(self):
        print("TotalEmployee %d" % Employee.empCount)

    def displayEmployee(self):
        print("Name: ", self.name, ", Salary: ", self.salary)

empCount 变量是一个类变量,所有类的实例对象都具有这个成员。你可以在内部类或外部类使用 Employee.empCount 访问。

第一种方法__init__()方法是一种特殊的方法,被称为类的构造函数或初始化方法,当创建了这个类的实例时就会调用该方法。一个类可以有多个构造函数

self 代表类的实例,self 在定义类的方法时是必须有的,虽然在调用时不必传入相应的参数。Self代表了实例对象,而不是类,那就是:类的方法与普通的函数只有一个特别的区别——它们必须有一个额外的第一个参数名称, 按照惯例它的名称是 self。

创建实例对象

实例化类其他编程语言中一般用关键字 new,但是在 Python 中并没有这个关键字,类的实例化类似函数调用方式。

以下使用类的名称Employee 来实例化,并通过 __init__ 方法接受参数。

"创建 Employee 类的第一个对象"
emp1 = Employee("Zara", 2000)
"创建 Employee 类的第二个对象"
emp2 = Employee("Manni", 5000)
操作对象属性

下面是读取对象属性的实例:

#!/usr/bin/python
# -*- coding: UTF-8 -*-
class Employee:
    '所有员工的基类'
    empCount = 0
    def __init__(self, name, salary):
        self.name = name
        self.salary = salary
        Employee.empCount += 1


    def displayCount(self):
        print("Total Employee %d" % Employee.empCount)


    def displayEmployee(self):
        print("Name : ", self.name, ", Salary: ", self.salary)
"创建 Employee 类的第一个对象"
emp1 =Employee("Zara", 2000)
"创建 Employee 类的第二个对象"
emp2 =Employee("Manni", 5000)
emp1.displayEmployee()
emp2.displayEmployee()
print "TotalEmployee %d" % Employee.empCount

以下函数还可以对属性进行读取之外的操作:

getattr(obj,name[, default]) : 访问对象的属性。
hasattr(obj,name): 检查是否存在一个属性。
setattr(obj,name,value): 设置一个属性。如果属性不存在,会创建一个新属性。
delattr(obj,name) : 删除属性。
Python内置的类属性
__dict__ : 类的属性(包含一个字典,由类的数据属性组成)
__doc__ :类的文档字符串
__name__: 类名
__module__: 类定义所在的模块(类的全名是'__main__.className',如果类位于一个导入模块mymod中,那么className.__module__ 等于 mymod)
__bases__ : 类的所有父类构成元素(包含了一个由所有父类组成的元组)
Python内置的类方法
__init__ 构造函数,在生成对象时调用
__del__ 析构函数,释放对象时使用
__repr__ 打印,转换
__setitem__按照索引赋值
__getitem__按照索引获取值
__len__获得长度
__cmp__比较运算
__call__函数调用
__add__加运算
__sub__减运算
__mul__乘运算
__p__除运算
__mod__求余运算
__pow__称方




我们可以为这些函数进行重写,实现我们想要的功能。例如这里对所有的读写操作进行监督屏蔽。
def __getitem__(self,key):                 #在字典中获取值时会自动调用 __getitem__函数,设置值时会自动调用__setitem__函数
    print("-------------派生类字典读取值")
def __setitem__(self,key,value):
    print("-------------派生类字典设置值")
def __getattr__(self,name):               #读取类属性(包括继承的属性)会自动执行__getattr__函数,设置属性会自动执行__setattr__函数
    print("-------------读取派生类属性")
def __setattr__(self,name,value):
    print("-------------设置派生类属性值")


类的继承

面向对象的编程带来的主要好处之一是代码的重用,实现这种重用的方法之一是通过继承机制。继承完全可以理解成类之间的类型和子类型关系。

派生类继承的是基类的类变量(不包含实例变量)和方法。在派生类中调用基类的构造函数时,传入的self是派生类的实例对象的引用。所以此时基类的构造函数新增加的实例变量,直接添加到了派生类实例对象上。所以整个过程中,我们把构造函数想想成初始化函数更好。并且在继承过程中,不存在基类的实例对象。

在python中继承中的一些特点:

1:在继承中基类的构造(__init__()方法)不会被自动调用,它需要在其派生类的构造中亲自专门调用。

2:在调用基类的方法时,需要加上基类的类名前缀,且需要带上self参数变量。区别于在类中调用普通函数时并不需要带上self参数

3:Python总是首先查找对应类型的方法,如果它不能在派生类中找到对应的方法,它才开始到基类中逐个查找。(先在本类中查找调用的方法,找不到才去基类中找)。

class Parent:       # 定义父类
    parentAttr = 100
    def __init__(self):
        print("调用父类构造函数")
    def parentMethod(self):
        print('调用父类方法')
    def setAttr(self, attr):
        Parent.parentAttr = attr
    def getAttr(self):
        print("父类属性 :", Parent.parentAttr)

class Child(Parent):
    # 定义子类
    def __init__(self):
        print("调用子类构造方法")  # 无论子类还是父类,都要单独写一次_init_
    def childMethod(self):
        print('调用子类方法')
    def getAttr(self):
        print('重写父类方法,因为父类方法不能满足需求')



c = Child()  # 实例化子类
c.childMethod()  # 调用子类的方法
c.parentMethod()  # 调用父类方法
c.setAttr(200)  # 再次调用父类的方法 - 设置属性值
c.getAttr()  # 再次调用父类的方法 - 获取属性值

你可以使用issubclass()或者isinstance()方法来检测,一个类或对象是否为其他类或对象的子类。

issubclass() - 布尔函数判断一个类是另一个类的子类或者子孙类,语法:issubclass(sub,sup)

isinstance(obj, Class) 布尔函数如果obj是Class类的实例对象或者是一个Class子类的实例对象则返回true。

如果在继承元组中列了一个以上的类,那么它就被称作”多重继承” 。

语法:

派生类的声明,与他们的父类类似,继承的基类列表跟在类名之后。

多态

如果父类方法的功能不能满足需求,可以在子类重写父类的方法。实例对象调用方法时会调用其对应子类的重写后的方法

运算符重载

Python同样支持运算符重载,实例如下:

class Vector:
    def __init__(self, a, b):
        self.a = a
        self.b = b
    def __str__(self):
        return 'Vector(%d, %d)' % (self.a, self.b)
    def __add__(self, other):
        return Vector(self.a + other.a, self.b + other.b)

v1 = Vector(2, 10)
v2 = Vector(5, -2)
print(v1 + v2)

以上代码执行结果如下所示:

Vector(7,8)
类的私有属性及方法

1)类的私有属性

__private_attrs:两个下划线开头,声明该属性为私有,不能在类的外部被使用或直接访问。在类内部的方法中使用时self.__private_attrs。

2)类的私有方法

__private_method:两个下划线开头,声明该方法为私有方法,不能在类地外部调用。在类的内部调用self.__private_methods

3)实例


class JustCounter:
    __secretCount = 0    # 私有变量
    publicCount = 0      # 公开变量
    def count(self):
        self.__secretCount += 1
        self.publicCount += 1
        print(self.__secretCount)  # 在内部使用私有化属性,不会产生错误

counter = JustCounter()
counter.count()
counter.count()
print(counter.publicCount)
print(counter.__secretCount) # 报错,实例不能访问私有变量
单下划线、双下划线、头尾双下划线说明

实例对象无法访问私有的类变量,但是可以添加同名的私有实例变量。

__foo__: 定义的是特列方法,类似 __init__() 之类的。

_foo: 以单下划线开头的表示的是 protected 类型的变量,即保护类型只能允许其本身与子类进行访问,不能用于 from module import *

__foo: 双下划线的表示的是私有类型(private)的变量, 只能是允许这个类本身进行访问了。

方法

实例方法:只能通过实例调用,实例方法第一个定义的参数只能是实例本身引用。也就是说在实例方法中修改实例变量。可以读取实例变量和类变量。

class Myclass:
  def foo(self):
    print(id(self),'foo')

a=Myclass()#既然是实例对象,那就要创建实例
a.foo()#输出类里的函数地址
print(id(a))#输出类对象的地址

#结果地址一样

类方法:定义类方法,要使用装饰器@classmethod,定义的第一个参数是能是类对象的引用,可以通过类或者实例直用。类方法用来修改类变量。

class Myclass:
    @classmethod#类装饰器
    def foo2(cls):
        print(id(cls),'foo2')  

#类对象,直接可以调用,不需要实例化
print(id(Myclass),'yy')
Myclass.foo2()#直接可以调用

静态方法:定义静态方法使用装饰器@staticmethod,没有默认的必须参数,通过类和实例直接调用

class Myclass:
  @staticmethod#静态方法
  def foo3():
    print('foo3')

Myclass.foo3()#没有参数
a.foo3()
#结果foo3
全解demo

People.py模块

__all__=["default_age","default","Moniter"]            # __all__变量,设置导入模块import*时将会自动引入的函数、变量、类
default_age = 12                                          #定义模块变量
def set_default_age(age=13):                               #定义模块函数
    print("默认年龄为"+str(age)+"岁")


class Parent(object):                                  #定义模块类。()内指定基类,当是object可以省略不写
    print("定义了Student类")                          #定义类时就会执行内部的执行语句
    default_name='student'                             #定义一个类变量
    __default_age=12                                    #函数名或属性名前面为双下划线表示成员私有。只能在当前类或对象空间内使用。
    def __init__(self, name1='student1',age1=13):     #init是构造函数,self代表类的实例对象。参数可以设置默认值。
        self.name=name1                                 #自动新增两个实例变量
        self.age=age1
        print("基类构造函数设置了"+self.name)
    def getname(self):                                  #实例方法,函数名为引用变量,可以进行赋值,即变更函数体。函数引用变量调用时使用(),不带括号代表变量。getname代表函数引用变量,getname()代表代表调用函数
        print('基类读取名称'+self.name)
        return self.name
    def setname(self,name1):
        self.name=name1
        print("基类设置名称"+self.name)


# 派生类继承了基类的类变量和类方法和实例方法(没有实例变量,因为实例变量是在实例以后才存在的)
class Child(Parent):                            #生成派生类,可以多重继承,但是应尽量避免。继承后会包含基类的函数和特性。
    def __init__(self,name1="child"):          #派生类构造函数不会自动调用基类构造函数
        self.name = name1                       #在当前实例对象中新增name实例变量
        Parent.__init__(self)                   #两种方法,调用超类的构造函数。基类中就修改了name实例变量,新增了age实例变量
        # super(Child,self).__init__(name1)
        print("派生类构造函数"+self.name)                #这里读取的就是最后一次对name的修改(基类中对他的修改)

    def setname(self, name1):                           #重写基类中的方法。其实是在派生类中添加了一个新方法,因此在查找此函数时就必用向上查找了。
        self.name = "新"+name1
        print("基类设置名称" + self.name)

    def getage(self):                                   #派生类添加新的实例方法
        print("派生类读取年龄"+str(self.__default_age)) #派生类是无法读取基类的私有类变量的。因此这句话会报错

    @staticmethod                                       #@staticmethod声明函数为静态方法,通过类和实例直接调用
    def info():
        print("派生类的静态函数")

    @classmethod                                        #@classmethod声明函数为类方法,第一个参数是能是类对象的引用,可以通过类或者实例直用
    def setsex(self):                                  #类方法self表示对类的引用
        self.sex='男'                                   #添加类变量
        print("派生类设置性别"+self.sex)


print('Peopeo类开始运行')    #导入模块或执行模块都会执行函数

# 当一个module被执行时,moduel.__name__的值将是"__main__",而当一个 module被其它module引用时,module.__name__将是module自己的名字
if __name__=="__main__":     #只有在执行当前模块时才会运行此函数
    set_default_age()


调用函数

# 只有有__init__.py文件的文件夹才能是package,才支持引入
import People    #引用此模块,就相当于将此模块在此处展开。

# #调用模块变量、模块函数
# People.set_default_age(People.default_age)
# print('================================')
# #调用模块中的类
parent1 = People.Parent('student1')   #调用类的构造函数,实例化一个对象,不需要new,会添加两个实例变量name和age
print(parent1.default_name)             #读取实例的数据成员(类变量和实例变量)
parent1.default_name='luanpeng'        #修改实例的数据成员
People.Parent.default_name='Student'   #修改类变量
parent1.name='luanpeng'               #访问修改实例对象中的属性
parent2 = People.Parent('student2')   #调用类的构造函数,实例化一个对象,不需要new
print(parent2.default_name)            #读取实例的数据成员(类变量和实例变量)
# # print(parent1.__default_age)       #实例变量没有复制类的私有类变量
parent1.__default_age=14              #添加一个私有的实例变量
print(parent1.__default_age)          #可以访问自身的私有实例变量
parent1.getname()                     #调用类方法

print('================================')
child1 = People.Child()  #调用类的构造函数,实例化一个对象
print('================================')
child1.setname('child')  #调用派生类重写或继承的方法
# child1.getage()  #调用派生类添加的方法,方法类访问了基类的私有变量,会报错
print('================================')
child1.info()         #调用静态函数,方法1
People.Child.info()   #调用静态函数,方法2
print('================================')
# print(child1.sex)   #类变量中不存在sex,所以无法查找到,访问出错
child1.setsex()    #调用类方法,添加类变量
print(child1.sex)  #访问类变量
child2 = People.Child()  #使用修改后的类重新实例化一个对象
print(child2.sex)     #可以查找到类变量sex

print('================================')
print(issubclass(People.Child,People.Parent)) # 布尔函数(Child,Parent)判断一个类是另一个类的子类或者子孙类,语法:issubclass(sub,sup)
print(isinstance(child1, People.Parent))  #布尔函数如果obj是Class类的实例对象或者是一个Class子类的实例对象则返回true。
print('================================')


如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网