class Role(object):
n = 123 # 类变量,像__init__中life_value,money默认参数用类变量,如果多个类的实例那就节省了内存,类变量只在类中存一份,实例中不存
name = "我是类name"
n_list = []
def __init__(self, name, role, weapon, life_value=100, money=15000): #初始化方法(或构造方法);在生成一个角色时要初始化的一些属性就填写在这里;
#这些name,role,weapon,life_value,money属性都是全局的;
self.name = name
self.role = role
self.weapon = weapon
self.money_1 = money #实例调用时根据selef.xxx调用,即 r1.money_1,一般属性名称与参数名一致
self.__life_value = life_value #私有属性__life_value,只能在类中调用,实例不可以调用,__life_value存储在实例中,Python解释器把私有属性的名称改变了
def __del__(self): #析构函数,实例被释放的时候自动调用
print("%s 彻底死了。。。。" %self.name)
def show_status(self): #获取属性含私有属性的方法
print("name:%s weapon:%s life_val:%s" % (self.name,self.weapon,self.__life_value))
def __shot(self): #私有方法
print("shooting...")
def got_shot(self): #更改私有属性的方法
self.__life_value -= 50
print("ah...,I got shot...")
def buy_gun(self, gun_name):
print("just bought %s" % gun_name)
r1 = Role('Alex', 'police', 'AK47') #实例化为一个实例r1(生成一个对象r1);会自动把参数传给Role下面的__init__(...)方法;
#申请了一个块内存命名为r1(也就是r1指向一个内存地址),把r1的地址和赋值的参数传给Role,调用Role的__init__的方法,
#r1的内存中存放的是r1.name='Alex',r1.role='police',r1.weapon='AK47', r1.life_value=100, r1.money_1=15000 这些属性
r1.name = "ABC" #更改r1实例中r1.name的值;r1的内存中,生成一块新的内存,存放字符串ABC ,r1.name 指向这块内存;不是类变量name是r1实例的name
r1.n_list.append("from r1") #调用的是Role类n_list变量的内存
r1.bullet_prove = True #r1实例增加一个属性
r1.n = "改类变量" #实例r1中新增一个n的变量;虽然Role类中有n变量;
#调用的时候,先调用实例有的变量,实例没有才调用类的变量;
print("r1:", r1.weapon, r1.n)
r1. __del__() #直接调用析构函数,不会释放r1实例
r1.got_shot()
# r1.__shot() #不能调用私有方法
r1.show_status()
del r1.weapon #删除r1.weapon这个属性
print(r1._Role__life_value)
#不能直接访问__life_value是因为Python解释器对外把__life_value变量改成了_Role__life_value,所以,仍然可以通过_Role__life_value来访问__life_value变量
#但是强烈建议你不要这么干,因为不同版本的Python解释器可能会把__life_value改成不同的变量名。
r2 = Role('Jack', 'terrorist', 'B22')
r2.n_list.append("from r2")#调用的是Role类n_list变量的内存
self说明:
class中self 类似于下面代码test_self函数中的变量a:
def test_self (a,name):
a.name = name
print(a.name) #作用域是局部的
def cc ():
pass
print(id(cc)) #打印cc函数的地址
cc = test_self(cc,'alex')
# print(cc.name) #报错没有属性name,因为作用域是局部的
print(id(cc))#打印cc变量的地址,和上面cc函数的地址不同
class Role(object):
def __init__(this,name,age):
this.name = name
this.age = age
#把self 名称写成什么都可以,只是一个参数名称,实际传递进去的都是实例;一般惯例是写成self,所有默认用self就好了;
A = Role('alex',22)
print(A.name)
和普通的函数相比,在类中定义的函数只有一点不同,就是第一个参数永远是实例变量self,并且,调用时,不用传递该参数。除此之外,类的方法和普通函数没有什么区别,所以,你仍然可以用默认参数、可变参数、关键字参数和命名关键字参数。
私有属性说明:
如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__,在Python中,实例的变量名如果以__开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问.
需要注意的是,在Python中,变量名类似__xxx__的,也就是以双下划线开头,并且以双下划线结尾的,是特殊变量,特殊变量是可以直接访问的,不是private变量,所以,不能用__name__、__score__这样的设置私有变量名(属性名)。
析构方法:
析构方法类默认就有的只是什么都没有做,写__del__等于重构了析构方法;
面向对象与面向过程区别:
面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。
面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。
例如五子棋,面向过程的设计思路就是首先分析问题的步骤:1、开始游戏,2、黑子先走,3、绘制画面,4、判断输赢,5、轮到白子,6、绘制画面,7、判断输赢,8、返回步骤2,9、输出最后结果。把上面每个步骤用分别的函数来实现,问题就解决了。
而面向对象的设计则是从另外的思路来解决问题。整个五子棋可以分为 1、黑白双方,这两方的行为是一模一样的,2、棋盘系统,负责绘制画面,3、规则系统,负责判定诸如犯规、输赢等。第一类对象(玩家对象)负责接受用户输入,并告知第二类对象(棋盘对象)棋子布局的变化,棋盘对象接收到了棋子的i变化就要负责在屏幕上面显示出这种变化,同时利用第三类对象(规则系统)来对棋局进行判定。
可以明显地看出,面向对象是以功能来划分问题,而不是步骤。同样是绘制棋局,这样的行为在面向过程的设计中分散在了总多步骤中,很可能出现不同的绘制版本,因为通常设计人员会考虑到实际情况进行各种各样的简化。而面向对象的设计中,绘图只可能在棋盘对象中出现,从而保证了绘图的统一。
功能上的统一保证了面向对象设计的可扩展性。比如我要加入悔棋的功能,如果要改动面向过程的设计,那么从输入到判断到显示这一连串的步骤都要改动,甚至步骤之间的循序都要进行大规模调整。如果是面向对象的话,只用改动棋盘对象就行了,棋盘系统保存了黑白双方的棋谱,简单回溯就可以了,而显示和规则判断则不用顾及,同时整个对对象功能的调用顺序都没有变化,改动只是局部的。
再比如我要把这个五子棋游戏改为围棋游戏,如果你是面向过程设计,那么五子棋的规则就分布在了你的程序的每一个角落,要改动还不如重写。但是如果你当初就是面向对象的设计,那么你只用改动规则对象就可以了,五子棋和围棋的区别不就是规则吗?(当然棋盘大小好像也不一样,但是你会觉得这是一个难题吗?直接在棋盘对象中进行一番小改动就可以了。)而下棋的大致步骤从面向对象的角度来看没有任何变化。
当然,要达到改动只是局部的需要设计的人有足够的经验,使用对象不能保证你的程序就是面向对象,初学者或者很蹩脚的程序员很可能以面向对象之虚而行面向过程之实,这样设计出来的所谓面向对象的程序很难有良好的可移植性和可扩展性。
参考:
https://www.cnblogs.com/alex3714/articles/5188179.html
https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0014318650247930b1b21d7d3c64fe38c4b5a80d4469ad7000
面向对象与面向过程区别参考:
https://zhidao.baidu.com/question/2089034.html