全栈工程师开发手册 (作者:栾鹏)
python教程全解

python面向对象编程全解。

面向对象技术简介

一个类占有一个独立的空间,类中的属性叫做类变量,类中的函数,叫做类的方法。

类(Class):也可以成为类对象。类对象中包含了一批实例对象共有的属性和方法。

类变量:定义在类中且在函数体之外的变量。类变量在所有的实例变量中是共享的,类变量修改了,所有实例对象读取到的值都会修改。

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

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

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

方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。其实只是在派生类中添加了同名方法,以至于查询方法时不会再向基类查询

继承:即一个派生类(derived class)继承基类(base class)的属性和方法。继承也允许把一个派生类的对象作为一个基类对象对待。(就是说派生类还可以再派生孙子类)

实例化:创建一个类的实例,类的具体对象。在实例对象开辟一个空间,并为实例对象添加对类的引用。并没有复制类中的属性和方法到实例对象中。

实例对象:通过类定义的数据结构实例。

方法(与实例化和继承混合看)

在python中没有方法重载,因为本来函数的参数就是可以省略的。
后定义的函数会覆盖先定义的同名方法。

实例方法:只能通过实例对象调用,因为实例方法第一个定义的参数必须是实例对象本身。

class Myclass:def foo(self):print(id(self),'foo')   #id()是获取对象的空间地址a=Myclass()#既然是实例对象,那就要创建实例
a.foo()#输出类里的函数地址
print(id(a))#输出类对象的地址#结果地址一样

类方法:定义类方法,要使用装饰器@classmethod,定义的第一个参数一定是类的引用,不过可以通过类或者实例的引用。

class Myclass:@classmethod#类装饰器def foo2(self):print(id(self),'foo2')  print(id(Myclass))  #类对象,直接可以调用,不需要实例化。这句说明了类也是有存储空间的
Myclass.foo2()           #类方法,直接可以调用,不需要实例化对象

静态方法:定义静态方法使用装饰器@staticmethod,没有默认的必须参数,可以通过类和实例直接调用。静态方法就如同类外函数一样。若在静态函数内访问类变量也是需要 类名.变量名 的方式访问。

class Myclass:@staticmethod#静态方法def foo3():   #没有self参数print('foo3')Myclass.foo3()   #通过类调用
a=Myclass()
a.foo3()       #通过实例调用
#结果foo3

实例化和继承的内存操作(最重要)

实例化:为实例化对象新开辟一个空间。并为实例对象添加到类对象的引用,用于变量的查找。不过并没有为实例对象复制任何内容,这也就大大节省了空间。实例对象可以自定义自己的空间,但是不能修改类对象空间。

通过类名,可以调用类对象的类方法和静态方法,实例方法无法通过类名调用,因为实例方法的self必须是实例对象。类方法中self表示类对象。

通过实例对象,可以访问类对象的所有属性,调用类对象的所有方法。但是不能修改类对象中的属性和方法的指向(因为属性和方法都是引用变量),不过可以修改属性和方法指向的数据。

继承:继承的过程和实例化的过程相似,也是为派生类对象开辟一个独立的空间,并为派生类对象天剑了到基类对象的引用,用于变量查找。没有为派生类对象复制任何内容,大大节省了空间。派生类对象可以自定义自己的空间,为派生类对象添加派生类的类变量,实例方法,类方法、静态方法。

创建类

#!/usr/bin/python
# -*- coding: UTF-8 -*-
class Employee:'所有员工的基类'empCount = 0def __init__(self, name, salary):self.name = nameself.salary = salaryEmployee.empCount += 1def displayCount(self):print("TotalEmployee %d" % Employee.empCount)def displayEmployee(self):print("Name: ", self.name, ", Salary: ", self.salary)

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

第一种方法__init__()方法是一种特殊的方法,被称为类的构造函数或初始化方法,当创建了这个类的实例时,就会先为实例对象开辟空间,添加到类对象的引用,然后就会调用该方法。(其实是先调用的__new__方法,再调用的__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 = 0def __init__(self, name, salary):self.name = nameself.salary = salaryEmployee.empCount += 1def 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__乘运算
__div__除运算
__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("-------------设置派生类属性值")

类的继承

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

除了在前面继承时的内存操作必须要掌握外,你还需要知道

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

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

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

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

class Parent:       # 定义父类parentAttr = 100def __init__(self):print("调用父类构造函数")def parentMethod(self):print('调用父类方法')def setAttr(self, attr):Parent.parentAttr = attrdef 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 = aself.b = bdef __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 += 1self.publicCount += 1print(self.__secretCount)  # 在内部使用私有化属性,不会产生错误counter = JustCounter()
counter.count()
counter.count()
print(counter.publicCount)
print(counter.__secretCount) # 报错,实例不能访问私有变量

单下划线、双下划线、头尾双下划线说明

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

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

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

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

全解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_arr = []                                    #定义一个类变量(可修改变量)__default_age=12                                    #函数名或属性名前面为双下划线表示成员私有。只能在当前类或对象空间内使用。在存储时是存储成_Parent__default_agedef __init__(self, name1='student1',age1=13):     #init是构造函数,self代表类的实例对象。参数可以设置默认值。self.name=name1                                 #自动新增两个实例变量self.age=age1print("基类构造函数设置了"+self.name)def getname(self):                                  #实例方法,函数名为引用变量,可以进行赋值,即变更函数体。函数引用变量调用时使用(),不带括号代表变量。getname代表函数引用变量,getname()代表代表调用函数print('基类读取名称'+self.name)return self.namedef setname(self,name1):self.name=name1print("基类设置名称"+self.name)@staticmethod                                         # @staticmethod声明函数为静态方法,通过类对象和实例对象直接调用def info():                                          #静态方法就像类外函数一样。如果函数内需要读写类变量,需要使用Parent.default_nameprint("派生类的静态函数"+Parent.default_name)@classmethod  # @classmethod声明函数为类方法,第一个参数是能是类对象的引用,可以通过类或者实例直用def setsex(cls):  # 类方法self表示对类的引用self.sex = '男'  # 添加类变量print("派生类设置性别" + self.sex)# 派生类继承了基类的类变量和类方法和实例方法(没有实例变量,因为实例变量是在实例以后才存在的)
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 = "新"+name1print("基类设置名称" + self.name)def getage(self):                                   #派生类添加新的实例方法print("派生类读取年龄"+str(self.__default_age)) #派生类是无法读取基类的私有类变量的。因此这句话会报错print('Peopeo类开始运行')    #导入模块或执行模块都会执行函数# 当一个module被执行时,moduel.__name__的值将是"__main__",而当一个 module被其它module引用时,module.__name__将是module自己的名字
if __name__=="__main__":     #只有在执行当前模块时才会运行此函数set_default_age()

调用函数

# 只有有__init__.py文件的文件夹才能是package,才支持引入
import People    #引用此模块,就相当于将此模块在此处展开。
#python中一切变量都是引用变量,指向的对象包含不可变量(整型、字符串、元组)和可变量。
# 因此如果修改了不可变量,实质是新开一个空间,修改引用指向。如果修改可变量,就是保持引用指向,在原位置修改数据# #调用模块变量、模块函数
People.set_default_age(People.default_age)
print('=============实例化===================')
#实例化对象,开辟新内存,保留对类的引用,但是不复制属性和方法。同时调用init初始化,
#因此实例变量可以访问类变量、类方法、静态方法、实例方法。以及自己创建的实例变量。
# 类对象无法访问实例变量。因为并没有一个从类对象到实例对象的指针#实例变量可以读取的东西:类的公有属性和方法,自身的所有属性和方法。
#实例变量可以修改的东西:类对象的引用变量指向的数据,和自身的所有属性和方法
#实例变量不能修改的东西:类对象的引用变量的指向(包含属性和方法)
parent1 = People.Parent('student1')   #实例化,盗用初始化函数,创建了实例变量name和age
print('基类对象:',People.Parent.__dict__)     #打印对象的自有属性
print('基类实例对象:',parent1.__dict__)    #这一步可以看出实例化没有将类中的属性和方法引用复制到实例对象空间中。
print('==============实例对象读写数据==================')
parent1.default_name   #实例可以访问类变量,因为变量沿原型链的查找
parent1.default_name = 'Student'   #实例无法修改类变量(引用变量)的指向,所以这个是在实例对象中添加了一个实例变量
parent1.default_arr.append(1)   #实例可以修改类变量指向的数据内容
parent1.default_arr = [1,2]    #实例无法修改类变量(引用变量)的指向,所以这个是在实例对象中添加了一个实例变量
# print(parent1.__default_age)   #实例对象不能访问类对象的私有类变量
parent1.__default_age=14     #为实例对象添加实例变量(在执行时添加的不再是私有变量)
print(parent1.__default_age)  #实例对象可以访问到自身的所有属性和方法print('基类对象:',People.Parent.__dict__)
print('基类实例对象:',parent1.__dict__)
print('=============基类对象读写数据===================')
#类对象可以访问和修改的内容:类的属性和方法
People.Parent.default_name='Student'   #修改类变量的指向
People.Parent.default_arr=[11]          #修改类变量的指向
People.Parent.default_arr.append(12)    #修改类变量指向的内容
People.Parent.__default_age=14          #通过类名无法修改私有类变量,因为在存储中私有变量的存储名为_Parent__default_age。python并不建议修改私有变量,虽然可以通过这个名称修改变量值
print('基类对象:',People.Parent.__dict__)
print('基类实例对象:',parent1.__dict__)print('=============继承===================')
#派生类,开辟新内存,保留对基类的引用,但是不复制属性和方法。
# 因此派生类对象可以访问基类变量、基类方法、基类静态方法、基类实例方法。以及自己创建的派生类属性和方法。基类对象无法访问派生类对象。因为并没有一个从基类对象到派生类对象的指针#派生类对象可以读取的东西:基类的公有和保护属性和方法,自身的所有属性和方法。
#派生类对象可以修改的东西:基类对象的引用变量指向的数据,和自身的所有属性和方法
#派生类不能修改的东西:基类对象的引用变量的指向(包含属性和方法)print('基类对象:',People.Parent.__dict__)     #打印对象的自有属性
print('派生类对象:',People.Child.__dict__)    #这一步可以看出实例化没有将类中的属性和方法引用复制到实例对象空间中。
print('=============派生类对象读写数据===================')
People.Child.default_name   #派生类对象可以访问基类的类变量,因为变量沿原型链的查找
People.Child.default_name = 'child'   #派生类对象无法修改基类的类变量(引用变量)的指向,所以这个是在派生类对象中添加了一个类变量
People.Child.default_arr.append(1)   #派生类对象可以修改基类的类变量指向的数据内容
People.Child.default_arr = [1,2]    #派生类对象无法修改基类的类变量(引用变量)的指向,所以这个是在派生类对象中添加了一个类变量
# print(People.Child.__default_age)   #派生类对象不能访问基类对象的私有类变量
People.Child.__default_age=14     #为派生类对象添加类变量(在执行时添加的不再是私有变量)
print(People.Child.__default_age)  #类对象可以访问到自身的所有属性和方法print('基类对象:',People.Parent.__dict__)
print('派生类对象:',People.Child.__dict__)
print('=============派生类的实例对象读写数据===================')
#基类的实例对象和基类的关系等同于派生类的实例对象和派生类的关系
# 派生类的初始化函数调用不会自动调用基类的初始化函数
child1 = People.Child()  #调用类的初始化函数,实例化一个对象,这里在派生类的实例对象中添加了name和age属性
child1.setname('child')  #调用派生类对象中的重写或继承的方法
# child1.getage()  #调用派生类对象添加的方法,方法访问了基类的私有变量,会报错
print('派生类对象:',People.Child.__dict__)
print('派生类实例对象:',child1.__dict__)print('==============静态方法==================')
parent1.info()         #调用静态函数,方法1
People.Parent.info()   #调用静态函数,方法2
print('=============类方法===================')
# print(parent1.sex)   #类对象和实例对象中不存在sex,所以无法查找到,访问出错
parent1.setsex()    #调用类方法,在类对象中添加类变量
print(parent1.sex)  #通过实例对象访问类变量print('基类对象:',People.Parent.__dict__)
print('基类实例1对象:',parent1.__dict__)print('===========原型链查询=====================')
print(issubclass(People.Child,People.Parent)) # 布尔函数(Child,Parent)判断一个类是另一个类的子类或者子孙类,语法:issubclass(sub,sup)
print(isinstance(child1, People.Parent))  #布尔函数如果obj是Class类的实例对象或者是一个Class子类的实例对象则返回true。

python基础系列教程——python面向对象编程全解相关推荐

  1. python数据挖掘系列教程——PySpider框架应用全解

    全栈工程师开发手册 (作者:栾鹏) python教程全解 python数据挖掘系列教程--PySpider框架应用全解. PySpider介绍 pyspider上手更简单,操作更加简便,因为它增加了 ...

  2. python基础系列教程——python中的字符串和正则表达式全解

    全栈工程师开发手册 (作者:栾鹏) python教程全解 转义字符 正则表达式是建立在字符串的基础上,当需要在字符中使用特殊字符时,python用反斜杠\转义字符.如下表: 转义字符 描述\(在行尾时 ...

  3. python基础系列教程——python基础语法全解

    点击此处​​​​​​​ python教程全解 了解python 1.  了解Python Python是一种解释型(这意味着开发过程中没有了编译这个环节).面向对象(支持面向对象的风格或代码封装在对象 ...

  4. python基础系列教程——Python的安装与测试:python解释器、PyDev编辑器、pycharm编译器

    分享一个朋友的人工智能教程.零基础!通俗易懂!风趣幽默!还带黄段子!大家可以看看是否对自己有帮助:点击打开 全栈工程师开发手册 (作者:陈玓玏) python教程全解 白手起家,从头开启python的 ...

  5. python基础系列教程——Python中的编码问题,中文乱码问题

    全栈工程师开发手册 (作者:陈玓玏) python教程全解 如果不声明编码,则中文会报错,即使是注释也会报错.只要写中文,必须加一句:# -- coding:utf-8 --.原因:答案在PEP-02 ...

  6. python基础系列教程——python所有包库的下载

    下载地址:https://pypi.python.org/pypi?%3Aaction=browse 支持搜索 Index by date: multidict pymatgen moderngl j ...

  7. Python基础十五:面向对象编程四:高级特性

    Python基础十五:面向对象编程四:高级特性 Python基础系列内容为学习廖雪峰老师Python3教程的记录,廖雪峰老师官网地址:廖雪峰Python3教程 Author:yooongchun Em ...

  8. jquery系列教程1-选择器全解

    全栈工程师开发手册 (作者:栾鹏) 快捷链接: jquery系列教程1-选择器全解 jquery系列教程2-style样式操作全解 jquery系列教程3-DOM操作全解 jquery系列教程4-事件 ...

  9. js系列教程9-表单元素全解

    全栈工程师开发手册 (作者:栾鹏) 快捷链接: js系列教程1-数组操作全解 js系列教程2-对象和属性全解 js系列教程3-字符串和正则全解 js系列教程4-函数与参数全解 js系列教程5-容器和算 ...

最新文章

  1. ArrayList如何实现插入的数据按自定义的方式有序存放
  2. oracle引用vs,VS2013中使用oracle,有关引用哪个.dll
  3. Java并发编程实战~Thread-Per-Message模式
  4. c matlab.h,用matlab和c写程序,include的mex.h在哪里?
  5. 采样率,码率,帧率,I 帧,P 帧,B帧,RTP时间戳
  6. php 编码规范哪些_PHP 代码规范有哪些【详细讲解】
  7. 工作好多年可能还未真正了解接口和抽象类
  8. Maven学习总结(3)——使用Maven构建项目
  9. [Python] 维度交换函数:transpose(m,n,r)和permute(m,n,r)
  10. 2022 基于SpringBoot/SSM的数据库查询平台
  11. 常用传感器讲解四--水位传感器(water sensor)
  12. 视频APP软件开发功能架构
  13. 100比例怎么用计算机算,比例尺1:100怎么算
  14. 【unity 保卫星城】--- 开发笔记07(追踪导弹武器)
  15. 谈谈数据结构的重要性
  16. SpringBoot的热布署和多环境配置(四)
  17. URL中的特殊格式进行转换
  18. 如何提高加好友通过率
  19. node16 node-sass 版本
  20. smarty 的安装与使用

热门文章

  1. 科大讯飞刘聪:如何持续保持语音识别技术的领先
  2. 长虹智慧厨房解决方案,让你AI上智慧家居生活
  3. 普强“千语”语音识别引擎应用场景
  4. 长虹新一代人工智能电视Q6A、Q6K发布,搭载远场语音识别
  5. php中splite,PHP语言 的 chunk_split() 函数
  6. 怎么用鼠标选中java中table的某一行_为什么同事的工作效率那么高?学会这些鼠标双击技巧,你也可以的...
  7. perl linux 独立运行,Perl脚本打包为独立执行程序
  8. mysql中innodb的工作原理_解读MySQL的InnoDB引擎日志工作原理
  9. mysql数据库函数详解_MySQL数据库之字符函数详解
  10. jQuery 学习-样式篇(六):jQuery 获取和设置表单元素的值