36~040类和对象
-
是数据和函数的一种封装形式,对象 = 属性+方法(对象是某个类的一个实例,创建类的一个实例,用这个实例表示类就叫对象)
-
类的定义:
class Turtle: #Python中类名是以大写字母开头 #属性 color = "green" weight = 10 legs = 4 shell = True mouth = "大嘴巴" #方法 def climb(self): print("爬") def run(self): print("跑") def bite(self): print("咬") def eat(self): print("吃") def sleep(self): print("睡觉")
-
创建类的实例:对象
>>> tt = Turtle() >>> tt <__main__.Turtle object at 0x000001B2993EB370>
-
通过对象调用对象的方法
>>> tt.climb() 爬 >>>
-
面向对象的特征:
-
封装:属性+方法
-
继承:继承是子类自动共享父类之间数据和方法的机制
>>> class MyList(list): #创建一个MyList类,这个类继承了list类 pass #pass的意思就是啥也不干 >>> mylist1 = MyList()#创建MyList类的对象 >>> mylist1.append(0)#通过自己创建的类调用父类list的方法 >>> mylist1.append(5) >>> mylist1#打印看结果 [0, 5]
-
多态:不同对象对同一方法会响应不同的行动
>>> class A: def fun(self): print("My A") >>> class B: def fun(self): print("My B") >>> a = A() >>> b = B() >>> a.fun()#调用的方法都是同名的,但他们的实现却不一样,这就是多态 My A >>> b.fun()#调用的方法都是同名的,但他们的实现却不一样,这就是多态 My B
-
-
面向对象编程:
-
self是什么:Python的self就相当于C++的this指针,对象的方法被调用的时候,对象会将自身作为第一个参数传给self参数,这样才分别了多个对象调用同一方法却会响应不同的行动。
只是C++和其他面向对象语言中,函数的this指针都省略了,而Python的是必须写在自己定义的方法的第一个参数中。
>>> class Ball: def setName(self,name): self.name = name def Kick(self): print("我叫%s,该死的谁踢我。。。" % self.name) >>> a = Ball() >>> a.setName("球A") >>> b = Ball() >>> b.setName("球B") >>> c = Ball() >>> c.setName("球C") >>> a.Kick() 我叫球A,该死的谁踢我。。。 >>> b.Kick() 我叫球B,该死的谁踢我。。。 >>> c.Kick() 我叫球C,该死的谁踢我。。。
-
-
Python的魔法方法
-
如果你的对象实现了这些方法中的某一个,那么这个方法就会在特殊情况下呗Python所调用,而这一切都是自动发生的。
-
__init__(self, param1,param2…)方法:他是一个构造方法,在我们创建一个类的实例的时候,这个方法就会在创建的时候被自动调用,如果有参数,他就会自动传入到init方法中,我们可以通过重写这个方法来对构造函数进行编写。
>>> class Ball: def __init__(self,name="球"): self.name = name def Kick(self): print("我叫%s,该死的谁踢我。。。" % self.name) >>> b = Ball("土豆") #传入一个参数,会调用构造方法 >>> b.Kick() 我叫土豆,该死的谁踢我。。。 >>> a = Ball() #不传参就会调用默认参数 >>> a.Kick() 我叫球,该死的谁踢我。。。
-
-
公有和私有
-
为了实现成员私有的特征,Python实现了一个name mangling技术
-
在Python中定义私有变量只需要在变量名或函数名前加上"__"两个下划线,那么这个函数或变量就会变成私有的了。
-
实际上Python是将带有两个下划线开头的成员,改成了:_类名__成员名
>>> class Person: __name="小甲鱼" >>> p = Person() >>> p.__name Traceback (most recent call last): File "<pyshell#8>", line 1, in <module> p.__name AttributeError: 'Person' object has no attribute '__name' >>> p.name Traceback (most recent call last): File "<pyshell#9>", line 1, in <module> p.name AttributeError: 'Person' object has no attribute 'name'
-
但是我们可以通过内部提供的方法进行访问
>>> class Person: __name="小甲鱼" def getName(self): return self.__name >>> p = Person() >>> p.getName <bound method Person.getName of <__main__.Person object at 0x000002163A133F10>> >>> name = p.getName() >>> name '小甲鱼'
-
实际上Python是将带有两个下划线开头的成员,改成了:_类名__成员名,用这种形式进行访问
>>> p._Person__name '小甲鱼'
-
-
-
继承:
-
语法:
class 类名(父类名):
>>> class Parent: def hello(self): print("正在调用父类") >>> class Child(Parent): pass >>> p = Parent() >>> p.hello() 正在调用父类 >>> c = Child() >>> c.hello() 正在调用父类
-
如果子类定义与父类同名的方法或属性,则会自动覆盖父类对应的方法或属性
-
-
多重继承:
语法:
class 类名(父类1,父类2…)
-
组合
所谓组合就是把类的实例化放到新类里面
-
类、类对象、实例对象
Python类中的定义的属性他们都是静态属性,创建对象的时候不会进行成员共享,因为创建对象都会重新开辟内存,所以不会共享这个类的数据,但是如果用类名直接进行成员的修改,那么相应实例的对象都会改变
-
类和对象一些相关的BIF
-
issubclass(class,classinfo):查看第一个参数是否是第二个参数的子类
1.一个类被认为是其自身的子类
2.classinfo 可以是类对象组成的元组,只要class与其中任何一个候选类的子类,则返回true
>>> class A: pass >>> class B(A): pass >>> issubclass(A,B) False >>> issubclass(B,A) True
-
isinstance(object,classinfo):查看一个实例对象是否属于这个类,检查第一个参数是否属于第二个参数
1.如果第一个参数不是对象,则永远返回Flase
2.如果第二个参数不是类或者有类对象组成的元组,那么会抛出一个TypeError异常
>>> b1 = B() >>> isinstance(b1,B) True >>> isinstance(b1,A)#因为B继承自A True >>> isinstance(b1,(A,B)) True
-
hasattr(object,字符串形式的属性名):查看第二个参数是否是第一个参数的属性
>>> hasattr(c1,"x") True
-
getattr(object,name[,default]):获取第一个参数中以第二个参数为属性名的属性值。如果存在此参数则打印属性值,如果不存在此参数,则打印第三个参数默认设定的值,第二个参数和第三个参数都是字符串形式的。
>>> getattr(c1,"x","您访问的属性不存在.") 0 >>> getattr(c1,"asdasd","您访问的属性不存在.") '您访问的属性不存在.'
-
setattr(object,name,value):设置属性
>>> setattr(c1,"y","0000") >>> c1.y '0000'
-
delattr(object,name):删除属性
>>> delattr(c1,"y") >>> c1.y Traceback (most recent call last): File "<pyshell#57>", line 1, in <module> c1.y AttributeError: 'C' object has no attribute 'y'
-
property(fget = None,fset = None,fdel = None,doc = None):通过属性方法来设置属性
当我们用c1.x = …时,使用到赋值就会自动调用property的第二个参数的方法,使用del就会默认调用第三个参数,直接打印c1.x
>>> class C: def __init__(self,size=10): self.size = size def getSize(self): return self.size def setSize(self,value): self.size = value def delSize(self): del self.size x = property(getSize,setSize,delSize) >>> c1 = C() >>> c1.getSize() 10 >>> c1.x 10 >>> c1.x = 18 >>> c1.x 18 >>> c1.size 18 >>> c1.getSize() 18 >>> del c1.x >>> c1.size Traceback (most recent call last): File "<pyshell#78>", line 1, in <module> c1.size AttributeError: 'C' object has no attribute 'size'
-
041-045魔法方法
-
魔法方法总是被双下划线包围,例如__init__
魔法方法的“魔力”体现在他们总能够在适当的时候被自动调用
-
构造和析构
-
__init__(self[,…]):他不能做返回值,不要试图给init做任何返回操作
>>> class A: def __init__(self): return "A fo A-C" >>> a = A() Traceback (most recent call last): File "<pyshell#18>", line 1, in <module> a = A() TypeError: __init__() should return None, not 'str'
-
__new__(cls[,…])他是类创建第一个调用的方法,然后再将new方法的参数原封不动的传入到init方法中,返回一个class类对象,极少去重写,除非有必须进行的统一操作才重写。比如我传入的字符串都必须都要转为大写字符串并返回,这里就体现了new的特性,我们使用init是不能进行改变的,因为他不能做任何返回操作,而new可以。
>>> class CapStr(str): def __new__(cls,string): string = string.upper() return str.__new__(cls,string) >>> a = CapStr("nihaoya") >>> a 'NIHAOYA'
-
__del__(self):他可以理解成一个析构器:当对象快要被消灭的时候,这个方法就会被自动调用,当垃圾回收机制运行时就会被调用
-
-
算数运算
当对象进行算数运算的时候,会触发对应的魔法方法,他内部是按照符号来调用内置的方法,我们也可以对这些方法进行重写,Python就会按照我们重写的方法进行运算
-
还可以进行重写反运算(反运算是当左操作数不支持响应的操作时被调用),但要注意顺序问题,例如3-a,因为3就是一个整数,那么他就会去找a的__sub__方法,然后在他的sub方法中,self就是他自身的参数,而other就是3,所以正确的顺序应该是a-3
-
还可以进行增量运算,跟重写普通魔法方法是一样的,就是改个符号调用不同的方法
-
一元操作符
比如说a = A(5),然后在程序中写的是-a,这样他就会调用他的__pos__方法
-
__str__方法使我们直接使用对象进行打印的时候调用的。
.
-
-
定时器小作业
注意点:1.要使用到time模块,先import time。
-
属性访问
-
之前我们访问属性可以类和对象一些相关的BIF,使用getattr()方法来获取并打印。也可以通过**x = property(getSize,setSize,delSize)**的方式来进行打印。
-
那么属性访问也是有魔法方法的
-
getattribute会比getattr先调用
-
注意:setattr方法的无限递归
-
解决方法1:
-
解决方法2:
-
-