起因
在(十二)中说到pytorch中创建神经网络的两种方法:一个是Sequential类(这也是一种继承父类属性和方法并可对其方法重构的子类),另一个是自己编写代码,继承nn.module类,对其内部属性和方法进行重构。这个过程其实在一开始看到这些代码时似懂非懂,比如类方法,和super是什么意思等,在学习pytorch相关教材时不是很明白是什么意思,只能照猫画虎,不太明白内部为什么那么写。
在学习python面向对象编程后可以很好的理解
Python面向对象编程
和C++不同,python面向对象编程有自己的一套方法。下面进行简介和学习过程中编写的一些练习代码:
一、命名、初始化、和__init__方法
#大驼峰命名法
#不继承任何父类的话可以不加括号
#self代表对象本身
class Person:
#初始化一个对象(实例化)__init__初始化方法
def __init__(self,name,age,height):
self.name=name
self.age=age
self.height=height
def run(self):
print('%s is runing!'%self.name)
def eat(self):
print("%s is eating!"%self.name)
#实例化一个对象,会被自动调用__init__
xiaoming=Person('xiaoming',18,1.75)
#按下tab键可以看到对象的属性和方法
xiaoming.eat()
xiaoming is eating!
lili=xiaoming
print(id(lili))
print(id(xiaoming))
140656508225040
140656508225040
二、__str__和__del__方法
class Cat:
def __init__(self, new_name):
self.name = new_name
#初始化时候打印
print("%s 来了" % self.name)
def __del__(self): #对象销毁的时候调用
print("%s 我去了" % self.name)
def __str__(self): #打印对象调用这个
# 必须返回一个字符串
return "我是小猫[%s]" % self.name
tom=Cat('Tom')
#print时候调用对象的__str__方法
print(tom)
#销毁对象时调用对象的__del__方法
del tom
pass
#流程:首先申请一个空间然后执行__init__方法
Tom 来了
我是小猫[Tom]
Tom 我去了
#封装:属性方法放在一起疯撞到一个抽象类里,细节被封装
#跑步减肥,吃东西增重
class Person:
#初始化一个对象(实例化)__init__初始化方法
def __init__(self,name,age,weight):
self.name=name
self.age=age
self.weight=weight
def run(self):
print('%s is runing!'%self.name)
self.weight-=0.5
def eat(self):
print("%s is eating!"%self.name)
self.weight+=1
#实例化一个对象,会被自动调用__init__
xiaoming=Person('xiaoming',18,50)
#按下tab键可以看到对象的属性和方法
xiaoming.eat()
print(xiaoming.weight)
xiaoming is eating!
51
三、家具类,在户型属性中包含另一个类
class HouseItem:
def __init__(self,name,aera):
self.name=name
self.aera=aera
def __str__(self):
return "[%s] 占地 %.2f" % (self.name, self.aera)
class House:
def __init__(self,house_type,area):
self.house_type=house_type
self.area=area
#剩余面积
self.free_area=area
#初始化一个家具列表
self.item_list=[]
def __str__(self):
return ("户型:%s\n总面积:%.2f[剩余:%.2f]\n家具:%s"
% (self.house_type, self.area,
self.free_area, self.item_list))
def add_item(self,item:HouseItem): #加注解是为了告知集成开发环境变量类型,其中item是实例化变量名,HouseItem是变量类型名
if self.free_area>=item.aera:
self.item_list.append(item)
self.free_area -= item.aera
else:
print("放不下了")
#是否是猪函数直接运行、如果是作为模块导入则if判断为false
if __name__ == '__main__':
# 1. 创建家具
bed = HouseItem("席梦思", 4)
chest = HouseItem("衣柜", 2)
table = HouseItem("餐桌", 1.5)
house=House('小三房',3)
house.add_item(bed)
house.add_item(chest)
print(house)
放不下了
户型:小三房
总面积:3.00[剩余:1.00]
家具:[<main.HouseItem object at 0x7fed26721be0>]
四、封装
1 封装是面向对象编程的一大特点
2面向对象编程的 第一步子一将属性和方法封装到一个抽象的类中
3 外界使用 类创建 对象,然后 让对象调用方法
4 对象方法的细节 都被封装在 类的内部
一个对象的 属性 可以是 另外一个类创建的对象
士兵与枪的类
#枪类,有名字和子弹数量属性,和shoot方法
class Gun:
def __init__(self,name):
self.name=name
self.bullet_count=0
def add_bullet(self,count):
self.bullet_count+=count
print("当前有%d颗子弹"%self.bullet_count)
def shoot(self):
for i in range(0,50):
if self.bullet_count>0 :
self.bullet_count-=1
print("本次射击共射出%d颗子弹"%(i+1))
else :
print("没子弹了")
return
def __str__(self):
return '子弹剩余'+str(self.bullet_count)
#士兵类,士兵需要拿枪并且射击
class Soldier:
def __init__(self, name):
self.name = name
# 2. 枪 - 新兵没有枪,gun:Gun 其中冒号目的是指示枪的类型是一个Gun类
self.gun:Gun = None
def fire(self):
# 1. 判断士兵是否有枪
if self.gun is None:
print("[%s] 还没有枪..." % self.name)
return
# 2. 高喊口号
print("冲啊...[%s]" % self.name)
# 3. 让枪装填子弹
self.gun.add_bullet(10)
# 4. 让枪发射子弹
self.gun.shoot()
# 1. 创建枪对象
ak47 = Gun("AK47")
# 2. 创建许三多
xusanduo = Soldier("许三多")
xusanduo.gun = ak47
xusanduo.fire()
print(xusanduo.gun)
ak48=ak47
#is判断是否是同一个地址
print(ak48 is ak47)
冲啊...[许三多]
当前有10颗子弹
本次射击共射出1颗子弹
本次射击共射出2颗子弹
本次射击共射出3颗子弹
本次射击共射出4颗子弹
本次射击共射出5颗子弹
本次射击共射出6颗子弹
本次射击共射出7颗子弹
本次射击共射出8颗子弹
本次射击共射出9颗子弹
本次射击共射出10颗子弹
没子弹了
子弹剩余0
True
五、私有属性和私有方法
#私有属性和私有方法通过前面两个_来标识私有属性
class Women:
def __init__(self, name):
self.name = name
# 不要问女生的年龄,
self.__age = 18
def eat(self):
self.__secret() #私有方法只能被自己的方法调用
print("我是在eat调用age",self.__age)
def __secret(self):
print("我是私有方法")
print("我的年龄是 %d" % self.__age) #私有属性只能被自己的方法调用
xiaomei=Women('小美')
print(xiaomei.name)
#无法打印私有属性,只能通过私有方法调用
#print(xiaomei.__age)
#此外,原方法只有print而没有返回值,如果用print(xiaomei.eat())则会返回NONE
xiaomei.eat()
#私有方法也无法被外界调用
#xiaomei__secret()
#总结:1、私有属性和私有方法都无法被外界调用。2、通过类中的公用方法可以访问私有方法和私有属性。
小美
我是私有方法
我的年龄是 18
我是在eat调用age 18
六、继承——单继承
子类拥有父类的所有属性和方法
# 定义一个父类
class Animal:
def eat(self):
print("吃---")
def drink(self):
print("喝---")
def run(self):
print("跑---")
def sleep(self):
print("睡---")
#继承父类所有方法
class Dog(Animal):
def bark(self):
print("汪汪叫")
class Cat(Animal):
def catch(self):
print('爬树')
# 继承狗类,拥有父类和父类的父类的全部方法,
# 子类可以对父类方法进行重写
class XiaoTianQuan(Dog):
def fly(self):
print('会飞')
def bark(self):
super().bark() #调用父类的方法bark
print('像神一样的叫唤')
# 创建一个对象 - 狗对象
wangcai = Dog()
wangcai.eat()
wangcai.drink()
wangcai.run()
wangcai.sleep()
wangcai.bark()
shenquan=XiaoTianQuan()
shenquan.eat()
吃---
喝---
跑---
睡---
汪汪叫
吃---
子类继承不能访问父类私有属性和私有方法
私有属性和私有方法只能在本类使用
class A:
def __init__(self):
self.num1 = 100
self.__num2 = 200
def __test(self):
print("私有方法 %d %d" % (self.num1, self.__num2))
class B(A):
def demo(self):
print(self.num1)
# 1. 在子类的对象方法中,不能访问父类的私有属性
# print("访问父类的私有属性 %d" % self.__num2)
# 2. 在子类的对象方法中,不能调用父类的私有方法
# self.__test()
pass
b=B()
b.demo()
100
七、继承——多继承
A和B父类可能有同样的方法
使用__mro__方法关注多继承时候方法、属性的搜索顺序和调用路径,尤其是继承多次,多种继承,很难判断什么顺序
class A:
def demo(self):
print('A demo')
def test(self):
print('A test')
class B:
def demo(self):
print('B demo')
def test(self):
print('B test')
class C(A,B):
def demo(self):
print('C demo')
#使用__mro__方法查看属性和方法的搜索调用顺序
print(C.__mro__)
c=C()
c.demo()
(<class 'main.C'>, <class 'main.A'>, <class 'main.B'>, <class 'object'>)
C demo
八、多态
是通过继承和重写父类方法为前提实现的(类似于c++的重载)
面向对象的三大特性
一、封装:根据职责将属性和方法封装到一个抽象类里
二、继承:实现代码重用,子类和父类相同属性方法,不需要在子类重新编写代码
三、多态:不同子类对象调用相同父类方法,产生不同执行结果
面向对象设计的两大原则:
一、单一职责,对象的很多方法,每个方法负责解决一个问题
二、开放封闭:对扩展开放,对修改封闭
class Dog(object):
def __init__(self, name):
self.name = name
def game(self):
print("%s 蹦蹦跳跳的玩耍..." % self.name)
#c++里可以通过改变输入参数格式和数量可以多个函数都能用,python只用本类被重写的。
#所以python只有重写,没有重载
class XiaoTianDog(Dog):
def game(self):
print("%s 飞到天上去玩耍..." % self.name)
class Person(object):
def __init__(self, name):
self.name = name
def game_with_dog(self, dog):
print("%s 和 %s 快乐的玩耍..." % (self.name, dog.name))
# 让狗玩耍
dog.game()
# 1. 创建一个狗对象
# wangcai = Dog("旺财")
wangcai = XiaoTianDog("飞天旺财")
# 2. 创建一个小明对象
xiaoming = Person("小明")
# 3. 让小明调用和狗玩的方法
xiaoming.game_with_dog(wangcai)
#多态是不同的对象调用同一个方法,实现不同的行为,就是多态
小明 和 飞天旺财 快乐的玩耍...
飞天旺财 飞到天上去玩耍...
总结
以上是学习python面向对象编程的学习和写代码进行练习。