python ——面向对象进阶
属性
如果你已经了解Python类中的方法,那么属性就非常简单了,因为Python中的属性其实是普通方法的变种。
哎,其实就是这样,我们看一下当我们想查看税后工资的时候,这其实是一个人的属性,但是它却要经过一些特殊的处理或者计算,让我们必须写在一个方法里,这个时候我们使用@property这个修饰符,就可以像使用字段一样调用这个方法了。对,属性是处女座就是这么矫情!!!当然如果你和我一样是神经大条的射手座,完全不用care这个属性什么鬼的。
尽管如此,在这里还是要说一说要注意一下几点:
1.定义时,在普通方法的基础上添加 @property 装饰器;
2.定义时,属性仅有一个self参数
3.调用时,无需括号
1.staticmethod和classmethod
staticmethod 静态方法: 让类里的方法,直接被类调用,就像正常的函数一样
宝宝,男
博博,女
海娇,男
海燕,女
海东,男
海峰,男
student.txt
class Student:
# f = open('student', encoding='utf-8')
def __init__(self):
pass @staticmethod
def show_student_info():
f = open('student', encoding='utf-8') #静态方法不能和类属性直接交互,如果f放在第2行,f将作为类属性,那么下面的f将不能被调用
for line in f:
name, sex = line.strip().split(',')
print(name, sex)
Student.show_student_info()
classmethod 类方法: 默认参数cls,可以直接用类名调用,与类属性交互
class Student:
f = open('student', encoding='utf-8')
def __init__(self):
pass
@classmethod #类方法: 默认参数cls,可以直接用类名调用,与类属性交互
def show_student_info(cls):
for line in cls.f:
name, sex = line.strip().split(',')
print(name, sex) Student.show_student_info()
classmethod和staticmethod的异同:
相同点:都可以直接被类调用,不需要实例化
不同点:
类方法(classmethod)必须有一个参数cls表示这个类,可以使用类属性
静态方法(staticmethod)不需要参数,但是静态方法不能直接使用类属性
方法包括:普通方法、静态方法和类方法,三种方法在内存中都归属于类,区别在于定义和调用的方式不同。
- 普通方法:由对象调用;至少一个self参数;执行普通方法时,自动将调用该方法的对象赋值给self;
- 类方法:由类调用; 至少一个cls参数;执行类方法时,自动将调用该方法的类复制给cls;
- 静态方法:由类调用;无默认参数;
2.绑定方法和非绑定方法
绑定方法:普通方法、类方法
普通方法:默认有一个self对象传进来,并且只能被对象调用————绑定到对象
类方法:默认有一个cls传进来表示本类,并且可以被类和对象(不推荐)调用————绑定到类
非绑定方法:
静态方法:没有默认参数,并且可以被类和对象(不推荐)调用————非绑定
3.isinstance 和 issubclass
isinstance(obj,cls)检查是否obj是否是类 cls 的对象
issubclass(sub, super)检查sub类是否是 super 类的派生类
class Foo:
pass
class Son(Foo):
pass
s=Son()
print(isinstance(s,Son)) #True
print(isinstance(s,Foo)) #True
print(type(s) is Son) #False
print(type(s) is Foo) #False
#isinstance和type的区别在于:当存在继承时,isinstance在判断时比较模糊,type则不会存在这个问题
print(issubclass(Son,Foo)) #True
print(issubclass(Son,object)) #True
print(issubclass(Foo,object)) #True
print(issubclass(int,object)) #True
4.反射
反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)
注:getattr,hasattr,setattr,delattr对模块的修改都在内存中进行,并不会影响文件中真实内容。
四个可以实现自省的函数
下列方法适用于类和对象(一切皆对象,类本身也是一个对象)
常用:hasattr、getattr
不常用:setattr、delattr
class Foo:
f = '类的静态变量'
def __init__(self,name,age):
self.name=name
self.age=age def say_hi(self):
print('hi,%s'%self.name) obj=Foo('egon',73) #检测是否含有某属性
print(hasattr(obj,'name')) #True
print(hasattr(obj,'say_hi')) #True #获取属性
n=getattr(obj,'name')
print(n) #egon
func=getattr(obj,'say_hi')
func() # hi,egon # print(getattr(obj,'aaaaaaaa','不存在啊')) #报错 #设置属性
setattr(obj,'sb',True)
setattr(obj,'show_name',lambda self:self.name+'sb')
print(obj.__dict__) #{'name': 'egon', 'age': 73, 'sb': True, 'show_name': <function <lambda> at 0x0097C5D0>}
print(obj.show_name(obj)) #egonsb
#用setattr为对象设置方法时:需要在()内手动传入绑定的对象,不能直接obj.show_name(),会报错 #删除属性
delattr(obj,'age')
delattr(obj,'show_name')
# delattr(obj,'show_name111')#不存在,则报错 print(obj.__dict__) #{'name': 'egon', 'sb': True}
四中方法的使用演示
在对象中应用反射
class Foo:
def __init__(self,name,age):
self.name=name
self.age=age
def func(self):
print(123) egg=Foo('hc',73)
print(egg.name) #hc
print(egg.__dict__) #可以查看类的属性,不能查看方法 #{'name': 'hc', 'age': 73}
print(egg.__dict__['name']) #hc # 常用
# hasattr 判断对象是否存在某属性或方法
# getattr 如果存在这个方法或者属性,就返回属性值或者方法的内存地址;如果不存在,报错 print(hasattr(egg,'name')) #True
print(getattr(egg,'name')) #hc
print(hasattr(egg,'func')) #True
print(getattr(egg,'func')) #<bound method Foo.func of <__main__.Foo object at 0x00E2FBF0>> if hasattr(egg,'func'): #返回bool
Foo_func=getattr(egg,'func') #如果存在这个方法或者属性,就返回属性值或者方法的内存地址
#如果不存在,报错,因此要配合hasattr使用
Foo_func() #
在类中应用反射
class Foo:
f=123 #类变量 @classmethod
def class_method_demo(cls):
print('class_method_demo') def class_method_demo1(self):
print('class_method_demo1') if hasattr(Foo,'f'):
print(getattr(Foo,'f')) print(hasattr(Foo,'class_method_demo')) #True
print(hasattr(Foo,'class_method_demo1')) #True
method=getattr(Foo,'class_method_demo')
method1=getattr(Foo,'class_method_demo1')
method() #class_method_demo
method1() #TypeError: class_method_demo1() missing 1 required positional argument: 'self' #类也是对象
类也是对象
在模块中应用反射 : 本模块和导入的模块
def test():
print('test')
my_module.py
import my_module
print(hasattr(my_module,'test')) #True
func_test=getattr(my_module,'test')
func_test() #test
getattr(my_module,'test')() #test #和上面注释掉的2行等价
import 其他模块应用反射
def demo1():
print('demo1')
import sys
# print(sys.modules) # 一个模块字典,
# print(__name__) #__main__
# print(sys.modules[__name__]) #返回本py文件里的模块 <module '__main__' from 'E:/PycharmProjects/untitled/8.16/6反射3.py'>
module_obj=sys.modules[__name__] #sys.modules[__main__]
print(hasattr(module_obj,'demo1')) #True #在本模块中找函数demo1
getattr(module_obj,'demo1')() #demo1
在本模块中应用反射
5 __str__,__repr__
先来一段代码,再来引入我们的正题:
lst = list([1,2,3,4])
class Foo:
def __init__(self,name):
self.name = name f = Foo('xiaohua') print(lst)
print(f) ######输出结果#########
[1, 2, 3, 4]
<__main__.Foo object at 0x0000005FE8BC9208>
我们都知道在python里面,list是一种数据类型,而且也是一个类。当我们以list()来创建一个序列时,我们也就创建了一个List对象。如上面的lst,知道了lst是List类型的对象后,我们print(lst)时,为什么没有像f一样,打印出对象的内存地址,而是直接打印出给对象赋的值呢?其实,这一切是因为在list类的内部,实现了__str__功能所导致的。下面,我们通过一些实例,来理解__str__的用法。
class Foo:
def __init__(self,name):
self.name = name
def __str__(self):
return '我执行了' f = Foo('xiaohua')
print(f) #######输出结果############
我执行了
看,当我再次打印对象的时候,没有打印出对象的内存地址,而是打印出了我们设定的值。__str__就是帮我们实现这种功能的!我们可以定制自己__str__,让他返回一些有意义的信息。
def __str__(self):
return 'name:%s' % self.name print(f) ####输出结果#####
name:xiaohua
class Foo:
def __init__(self,name):
self.name = name
def __str__(self):
return '%s obj info in str'%self.name
def __repr__(self):
return 'obj info in repr' f = Foo('hc')
print(f) # hc obj info in str
print('%s'%f) # hc obj info in str
print('%r'%f) #obj info in repr
print(repr(f)) #repr(f)等价于f.__repr__() # obj info in repr
print(str(f)) #str(f)等价于f.__str__() # hc obj info in str
__str__和__repr__必须return 字符串
当打印一个对象的时候,如果实现了str,打印__str__中的返回值,当__str__没有被实现的时候,就会调用__repr__方法(即__str__和__repr__同时存在时,会执行str,不会执行repr)
但是当你用字符串格式化的时候 %s和%r会分别去调用__str__和__repr__
不管是在字符串格式化的时候还是在打印对象的时候,repr方法都可以作为str方法的替补
但反之不行
用于友好的表示对象。如果str和repr方法你只能实现一个:先实现repr
6 __new__,__del__
__new__:创建对象时被调用,比__init__先执行。
class Foo(object):
def __init__(self):
print('init') def __new__(cls, *args, **kwargs):
print('new %s' %cls)
return object.__new__(cls, *args, **kwargs)
Foo() ###输出结果#######
new <class '__main__.Foo'> # 比init先打印
init
从上面,我们可以总结出如下几点:
继承自object的新式类才有__new__
__new__至少要有一个参数cls,代表要实例化的类,此参数在实例化时由Python解释器自动提供
__new__必须要有返回值,返回实例化出来的实例,这点在自己实现__new__时要特别注意,可以return父类__new__出来的实例,或者直接是object的__new__出来的实例
__init__有一个参数self,就是这个__new__返回的实例,__init__在__new__的基础上可以完成一些其它初始化的动作,__init__不需要返回值
若__new__没有正确返回当前类cls的实例,那__init__是不会被调用的,即使是父类的实例也不行:
class A(object):
pass class B(A):
def __init__(self):
print('init') def __new__(cls, *args, **kwargs):
print('new %s' % cls)
return object.__new__(A, *args, **kwargs)
b = B()
print(type(b)) 输出结果:
new <class '__main__.B'>
<class '__main__.A'>
class A:
def __init__(self): #有一个方法在帮你创造self
print('in init function')
self.x = 1 def __new__(cls, *args, **kwargs):
print('in new function')
return object.__new__(cls, *args, **kwargs)
a = A()
b = A()
c = A()
print(a,b,c) ################单例模式###############
class Singleton:
def __new__(cls, *args, **kw):
if not hasattr(cls, '_instance'):
cls._instance = object.__new__(cls, *args, **kw)
return cls._instance one = Singleton()
two = Singleton()
three = Singleton()
print(one,two,three) one.name = 'alex'
print(two.name) ######结果如下########
in new function
in init function
in new function
in init function
in new function
in init function
<__main__.A object at 0x0297F6F0> <__main__.A object at 0x0297FB50> <__main__.A object at 0x0297FC10>
<__main__.Singleton object at 0x0297FC70> <__main__.Singleton object at 0x0297FC70> <__main__.Singleton object at 0x0297FC70>
alex
__del__:在对象被删除或者程序执行完毕后,被调用
# 以下代码执行完毕后,自动执行del
class B:
def __del__(self):
print('我执行了')
b = B() ######输出结果#########
我执行了
#显式调用del来删除对象时,触发__del__执行
import time
class B:
def __del__(self):
print('我执行了')
b = B()
del b # 触发__del__执行
time.sleep(5)
print('主程序结果') ###输出结果####
我执行了
#等待5秒
主程序结果
7.item系列
__getitem__\__setitem__\__delitem__
我们在列表中学过这种取元素的方式。比如说lst = [1,2,3,4],取第一个元素 lst[0],又或者在字典中dd ={'name':'xiaohua'} 取元素dd['name']。实际上,这种取元素的方式,与__getitem__,__setitem__,__delitem__三个函数有关。
下面,我们一一来看看上述三个函数的用法:
__getitem__:当我们想要按照 obj[attr]方式调用对象的属性时,触发这个函数的执行
class Foo:
def __init__(self,name):
self.name = name
def __getitem__(self, item):
print('我执行了') f = Foo('alex')
print(f.__dict__) # 对象的名称空间只有一个属性
f['name'] # 触发getitem执行 #####输出结果########
{'name': 'alex'}
我执行了
从上面结果,可以看出,当我试图以f['name']方式调用属性的时候,就会触发__getitem__执行。一般将__getitem__设置为如下:
class Foo:
def __init__(self,name):
self.name = name
def __getitem__(self, item):
print(self.__dict__[item]) f = Foo('alex')
print(f.__dict__)
f['name']
########输出结果#######
{'name': 'alex'}
alex
__setitem__:当我以f['name'] = 'xiaohua' 方式修改对象属性值的时候,会触发该函数的执行。
class Foo:
def __init__(self,name):
self.name = name def __setitem__(self, key, value):
print('我执行了') f = Foo('alex')
print(f.__dict__)
f['x'] = 3 # 触发setitem执行 #########输出结果#########
我执行了
一般将setitem设置为如下,当然你也可以按照自己的方式进行设置。
class Foo:
def __init__(self,name):
self.name = name def __setitem__(self, key, value):
self.__dict__[key] = value f = Foo('alex')
print(f.__dict__)
f['x'] = 3
print(f.__dict__) ###输出结果#######
{'name': 'alex'}
{'name': 'alex', 'x': 3}
__delitem__:当以del f['name'] 方式删除对象的属性值时,会触发這个函数的执行
class Foo:
def __init__(self,name):
self.name = name def __delitem__(self, key):
print('我执行了') f = Foo('alex')
print(f.__dict__)
del f['name'] # 触发delitem执行 ####输出结果#####
{'name': 'alex'}
我执行了
一般设置为如下方式:
class Foo:
def __init__(self,name):
self.name = name def __delitem__(self, key):
del f.__dict__[key] f = Foo('alex')
print(f.__dict__)
del f['name']
print(f.__dict__)
#########输出结果####
{'name': 'alex'}
{}
8__call__
对象后面加括号,触发执行。
注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
class Foo: def __init__(self):
pass def __call__(self, *args, **kwargs): print('__call__') obj = Foo() # 执行 __init__
obj() # 执行 __call__ Foo()()等价于obj()
9 __len__
class A:
def __init__(self):
self.a = 1
self.b = 2 def __len__(self):
return len(self.__dict__)
obj = A()
print(len(obj))
http://www.cnblogs.com/wupeiqi/p/4766801.html
python ——面向对象进阶的更多相关文章
- Python面向对象进阶(二)
Python面向对象进阶2.html :first-child{margin-top:0!important}img.plugin{box-shadow:0 1px 3px rgba(0,0,0,.1 ...
- Python开发【第七篇】:面向对象 和 python面向对象进阶篇(下)
Python开发[第七篇]:面向对象 详见:<Python之路[第五篇]:面向对象及相关> python 面向对象(进阶篇) 上一篇<Python 面向对象(初级篇)> ...
- Python面向对象进阶和socket网络编程-day08
写在前面 上课第八天,打卡: 为什么坚持?想一想当初: 一.面向对象进阶 - 1.反射补充 - 通过字符串去操作一个对象的属性,称之为反射: - 示例1: class Chinese: def __i ...
- Python面向对象进阶和socket网络编程
写在前面 为什么坚持?想一想当初: 一.面向对象进阶 - 1.反射补充 - 通过字符串去操作一个对象的属性,称之为反射: - 示例1: class Chinese: def __init__(self ...
- python面向对象进阶(八)
上一篇<Python 面向对象初级(七)>文章介绍了面向对象基本知识: 面向对象是一种编程方式,此编程方式的实现是基于对 类 和 对象 的使用 类 是一个模板,模板中包装了多个“函数”供使 ...
- python面向对象进阶
前言 上节大话python面向对象对面向对象有了一些了解,这次就不用大话风格了 (ps:真心不好扯啊) isinstance与issubclass isinstance(obj,cls)检查是否obj ...
- python 面向对象进阶之内置方法
一 isinstance(obj,cls)和issubclass(sub,super) 1.1,isinstance(obj,cls)检查是否obj是否是类 cls 的对象 class Foo(obj ...
- Python 面向对象 (进阶篇)
<Python 面向对象(初级篇)>文章介绍了面向对象基本知识: 面向对象是一种编程方式,此编程方式的实现是基于对 类 和 对象 的使用 类 是一个模板,模板中包装了多个“函数”供使用(可 ...
- Python之路-python(面向对象进阶)
一.面向对象高级语法部分 1.静态方法.类方法.属性方法 2.类的特殊方法 3.反射 二.异常处理 三.Socket开发基础 一.面向对象高级语法部分 静态方法(@staticmethod) 定义:只 ...
- Python学习笔记【第十篇】:Python面向对象进阶
保护对象的属性 如果有一个对象,当需要对其进行修改属性时,有2种方法 对象名.属性名 = 数据 ---->直接修改 对象名.方法名() ---->间接修改 为了更好的保存属性安全,即不能随 ...
随机推荐
- 开源分享,使用Servlet实现360商城
简介 今天翻看硬盘,无意间看到这个项目的workspace,掀起了我无尽的回忆啊,一把辛酸一把泪. 现在把这个现在看来比较low的项目分享出来,也算记录下当初菜鸟的成长之路了,也希望能够对刚入门的朋友 ...
- HTML基本结构与标签总结整理篇
HTML基本结构与标签总结整理篇 前言:这是笔者的学习总结与整理,如果有错误或疑问的地方,欢迎指正与讨论!另:此文会不定时更新~ 1.了解HTML 学习前端技术,必然涉及三个方面:html(结构).c ...
- APP测试相关点归纳
APP测试相关点归纳 1.1测试周期 测试周期可按项目的开发周期来确定测试时间,一般测试时间为一两周,根据项目情况以及版本质量可适当缩短或延长测试时间.正式测试前需确认项目排期. 1.2测试资源 ...
- VB6之ICMP实现ping功能
代码备忘 'code by lichmama from cnblogs.com Private Type IPAddr ip1 As Byte ip2 As Byte ip3 As Byte ip4 ...
- "HK"日常之制作一只QQ刷屏
刷屏器是什么?可以吃吗?如果可以吃它好吃吗? um. 刷屏器就是可以定时发生信息的东西 刷屏器可以应用于很多方面,例如别人不理你了或者在QQ斗图的时候.警告:本教程仅作为学习研究,禁止其他用途!--- ...
- Luogu 1006 传纸条 / NOIP 2008 传纸条(动态规划)
Luogu 1006 传纸条 / NOIP 2008 传纸条(动态规划) Description 小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题.一次素质拓展活动中,班上同学安排做成一个m ...
- Java 9 揭秘(12. Process API 更新)
Tips 做一个终身学习的人. 在本章中,主要介绍以下内容: Process API是什么 如何创建本地进程 如何获取新进程的信息 如何获取当前进程的信息 如何获取所有系统进程的信息 如何设置创建,查 ...
- [noip 2015]运输计划 [LCA][树链剖分]
用了luogu上的题目描述 题目背景 公元 2044 年,人类进入了宇宙纪元. 题目描述 L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之间,这 n-1 条航道连通了 L 国的 ...
- (转)浅析CSS——元素重叠及position定位的z-index顺序
多次在项目中遇到html页面元素的非期待重叠错误,多数还是position定位情况下z-index的问题.其实每次解决类似问题思路大致都是一样的,说到底还是对z-index的理解比较模糊,可以解决问题 ...
- 不借助工具在浏览器中通过Web API执行Dynamics 365操作(Action)实例
摘要: 本人微信和易信公众号: 微软动态CRM专家罗勇 ,回复262或者20170727可方便获取本文,同时可以在第一间得到我发布的最新的博文信息,follow me!我的网站是 www.luoyon ...