面向对象
python是一个面向对象语言
python把面向过程(函数)和面向对象结合的非常好
类,对象
类:设计图
类是一系列具有相同特征或者行为的事物的一个抽象
对象:根据设计图造出来的具体存在
由类创建出来的一个具体存在
Python中所有都是对象
a = 10
print(type(a)) # <class 'int'>
b = True
print(type(b)) # <class 'bool'>
def fn():
pass
print(type(fn)) # <class 'function'>
a2 = int(10)
print(type(a2)) # <class 'int'>
print(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)
bite(jsl)
语法:
class 类名:
def 方法名(self,其他参数):
pass
class ultraman:
name = '奥特曼'
def shoot(m): //m 不是怪兽,而是self
print('ultraman is shooting %s'%(m['name']))
dj = ultraman()
dj.name = '迪迦奥特曼'
jack = ultraman()
jack.name = '杰克奥特曼'
dj.shoot(jsl)
jack.shoot(jsl)
self
类的方法和普通方法的区别,就在于,类的方法必须有一个额外的参数,而且必须放在第一个参数的位置,我们在调用的时候,不需要给这个参数赋值,由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 A{
void f(){}
}
A a = new A();
a.f();
A.getClass().getMethod('f').invoke(a)
python中也可以用类名方法名类似的方式去调用,不建议这样使用,因为看起来不太面向对象
Ultraman.shoot(dj,jsl)
类属性
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)
因为成员变量是在方法中创建的,如果在init 方法调用之前访问,就会报错
希望有一个方法能够在对象创建的时候就把成员变量创建好,这个方法的作用很像构造函数
特殊方法
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参数,用于绑定此方法的执行对象,调用一般是sb.doSth(参数),也可以Class.dosth(sb,参数)
类方法
一般在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___()
返回对象的描述信息,相当于java对象中的toString()
class Ultraman:
def __init__(self,name):
self.name = name
def __str__(self):
return '%s奥特曼'%(self.name)
def
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.password = password
self.name = name
self.personId = personId
self.balance = balance
self.op_history = {}
# def __init__(self):
# self.account_id = 10001
# self.password = '888888'
# self.name = 'guest'
# self.personId = ''
# self.balance = 0
# op_history = {}
def deposit(self, amount):
'''
存钱
:param amount
:return:
'''
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','谷爱凌','US122321',100000)
a1.deposit(5000)
a1.withdraw(80000)
print(a1)
a1.list_op_history()