面向对象
python作为一个面向对象语言,把面向过程(函数)和面向对象结合的非常好。
类和对象
类:设计图,是一系列具有相同特征或者行为的事物的一个抽象
对象:根据设计图造出来的具体存在,由类创建出来的一个具体存在
a=10
print(type(a))#输出a的种类
#<class 'int'>
b=True
print(type(b))#输出b的种类
#<class 'bool'>
def fn():
pass
print(type(fn))#输出fn的种类
a2=int(10)
print(type(a2))
#<class 'int'>
print(a==a2)#判断a是否等于a2
#True
属性,方法
属性:对象特征(名词,形容词)的描述
方法:对象具备的行为(动词)
设计类的时候,使用名词分析法分析整个业务流程,抽取出名词作为类,剩下的归为属性和方法。
sb.doSth的原则,将动词归到某个类中
DDD领域建模
def ultraman(name,age,sex,perform):
return{
'name':name,
'age':age,
'sex':sex,
'perform':perform
}#定义奥特曼对象,具有姓名,年龄,性别,技能四个属性
def shoot(m):
print('ultraman is shooting %s'%(m['name']))
dijia=ultraman('迪迦',3000,'男','光线炮')
print(dijia)
def monster(name,m_type):
data={
'name':name,
'type':m_type
}
return data
def bite(u):
print('monster bite %s'%(u['name']))
jsl=monster('哥斯拉','恐龙')
print(jsl)
shoot(jsl)
#迪迦打了哥斯拉一拳
bite(dijia)
#哥斯拉咬了迪迦一口
shoot(dijia)
#迪迦又打了哥斯拉一拳
#……
class 类名:
def 方法名(self,其他参数):
pass
class ultraman:
name='奥特曼'
def shoot(m):
print('ultraman is shooting %s'%(m['name']))
dj=ultraman()
dj.name='迪迦奥特曼'
jack=ultraman()
jack.name='杰克奥特曼'
dj.shoot(jsl)
jack.shhot(jsl)
类的方法和普通方法的区别是,类的方法必须有一个额外的参数,而且必须放在第一个参数的位置,在调用的时候不需要给这个参数赋值,由python自动赋值,赋值就是对象本身的引用,相当于this,这个名字一般约定俗成为self,但是写其他的名字也一样。
class Ultraman:
name='奥特曼'
def shoot(self,m):#m不是怪兽,self是怪兽
print('ultraman is shooting %s'%(m['name']))
dj=Ultraman()
dj.shoot(jsl)
在java中,方法的执行必须是sb.doSth
类属性
class Ultraman: name = '奥特曼' # 并不是对象的属性,而是类属性 def shoot(self,m): # m 不是怪兽,而是self # NameError: name 'name' is not defined print('%s is shooting %s'%(name ,m['name'])) dj = Ultraman() dj.name = '迪迦' dj.shoot(jsl)
类中直接定义的变量为类变量,类变量可以用类名和变量名来访问,也可以用对象.变量名来访问。
class A{ static int i; } A a = new A(); System.println(a.i); //只不过这样写不好 System.println(A.i);
成员变量
外部创建
class Ultraman: name = '奥特曼' # 并不是对象的属性,而是类属性 def shoot(self,m): # m 不是怪兽,而是self print('%s is shooting %s'%(self.name ,m['name'])) dj = Ultraman() dj.shoot(jsl) # 因为没有给dj这个对象去创建自由的属性name,所以self.name实际是类变量name dj.name = '迪迦' # 其实是用外部创建的方式给Ultraman类创建了一个成员变量
方法内部赋值
class Ultraman: def init(self,name): self.name = name def shoot(self,m): # m 不是怪兽,而是self print('%s is shooting %s'%(self.name ,m['name'])) dj = Ultraman() dj.init('迪迦') dj.shoot(jsl)
特殊方法
python为了解决一些特殊问题,定义了一些特殊方法
这些方法都是以__开头__结尾(两个没有空格的下划线)
特殊方法不需要调用,也不应该自己去调用,这些方法会在特殊的书剑自己去调用
__init__
相当于构造函数,在创建对象的时候执行,在创建对象的时候要注意方法的参数
class Ultraman:
def __init__(self,name):
self.name = name
def shoot(self,m): # m 不是怪兽,而是self
print('%s is shooting %s'%(self.name ,m['name']))
d=Dog()实际上是调用一个默认的__init__(self)方法
写了之后没有默认值,就必须匹配参数
class Ultraman:
def __init__(self,name):
self.name = name
self.gender = '男'
dj = Ultraman('迪迦')
实例方法:
默认情况下写在类中的方法都是实例方法,至少有一个self参数用于绑定此方法的执行对象
类方法:
一般在python中很少用到类方法和静态方法,除了一些特殊的设计模式
class Ultraman:
def __init__(self,name):
self.name=name
@classmethod
def shoot(cls):
print(cls)
当我们给方法加上```@classmethod```的时候,这个方法的第一个参数就是他的类,起名为cls
调用的时候一般建议使用类名.方法名调用,也可以用对象.方法名调用
@classmethod
def shoot(cls):
print(self.gender) # 类方法不可以调用实例对象
静态方法:
静态方法-即函数,区别就是命名空间在该类中,并非全局空间
静态方法中没有self也没有cls,所以静态方法中不可以去访问任何类属性和类方法,成员属性
class Ultraman:
name = '奥特曼'
def __init__(self,name):
self.name = name
@staticmethod
def shoot(m):
print(m) # 这就是一个普通的函数方法,只不过命名空间在类中
# print(self.name)
# print(cls.name)
内置方法和属性
'__delattr__',
'__dict__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__gt__',
'__hash__',
'__init__',
'__init_subclass__',
'__le__',
'__lt__',
'__module__',
'__ne__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__',
'__weakref__',
__str__()
class Ultraman: def __init__(self,name): self.name=name def __str__(self): return '%s奥特曼'%(self.name) dj=Ultraman('迪迦') print(dj)
__repr__()
是在repr()方法后执行
str()获得对象的字符串表现形式:一般得到一个好看的打印效果
__repr__是在调用repr()方法后自动执行的,一般除了表现出数据内容,还会表现出数据类型
class Ultraman: def __init__(self,name): self.name=name def __str__(self): return '%s奥特曼'%(self.name) def __repr__(self): return 'Ultraman:%s'%(str(self)) dj=Ultraman('迪迦') print(dj)
__del__
对象被删除的时候,垃圾收集的时候执行的方法,类似于java中的finalize()方法或者是c++中的析构函数
class Ultraman: def __init__(self,name): self.name = name def __del__(self): print(self.name,'del') dj = Ultraman('迪迦') del dj
__gt__
会在对象做大于比较的时候调用,返回值将作为比较的结果
class Ultraman: def __init__(self,name,weight): self.name=name self.weight=weight def __gt__(self,other): return self.weight>other.weight dj=Ultraman('迪迦',10000) jack=Ultraman('杰克',9000) print(dj>jack)
__bool__
用于当bool()方法转换对象时执行
class Ultraman: def __init__(self,name,weight): self.name=name self.weight=weight def __bool__(self): return self.weight>9500 dj=Ultraman('迪迦',10000) jack=Ultraman('杰克',9000)
类似的运算符重载
class Ultraman: def __init__(self,name,weight): self.name = name self.weight = weight def __add__(self,other): return self.weight + other.weight dj = Ultraman('迪迦',10000) jack = Ultraman('杰克',9000) print(dj + jack)
封装
面向对象三大特性:封装、继承和多态。
面向对象第一步就是将数学和方法封装到一个抽象的类里面
外界使用类来创建对象,然后通过对象来访问属性和方法
对象的实现细节全部被封装在了类的内部
import datetime
import random
class Account:
#银行账户
def __init__(self,account_id,password,name,personId,balance):
self.account_id=account_id
self.passwd=password
self.name=name
self.personId=personId
self.balance=balance
self.op_history={}
def deposit(self,amount):
#存钱
self.balance+=amount
rand=random.randint(1,1000)
key=str(datetime.datetime.now())+'-'+str(rand)
self.op_history[key]='存钱%d'%(amount)
def withdraw(self,amount):
if amount>self.balance:
print('存款余额不足')
else:
self.balance-=amount
rand=random.randint(1,1000)
key=str(datetime.datetime.now())+'-'+str(rand)
self.op_history[key]='取钱%d'%(amount)
def __str__(self):
return '%d %s %d'%(self.account_id,self.name,self.balance)
def list_op_history(self):
for k in self.op_history:
print(k,self.op_history[k])
a1 = Account(10002,'123456','mika','22222',100000)
a1.deposit(5000)
a1.withdraw(80000)
print(a1)
a1.list_op_history()