面向对象高阶

isinstance

  • 判断是否为实例化对象,以后可以用来取代type
  • 和type的区别:
  1. class Foo:
  2. pass
  3. class Bar(Foo):
  4. pass
  5. b = Bar()
  6. print(isinstance(b, Bar)) # True 未来推荐使用
  7. print(isinstance(b, Foo)) # True 会检测父类
  8. print(type(b) == type(Bar)) # False type(b)是Bar
  9. print(type(b) == type(Foo)) # False
  10. print(type(b) == Foo) # False
  11. print(type(b) == Bar) # True
  • isinstance:判断对象是否是这个类实例化出来的,实例化具有传递性,会检测父类
  • type:获取实例化出这个对象的类,不会检测父类

issubclass

  • 判断某个类是否是另一个类的子类(参数必须为类)
  1. print(issubclass(Bar, Foo)) # True

反射(自省)

  • 通过字符串去访问对象的属性,调用对象的方法,而Python中一切皆对象,都可以使用反射

模块的使用

  1. import time
  2. choice = input('choice func:>>>').strip()
  3. print(getattr(time, choice)())
  4. # 其实就是这个用法
  5. # getattr(module, method)()

放在类的使用

  1. hasattr
  2. getattr
  3. setattr
  4. delattr
  1. class Foo():
  2. count = 0
  3. def eat(self):
  4. print('eat')
  5. f = Foo()
  6. if hasattr(f, 'eat'): # 判断有没有
  7. getattr(f, 'eat')() # 获取并运行 # 'eat'
  8. f.count = 1
  9. print(f.__dict__) # {'count': 1}
  10. setattr(f, 'eat', 222)
  11. print(f.__dict__) # {'count':1, 'eat': 222}
  12. print(getattr('eat')) # 222
  13. setattr(f, 'count', 11)
  14. print(f.__dict__) # {'count':11, 'eat':222}
  15. delattr(f, 'count') # {'eat': 222}
  16. print(f.__dict__)
  • 可以用来写通用评论借口

call

  1. class Foo:
  2. def __init__(self, name):
  3. self.name = name
  4. def __call__(self, *args, **kwargs):
  5. print('我触发了')
  6. f = Foo('leijun')
  7. f() # 对象加括号出发call
  1. 我触发了

补充

1.getattr

  • 厉害之处:除了对类反射,还能对文件(模块)反射。
  1. class A:
  2. def __init__(self):
  3. self.name = 'nick'
  4. # self.age='18'
  5. def method(self):
  6. print("method print")
  7. a = A()
  8. print(getattr(a, 'name',
  9. 'not find')) # 如果a 对象中有属性name则打印self.name的值,否则打印'not find'
  10. print(getattr(a, 'age',
  11. 'not find')) # 如果a 对象中有属性age则打印self.age的值,否则打印'not find'
  12. print(getattr(a, 'method', 'default')) # 如果有方法method,否则打印其地址,否则打印default
  13. print(getattr(a, 'method', 'default')()) # 如果有方法method,运行函数并打印None否则打印default

2.动态导入(importlib)

  • 注意:只能导到模块,不要导里面的东西,如果要使用内部的东西,使用getattr()

例如:

  1. # 文件目录结构为
  2. |- import_lib
  3. |= metaclass.py
  4. |- test.py
  5. # 这时如果要在test中动态导入metaclass
  6. |- test.py
  7. import importlib
  8. # 绝对导入
  9. module_name = __import__('import_lib.metaclass') # 这时解释器自己内部用的
  10. # module_name = importlib.import_module('import_lib.metaclass') # 与上面的效果一致,官方建议使用这个
  11. # 相对导入
  12. module_name = importlib.import_module('.metaclass.py', 'import_lib')
  13. # 如果要用里面的东西
  14. res = getattr(module_name, xxx)

3.类的其他成员

_str_

改变对象的字符串显示。可以理解为使用print函数打印一个对象时,会自动调用对象的__str__方法

  1. class Student:
  2. def __init__(self, name, age):
  3. self.name = name
  4. self.age = age
  5. # 定义对象的字符串表示
  6. def __str__(self):
  7. return self.name
  8. s1 = Student('张三', 24)
  9. print(s1) # 会调用Student的__str__方法

_repr_

在python解释器环境下,会默认使用对象的__repr__表示。

  1. class Student:
  2. def __init__(self, name, age):
  3. self.name = name
  4. self.age = age
  5. def __repr__(self):
  6. return self.name
  7. s1 = Student('张三', 24)
  8. print(s1) # 会调用Student的__repr__方法

总结:

  1. str函数或者print函数调用的是obj.__str__()
  2. repr函数或者交互式解释器调用的是obj.__repr__()

注意:

  1. 如果__str__没有被定义,那么就会使用__repr__来代替输出。
  2. __str____repr__方法的返回值都必须是字符串。

_del_

析构方法,当对象在内存中被释放时,自动触发执行。

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

  1. class A:
  2. def __del__(self):
  3. print('删除了...')
  4. a = A()
  5. print(a) # <__main__.A object at 0x10164fb00>
  6. del a # 删除了...
  7. print(a) # NameError: name 'a' is not defined

__dict__和__slots__

Python中的类,都会从object里继承一个__dict__属性,这个属性中存放着类的属性和方法对应的键值对。一个类实例化之后,这个类的实例也具有这么一个__dict__属性。但是二者并不相同。

  1. class A:
  2. some = 1
  3. def __init__(self, num):
  4. self.num = num
  5. a = A(10)
  6. print(a.__dict__) # {'num': 10}
  7. a.age = 10
  8. print(a.__dict__) # {'num': 10, 'age': 10}

从上面的例子可以看出来,实例只保存实例的属性和方法,类的属性和方法它是不保存的。正是由于类和实例有__dict__属性,所以类和实例可以在运行过程动态添加属性和方法。

但是由于每实例化一个类都要分配一个__dict__变量,容易浪费内存。因此在Python中有一个内置的__slots__属性。当一个类设置了__slots__属性后,这个类的__dict__属性就不存在了(同理,该类的实例也不存在__dict__属性),如此一来,设置了__slots__属性的类的属性,只能是预先设定好的。

当你定义__slots__后,__slots__就会为实例使用一种更加紧凑的内部表示。实例通过一个很小的固定大小的小型数组来构建的,而不是为每个实例都定义一个__dict__字典,在__slots__中列出的属性名在内部被映射到这个数组的特定索引上。使用__slots__带来的副作用是我们没有办法给实例添加任何新的属性了。

注意:尽管__slots__看起来是个非常有用的特性,但是除非你十分确切的知道要使用它,否则尽量不要使用它。比如定义了__slots__属性的类就不支持多继承。__slots__通常都是作为一种优化工具来使用。--摘自《Python Cookbook》8.4

  1. class A:
  2. __slots__ = ['name', 'age']
  3. a1 = A()
  4. # print(a1.__dict__) # AttributeError: 'A' object has no attribute '__dict__'
  5. a1.name = '张三' # 可以对__slots__中的对象进行定义
  6. a1.age = 24
  7. # a1.hobby = '泡妞' # AttributeError: 'A' object has no attribute 'hobby'
  8. print(a1.__slots__) # ['name', 'age']

注意事项:

__slots__的很多特性都依赖于普通的基于字典的实现。

另外,定义了__slots__后的类不再 支持一些普通类特性了,比如多继承。大多数情况下,你应该只在那些经常被使用到的用作数据结构的类上定义__slots__,比如在程序中需要创建某个类的几百万个实例对象 。

关于__slots__的一个常见误区是它可以作为一个封装工具来防止用户给实例增加新的属性。尽管使用__slots__可以达到这样的目的,但是这个并不是它的初衷。它更多的是用来作为一个内存优化工具。

__item__系列

  1. class Foo:
  2. def __init__(self, name):
  3. self.name = name
  4. def __getitem__(self, item):
  5. print(self.__dict__[item])
  6. def __setitem__(self, key, value):
  7. print('obj[key]赋值时,执行我') # 注意是obj[key],不是obj.key
  8. self.__dict__[key] = value
  9. def __delitem__(self, key):
  10. print('del obj[key]时,执行我')
  11. self.__dict__.pop(key)
  12. def __delattr__(self, item):
  13. print('del obj.key时,执行我')
  14. self.__dict__.pop(item)
  15. f1 = Foo('sb')
  16. print(f1.__dict__)
  17. f1['age'] = 18
  18. f1.hobby = '泡妞'
  19. del f1.hobby
  20. del f1['age']
  21. f1['name'] = 'lqz'
  22. print(f1.__dict__)

_init_

使用Python写面向对象的代码的时候我们都会习惯性写一个 __init__ 方法,__init__ 方法通常用在初始化一个类实例的时候。例如:

  1. class Person:
  2. def __init__(self, name, age):
  3. self.name = name
  4. self.age = age
  5. def __str__(self):
  6. return '<Person: {}({})>'.format(self.name, self.age)
  7. p1 = Person('张三', 24)
  8. print(p1)

上面是__init__最普通的用法了。但是__init__其实不是实例化一个类的时候第一个被调用的方法。当使用 Persion(name, age) 来实例化一个类时,最先被调用的方法其实是 __new__ 方法。

_new_

其实__init__是在类实例被创建之后调用的,它完成的是类实例的初始化操作,而 __new__方法正是创建这个类实例的方法

  1. class Person:
  2. def __new__(cls, *args, **kwargs):
  3. print('调用__new__,创建类实例')
  4. return super().__new__(Person) # 这里要用父类的
  5. def __init__(self, name, age):
  6. print('调用__init__,初始化实例')
  7. self.name = name
  8. self.age = age
  9. p1 = Person('张三', 24)

输出:

  1. 调用__new__,创建类实例
  2. 调用__init__,初始化实例

__new__方法在类定义中不是必须写的,如果没定义的话默认会调用object.__new__去创建一个对象(因为创建类的时候默认继承的就是object)。

如果我们在类中定义了__new__方法,就是重写了默认的__new__方法,我们可以借此自定义创建对象的行为。

举个例子:

重写类的__new__方法来实现单例模式。

  1. class Singleton:
  2. # 重写__new__方法,实现每一次实例化的时候,返回同一个instance对象
  3. def __new__(cls, *args, **kw):
  4. if not hasattr(cls, '_instance'):
  5. cls._instance = super().__new__(Singleton)
  6. return cls._instance
  7. def __init__(self, name, age):
  8. self.name = name
  9. self.age = age
  10. s1 = Singleton('张三', 24)
  11. s2 = Singleton('李四', 20)
  12. print(s1, s2) # 这两实例都一样
  13. print(s1.name, s2.name)

_call_

__call__ 方法的执行是由对象后加括号触发的,即:对象()。拥有此方法的对象可以像函数一样被调用。

  1. class Person:
  2. def __init__(self, name, age):
  3. self.name = name
  4. self.age = age
  5. def __call__(self, *args, **kwargs):
  6. print('调用对象的__call__方法')
  7. a = Person('张三', 24) # 类Person可调用
  8. a() # 对象a可以调用

注意:

__new____init____call__等方法都不是必须写的。

_doc_

定义类的描述信息。注意该信息无法被继承。

  1. class A:
  2. """我是A类的描述信息"""
  3. pass
  4. print(A.__doc__)

__iter__和__next__

如果一个对象拥有了__iter____next__方法,那这个对象就是可迭代对象

  1. class A:
  2. def __init__(self, start, stop=None):
  3. if not stop:
  4. start, stop = 0, start
  5. self.start = start
  6. self.stop = stop
  7. def __iter__(self):
  8. return self
  9. def __next__(self):
  10. if self.start >= self.stop:
  11. raise StopIteration
  12. n = self.start
  13. self.start += 1
  14. return n
  15. a = A(1, 5)
  16. from collections import Iterator
  17. print(isinstance(a, Iterator))
  18. for i in A(1, 5):
  19. print(i)
  20. for i in A(5):
  21. print(i)
  22. aaa=A(1)
  23. print(next(aaa))
  24. print(next(aaa)) #抛异常

__enter__和__exit__

一个对象如果实现了__enter____exit__方法,那么这个对象就支持上下文管理协议,即with语句

  1. class A:
  2. def __enter__(self):
  3. print('进入with语句块时执行此方法,此方法如果有返回值会赋值给as声明的变量')
  4. return 'oo'
  5. def __exit__(self, exc_type, exc_val, exc_tb):
  6. print('退出with代码块时执行此方法')
  7. print('1', exc_type)
  8. print('2', exc_val)
  9. print('3', exc_tb)
  10. with A() as f:
  11. print('进入with语句块')
  12. # with语句中代码块出现异常,则with后的代码都无法执行。
  13. # raise AttributeError('sb')
  14. print(f) #f打印出oo
  15. print('嘿嘿嘿')

上下文管理协议适用于那些进入和退出之后自动执行一些代码的场景,比如文件、网络连接、数据库连接或使用锁的编码场景等。

_len_

拥有__len__方法的对象支持len(obj)操作。

  1. class A:
  2. def __init__(self):
  3. self.x = 1
  4. self.y = 2
  5. def __len__(self):
  6. return len(self.__dict__)
  7. a = A()
  8. print(len(a))

_hash_

拥有__hash__方法的对象支持hash(obj)操作。

  1. class A:
  2. def __init__(self):
  3. self.x = 1
  4. self.x = 2
  5. def __hash__(self):
  6. return hash(str(self.x) + str(self.x))
  7. a = A()
  8. print(hash(a))

_eq_

拥有__eq__方法的对象支持相等的比较操作

  1. class A:
  2. def __init__(self,x,y):
  3. self.x = x
  4. self.y = y
  5. def __eq__(self,obj):
  6. # 打印出比较的第二个对象的x值
  7. print(obj.x)
  8. if self.x +self.y == obj.x+obj.y:
  9. return True
  10. else:
  11. return False
  12. a = A(1,2)
  13. b = A(2,1)
  14. print(a == b)

day37-1 面向对象高阶的更多相关文章

  1. Python 面向对象高阶-----metaclass

    Python 面向对象高阶-----metaclass 前言 类也是对象,既然类是对象,那就自然是某个东西的实例化,这个东西就是type 首先看下type是怎么回事 type type最常用的方法就是 ...

  2. scala面向对象.高阶函数,柯里化,Actor编程简介

    1.定义一个类 class Person{ //用val修饰的变量是只读属性,有getter但是没有setter val id ="111" //用var修饰的变量既有getter ...

  3. day6-3面向对象高阶

    面向对象是一种编程方式,此编程方式的实现是基于对 类 和 对象 的使用 类 是一个模板,模板中包装了多个“函数”供使用(可以讲多函数中公用的变量封装到对象中) 对象,根据模板创建的实例(即:对象),实 ...

  4. swift是面向对象、面向协议、高阶类型、灵活扩展、函数式编程语言

    swift是面向对象.面向协议.高阶类型.灵活扩展.函数式编程语言

  5. python学习道路(day4note)(函数,形参实参位置参数匿名参数,匿名函数,高阶函数,镶嵌函数)

    1.函数 2种编程方法 关键词面向对象:华山派 --->> 类----->class面向过程:少林派 -->> 过程--->def 函数式编程:逍遥派 --> ...

  6. Python 函数式编程 & Python中的高阶函数map reduce filter 和sorted

    1. 函数式编程 1)概念 函数式编程是一种编程模型,他将计算机运算看做是数学中函数的计算,并且避免了状态以及变量的概念.wiki 我们知道,对象是面向对象的第一型,那么函数式编程也是一样,函数是函数 ...

  7. JavaScript 高阶函数 + generator生成器

    map/reduce map()方法定义在JavaScript的Array中,我们调用Array的map()方法,传入我们自己的函数,就得到了一个新的Array作为结果: function pow(x ...

  8. JavaScript之闭包与高阶函数(一)

    JavaScript虽是一门面向对象的编程语言,但同时也有许多函数式编程的特性,如Lambda表达式,闭包,高阶函数等. 函数式编程是种编程范式,它将电脑运算视为函数的计算.函数编程语言最重要的基础是 ...

  9. 老师博客copy -高阶函数2

    新闻 管理   Py西游攻关之函数   一 函数是什么? 函数一词来源于数学,但编程中的「函数」概念,与数学中的函数是有很大不同的,具体区别,我们后面会讲,编程中的函数在英文中也有很多不同的叫法.在B ...

随机推荐

  1. [bzoj4066/2683]简单题_KD-Tree

    简单题 bzoj-4066 题目大意:n*n的棋盘,开始为均为0,支持:单点加权值,查询矩阵权值和,强制在线. 注释:$1\le n\le 5\cdot 10^5$,$1\le m \le 2\cdo ...

  2. 洛谷 P3496 [POI2010]GIL-Guilds

    P3496 [POI2010]GIL-Guilds 题目描述 King Byteasar faces a serious matter. Two competing trade organisatio ...

  3. jQuery和CSS3炫酷button点击波特效

    这是一款效果很炫酷的jQuery和CSS3炫酷button点击波特效.该特效当用户在菜单button上点击的时候.从鼠标点击的点開始,会有一道光波以改点为原点向外辐射的动画效果,很绚丽. 在线演示:h ...

  4. CSDN处理问题神速,顶你,为你点32个赞!

    今天10点左右发表了一篇文章,发表之后.文章状态待审核,博文首页不能显示文章,例如以下图所看到的: 于是果断给官网发了第一封Email.10点19分.CSDN给予回复,内容例如以下: 尊敬的用户您好: ...

  5. tolua reference

    Using Lua API and tag method facilities, tolua maps C/C++ constants, external variables, functions, ...

  6. C++学习笔记22,普通函数重载(1)

    转载请注明出处:http://blog.csdn.net/qq844352155/article/details/31353325 该博文仅用于交流学习,请慎用于不论什么商业用途,本博主保留对该博文的 ...

  7. 在Android中创建文件

    import java.io.File; import java.io.IOException; import android.app.Activity; import android.os.Bund ...

  8. 最简单的C# Windows服务程序

    通过这个示例了解如何通过C#如何创建一个Windows服务程序. 工具/原料   Vistual Studio 2015 c# 方法/步骤     打开vs2015 文件->新建项目->V ...

  9. 【JLOI 2014】 松鼠的新家

    [题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=3631 [算法] 树上差分 [代码] #include<bits/stdc++. ...

  10. LA4122

    哈夫曼树+搜索 抄了抄代码 先开始不知道怎么限制哈夫曼树,然后看了看代码,是用bfs序来限制.因为每个节点的右子树节点肯定不小于左儿子,同一层也是.所以先搞出bfs序,然后搜索,判断每一层右边是否大于 ...