面向对象编程

  面向对象编程:使用类和对象实现一类功能。

类与对象

  类:类就是一个模板,模板里可以包含多个函数,函数里实现一些功能。

  对象:是根据模板创建的实例,通过实例对象可以执行类中的函数。

面向对象应用

  根据模板创建一系列例子的时候;当多个函数需要用到共同的参数时(提取公共参数放入构造函数中);应用场景(SSH)

定义类

class 类:
def func1(self):
def func22(self):

类的特性

封装:将内容封装到某个地方,以后再去调用被封装在某处的内容;对于面向对象的封装来说,其实就是使用构造方法将内容封装到对象中,然后通过对象直接或者self间接获取被封装的内容。类中封装了字段和方法,对象中封装了普通字段的值。

  1. 防止数据被随意修改;
  2. 使外部程序不需要关注对象内部的构造,只需要通过此对象对外提供的接口进行直接访问即可。

继承:对于面向对象的继承来说,其实就是将多个类共有的方法提取到父类中,子类仅需继承父类而不必一一实现每个方法。即通过父类,子类以最小代码量的方式实现不同角色的共同点和不同点的同时存在。

class Person(object):
def __init__(self, name,age):
self.name=name
self.age=age class BlackPerson(Person):
def __init__(self, nation): # 先继承,再重构
self.nation=nation
Person.__init__(self,name,age) b = BlackPerson('A',22,'blabla')
# Person.__init__(self,name,age) 这里的self相当于b,b.name='A',b.age=22 # 继承方法二:新式类写法
super(BlackPerson, self).__init__(name,age)

实例

class SchoolMember(object):
members = 0 #初始学校人数为0
def __init__(self,name,age):
self.name = name
self.age = age def tell(self):
for k,v in self.__dict__:
print(k,v) def enroll(self):
'''注册'''
SchoolMember.members +=1
print("\033[32;1mnew member [%s] is enrolled,now there are [%s] members.\033[0m " %(self.name,SchoolMember.members)) def __del__(self):
'''析构方法'''
print("\033[31;1mmember [%s] is dead!\033[0m" %self.name) class Teacher(SchoolMember):
def __init__(self,name,age,course,salary):
super(Teacher,self).__init__(name,age)
self.course = course
self.salary = salary
self.enroll() def teaching(self):
'''讲课方法'''
print("Teacher [%s] is teaching [%s] for class [%s]" %(self.name,self.course,'s12')) class Student(SchoolMember):
def __init__(self, name,age,grade,sid):
super(Student,self).__init__(name,age)
self.grade = grade
self.sid = sid
self.enroll() if __name__ == '__main__':
pass

多继承:Python的类如果继承了多个类,那么其寻找方法的方式有两种,分别是:深度优先和广度优先

经典类与新式类:当前类或者父类继承了object类,那么该类便是新式类,否则便是经典类。

class 类名(object):   新式类,使用super来继承父类属性,         super(BlackPerson, self).__init__(name,age) 
class 类名:       经典类,使用类名.__init__()继承父类属性, Person.__init__(self,name,age)

继承查找方式:

  • python3:广度查找
  • python2:经典类,深度查找;新式类,广度查找

经典类多继承:深度查找

#-*-coding:utf-8 -*-
class D:
def bar(self):
print ('D.bar')
class C(D): def bar(self):
print ('C.bar')
class B(D): def bar(self):
print ('B.bar')
class A(B, C): def bar(self):
print ('A.bar') a = A()
# 执行bar方法时
# 首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去D类中找,如果D类中么有,则继续去C类中找,如果还是未找到,则报错
# 所以,查找顺序:A --> B --> D --> C
# 在上述查找bar方法的过程中,一旦找到,则寻找过程立即中断,便不会再继续找了
a.bar()

新式类多继承:广度查找

class D(object):

    def bar(self):
print ('D.bar')
class C(D):
def bar(self):
print ('C.bar')
class B(D):
def bar(self):
print ('B.bar')
class A(B, C):
def bar(self):
print ('A.bar')
a = A()
# 执行bar方法时
# 首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去C类中找,如果C类中么有,则继续去D类中找,如果还是未找到,则报错
# 所以,查找顺序:A --> B --> C --> D
# 在上述查找bar方法的过程中,一旦找到,则寻找过程立即中断,便不会再继续找了
a.bar()

通过组合实现代码扩展

class Person(object):
def __init__(self, name,age):
self.name=name
self.age=age class BlackPerson(Person):
def __init__(self, nation,name,age,person_obj): # 先继承,再重构
self.nation=nation
self.person=person_obj #实例化组合实现扩展

多态:接口重用,一种接口,多种实现。

class F1:
pass
class S1(F1):
def show(self):
print ('S1.show')
class S2(F1):
def show(self):
print ('S2.show')
def Func(obj):
print (obj.show()) s1_obj = S1()
Func(s1_obj) s2_obj = S2()
Func(s2_obj)

实例化

类 =》实例化 =》 实例对象

obj = 类()
obj.函数1()
obj是对象,实例化的过程,通过对象去访问类中的函数

类的成员

所有成员中,只有普通字段的内容保存对象中,即:根据此类创建了多少对象,在内存中就有多少个普通字段。而其他的成员,则都是保存在类中,即:无论对象的多少,在内存中只创建一份。

构造函数__init__

self.name = name # 属性,成员变量,普通字段(对象可以访问;类内部可以访问;派生类中可以访问)

公有属性(静态字段):在类里直接定义的属性即为公有属性,所有实例化后的实例对象都能访问的属性。每个对象中保存相同的东西时,可以使用静态字段。

修改共有属性

类名.公有属性名 = value       # 改变所有实例的属性值
实例名.公有属性名 = value # 改变单个实例的属性值

注:实例化对象时,实例内存中没有存储公有属性,访问公有属性会直接通过类的内存中寻找;当使用实例名.公有属性 = value后,会在实例内存中生成一个公有属性名的变量,以后访问直接访问实例内存的值。前者相当于全局变量,后者为局部变量。

普通字段:在__init__里定义的属性为成员属性

私有属性:__private_attr_name = value; 私有成员命名时,前两个字符是下划线;仅类内部可以访问

访问私有属性

#  对外提供只读访问接口
def get_private_attr_name(self):
return self.__private_attr_name # 强制访问私有属性:
实例化名._类名__私有属性名

析构方法

在引用完成后,即实例被清除后(例如,del 实例名),执行析构方法,清空在内存中保存的实例信息。比如在server断开连接后,执行连接close等方法。

定义:def __del__(self)

类成员:方法

  • 普通方法:由对象调用;至少一个self参数;执行普通方法时,自动将调用该方法的对象赋值给self;
  • 类方法:    由类调用; 至少一个cls参数;执行类方法时,自动将调用该方法的类复制给cls;
  • 静态方法:由类或对象调用;无默认参数;

公有方法:在类中定义的方法为公有方法,缩进和公有属性一个级别。可以在类外面定义一个方法,然后通过实例名.方法名 = 新定义的方法名来实现。

静态方法

  定义:@staticmethod

  • 在类中的一个方法,只是名义上归类管理,但是和类基本没太大关系,只是通过类名或者实例名调用,在静态方法中访问不了类或实例中的任何属性;
  • self参数的区别,如果静态方法有参数self,调用时需要把实例当做self传入。
  • 制作工具包时,可以使用,工具包中的各种方法可以没什么关联,例如os模块。

类方法:只能访问类变量,不能访问实例变量。

  定义:@classmethod

class Foo:
def __init__(self, name):
self.name = name def ord_func(self):
""" 定义普通方法,至少有一个self参数 """
print('普通方法') @classmethod
def class_func(cls):
""" 定义类方法,至少有一个cls参数 """
print('类方法') @staticmethod
def static_func():
""" 定义静态方法 ,无默认参数"""
print ('静态方法') # 调用普通方法
f = Foo('name')
f.ord_func() # 调用类方法
Foo.class_func() # 调用静态方法
Foo.static_func()
f.static_func()

注:self就是调用当前方法的对象,类的方法保存类内存中,实例不保存类的方法,调用类方法时相当于实例指针指向类;实例化时,成员属性(普通属性)保存在实例内存中,公有属性(静态属性)保存在类内存中,可以节省内存。(静态字段的使用场景,每个对象中保存相同的东西时,可以使用静态属性)

属性方法

  定义:在普通方法的基础上添加 @property 装饰器;属性仅有一个self参数;调用时,无需括号;把一个方法变成一个静态属性。

  • 不能直接给属性方法赋值,需要使用@属性方法名.setter重新定义属性方法,并且赋值。
  • 删除属性,使用@属性方法名.deleter重新定义属性方法,并且赋值。
class Foo:

    def func(self):
print('this is method test') # 定义属性
@property
def prop(self):
print("this is property")
return 'test property'
# ############### 调用 ###############
foo_obj = Foo() foo_obj.func()
print(foo_obj.prop ) #调用属性
'''
this is method test
this is property
test property
'''

经典类中的属性只有一种访问方式,其对应被 @property 修饰的方法;新式类中的属性有三种访问方式,并分别对应了三个被@property(获取)、@方法名.setter(修改)、@方法名.deleter(删除)修饰的方法。

class Goods(object):

    def __init__(self):
# 原价
self.original_price = 100
# 折扣
self.discount = 0.8 @property
def price(self):
# 实际价格 = 原价 * 折扣
new_price = self.original_price * self.discount
return new_price @price.setter
def price(self, value):
self.original_price = value @price.deleter
def price(self):
del self.original_price obj = Goods()
print(obj.price ) # 获取商品价格
obj.price = 200 # 修改商品原价
print(obj.price)
del obj.price # 删除商品原价

静态字段方法

静态字段方法:创建值为property对象的静态字段

由于静态字段方式创建属性具有三种访问方式,我们可以根据他们几个属性的访问特点,分别将三个方法定义为对同一个属性:获取、修改、删除。

class Goods(object):

    def __init__(self):
# 原价
self.original_price = 100
# 折扣
self.discount = 0.8 def get_price(self):
# 实际价格 = 原价 * 折扣
new_price = self.original_price * self.discount
return new_price def set_price(self, value):
self.original_price = value def del_price(self):
del self.original_price PRICE = property(get_price, set_price, del_price, 'description...') obj = Goods()
print(obj. PRICE ) # 获取商品价格
obj. PRICE = 200 # 修改商品原价
print(obj.PRICE)
print(obj.PRICE.__doc__)
del obj. PRICE # 删除商品原价

property的构造方法中有个四个参数:

  • 第一个参数是方法名,调用对象.属性时,自动触发执行方法
  • 第二个参数是方法名,调用对象.属性=xx 时,自动触发执行方法
  • 第三个参数是方法名,调用del 对象.属性时,自动触发执行方法
  • 第四个参数是字符串,调用对象.属性.__doc__ ,此参数是该属性的描述信息

类的特殊成员

__doc__:表示类的描述信息

class Foo(object):
""" description... """ def func(self):
pass a = Foo()
print (a.__doc__)
# description...

__moudle__:表示当前操作的对象在哪个模块

__class__:表示当前操作的对象的类是什么

# moudle file
class Foo(object):
""" description... """
def func(self):
pass # import file
from lib.test import Foo obj = Foo()
print(obj.__module__)
print(obj.__class__)
# lib.test
# <class 'lib.test.Foo'>

__init__:构造方法,通过类创建对象时,自动触发执行。

__del__:析构方法

  当对象在内存中被释放时,自动触发执行;此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。

__call__:对象后面加括号,触发执行

class Foo:
def __init__(self):
pass def __call__(self, *args, **kwargs):
print('__call__') obj = Foo() # 执行 __init__
obj() # 执行 __call__ #构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()

__dict__:类或对象中的所有成员

class Province(object):

    country = 'China'

    def __init__(self, name, count):
self.name = name
self.count = count def func(self, *args, **kwargs):
pass # 获取类的成员,即:静态字段、方法、
print (Province.__dict__)
# {'__dict__': <attribute '__dict__' of 'Province' objects>, 'country': 'China', '__doc__': None,
# '__module__': '__main__', 'func': <function Province.func at 0x0000000000A2E598>,
# '__init__': <function Province.__init__ at 0x0000000000A2E510>,
# '__weakref__': <attribute '__weakref__' of 'Province' objects>} obj1 = Province('Jiangxi',100000)
print (obj1.__dict__)
# {'name': 'Jiangxi', 'count': 100000} obj2 = Province('HuNan', 200000)
print(obj2.__dict__)
# {'name': 'HuNan', 'count': 200000}

__str__:如果一个类中定义了__str__方法,那么在打印对象时,默认输出该方法的返回值。

class Province(object):

    country = 'China'

    def __init__(self, name, count):
self.name = name
self.count = count def __str__(self):
return '__str__: %s' % self.name obj1 = Province('Jiangxi',100000)
print(obj1)
#__str__: Jiangxi

__getitem__、__setitem__、__delitem__(用于索引操作,如字典。以上分别表示获取、设置、删除数据)

class Foo(object):

    def __init__(self ):
self.data = {} def __getitem__(self, key):
print('__getitem__ ',key)
return self.data.get(key) def __setitem__(self, key, value):
print('__setitem__ ',key,value)
self.data[key] = value def __delitem__(self, key): #可以用来判断是否删除
print('__delitem__',key)
del self.data[key] obj = Foo()
obj['name'] = 'Greath'
print(obj['name'])

__new__:用于创建实例,在实例化时,先执行__new__(cls,*args,**kwargs),然后执行__init__(self),如果需要自定义实例化内容时,需要用到__new__(),然后return object.__new__(cls), cls相当于类名

__metaclass__:用来表示该类由 谁 来实例化创建,用于关联原类(__metaclass__ = Mytype),在自定义类时,可以通过自定义原类中的__call__()方法,__new__()是通过原类中的__call__方法来创建的。

# -*-coding:utf-8 -*-

'''

class Foo(object):
def __init__(self):
pass obj = Foo()
print(type(obj)) # <class '__main__.Foo'>
print(type(Foo)) # <class 'type'>
# obj 是通过 Foo 类实例化的对象,其实,不仅 obj 是一个对象,Foo类本身也是一个对象,
# 因为在Python中一切事物都是对象。
# obj对象是Foo类的一个实例,Foo类对象是 type 类的一个实例,即:Foo类对象 是通过type类的构造方法创建。 # 通过type创建类: 类是由 type 类实例化产生
def func(self):
pass Foo = type('Foo', (object,), {'func': func})
# type第一个参数:类名
# type第二个参数:当前类的基类
# type第三个参数:类的成员
''' class MyType(type): def __init__(self, what, bases=None, dict=None):
super(MyType, self).__init__(what, bases, dict)
print('Mytype init') def __call__(self, *args, **kwargs):
print('Mytype call')
obj = self.__new__(self, *args, **kwargs)
self.__init__(obj) class Foo(object): __metaclass__ = MyType def __init__(self):
# self.name = name
print('Foo init') def __new__(cls, *args, **kwargs):
print('Foo new')
return object.__new__(cls, *args, **kwargs) # 第一阶段:解释器从上到下执行代码创建Foo类
# 第二阶段:通过Foo类创建obj对象
obj = Foo()
#
# Foo new
# Foo init #python2和python3区别: 在python2中输出情况:Mytype init,Mytype call,Foo new,Foo init

注:

类的生成调用顺序依次是 __init__ (原类init)--> __call__(原类call) --> __new__(新类new)-->__init__(新类init)

metaclass 详解文章:http://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python 得票最高那个答案写的非常好

反射

通过字符串的形式调用对象的相关成员,由以下4个内置函数实现:

  • hasattr(obj,str_attr):判断obj是否含有以str_attr字符串对应的方法或属性,返回True or False
  • getattr(obj, str_attr):获取 obj 的 str_attr,返回obj.str_attr的地址
  • setattr(obj, str_attr, value):设置一个新属性,相当于obj.str_attr = value
  • delattr(obj, str_attr):删除属性str_attr
# -*-coding:utf-8 -*-

class Foo(object):
def __init__(self):
self.name = 'greath' def func(self):
print('this is func')
obj = Foo()
# #### 检查是否含有成员 ####
print(hasattr(obj, 'name')) # True
print(hasattr(obj, 'func')) # True # #### 获取成员 ####
print(getattr(obj, 'name')) # greath
getattr(obj, 'func')() # this is func # #### 设置成员 ####
setattr(obj, 'age', 18)
setattr(obj, 'show', lambda num: num + 1)
print(obj.age) #
print(obj.show(10)) # choice = input('>>')
setattr(obj, choice, 'CH') # CH
print(getattr(obj,choice))
#print(obj.choice) # AttributeError: 'Foo' object has no attribute 'choice' # #### 删除成员 ####
delattr(obj, 'name')
#print(obj.name) # AttributeError: 'Foo' object has no attribute 'name'

python修炼之路---面向对象的更多相关文章

  1. Python学习之路--面向对象

    1.面向对象概述 面向过程:根据业务逻辑从上到下写垒代码  函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可  面向对象:对函数进行分类和封装,让开发“更快更好更强...”  面向 ...

  2. Python修炼之路-函数

    Python编程之函数 程序的三种方式 面向对象:类------->class 面向过程:过程------>def 函数式编程:函数------>def 定义函数 函数:逻辑结构化与 ...

  3. python修炼之路——控制语句

    Python编程之print python2.x和python3.x的print函数区别:python3.x的print函数需要加括号(),python2.x可以不加. #-*- coding:utf ...

  4. Python修炼之路-数据类型

    Python编程之列表 列表是一个使用一对中括号"[   ]" 括起来的有序的集合,可以通过索引访问列表元素,也可以增加和删除元素. 列表的索引:第一个元素索引为0,最后一个元素索 ...

  5. Python修炼之路-异常

    异常处理 在程序出现bug时一般不会将错误信息直接显示给用户,而是可以自定义显示内容或处理. 常见异常 AttributeError # 试图访问一个对象没有的树形,比如foo.x,但是foo没有属性 ...

  6. Python修炼之路-文件操作

    Python编程之文件操作 文件操作流程 打开文件,得到文件句柄并赋值给一个变量 通过句柄对文件进行操作 关闭文件 每次文件打开.读取信息时,Python自动记录所达到的位置,好比一个书签,之后每一次 ...

  7. Python修炼之路-模块

    模块 模块与包 模块:用来从逻辑上组织python代码(可以定义变量.函数.类.逻辑:实现一个功能),本质就是.py结尾的python文件. 例如,文件名:test.py,对应的模块名为:test 包 ...

  8. Python修炼之路-装饰器、生成器、迭代器

    装饰器 本质:是函数,用来装饰其他函数,也就是为其他函数添加附加功能. 使用情景 1.不能修改被装饰的函数的源代码:        2.不能修改被装饰的函数的调用方式. 在这两种条件下,为函数添加附加 ...

  9. Python修炼之路-Socket

    网络编程 socket套接字 socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过“套接字”向网络发出请求或者应答网络请求. socket ...

随机推荐

  1. 前端必须掌握的 nginx 技能(3)

    概述 作为一个前端,我觉得必须要学会使用 nginx 干下面几件事: 代理静态资源 设置反向代理(添加https) 设置缓存 设置 log 部署 smtp 服务 设置 redis 缓存(选) 下面我按 ...

  2. GIS开源程序收集

    每一个项目包含以下信息: 名称 主题 分类 描述 开始时间 语言 许可 演示网址 项目网址 成熟度 活跃度 评价   分类包括:GIS基础函数库.GIS控件.GIS桌面程序.GIS数据引擎.WEBGI ...

  3. Java-Logger日志

    <转载于--https://www.cnblogs.com/yorickLi/p/6158405.html> Java中关于日志系统的API,在 java.util.logging 包中, ...

  4. Report List 报表开发

    1. Report List的输出定义 * ...NO STANDARD PAGE HEADING: 输出的报表不包含表头: * ...LINE-SIZE col : 输出的报表不包含表头: * .. ...

  5. Centos7 安装可视化界面

    yum group list Output: Loaded plugins: fastestmirror There is no installed groups file. Maybe run: y ...

  6. 基于Opencv的自适应中值滤波函数selfAdaptiveMedianBlur()

    7.3.3 自适应滤波器 自适应中值滤波器 对于7.3.2节所讨论的中值滤波器,只要脉冲噪声的空间密度不大,性能还是可以的(根据经验需Pa和Pb小于0.2).本节将证明,自适应中值滤波器可以处理更大概 ...

  7. Buffer对象与JSON对象相互转换

    > buffer=new Buffer('换汤不换药');<Buffer e6 88 91 e7 88 b1 e4 bd a0 ef bc 8c e7 89 a9 e7 90 86> ...

  8. [ASP.NET] 前台代码绑定后台变量方法总结 [转]

    原文链接:https://www.cnblogs.com/lerit/archive/2010/10/22/1858007.html 经常会碰到在前台代码中要使用(或绑定)后台代码中变量值的问题.一般 ...

  9. CentOS7设置集群环境SSH免密访问

    1.准备工作 1)通过克隆或者其他方式获得可互相通信的多台节点(本文为3台虚拟机:hadoop101.hadoop102.hadoop103) 2)配置节点的静态IP.hostname.hosts,参 ...

  10. gcc数据对齐之: howto 1.

    GCC支持用__attribute__为变量.类型.函数.标签指定特殊属性.这些不是编程语言标准里的内容,而属于编译器对语言的扩展. 本文介绍其中的两个属性:aligned和packed. align ...