组合 BIF(内置函数issubclass,isinstance)"/>
python 常用语法及命令(六) 类 对象 继承(菱形继承问题) 组合 BIF(内置函数issubclass,isinstance)
封装 继承 多态
面向对象是相对于面向过程来讲的,面向对象方法,把相关的数据和方法组织为一个整体来看待,从更高的层次来进行系统建模,更贴近事物的自然运行模式。
1、self
就是 c++中的this指针
>>> class Person:def setName(self, name):self.name = namedef getName(self):print("我叫%s" % self.name)>>> name1 = Person()
>>> name1.setName('鸣人')
>>> name2 = Person()
>>> name2.setName('佐助')
>>> name1.getName()
我叫鸣人
>>> name2.getName()
我叫佐助
2、__init__(self,parm1,parm2)
类似c++的构造函数,创建对象自动调用,__init__有参数,创建对象没有参数,会报错
>>> class Person:def __init__(self,name):self.name = namedef getName(self):print("我是%s" % self.name)>>> name1 = Person('鸣人')
>>> name1.getName()
我是鸣人
>>> name2 = Person()
Traceback (most recent call last):File "<pyshell#307>", line 1, in <module>name2 = Person()
TypeError: __init__() missing 1 required positional argument: 'name'
3、公有私有
python默认是公有的,在python中定义私有变量只需要在变量名或函数名前加上”__“两个下划线,那么这个函数或变量就会变为私有了。私有变量通过成员函数调用,也可以通过_类名__变量名访问,所以其实python的私有是伪私有
>>> class Person:__name = '鸣人'def getName(self):return self.__name>>> p = Person()
>>> p.__name() #不能直接访问私有变量
Traceback (most recent call last):File "<pyshell#312>", line 1, in <module>p.__name()
AttributeError: 'Person' object has no attribute '__name'
>>> p._Person__name #通过 _类名__ 访问
'鸣人'
>>> p.getName() #成员函数访问私有变量
'鸣人'
4、继承
1)格式: class DerivedClassName(BaseClassName):
>>> class Parent:def hello(self):print("调用父类...")>>> class Child(Parent):pass>>> p = Parent()
>>> p.hello()
>>> c = Child()
>>> c.hello()
调用父类...
2)子类中定义与父类同名的方法或属性,则会自动覆盖父类对于的方法或属性
import random as rclass Fish:def __init__(self):self.x = r.randint(0,10)self.y = r.randint(0,10)def move(self):self.x = -1print("我的位置是:", self.x, self.y)class Goldfish(Fish):passclass Salmon(Fish):passclass Shark(Fish):def __init__(self):self.hungry = Truedef eat(self):if self.hungry:print("肚子饿")else:print("吃饱了")
子类Sharkde的__init__覆盖了父类的__init__
解决方法有两种:
1)调用未绑定的父类方法
shark = Shark()
Fish.__init__(shark)
shark.move()
修改类 加上Fish.__init__(self)
class Shark(Fish):def __init__(self):Fish.__init__(self)self.hungry = True
2)使用super()函数 传入父类的方法
父类__init__有参数,要传参数给super().__init__(param)
class Shark(Fish):def __init__(self):super().__init__()self.hungry = True
>>> class point():def __init__(self,x,y):self.x = xself.y = ydef __add__(self,other):out_x = self.x + other.xout_y = self.y + other.yreturn out_x,out_y
>>> class point3(point):def __init__(self,x,y,z):self.z = zsuper().__init__(x,y)def __add__(self,other):out_x = self.x + other.xout_y = self.y + other.yout_z = self.z + other.zreturn out_x,out_y,out_z>>> p1 = point3(1,2,3)
>>> p2 = point3(4,5,6)
>>> p1 + p2
(5, 7, 9)
5、多重继承
class DerivedClassName(Base1,Base2,Base3,...):
>>> class Base1:def foo1(self):print("Base1的函数...")>>> class Base2:def foo2(self):print("Base2的函数...")>>> class C(Base1,Base2):pass>>> c = C()
>>> c.foo1()
Base1的函数...
>>> c.foo2()
Base2的函数...
菱形继承
内容来自(.php?mod=viewthread&tid=48759&extra=page%3D1%26filter%3Dtypeid%26typeid%3D403)
python的多重继承也会想C++一样产生菱形继承问题也叫钻石继承,
class A():def __init__(self):print("进入A…")print("离开A…")class B(A):def __init__(self):print("进入B…")A.__init__(self)print("离开B…")class C(A):def __init__(self):print("进入C…")A.__init__(self)print("离开C…")class D(B, C):def __init__(self):print("进入D…")B.__init__(self)C.__init__(self)print("离开D…")>>> d = D()
进入D…
进入B…
进入A…
离开A…
离开B…
进入C…
进入A…
离开A…
离开C…
离开D…
Python 使用了一个叫“方法解析顺序(Method Resolution Order,MRO)”的东西,还用了一个叫 C3 的算法来解决这个问题
MRO 的顺序基本就是:在避免同一类被调用多次的前提下,使用广度优先和从左到右的原则去寻找需要的属性和方法。
在继承体系中,C3 算法确保同一个类只会被搜寻一次。例子中,如果一个属性或方法在 D 类中没有被找到,Python 就会搜寻 B 类,然后搜索 C类,如果都没有找到,会继续搜索 B 的基类 A,如果还是没有找到,则抛出“AttributeError”异常。
super ()函数也可以解决这个问题
class A():def __init__(self):print("进入A…")print("离开A…")class B(A):def __init__(self):print("进入B…")super().__init__()print("离开B…")class C(A):def __init__(self):print("进入C…")super().__init__()print("离开C…")class D(B, C):def __init__(self):print("进入D…")super().__init__()print("离开D…")>>> d = D()
进入D…
进入B…
进入C…
进入A…
离开A…
离开C…
离开B…
离开D…
6、组合
组合指的是,在一个类中以另外一个类的对象作为数据属性,称为类的组合。
一个类的对象作为另一个类的变量
(.html)
>>> class Turle:def __init__(self,x):self.num = x>>> class Fish:def __init__(self,x):self.num = x>>> class Pool:def __init__(self,x,y):self.turle = Turle(x)self.fish = Fish(y)def print_num(self):print("水池总共有%d只乌龟, %d条小鱼" % (self.turle.num,self.fish.num))>>> pool = Pool(5,100)
>>> pool.print_num()
水池总共有5只乌龟, 100条小鱼
7、类、类对象、实例对象
>>> class C:count =0>>> a = C()
>>> b = C()
>>> c = C()
>>> a.count
0
>>> b.count
0
>>> c.count
0
>>> c.count += 10
>>> c.count
10
>>> a.count
0
>>> b.count
0
>>> C.count
0
>>> C.count += 100
>>> a.count
100
>>> b.count
100
>>> c.count
10
可以看到类的变量类似于静态变量,但是当对象小c赋值之后,覆盖了原有属性,对象a,b,c的操作是互不影响的,但是在对象没有使用前,使用类大C对变量赋值,会改变对象变量的值。
在创建对象后,所有对象指向同一个内存空间,当对每个对象赋值后才开辟自己的的内存空间。
所以不要使用类的变量,要用实例化对象变量。
属性的名字跟方法名相同,会覆盖掉方法。
因此,1>不要试图在一个类里定义出所有能想到的特性和方法,应该利用继承和组合机制来进行扩展
2>用不同的词性命名,如属性名用名词,方法名用动词。
>>> class C:def x(self):print("X!")>>> c = C()
>>> c.x()
X!
>>> c.x = 1
>>> c.x
1
>>> c.x()
Traceback (most recent call last):File "<pyshell#616>", line 1, in <module>c.x()
TypeError: 'int' object is not callable
8、绑定
python严格要求方法需要有实例才能被调用,这种限制其实就是python的绑定概念
也就是类内的函数需要self参数
>>> class BB:def printBB():print("you can you BB")>>> BB.printBB()
you can you BB
>>> bb = BB()
>>> bb.printBB()
Traceback (most recent call last):File "<pyshell#623>", line 1, in <module>bb.printBB()
TypeError: printBB() takes 0 positional arguments but 1 was given
对象bb不能调用函数printBB,因为bb在调用printBB的形式是bb.printBB(bb),因此需要参数self接收bb,来绑定。
再来看
>>> class CC:
... def setXY(self,x,y):
... self.x=x
... self.y=y
... def printXY(self):
... print(self.x,self.y)
...
>>> dd = CC()
>>> dd.__dict__
{}
>>> CC.__dict__
mappingproxy({'__doc__': None, '__dict__': <attribute '__dict__' of 'CC' objects>, 'setXY': <function CC.setXY at 0x000001B0DC4AE620>, '__module__': '__main__', 'printXY': <function CC.printXY at 0x000001B0DC4AE6A8>, '__weakref__': <attribute '__weakref__' of 'CC' objects>})
>>> dd.setXY(4,5)
>>> dd.__dict__
{'y': 5, 'x': 4}
>>> CC.__dict__
mappingproxy({'__doc__': None, '__dict__': <attribute '__dict__' of 'CC' objects>, 'setXY': <function CC.setXY at 0x000001B0DC4AE620>, '__module__': '__main__', 'printXY': <function CC.printXY at 0x000001B0DC4AE6A8>, '__weakref__': <attribute '__weakref__' of 'CC' objects>})
对象dd属性现在是空的,dd.setXY(4,5),形式是dd.setXY(dd,4,5),4,5再实例对象dd空间中
>>> del CC
>>> ee = CC()
Traceback (most recent call last):File "<stdin>", line 1, in <module>
NameError: name 'CC' is not defined
>>> dd.printXY()
4 5
即使把类CC删除,对象依然能调用类内的函数,因为类中定义的属性和方法是静态的,即使CC被删除,但静态变量不会被销毁。
总的来说 绑定就是需要self参数。
用类的实例对象访问的类成员方法称为绑定方法;用类名调用的类成员方法称为非绑定方法
9、类相关的BIF(内置函数)
1>issubclass(class,classinfo) class是classinfo的子类返回True
-- 一个类会被认为是其自身的子类
--classinfo可以是类对象组成的元祖,只要class是其中任何一个候选类的子类,则返回True
>>> class A:
... pass
...
>>> class B(A):
... pass
...
>>> issubclass(B,A)
True
>>> issubclass(B,B)
True
>>> issubclass(B,object)
True
>>> class C:
... pass
...
>>> issubclass(B,C)
False
2>isinstance(object, classinfo) 检查一个实例对象是否属于一个类
--第一个参数不是对象,则永远返回False
--如果第二个参数不是类或者由类对象组成的元组,会抛出一个TypeError异常
>>> b1 = B()
>>> isinstance(b1,B)
True
>>> isinstance(b1,A)
True
>>> isinstance(b1,C)
False
>>> isinstance(b1,(A,B,C))
True
3> hasattr(object, name) 测试对象是否具有某个属性
--name要用引号 表示一个字符串,没有会报错
>>> class C:
... def __init__(self,x=0):
... self.x=x
...
>>> c1 = C()
>>> hasattr(c1,'x')
True
>>> hasattr(c1,x)
Traceback (most recent call last):File "<stdin>", line 1, in <module>
TypeError: hasattr(): attribute name must be string
4>getattr(object,name[, default])
-- 返回对象指定的属性值
--属性不存在返回default,如果没有default异常
>>> getattr(c1,'x')
0
>>> getattr(c1,'y')
Traceback (most recent call last):File "<stdin>", line 1, in <module>
AttributeError: 'C' object has no attribute 'y'
>>> getattr(c1,'y',"属性不存在")
5>setattr(object,name,value)
--设定对象指定属性的值
--属性不存在会新建一个属性并且值为value
>>> setattr(c1,'y',20)
>>> getattr(c1,'y')
20
6>delattr(object ,name)
--删除对象指定属性,属性不存在抛出异常
--可以先用hasattr检查
>>> delattr(c1,'y')
>>> delattr(c1,'y')
Traceback (most recent call last):File "<stdin>", line 1, in <module>
AttributeError: y
7>property(fget=None, fset=None,fdel=None,doc=None)
--通过属性设定属性
--获取属性,设置属性,删除属性
>>> class C:def __init__(self,x=10):self._x = xdef getx(self):return self._xdef setx(self, value):self._x = valuedef delx(self):del self._xx = property(getx, setx, delx, "I'm the 'x' property.")>>> c1 = C()
>>> c1.getx()
10
>>> c1.x
10
>>> c1.x=20
>>> c1._x
20
>>> c1.getx()
20
>>> del c1.x
同样是完成一件事,Python 其实提供了好几个方式供你选择。property() 是一个比较奇葩的BIF,它的作用把方法当作属性来访问,从而提供更加友好访问方式。
(.php?mod=viewthread&tid=51106&extra=page%3D1%26filter%3Dtypeid%26typeid%3D403)
10、构造 析构
1、__init__() __new__()
__init__()只能返回None,需要初始化的类使用__init__()
实例化时第一个调用的是__new__(cls[,...]) 参数是class类,返回一个对象,有python默认执行,一般不用重写。
>>> class CapStr(str):def __new__(cls,string):string = string.upper()return str.__new__(cls,string)>>> a = CapStr("hello world")
>>> a
'HELLO WORLD'
cls表示这个类本身。 self表示一个类的实例对象本身。如果用了staticmethod就无视这个self了,就将这个方法当成一个普通的函数使用了。
类先调用__new__方法,返回该类的实例对象,这个实例对象就是__init__方法的第一个参数self,即self是__new__的返回值。
(.html)
2、__del__(self)
析构
python 自动调用销毁对象
3、其他的类内函数
(.php?mod=viewthread&tid=48793&extra=page%3D1%26filter%3Dtypeid%26typeid%3D403)
魔法方法 | 含义 |
基本的魔法方法 | |
__new__(cls[, ...]) | 1. __new__ 是在一个对象实例化的时候所调用的第一个方法 2. 它的第一个参数是这个类,其他的参数是用来直接传递给 __init__ 方法 3. __new__ 决定是否要使用该 __init__ 方法,因为 __new__ 可以调用其他类的构造方法或者直接返回别的实例对象来作为本类的实例,如果 __new__ 没有返回实例对象,则 __init__ 不会被调用 4. __new__ 主要是用于继承一个不可变的类型比如一个 tuple 或者 string |
__init__(self[, ...]) | 构造器,当一个实例被创建的时候调用的初始化方法 |
__del__(self) | 析构器,当一个实例被销毁的时候调用的方法 |
__call__(self[, args...]) | 允许一个类的实例像函数一样被调用:x(a, b) 调用 x.__call__(a, b) |
__len__(self) | 定义当被 len() 调用时的行为 |
__repr__(self) | 定义当被 repr() 调用时的行为 |
__str__(self) | 定义当被 str() 调用时的行为 |
__bytes__(self) | 定义当被 bytes() 调用时的行为 |
__hash__(self) | 定义当被 hash() 调用时的行为 |
__bool__(self) | 定义当被 bool() 调用时的行为,应该返回 True 或 False |
__format__(self, format_spec) | 定义当被 format() 调用时的行为 |
有关属性 | |
__getattr__(self, name) | 定义当用户试图获取一个不存在的属性时的行为 |
__getattribute__(self, name) | 定义当该类的属性被访问时的行为 |
__setattr__(self, name, value) | 定义当一个属性被设置时的行为 |
__delattr__(self, name) | 定义当一个属性被删除时的行为 |
__dir__(self) | 定义当 dir() 被调用时的行为 |
__get__(self, instance, owner) | 定义当描述符的值被取得时的行为 |
__set__(self, instance, value) | 定义当描述符的值被改变时的行为 |
__delete__(self, instance) | 定义当描述符的值被删除时的行为 |
比较操作符 | |
__lt__(self, other) | 定义小于号的行为:x < y 调用 x.__lt__(y) |
__le__(self, other) | 定义小于等于号的行为:x <= y 调用 x.__le__(y) |
__eq__(self, other) | 定义等于号的行为:x == y 调用 x.__eq__(y) |
__ne__(self, other) | 定义不等号的行为:x != y 调用 x.__ne__(y) |
__gt__(self, other) | 定义大于号的行为:x > y 调用 x.__gt__(y) |
__ge__(self, other) | 定义大于等于号的行为:x >= y 调用 x.__ge__(y) |
算数运算符 | |
__add__(self, other) | 定义加法的行为:+ |
__sub__(self, other) | 定义减法的行为:- |
__mul__(self, other) | 定义乘法的行为:* |
__truediv__(self, other) | 定义真除法的行为:/ |
__floordiv__(self, other) | 定义整数除法的行为:// |
__mod__(self, other) | 定义取模算法的行为:% |
__divmod__(self, other) | 定义当被 divmod() 调用时的行为 |
__pow__(self, other[, modulo]) | 定义当被 power() 调用或 ** 运算时的行为 |
__lshift__(self, other) | 定义按位左移位的行为:<< |
__rshift__(self, other) | 定义按位右移位的行为:>> |
__and__(self, other) | 定义按位与操作的行为:& |
__xor__(self, other) | 定义按位异或操作的行为:^ |
__or__(self, other) | 定义按位或操作的行为:| |
反运算 | |
__radd__(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) |
__rsub__(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) |
__rmul__(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) |
__rtruediv__(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) |
__rfloordiv__(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) |
__rmod__(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) |
__rdivmod__(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) |
__rpow__(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) |
__rlshift__(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) |
__rrshift__(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) |
__rand__(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) |
__rxor__(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) |
__ror__(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) |
增量赋值运算 | |
__iadd__(self, other) | 定义赋值加法的行为:+= |
__isub__(self, other) | 定义赋值减法的行为:-= |
__imul__(self, other) | 定义赋值乘法的行为:*= |
__itruediv__(self, other) | 定义赋值真除法的行为:/= |
__ifloordiv__(self, other) | 定义赋值整数除法的行为://= |
__imod__(self, other) | 定义赋值取模算法的行为:%= |
__ipow__(self, other[, modulo]) | 定义赋值幂运算的行为:**= |
__ilshift__(self, other) | 定义赋值按位左移位的行为:<<= |
__irshift__(self, other) | 定义赋值按位右移位的行为:>>= |
__iand__(self, other) | 定义赋值按位与操作的行为:&= |
__ixor__(self, other) | 定义赋值按位异或操作的行为:^= |
__ior__(self, other) | 定义赋值按位或操作的行为:|= |
一元操作符 | |
__pos__(self) | 定义正号的行为:+x |
__neg__(self) | 定义负号的行为:-x |
__abs__(self) | 定义当被 abs() 调用时的行为 |
__invert__(self) | 定义按位求反的行为:~x |
类型转换 | |
__complex__(self) | 定义当被 complex() 调用时的行为(需要返回恰当的值) |
__int__(self) | 定义当被 int() 调用时的行为(需要返回恰当的值) |
__float__(self) | 定义当被 float() 调用时的行为(需要返回恰当的值) |
__round__(self[, n]) | 定义当被 round() 调用时的行为(需要返回恰当的值) |
__index__(self) | 1. 当对象是被应用在切片表达式中时,实现整形强制转换 2. 如果你定义了一个可能在切片时用到的定制的数值型,你应该定义 __index__ 3. 如果 __index__ 被定义,则 __int__ 也需要被定义,且返回相同的值 |
上下文管理(with 语句) | |
__enter__(self) | 1. 定义当使用 with 语句时的初始化行为 2. __enter__ 的返回值被 with 语句的目标或者 as 后的名字绑定 |
__exit__(self, exc_type, exc_value, traceback) | 1. 定义当一个代码块被执行或者终止后上下文管理器应该做什么 2. 一般被用来处理异常,清除工作或者做一些代码块执行完毕之后的日常工作 |
容器类型 | |
__len__(self) | 定义当被 len() 调用时的行为(返回容器中元素的个数) |
__getitem__(self, key) | 定义获取容器中指定元素的行为,相当于 self[key] |
__setitem__(self, key, value) | 定义设置容器中指定元素的行为,相当于 self[key] = value |
__delitem__(self, key) | 定义删除容器中指定元素的行为,相当于 del self[key] |
__iter__(self) | 定义当迭代容器中的元素的行为 |
__reversed__(self) | 定义当被 reversed() 调用时的行为 |
__contains__(self, item) | 定义当使用成员测试运算符(in 或 not in)时的行为 |
更多推荐
python 常用语法及命令(六) 类 对象 继承(菱形继承问题) 组合 BIF(内置函数issubclass,isinstance)
发布评论