python核心高级学习总结6------面向对象进阶之元类
元类引入
在多数语言中,类就是一组用来描述如何生成对象的代码段,在python中同样如此,但是在python中把类也称为类对象,是的,你没听错,在这里你只要使用class关键字定义了类,其解释器在执行时就会创建一个对象,但是这个对象比较特殊,它可以创建自己的实例对象(像其他语言一样)。你可以对它进行下面的操作:
1. 你可以将它赋值给⼀个变量
2. 你可以拷⻉它
3. 你可以为它增加属性
4. 你可以将它作为函数参数进⾏传递
动态创建类
听起来python在这方面跟一些语言的差别了吧,没错它还可以在运行时动态地创建它们,你可以在函数中创建类,用class关键字即可。
def choose_class(name):
if name == 'foo':
class Foo(object):
pass
return Foo # 返回的是类, 不是类的实例
else:
class Bar(object):
pass
return Bar
如果你想知道python中的变量或者数值的类型,你可以用万能而强大的type,如下(注意它们的返回值)
>>> print type(1) #数值的类型
<type 'int'>
>>> print type("1") #字符串的类型
<type 'str'>
>>> print type(ObjectCreator()) #实例对象的类型
<class '__main__.ObjectCreator'>
>>> print type(ObjectCreator) #类的类型
<type 'type'>
使用type创建类
Test2 = type("Test2",(),{}) #定了⼀个Test2类
In [5]: Test2() #创建了⼀个Test2类的实例对象
Out[5]: <__main__.Test2 at 0x10d406b38>
上面等价于
class Test2:
pass
使⽤type创建带有属性的类
Foo = type('Foo', (), {'bar':True})
可以翻译为
>>> class Foo(object):
… bar = True
这个类跟普通创建的类一样使用,如继承这个类,你可以用下面的方法
>>> FooChild = type('FooChild', (Foo,),{})
>>> print FooChild
<class '__main__.FooChild'>
>>> print FooChild.bar # bar属性是由Foo继承⽽来
True
同样等价于
>>> class FooChild(Foo):
… pass
注意:添加的属性都是类属性,第二个参数是继承自哪儿,采用元组的形式,也要知道在python中元组中只有一个参数表示方法只能是(xx,),而不能是(xx)
使⽤type创建带有⽅法的类
如果你想为你的类增加方法,那么你创建一个签名函数,然后添加其为属性赋值即可。
添加实例方法
In [46]: def echo_bar(self): #定义了⼀个普通的函数
...: print(self.bar)
...:
In [47]: FooChild = type('FooChild', (Foo,), {'echo_bar': echo_bar})
In [48]: hasattr(Foo, 'echo_bar') #判断Foo类中, 是否有echo_bar这个属性
Out[48]: False
In [49]:
In [49]: hasattr(FooChild, 'echo_bar') #判断FooChild类中, 是否有echo_bar这个
Out[49]: True
In [50]: my_foo = FooChild()
In [51]: my_foo.echo_bar()
True
添加类方法
In [42]: @classmethod
...: def testClass(cls):
...: print(cls.bar)
...:
In [43]:
In [43]: Foochild = type('Foochild', (Foo,), {"echo_bar":echo_bar,"testClass":testClass})
In [44]:
In [44]: fooclid = Foochild()
In [45]: fooclid.testClass()
True
添加静态方法
In [36]: @staticmethod
...: def testStatic():
...: print("static method ....")
...:
In [37]: Foochild = type('Foochild', (Foo,), {"echo_bar":echo_bar,“testStatic”:testStatic})
In [38]: fooclid = Foochild()
In [39]: fooclid.testStatic
Out[39]: <function __main__.testStatic>
In [40]: fooclid.testStatic()
static method ....
In [41]: fooclid.echo_bar()
True
看到这么多实现动态类的方法,你该明白python是怎么做到的,在这里就涉及到元类,元类就是用来创建类的东西,而创建类就是为了创建类的实例对象,所以可以这样理解,元类就是为了创建类对象的,而type实际上就是一个元类,传统类的元类就是types.classType,在python中元类的介绍中也介绍了元类,有兴趣的读者可以去看看。
SO,结论就是Python中所有的东⻄, 注意, 我是指所有的东⻄——都是对象。 这包括整数、 字符串、 函数以及类。 它们全部都是对象,⽽且它们都是从⼀个类创建⽽来, 这个类就是type。
__metaclass__属性
class Foo(object):
__metaclass__ = something…
#...省略...
那么当python解释器看到下面代码时
class Foo(Bar):
pass
python做了如下的操作:
2. 如果Python没有找到__metaclass__, 它会继续在Bar( ⽗类) 中寻找__metaclass__属性, 并尝试做和前⾯同样的操作。
3. 如果Python在任何⽗类中都找不到__metaclass__, 它就会在模块层次中去寻找__metaclass__, 并尝试做同样的操作。
4. 如果还是找不到__metaclass__,Python就会⽤内置的type来创建这个类对象。
在这个__metaclass__中可以放一些什么代码呢?------可以做任何涉及到类操作的事情,用type或者其子类来完成。
#coding=utf-8
class UpperAttrMetaClass(type):
# __new__ 是在__init__之前被调⽤的特殊⽅法
# __new__是⽤来创建对象并返回之的⽅法
# ⽽__init__只是⽤来将传⼊的参数初始化给对象
# 你很少⽤到__new__, 除⾮你希望能够控制对象的创建
# 这⾥, 创建的对象是类, 我们希望能够⾃定义它, 所以我们这⾥改写__new__
# 如果你希望的话, 你也可以在__init__中做些事情
# 还有⼀些⾼级的⽤法会涉及到改写__call__特殊⽅法, 但是我们这⾥不⽤
def __new__(cls, future_class_name, future_class_parents, future_clas
#遍历属性字典, 把不是__开头的属性名字变为⼤写
newAttr = {}
for name,value in future_class_attr.items():
if not name.startswith("__"):
newAttr[name.upper()] = value
# ⽅法1: 通过'type'来做类对象的创建
# return type(future_class_name, future_class_
parents, newAttr)
# ⽅法2: 复⽤type.__new__⽅法
# 这就是基本的OOP编程, 没什么魔法
# return type.__new__(cls, future_class_name, future_class_parent
# ⽅法3: 使⽤super⽅法
return super(UpperAttrMetaClass, cls).__new__(cls, future_class_n
#python2的⽤法
class Foo(object):
__metaclass__ = UpperAttrMetaClass
bar = 'bip'
# python3的⽤法
# class Foo(object, metaclass = UpperAttrMetaClass):
# bar = 'bip'
print(hasattr(Foo, 'bar'))
# 输出: False
print(hasattr(Foo, 'BAR'))
# 输出:True
f = Foo()
print(f.BAR)
# 输出:'bip'
1. 拦截类的创建
2. 修改类
3. 返回修改之后的类
哈哈,我想说的是对于元类咱们99%的人不会用到。
python核心高级学习总结6------面向对象进阶之元类的更多相关文章
- python 面向对象进阶之元类metaclass
一:知识储备 exec exec:三个参数 参数一:字符串形式的命令 参数二:全局作用域(字典形式),如果不指定,默认为globals() 参数三:局部作用域(字典形式),如果不指定,默认为local ...
- python核心高级学习总结5--------python实现线程
在代码实现上,线程的实现与进程的实现很类似,创建对象的格式都差不多,然后执行的时候都是用到start()方法,与进程的区别是进程是资源分配和调度的基本单位,而线程是CPU调度和分派的基本单位.其中多线 ...
- python核心高级学习总结7---------正则表达式
正则表达式在爬虫项目中应用很广泛,主要方面就是在字符串处理方面,经常会涉及到字符串格式的校验,用起来经常要查看文档才能完成,所以抽了个时间将正则的内容复习了一下. Start re---导入re模块使 ...
- python核心高级学习总结8------动态性、__slots__、生成器、迭代器、装饰、闭包
python的动态性 什么是动态性呢,简单地来说就是可以在运行时可以改变其结构,如:新的函数.对象.代码都可以被引进或者修改,除了Python外,还有Ruby.PHP.javascript等也是动态语 ...
- python核心高级学习总结3-------python实现进程的三种方式及其区别
python实现进程的三种方式及其区别 在python中有三种方式用于实现进程 多进程中, 每个进程中所有数据( 包括全局变量) 都各有拥有⼀份, 互不影响 1.fork()方法 ret = os.f ...
- python核心高级学习总结1---------*args和**kwargs
*args 和 ** kwargs 的用法 首先,这两者在用法上都是用来补充python中对不定参数的接受. 比如下面的列子 def wrappedfunc(*args, **kwargs): pri ...
- python核心编程学习记录之面向对象编程
未完待续525
- python核心高级学习总结4-------python实现进程通信
Queue的使用 Queue在数据结构中也接触过,在操作系统里面叫消息队列. 使用示例 # coding=utf-8 from multiprocessing import Queue q = Que ...
- python核心高级学习总结2----------pdb的调试
PDB调试 def getAverage(a,b): result =a+b print("result=%d"%result) return result a=100 b=200 ...
随机推荐
- CF1066F Yet another 2D Walking
DP 由图可以知道优先级相同的点都在一个"7"字形中 所以在走当前的优先级的点时最好从右下的点走到左上的点,或从从左上的点走到右下的点 那记dp[i][0]表示在走完第i个优先级时 ...
- 【SpringCloud】05.Eureka的高可用
1.简单情况 2.为了达到Eureka的高可用,可以多个Eureka互相注册. 3.我们需要修改两处: Eureka Client Eureka Server 3.1 Eureka Client 在C ...
- Android Google官方文档(cn)解析之——Intents and Intent filter
应用程序核心组件中的三个Activity,service,还有broadcast receiver都是通过一个叫做intent的消息激活的.Intent消息传送是在相同或不同的应用程序中的组件之间后运 ...
- F1分数
分类的常用指标有: accuracy:准确率 recall:召回率 precison:精确率 f1score:f1分数,是recall和precison的调和均值. 准确率什么情况下失效? 在正负样本 ...
- 腾讯云--对象存储cos绑定自定义域名
1.登录腾讯云控制台,找到对象存储一栏 2.选择一个你想绑定域名的存储桶 3.进入你选择的存储桶,点击域名管理 4.选择自定义源站域名.在域名处填写你要设置的自定义域名,在源站类型处选择静态网站源站, ...
- 【linux】helloword原理分析及实战
目录 前言 linux中hello word原理 hello word 实战 学习参考 前言 hello word 著名演示程序,哈哈 下面在 arm linux 下展示一下hello world,便 ...
- binary hacks读数笔记(dlopen、dlsym、dlerror、dlclose)
1.dlopen是一个强大的库函数.该函数将打开一个动态库,并把它装入内存.该函数主要用来加载库中的符号,这些符号在编译的时候是不知道的.比如 Apache Web 服务器利用这个函数在运行过程中加载 ...
- PIP安装Django
1. 2. 3.升级PIP 4. 原来我已经用pycharm装过了,囧~
- SQL Server 数据库bak备份文件还原操作和mdf文件附加操作
前言:现在任何软件都离不开数据的支持,数据的价值是无价的,因此数据目前显得尤为重要,日常软件生产库的数据定时或实时备份必不可少,备份出的文件也需要进行验证,下边我将介绍SQL Server数据的的备份 ...
- 想换4K显示器了?那你搞懂啥是4K了吗?
前言 我们在科技资讯以及电脑显示器.数字电视等电子产品的宣传语中,经常能够看见4K的字样.最近,B站(哔哩哔哩)升级了HTML5播放器和视频云等相关服务,为广大用户提供了超高清(UHD: Ultra ...