概要

如何定义一个类

类里通常包含什么

各个部分解释

类是怎么来的

type和object的关系

判断对象的类型

上下文管理器

类结构

#!/usr/bin/env python#-*- coding: utf-8 -*-#Author: rex.cheny#E-mail: rex.cheny@outlook.com

#类名后面写(object)这种写法表示是新式类,不写object是经典类,两种的区别是多继承的问题。

classOOP(object):#定义类变量,类共享的,那么实例A修改以后实例B也会受到影响(修改不可比那对象感官上看不到修改,如果是可变类型比如列表,感官上就有影响了),

#所以类变量是定义共有的属性通常不能修改,虽然技术上也可以修改。不用实例化也可以访问类变量。

var1 = "hello" #不可变对象

list1 = [] #可变对象

def __call__(self, *args, **kwargs):"""这个函数不是析构函数也不是构造函数,对象或者实例可以像函数一样调用,就像执行普通函数一样。这个如果不需要也不用写。

:param args:

:param kwargs:

:return:"""

print("我是特殊函数 __call__")def __init__(self):"""构造函数,用于初始化类的实例,实例化对象的时候就会自动调用这个方法,比如把实例变量绑定到实例上。

这里这个self其实有些特别,也就是实例化的时候会自动把实例对象传递进来,self就是实例对象。

oop = OOP() 这里其实是 OOP(oop) 所以self就是实例oop,这个self也就是为了接受隐式传递进来的实例名称

除了在 __init__ 方法中定义的东西属于实例自己之外也就是在内存中也是独立的,其他的内容包括类变量、类里面的方法在内存中都只有一份所有

实例公用。

多说一句,其实实例化的时候先执行__new__方法,该方法调用__init__方法。"""

#在 __init__ 方法里定义的变量是实例变量,实例独享的。通过实例调用变量或者其他资源是先找实例本身,如果没有就找类的。

#比如类变量和实例变量同名,你通过实例访问这个变量时,它会给你返回实例变量的值。

#加 "_" 表示私有变量,不过使用 "_" 也可以通过某种方式直接访问,所以要想使用严格的私有变量要使用 "__" 双下划线。

self._Var2 = ""

print("我是构造函数 __init__")def __del__(self):"""析构函数,当实例对象删除时候调用,所以不需要设置参数,你也传递不了参数。它是在实例销毁的时候自动调用的。

对于python解释器来说,它有垃圾回收机制,只要有实例存在解释器就认为这个类被使用。如果你del这个实例,其实你删除的

是这个实例,也就意味着切断了实例和类的关系,当解释器发现某个类没有被引用了就可以在内存中删除了。

实例保存的是指向类的指针,实例放在栈里,类放在堆里。基本数据类型放在栈里,非基本数据类型真实的数据都是在堆里,而这个变量名在栈里。

这个方法你通常不用写。"""

print("我是析构函数 __del__")defmyMethod(self):"""为什么类里面的每一个方法都是有self呢?因为我们调用的时候虽然是通过实例名称来调用,但是实际上是

OOP.myMethod(oop)这种形式,你发现它还是会自动把实例传进来,这个self就是用来接收这个实例的。所以

你在自己的方法里面可以访问变量。实例 oop 本身没有 myMethod()方法,之所以可以调用成功就是 OOP.myMonth(oop) 完成的。

对于实例来说类里面的方法都是公用的,你实例化多个对象其实这些对象是多个,但是它们所公用的类方法和类变量在内存中也只有一份,

哪个个实例调用这个方法那么这个self就是哪个实例。记住一句话实例调用方法都是对实例自身进程操作的。

再说详细点,2个针对于同一个类的实例,A实例操作一个方法会影响B实例么?显然不能,这就是self必须存在的原因,在JAVA中也是一样,只是它使用this。

:return:"""

print("自定义方法")#设置成属性用于获取内部变量

@propertydefVar(self):returnself._Var2#设置成属性形式赋值给内部变量,这个必须写在@property下面

@Var.setterdefVar(self, value):

self._Var2=valuedefmain():

oop=OOP()

oop1=OOP()#调用实例的 __call__函数

oop()#通过属性方式修改变量

oop.Var = "world"

print(oop.Var)#判断是否有某种属性

#print(hasattr(oop, "_var1"))

#修改不可变对象(类变量)

print("通过实例oop查看类变量var1的值:", oop.var1)print("通过实例oop1查看类变量var1的值:", oop1.var1)print("通过实例oop修改类变量var1的值:改为100")

oop.var1= 100

print("通过实例oop查看类变量var1的值:", oop.var1)print("通过实例oop1查看类变量var1的值:", oop1.var1)#从值上看感觉类变量也属于实例,因为修改不影响,下面打印id你就看出来了

#print("通过实例oop查看类变量var1的内存地址:", id(oop.var1))

#print("通过实例oop1查看类变量var1的内存地址:", id(oop1.var1))

#print("通过实例oop修改类变量var1的值:改为100")

#oop.var1 = 100

#print("通过实例oop查看类变量var1的内存地址:", id(oop.var1))

#print("通过实例oop1查看类变量var1的内存地址:", id(oop1.var1))

#修改类变量可变类型变量

print("oop实例向list1添加一个元素A")

oop.list1.append("A")print("oop的 list1 内容为:", oop.list1)print("oop1的 list1 内容为:", oop1.list1)if __name__ == '__main__':

main()

关于类里面的类变量和实例变量还需要在说一下

#!/usr/bin/env python

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

class A:

# 类变量

a = 11

def __init__(self, x, y):

# 实例变量

self.x = x

self.y = y

a1 = A(1, 2)

# 这里你以为是修改的类A里面的a吗?其实不是,为什么,看下面

a1.a = 100

"""

这样定义其实会让a1这个实例多一个bb属性出来(新建到a1这个实例中),

所以上面那个a1.a 其实并不是A类里面的类变量a,而是属于实例自己的

"""

a1.bb = 200

print(a1.x, a1.y, a1.a, a1.bb) # 这也就是a1为什么会有bb

a2 = A(5, 6)

# 这里的a值还是11,a2这个实例本身没有a这个变量,但是它自己没有就会向上查找,它的上一级就是A这个类

print(a2.x, a2.y, a2.a)

A.a = 500 # 这样才会修改类变量,修改之后实例化的对象(之前或者之后)理论上都受到影响

print(A.a)

a3 = A(8, 9)

print("实例a3的a: ", a3.a)

print("实例a2的a: ", a2.a)

# a1之所以不受影响是因为之前 a1自己定义了一个a属性,这样它自己就有a属性,从而就不用去找类的a属性了

print("实例a1的a: ", a1.a)

类中其他特殊方法(也叫做魔法方法)

__dic__

#!/usr/bin/env python#-*- coding: utf-8 -*-#Author: rex.cheny#E-mail: rex.cheny@outlook.com

classTestObj(object):#类变量

var1 = 999

def __init__(self, name, age):

self.name=name

self.age=age

self.list1= ['A', 'B']

self.set1= (1, 2)

self.dic1= {"a": "a", "b": "b"}defmain():

TO= TestObj(name="Tom", age=23)print(TO.__dict__)

TO.name= "张三"

print(TO.__dict__)if __name__ == '__main__':

main()

作用:查看实例里面的属性,键为属性名,值为属性值,那都包含哪些属性呢? 所有 self.XXX 的都是属性。而且类变量也算。它永远返回的是实例当前的最新值。从输出看到类变量并没有输出。

其实这个属性通过类也可以调用

#!/usr/bin/env python#-*- coding: utf-8 -*-#Author: rex.cheny#E-mail: rex.cheny@outlook.com

classTestObj(object):#类变量

var1 = 999

def __init__(self, name, age):

self.name=name

self.age=age

self.list1= ['A', 'B']

self.set1= (1, 2)

self.dic1= {"a": "a", "b": "b"}defmain():#TO = TestObj(name="Tom", age=23)

#print(TO.__dict__)

#TO.name = "张三"

#print(TO.__dict__)

#通过类来调用

print(TestObj.__dict__)if __name__ == '__main__':

main()

除了输出类变量之外还有一些类本身的东西。

__str__和__unicode__方法

#!/usr/bin/env python#-*- coding: utf-8 -*-#Author: rex.cheny#E-mail: rex.cheny@outlook.com

classTestObj(object):#类变量

var1 = 999

def __init__(self, name, age):

self.name=name

self.age=agedefmain():

TO= TestObj(name="Tom", age=23)#打印实例

print(TO)if __name__ == '__main__':

main()

输出是对象的地址

这是默认输出,如果你想改变输出就是通过__str__来设置的,__unicode__是python2的方法,在python3中使用__str__

#!/usr/bin/env python#-*- coding: utf-8 -*-#Author: rex.cheny#E-mail: rex.cheny@outlook.com

classTestObj(object):#类变量

var1 = 999

def __init__(self, name, age):

self.name=name

self.age=age#定义__str__方法

def __str__(self):return "我是TestObj"

defmain():

TO= TestObj(name="Tom", age=23)#打印实例

print(TO)if __name__ == '__main__':

main()

作用:在类里定义这个方法,那么在打印对象时将输出该方法的返回值。在python3中是__str__ 在python2中是__unicode__。这个方法用的最多的是在Django的module中。

__getitem__、__setitem__和__delitem__方法

#!/usr/bin/env python#-*- coding: utf-8 -*-#Author: rex.cheny#E-mail: rex.cheny@outlook.com

classTestObj(object):#类变量

var1 = 999

def __init__(self, name, age):

self.dic1={}def __getitem__(self, item):print("__getitem__", item)returnself.dic1[item]def __setitem__(self, key, value):print("__setitem__", key, value)

self.dic1[key]=valuedef __delitem__(self, key):print("__deleteitem__", key)defmain():

TO= TestObj(name="Tom", age=23)

TO["name"] = "Lucy"TO["age"] = 23

print(TO.dic1)print(TO["name"])del TO["name"]if __name__ == '__main__':

main()

运行结果

通过这三个方法可以让操作实例跟操作字典一样。至于使用场景我也不知道,目前没有用到过。

这些魔法方法属于谁

#!/usr/bin/env python

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

class Company(object):

def __init__(self, employee_list):

self.employee = employee_list

def __getitem__(self, item):

return self.employee[item]

company = Company(["Tom", "Lucy", "Lily"])

print(company[:2])

for item in company:

print(item)

换成字典就不行了

__getitem__可以让我们增加一些更加方便的方式去操作对象,但是上面之所以不能切片了是因为字典本身不能切片,而且__getitem__里面的item是索引并不是键,所以当我们换成字典的时候就会出错。其实这种魔法方法不是为类而创建的的也不是object才有的,而是一种可以丰富对类的操作的一种方式。

上下文管理器

#!/usr/bin/env python

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

"""

正常使用try语句我们是这样的

"""

def exe_try():

dic1 = {"A": "2"}

try:

print(dic1["B"])

except KeyError as e:

# 抛出异常执行这里

print("KeyError")

else:

# 不抛出异常执行这里

print("没有异常")

finally:

# 无论是否抛出异常最后都执行这里

print("finished")

# exe_try()

"""

你是否想过一个问题,打开文件会抛出异常,通常打开文件后也需要关闭文件流,为什么用 with open()语句可以不用手动关闭文件流呢?

这就是上下文管理器

"""

class Sample:

def __init__(self):

# 首先执行这个方法

print("__init__")

def __enter__(self):

# 然后会自动调用这个方法,可以理解为获取资源

print("__enter__")

return self

def __exit__(self, exc_type, exc_val, exc_tb):

# 这个函数会自动调用,当跳出with语句的时候,目的是为了释放资源

print("__exit__")

def toDo(self):

print("to do something")

# 这个用法是不是很像 with open()呢?

with Sample() as sample:

sample.toDo()

"""

__enter__和__exit__构成了上下文管理器

"""

#!/usr/bin/env python

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

"""

如何把上下文管理器更加简化一下呢?

"""

import contextlib

@contextlib.contextmanager # 这个装饰器把下面的函数包装成上下文管理器,主要利用了yiele的特性

def myFun(arg1):

print("begin", arg1) # 相当于 __enter__ 里面的代码

yield {} # 这里必须有个生成器

print("finished") # 相当于 __exit__ 里面的代码

with myFun("AAA") as my:

print("BBB")

类是如何创建的

一切皆对象,任何一个对象都可以找到它属于什么类型,那么类也是对象,那类的类型是什么呢?

#!/usr/bin/env python#-*- coding: utf-8 -*-#Author: rex.cheny#E-mail: rex.cheny@outlook.com

__metaclass__ =typeclassTestObj(object):def __init__(self, name, age):

self.name=name

self.age=age#定义__str__方法

def __str__(self):return "我是TestObj"

defmain():

TO= TestObj(name="Tom", age=23)print(type(TO))print(type(TestObj))if __name__ == '__main__':

main()

输出

类的类型就是type,也就是说类是通过type来创建的。到底是怎么创建的呢?

#!/usr/bin/env python#-*- coding: utf-8 -*-#Author: rex.cheny#E-mail: rex.cheny@outlook.com

def __init__(self, name, age):

self.name=name

self.age=age"""TestObj 对象名称

type() 函数

"TestObj" 类名称

(object,) 继承自哪里,可以为空

{} 方法名称和方法,字典形式 方法就是上面定义的"""TestObj= type("TestObj", (object,), {"__init__": __init__})defmain():

TO= TestObj(name="Tom", age=23)print(type(TO))print(type(TestObj))if __name__ == '__main__':

main()

现在知道为什么TestObj的type是type了吧。

关于type和object

type用来生成类,而类用来生成实例,所以我们通过type命令可以查看这个实例或者说是对象是由谁生成的也就是其类型

a = 1

print(type(1), " 生成1")

print(type(int), " 生成int")

print(type(type), " 生成type")

# 基类

class MyClass:

pass

# object是所有类都要继承的类也就是最顶层的类,或者说所有类的父类,类的祖先

print("MyClass的基类是:", MyClass.__bases__)

print("type的基类是:", type.__bases__)

print("object的type是:", type(object))

print("Object的基类是:", object.__bases__)

type的基类是object, 而object的type是type,看起来是个环形。object是type的实例,而type又继承自object,type也是自己的实例。在Python中

一切为对象,list、str、int等都是对象,可能有人问这命名是类啊,没错它们是类但也是对象。这一点和JAVA有所区别。这些东西之所有是类但同时也是对象

是因为他们都是type的实例。它们继承自object但是它们也是type的实例,只有实例才可以叫做对象,否则它们就是类。

type是自己的实例,object是type的实例,而type又继承了object,str是type的实例同时继承了objcet。

判断对象类型

我们知道获取对象类型通过type来查看。但是还有一个叫做isinstance,这两个有什么区别呢?

#!/usr/bin/env python

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

class A:

pass

class B(A):

def test(self):

print("Test")

b = B()

print(isinstance(b, B))

print(isinstance(b, A))

print(type(b) is A)

结果是type不认为实例b是A的类型,但是isinstance则任务b是A的类型,b是B的实例,而B继承了A所以说b是A的类型也没有错。那他俩有什么区别呢?

发现用 isinstance 和 type 得到的结果不同,因为type(b) 指向的就是B这个类,而A就是A这个类,显然不相同,虽然B继承自A,但是用 isinstance 就会得到相同的结果,它会追溯它判断b是不是A这个类型,因为b是B的实例,而B继承自A,所以结果为 True。

说到底type不会认为子类的对象的类型是父类,而isinstance则会子类的对象也是父类的类型。

多继承时super的执行顺序

#!/usr/bin/env python

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

class A:

def __init__(self):

print("A")

class B(A):

def __init__(self):

print("B")

# 调用父类方法,Python2写法

# super(Son, self).__init__()

# 调用父类方法,Python3简化写法

super().__init__() #

class C(A):

def __init__(self):

print("C")

super().__init__() #

class D(B, C):

def __init__(self):

print("D")

super().__init__() #

# 打印D的MRO看一下

print(D.__mro__)

d = D()

常规上我们说super是调用父类方法,没错但是不太严谨,它是调用MRO路径寻找的下一个类的方法。当你使用单继承的时候看不出来,

当使用多继承的时候就会看出来。

__new__方法

#!/usr/bin/env python#-*- coding: utf-8 -*-#Author: rex.cheny#E-mail: rex.cheny@outlook.com

classTestObj(object):def __init__(self, name, age):

self.name=name

self.age=ageprint("__init__方法执行了")def __new__(cls, *args, **kwargs):"""该方法会在__init__之前调用.

:return:"""

print("__new__方法执行了")"""如果你的类里自己重写了 __new__ 方法那么下面的这个返回必须写,否则你定义的类将不会执行__init__方法。

这个类是继承自object,那么你其实并不知__new__原本具体都做什么,出于某些原因你必须要重写__new__方法,

当你的逻辑写完之后,就要通过 object.__new__(cls) 来调用父类的__new__方法,完成初始化。"""

return object.__new__(cls)defmain():

TO= TestObj(name="Tom", age=23)print(TO.name)if __name__ == '__main__':

main()

python魔法方法与函数_Python的魔法函数相关推荐

  1. python魔法方法是什么_Python魔法方法指南(基础)

    什么是魔法方法呢?它们在面向对象的Python的处处皆是.它们是一些可以让你对类添加"魔法"的特殊方法. 它们经常是两个下划线包围来命名的(比如__init__ ,__lt__ ) ...

  2. python中魔法方法repr_Python的两个魔法方法:__repr__和__str__

    目录 例子 关系 使用 官方文档 参考 __repr__ 和 __str__ 是 Python 的两个魔法方法(Magic/Special method),更多魔法方法可以参考 A Guide to ...

  3. python内置方法就是内置函数_python内置函数

    什么是内置函数? 就是python给你提供的,拿来直接用的函数, 比如print 和 input等等. 截止到python版本3.6.2 python一共提供了68个内置函数. 他们就是python直 ...

  4. python计算平方用map函数_python的map函数的使用方法详解以及使用案例(处理每个元素的自增、自减、平方等)...

    1.用我们之前学过的求一下平方(只有一个列表) #求平方 num=[1,5,6,2,7,8] a=[]for n innum: a.append(n**2)print(a) C:python35pyt ...

  5. python 方法的实例_python调用自定义函数的实例操作

    在python中,想要调用自定义函数必须先声明,然后才能调用.使用函数时,只要按照函数定义的形式,向函数传递必需的参数,就可以调用函数完成相应的功能或者获得函数返回的处理结果. (1)声明函数 pyt ...

  6. python中的方法什么意思_python中的函数和方法的区别是什么

    python中的函数和方法的区别: 1.函数要手动传self,方法不用传self. 2.如果是一个函数,要用类名去调用,如果是一个方法,要用对象去调用. 举例说明:class Foo(object): ...

  7. python怎么定义一个函数_Python定义一个函数的方法

    Python函数的定义 定义函数,也就是创建一个函数,可以理解为创建一个具有某些用途的工具.定义函数需要用 def 关键字实现,具体的语法格式如下: def 函数名(形参列表): //由零条到多条可执 ...

  8. python内置函数调用前_python之内置函数(一)

    一.内置函数 1.内置函数总览 abs() dict() help() min() setattr() all() dir() hex() next() slice() any() divmod() ...

  9. python如何自定义函数_python如何自定义函数_后端开发

    c语言特点是什么_后端开发 c语言特点是:1.语言简洁.紧凑,使用方便.灵活:2.运算符丰富:3.数据结构丰富,具有现代化语言的各种数据结构:4.具有结构化的控制语句:5.语法限制不太严度格,程序设计 ...

最新文章

  1. 【渝粤教育】 国家开放大学2020年春季 2071美学与美育 参考试题
  2. JAVA软件工程师应该具备的技能有哪些?
  3. if test 多条件_秒懂Python编程中的if __name__ == #39;main#39; 作用和原理
  4. Java历经20年沧桑,将持续革新
  5. IntelliJ IDEA关于logger的live template配置
  6. 【采访】腾讯社交广告高校算法大赛第三周周冠军——到底对不队比赛经验及心得分享
  7. ElasticSearch之 控制相关度原理讲解
  8. Java基础篇:类的通用格式
  9. 阿尔法贝塔剪枝——中国象棋人机对战
  10. Git客户端Tower for Mac 8.2
  11. 湘潭大学 计算机学院程诗婕,2019 CCF CCSP分赛区竞赛决出金银铜奖
  12. 清除U盘内所占的隐藏空间(U盘容量突然变小了)
  13. 利用kali hydra 暴力破解Windows7(hydra的基本用法)会继续更新
  14. pygame副产品—大战外星人
  15. ns-3学习手记11_ofswitch13安装教程
  16. 《Java黑皮书基础篇第10版》 第3章【习题】
  17. 谈谈HashMap为什么是线程不安全的?
  18. 浅谈TCP协议的端口(port)
  19. 白岩松---白说摘录
  20. 2018-06-03 对待知识的态度 --王小波

热门文章

  1. 张小龙演讲干货:微信的未来在哪?这里有7个答案
  2. class 人开枪射击子弹
  3. 软件下载相关的几个网站列表
  4. namenode和datanode工作机制_HDFS的namenode和datanode详解
  5. 地球暖化有新解决方案? 冰岛科学家研发出二氧化碳石头
  6. poi 双表头excel制作
  7. 师恩难忘,安发国际董事局主席高益槐新春佳节看望耄耋恩师
  8. java Map转Object Object转Map
  9. 暑期学习日记28:js逻辑
  10. 从零开始配置Vue项目(WebApp)