Python面向对象几个知识点
一、判断对象是否属于类、判断类是否派生自某个类
class Zero:
pass
class One(Zero):
pass
class Two(One, Zero):
pass
# 判断对象是否完全是某个类
print(type(Two()) == Two)#true
print(type(Two()) == Zero)#false
# 判断对象是否属于某个类
print(isinstance(Two(), Zero))#true
# 判断某个类是否是另一个类的子类
print(Zero in Two.__bases__)#true
print(issubclass(Two,Zero))
二、关于元类
在Python中,类型分为三个层次:元类、类、对象。
类是元类的实例化,对象是类的实例化。
在Python中,元类、类、对象三种东西相当于结点,它们之间的有向边表示继承关系。整个类型系统构成一个有向无环图。这个有向无环图分为三层,一个对象可以继承多个类。
metaclass的作用就是创建类
举一个小例子
class BaseMetaClass(type):
def __new__(cls, *args, **kwargs):
kind = type.__new__(cls, *args, **kwargs)
print(kind)
return kind
class Base(metaclass=BaseMetaClass):
pass
class One(Base):
pass
class Two(Base):
pass
输出为
<class '__main__.Base'>
<class '__main__.One'>
<class '__main__.Two'>
在此例中,只进行了类的声明,没有进行类的实例化。在进行类的声明过程中,会调用metaclass的new方法,new方法的返回值就是一个具体的类型。类型是特殊的对象。
Python中,内置函数type起的作用非常关键,它具有两个作用
type(obj)
查看obj的类型,type(cls)
查看cls的元类type(className,*arg,*karg)
构造函数产生新的类
在上述代码的基础上加几句话
class Three:
pass
print(type(One))#<class '__main__.BaseMetaClass'>
print(type(Three))#<class 'type'>
print(type(type))#<class 'type'>
三、一切皆type
在Java中,一切皆是Object
在Python中,一切皆是type
def f():
pass
ff = lambda: 0
x = []
for i in (list, dict, type, f, ff, x):
while type(i) != i:
print(i, end=' ')
i = type(i)
print(i)
输出为
<class 'list'> <class 'type'>
<class 'dict'> <class 'type'>
<class 'type'>
<function f at 0x000000CEE01B7F28> <class 'function'> <class 'type'>
<function <lambda> at 0x000000CEE07E5A60> <class 'function'> <class 'type'>
[] <class 'list'> <class 'type'>
四、函数中可以定义类,类中可以定义函数
函数是function类型,function是type类型
>>> def choose_class(name):
… if name == 'foo':
… class Foo(object):
… pass
… return Foo # 返回的是类,不是类的实例
… else:
… class Bar(object):
… pass
… return Bar
…
>>> MyClass = choose_class('foo')
>>> print MyClass # 函数返回的是类,不是类的实例
<class '__main__'.Foo>
>>> print MyClass() # 你可以通过这个类创建类实例,也就是对象
<__main__.Foo object at 0x89c6d4c>
五、使用type定义类型
type(类型名称,基类列表,属性字典)
A = type("A", (), {
'name': 'weidiao',
'age': 23,
'__str__': lambda self: '{},{}'.format(self.name, self.age)
})
x = A()
print(x)#输出为weidiao,23
六、__class__
属性
__class__
属性时是每一种类型必然包含的属性,该属性的取值相当于x.__class==type(x)
七、不要忘记python是一门脚本语言
下面定义了一个类A,它有name和age两个属性,但是我可以随意给这个对象添加属性。
A = type("A", (), {
'name': 'weidiao',
'age': 23,
'__str__': lambda self: '{},{},{}'.format(self.name, self.age,self.baga)#如果没有baga属性,此处会报错
})
x = A()
x.baga='3'
print(x)
八、调用父类构造函数的两种方法
在Java和C++中,子类的构造函数都会自动调用父类的构造函数。
在Python中,子类是不会自动调用父类的构造函数的,因为在Python中没有构造函数,而只有初始化函数!而初始化函数只相当于普普通通的函数,所以,这就需要我们手动来调用父类的构造函数。
首先来看,如果不调用父类构造函数会出现什么情况
class A:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return self.name + str(self.age)
class B(A):
def __init__(self):
pass
b = B()
print(b)
在此例中,B类没有调用A类的初始化函数,所以B类就缺少了name和age属性,B类的str相当于A类的str,print时就会因为缺少name和age属性报错
AttributeError: 'B' object has no attribute 'name'
有两种方法调用父类的构造函数
class A:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return self.name + str(self.age)
class B(A):
def __init__(self):
# A.__init__(self,'weidiao',23)
super(B,self).__init__('weidiao',23)
b = B()
print(b)
这两种方法第一种方法比较灵活,完全可以取代第二种方法。
A.__init__(self,args)
这种方式只初始化了父类A
super(B,self).__init__(self,args)
这种方式初始化了第一个父类(根据继承的顺序),所以这种方式是完全可以用FirstFather.__init()
进行取代的。
九、单例
Java中的对象的创建和对象的初始化这两个过程是紧密耦合在一起的,对象创建过程指的是为对象分配必要的内存空间,对象初始化指的是向内存中写入值。简言之,Java中一旦调用构造函数,对象空间开辟和对象初始化两种操作就同时完成了。在Java中,单例只创建一次且只初始化一次。
在Python中不是这样,Python中对象创建过程和对象初始化过程是分开的。class的__new__()
函数负责对象的创建,class的__init__()
负责对象的初始化。在Python中,单例可能创建一次,初始化多次。
下面看一种单例的写法:
class Dog:
dog = None
def __new__(cls, *args, **kwargs):
if cls.dog is None:
cls.dog = object.__new__(cls)
print('create singleton over')
return cls.dog
def __init__(self, name):
print('init is called')
self.name = name
# 下面这句话会报错,因为Dog.dog目前为None
# print(Dog.dog.name)
x = Dog('x')
y = Dog('y')
print(x.name) # y
print(y.name) # y
此例中,会发现init is called
输出两次,但是x和y实际上是同一个对象。也就是说,在Python中,只要调用对象的构造函数,必然会先调用__new__()
函数,__new__()
返回一个对象,然后Python会自动调用返回对象的__init__()
函数。
上面例子的另一种实现是把重写new函数的工作放到一个父类里面,这样就能够实现:只需要继承父类就能够让自己变成单例。
class Singleton:
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = object.__new__(cls)
return cls._instance
class Dog(Singleton):
def __init__(self, name):
self.name = name
x = Dog('x')
y = Dog('y')
print(x.name, y.name)
在Python中,我们创建的任何一个对象,无需重写setattr方法即可随便往对象上“悬挂”成员变量。
class Ha:
pass
x = Ha()
x.dog = 3
print(x.dog)
单例的实现
from functools import lru_cache
class Singleton:
@lru_cache()
def __new__(cls, *args, **kwargs):
obj = object.__new__(cls)
obj.inited = False
return obj
class Haha(Singleton):
def __init__(self, name):
if self.inited:
return
self.inited = True
self.name = name
print("inited")
x = Haha("x")
y = Haha("y")
print(x.name)
print(y.name)
总结
在语言的完美、统一程度上,Python无人可及,Java都比它差一点。
Python面向对象几个知识点的更多相关文章
- python面向对象进阶(八)
上一篇<Python 面向对象初级(七)>文章介绍了面向对象基本知识: 面向对象是一种编程方式,此编程方式的实现是基于对 类 和 对象 的使用 类 是一个模板,模板中包装了多个“函数”供使 ...
- python 面向对象(进阶篇)
上一篇<Python 面向对象(初级篇)>文章介绍了面向对象基本知识: 面向对象是一种编程方式,此编程方式的实现是基于对 类 和 对象 的使用 类 是一个模板,模板中包装了多个“函数”供使 ...
- python 面向对象学习
------Python面向对象初 下面写一个类的简单实用,以便方便理解类 #python 3.5环境,解释器在linux需要改变 #阅读手册查询readme文件 #作者:S12-陈金彭 class ...
- Python开发【第七篇】:面向对象 和 python面向对象进阶篇(下)
Python开发[第七篇]:面向对象 详见:<Python之路[第五篇]:面向对象及相关> python 面向对象(进阶篇) 上一篇<Python 面向对象(初级篇)> ...
- python 面向对象进阶之内置方法
一 isinstance(obj,cls)和issubclass(sub,super) 1.1,isinstance(obj,cls)检查是否obj是否是类 cls 的对象 class Foo(obj ...
- 【转】python 面向对象(进阶篇)
[转]python 面向对象(进阶篇) 上一篇<Python 面向对象(初级篇)>文章介绍了面向对象基本知识: 面向对象是一种编程方式,此编程方式的实现是基于对 类 和 对象 的使用 类 ...
- python 面向对象(进阶篇)转载武沛齐
上一篇<Python 面向对象(初级篇)>文章介绍了面向对象基本知识: 面向对象是一种编程方式,此编程方式的实现是基于对 类 和 对象 的使用 类 是一个模板,模板中包装了多个“函数”供使 ...
- Python 面向对象 (进阶篇)
<Python 面向对象(初级篇)>文章介绍了面向对象基本知识: 面向对象是一种编程方式,此编程方式的实现是基于对 类 和 对象 的使用 类 是一个模板,模板中包装了多个“函数”供使用(可 ...
- python 面向对象初级篇
Python 面向对象(初级篇) 概述 面向过程:根据业务逻辑从上到下写垒代码 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可 面向对象:对函数进行分类和封装,让开发" ...
随机推荐
- 自动化打包 Jenkins 持续集成 Git Gradle MD
Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...
- 字符串 CSV解析 表格 逗号分隔值 通讯录 电话簿 MD
Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...
- uboot mmc read/write命令用法
mmc read用来读取mmc内容到内存, mmc write用来写入内存内容到mmc中 具体用法, mmc read <device num> addr blk# cnt [partit ...
- VS2013开发一个简单的asmx接口程序
一.开发和调试 1:创建一个ASP.NET web应用程序 2:选择空的模板 3:系统生成项目目录 4:右键项目-添加项-新建项 5:选择Web 服务(ASMX) 6:选择之后项目中会有一个Test ...
- Anroid 解决小米和魅族不能在mac上调试
第一种方法 1.mac->关于本机->系统报告->usb->copy厂商ID** 2.cmd->echo " 0x2a45" >> ~/. ...
- MFC中调用web api
使用COM组件来调用,需要catch com error. IXMLHTTPRequestPtr pIXMLHTTPRequest = NULL; BSTR bstrString = NULL; HR ...
- (纪录片)你必须知道的科学 The Science That You Have To Know (2014)
简介: 类型: 纪录片制片国家/地区: 英国语言: 英语上映日期: 2014-2片长: 150分钟 主要内容: 你有没有认真想过,自己的身体有多奇妙?人体是世间最复杂的一项工程杰作,他也带来了一些非常 ...
- 【算法】插入排序(Insertion Sort)
(PS:内容参考MIT算法导论) 插入排序(Insertion Sort): 适用于数目较少的元素排序 伪代码(Pseudocode): 例子(Example): 符号(notation): 时间复杂 ...
- .geodatabase与gdb的相互转换
.geodatabase长得是gdb的全称,确实它们有一定的关系,但也有区别. 简单认识一下 有人也问过我,gdb外表像个文件夹,是怎么实现的.gdb数据库是ESRI特有的数据库,它是一些数据集定义. ...
- 解决工作中遇到的一个"打开,保存"文件框的bug的过程
工作中遇到的这个问题还是很有意思的.其中嵌套了很多奇葩性的问题. (转载请指明出于breaksoftware的csdn博客) 我们来看下故事的发生过程,QA同学发现我们存在如下的bug 看到如此多的串 ...