#类和类对象和实例对象
类的定义格式
class Human(类名):
/#属性
color = 'yellow'
legs = 2
hand = 2
/#方法
def run(self):
print('我正在跑!')
def eat(self):
print('嘿嘿!有吃的~_~')
def sleep(self):
print('我睡了,晚安@_@')
>>> aqiang = Human()
>>> aqiang.color
'yellow'
>>> aqiang.legs
2
>>> aqiang.hand
2
>>> aqiang.run()
我正在跑!
>>> aqiang.eat()
嘿嘿!有吃的~_~
>>> aqiang.sleep()
我睡了,晚安@_@
self
类对象的名字,用来区别各个类对象。
>>> class ball:
def setname(self,name):
self.name = name
def kick(self):
print('我叫%s,该死的,谁踢我...'% self.name)
>>> a = ball()
>>> a.setname('球A') #Python回自动将a传进setname参数中的self,下面同理
>>> b = ball()
>>> b.setname('球B')
>>> c = ball()
>>> c.setname('土豆')
>>> a.kick()
我叫球A,该死的,谁踢我...
>>> c.kick()
我叫土豆,该死的,谁踢我...
#面对对象的特征
封装
本质是将事物相关的属性和方法封装在一个类里面,我们调用类创建实例的时候,不用关心类内部的代码细节
继承
子类需要复用父类里面的属性或者方法,当然子类也可以提供自己的属性和方法
格式:class DerivedClassName(BaseClassName):
子类 基类、父类或、超类
子类会继承父类的所有东西
>>> class Parent:
def hello(self):
print('正在调用父类的方法...')
>>> class Child(Parent):
pass
>>> p = Parent()
>>> p.hello()
正在调用父类的方法...
>>> c = Child()
>>> c.hello()
正在调用父类的方法...
若子类中定义与父类同名的方法或属性,则会自动覆盖父类对应的方法或属性。
>>> class Child(Parent):
def hello(self):
print("正在调用子类的方法...")
>>> c = Child()
>>> c.hello()
正在调用子类的方法...
>>> p.hello()
正在调用父类的方法...
若出现子类重写的方法或者属性使父类原本的方法属性丢失该怎么办?
import random as r
class Fish:
def __init__(self):
self.x = r.randint(0,10)
self.y = r.randint(0,10)
def move(self):
self.x -= 1
print("我的位置是:",self.x,self.y)
class Goldfish(Fish):
pass
class Carp(Fish):
pass
class Salmon(Fish):
pass
class Shark(Fish):
def __init__(self):
self.hungry = True
def eat(self):
if self.hungry:
print("吃货的梦想就是天天有的吃^_^")
self .hungry = False
else:
print("太撑了,吃不下了!")
输出结果
>>> fish = Fish()
>>> fish.move()
我的位置是: 5 5
>>> fish.move()
我的位置是: 4 5
>>> goldfish = Goldfish()
>>> goldfish.move()
我的位置是: 2 8
>>> goldfish.move()
我的位置是: 1 8
>>> shark = Shark()
>>> shark.eat()
吃货的梦想就是天天有的吃^_^
>>> shark.eat()
太撑了,吃不下了!
>>> shark.move()
Traceback (most recent call last):
File "<pyshell#29>", line 1, in <module>
shark.move()
File "F:\小甲鱼学习记录\小甲鱼Python课后作业\test.py", line 8, in move
self.x -= 1
AttributeError: 'Shark' object has no attribute 'x'
可以发现shark里面的坐标没有初始化,对于这种我们可以通过调用未绑定的父类方法或使用super函数解决。
import random as r
class Fish:
def __init__(self):
self.x = r.randint(0,10)
self.y = r.randint(0,10)
def move(self):
self.x -= 1
print("我的位置是:",self.x,self.y)
class Goldfish(Fish):
pass
class Carp(Fish):
pass
class Salmon(Fish):
pass
class Shark(Fish):
def __init__(self):
Fish.__init__(self) #self是传shark这个子类
self.hungry = True
def eat(self):
if self.hungry:
print("吃货的梦想就是天天有的吃^_^")
self .hungry = False
else:
print("太撑了,吃不下了!")
或
import random as r
class Fish:
def __init__(self):
self.x = r.randint(0,10)
self.y = r.randint(0,10)
def move(self):
self.x -= 1
print("我的位置是:",self.x,self.y)
class Goldfish(Fish):
pass
class Carp(Fish):
pass
class Salmon(Fish):
pass
class Shark(Fish):
def __init__(self):
super().__init__()
self.hungry = True
def eat(self):
if self.hungry:
print("吃货的梦想就是天天有的吃^_^")
self .hungry = False
else:
print("太撑了,吃不下了!")
输出结果
>>> shark = Shark()
>>> shark.move()
我的位置是: 6 3
多重继承
格式:class DerivedClassName(Base1,Base2,Base3)
非不必要不使用,会使程序混乱
>>> class Base1:
def foo1(self):
print("我是foo1,我为Base1代言...")
>>> class Base2:
def foo2(self):
print("我是foo2,我为Base2代言...")
>>> class C(Base1,Base2):
pass
>>> c = C()
>>> c.foo1()
我是foo1,我为Base1代言...
>>> c.foo2()
我是foo2,我为Base2代言...
组合
所谓组合就是把类的实例化放到一个新类里面,即把旧类组合进去,就可以代替继承减少风险。
若类与类之间的关系是横向或者不相关的就使用组合,若是纵向关系的就使用继承。
class Turtle:
def __init__(self,x):
self.num = x
class Fish:
def __init__(self,x):
self.num = x
class Pool:
def __init__(self,x,y):
self.turtle = Turtle(x)
self.fish = Fish(y)
def print_num(self):
print("水池总共有乌龟%d只,小鱼%d条!"%(self.turtle.num,self.fish.num))
>>> pool = Pool(1,10)
>>> pool.print_num()
水池总共有乌龟1只,小鱼10条!
Mixin 编程机制
详细参考
多态
同一个方法不同对象调用同一个方法功能的表现形式不一样,例如:a、不同的两个对象,字符串的加法和整数的加法,同样是加法,实现的功能是不一样的; b、这两个对象之间没有任何直接继承关系,但是所有对象的最终父类都是元类
>>> class A:
def fun(self):
print("我是小A...")
>>> class B:
def fun(self):
print("我是小B...")
>>> a=A()
>>> b=B()
>>> a.fun()
我是小A...
>>> b.fun()
我是小B...
公有与私有
在类定义内的变量名字前加上双下横线即将变量变为私有。
>>> class person:
name = '小甲鱼'
>>> p = person()
>>> p.name
'小甲鱼'
>>> class person:
__name = '小甲鱼'
>>> p.__name
Traceback (most recent call last):
File "<pyshell#64>", 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()
'小甲鱼'
实际上Python只是将变量名进行重整,即将变量变为_类名__变量名。
>>> class person:
__name = '小甲鱼'
def getname(self):
return self.__name
>>> p = person()
>>> p.getname()
'小甲鱼'
>>> p._person__name
'小甲鱼'
类、类对象和实例对象
>>> class C:
count = 0
>>> a = C()
>>> b = C()
>>> c = 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 += 100
>>> a.count
100
>>> b.count
100
>>> c.count
10
当类在定义时就是类,定义后就是类对象,里面的方法和属性也是对象,当类被实例化后就是实例对象。上面的class C在定义时就是类,定义后就是类对象,a,b,c则是实例对象。
a.count,b.count都是100,而c.count是10,是因为类定义和类对象中的属性是绑定的属于静态类,a,b中的count是来自类C的,而c中的count由于改写,生成了一个新的count把来自类C的count覆盖掉。
若类中属性的名字跟方法名字相同,属性会覆盖方法。
>>> class C:
def x(self):
print("X-man!")
>>> c = C()
>>> c.x()
X-man!
>>> c.x = 1
>>> c.x
1
>>> c.x()
Traceback (most recent call last):
File "<pyshell#83>", line 1, in <module>
c.x()
TypeError: 'int' object is not callable
注意:
1.不要试图在一个类里边定义出所有能想到的特性和方法,应该利用继承和组合机制来进行扩展。
2.用不同的词性命名,如属性名用名词,方法名用动词。
绑定
Python严格要求方法需要有实例才能被调用,这种限制其实就是Python所谓的绑定概念。
当你未绑定时,将类实例化后调用方法就会报错。
>>> class BB:
def printBB():
print("no zuo no die")
>>> BB.printBB()
no zuo no die
>>> bb = BB()
>>> bb.printBB()
Traceback (most recent call last):
File "<pyshell#90>", line 1, in <module>
bb.printBB()
TypeError: printBB() takes 0 positional arguments but 1 was given
当将类删除后,其实例化对象还是能够调用类的方法,因为类的方法时属于静态的,当程序结束时才会释放,即使你将类删除,其类对象还是可以调用。
>>> class CC:
def setxy(self,x,y):
self.x = x
self.y = y
def printxy(self):
print(self.x,self.y)
>>> bb = CC()
>>> bb.setxy(1,2)
>>> bb.printxy()
1 2
>>> del CC
>>> aa = CC()
Traceback (most recent call last):
File "<pyshell#109>", line 1, in <module>
aa = CC()
NameError: name 'CC' is not defined
>>> bb.printxy()
1 2
类的内置函数
1.issubclass
issubclass(class , classinfo)
判断类是否继承于某个类
>>> 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
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、getattr、setattr、delattr
hasattr(object, 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 "<pyshell#151>", line 1, in <module>
hasattr(c1,x)
NameError: name 'x' is not defined
getattr(object, name[, default])
>>> getattr(c1,'x')
0
>>> getattr(c1,'y')
Traceback (most recent call last):
File "<pyshell#153>", line 1, in <module>
getattr(c1,'y')
AttributeError: 'C' object has no attribute 'y'
>>> getattr(c1,'y',"您所访问的属性不存在...")
'您所访问的属性不存在...'
setattr(object, name, value)
>>> setattr(c1,'y', 'FishC')
>>> getattr(c1,'y',"您所访问的属性不存在...")
'FishC'
delattr(object, name)
>>> delattr(c1,'y')
>>> delattr(c1,'y')
Traceback (most recent call last):
File "<pyshell#159>", line 1, in <module>
delattr(c1,'y')
AttributeError: y
注意参数name要加上字符串标志,否则报错
4.property
通过属性来设置属性,即设置一个属性来统一调用操作。
>>> 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.x
10
>>> c1.getsize()
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#181>", line 1, in <module>
c1.size
AttributeError: 'C' object has no attribute 'size'
当程序大改时,若不用property则用户的调用接口也可能会改变,若用property程序改变而调用接口可以不变,方便了用户调用。
(以上收集和转载自他人,便于自己学习、记录)