python菜鸟学习Day6(类,封装)

我们把重复执行的语句抽象成函数,然后直接调用函数名执行语句,这样代码维护就很方便。但当工程量越来越大,代码就越来越臃肿,维护就比较困难了。相对于面向工程的面向对象,就是以人的思维组织和处理工程项目,我们把一些数据结构和操作数据结构的函数的逻辑整体称为对象,数据结构和函数就是对象的属性和方法。在面向对象的思维里,自然界万物都是对象。当我们把具有相同特征的对象的属性和行为都抽象出来,就可以得到类,具体说,对象是类的实例,是独一无二的,类是对象的抽象,模板。对象是具体的,类是抽象的概念。比如,人是一个概念,有身高,性别等属性,能思考,行动等方法,张三是人这个类的一个实例。

封装

我们把具有相同行为的对象抽象归纳为类,通过封装隐藏内幕实现细节,只向外界暴露简单的接口。当我们创建对象后,只需要知道对象的方法名和需要的参数,就能执行方法中的程序,而不需要知道方法的实现细节。即把属性和方法封装,而只暴露方法名和需要的参数。

class Student(object):
	#__init__方法是类的初始化方法,在创建对象时进行初始化操作。
	def __init__(self,name=‘张三’,age=15):
		self.name = name
		self.age = age
	def study(self,course):
		print('%s正在学习%s' % (self.name,course))
	def watch_movie(self):
		if self.age>18:
			print('%s 只能看动画电影' % self.name)
		else:
			print('%s 可以看任何电影' % self.name)
def main():
	liLei = Student('liLei',22)
	liLei.study('machine learning')
	liLei.watch_movie()
if __name__=='__main__':
	main()

类内的属性和方法可以设置不同的 访问权限,公有的,可以被类外访问的,另一种就是私有的,不能被外界访问的,私有的属性和方法命名时用两个下划线开头。python并没有从语法上保证私有属性和方法的私有性,只是通过双下划线的命名规则妨碍对私有属性的访问。通过_类名__属性和方法名就能继续访问私有属性和方法.这样设定是因为程序员认为开放比封闭好。

class Test(object):
	def __init__(self,foo):
		#私有属性用双下划线开头
		self.__foo = foo
	def __bar(self):
		print(self.__foo)
		print('__bar')
def main():
	test = Test('hello')
	#直接访问私有属性出错AttributeError: 'Test' object has no attribute '__bar'
	test.__bar()
	test.__foo
	#通过一定的规则可以访问私有属性
	test._Test__bar()
	test._Test__foo
if '__name__'=='__main__'
	main()

在实际开放中并不建议将属性和方法设置成私有,这会导致子类无法访问。大多数程序员通过一种命名惯例,即属性或方法名用单下划线开头,表明本身是受保护的,类外访问徐慎重。这只是一种暗示和惯例。单下划线的属性和方法类外仍可以正常访问。。。

在类外直接访问类的属性和方法是很不规范的,所以可以通过getter(访问器)和setter(修改器)来访问和修改类的属性。因此可以通过@property包装器来包装getter和setter方法,这样对类的属性的访问既安全也方便。

class Person(object):
	def __init__(self,name,age):
		self._name = name
		self._age = age
	@property
	def age(self):
		return self._age
	@property
	def name(self):
		return self._name
	@age.setter
	def age(self,value):
		self._age = value
	def play_movie(self):
		if self._age<18:
			print('年龄小于18,只能看动画电影!')
		else:
			print('可以看任何电影!')
def main():
	person = Person('liWei',15)
	print(person._age)
	print(person.name)
	person.play_movie()
	person.age = 28
	person.play_movie()
	person._is_gay = True
    #AttributeError: can't set attribute
	#person.name = '牛向林'
if __name__ == '__main__':
	main()

python是一种动态语言,可以在程序运行中绑定属性和方法,当然也可以解绑定。如果要限定自定义类型的对象可以绑定的属性,可以在类中通过定义__slots__变量来限定。需要注意的是,__slots__限定绑定的属性只对当前类的对象有效,对子类没有任何作用。

class Person(object):
	#限定类对象可以绑定的属性,对子类对象无效
	__slots__ = ['_name','_age','_gender']
	def __init__(self,name,age):
		self._name = name
		self._age = age
	@property
	def age(self)
		return self._age
	@age.setter
	def age(self,value):
		self._age = value
def main():
	person = Person('LiWei',28)
	person._gender = male
	#'Person' object has no attribute '_is_gay'
	#person.is_gay = True
if __name__ == '__main__':
	main()

类中定义的方法有三种,对象方法、静态方法和类方法。对象方法是给对象传递消息,通过创建对象,对象.方法名()调用。类方法是静态方法,无需实例化对象,不再需要self作为第一参数。可以通过类名.方法名()调用。例如定义一个三角形类,需要判断传入的三条边是否能够构成三角形,这个判断方法需要在创建三角形对象前调用(还不知道能不能构成三角形),所以这个方法是静态方法,而不是对象方法。静态方法需要包装器@staticmethod。类方法需要包装器@classmethod,无需实例化对象,可以通过类名.方法名()调用,而且隐含参数不再是self,而是cls,表示类本身。这种用法爬虫框架scrapy有经常用,scrapy提供一个settings.py文件,开发者可以根据自己的实际情况设置一些值。需要获取这些值的类都有一个被classmethod方法修饰的from_settings()函数。这样做的好处是,可以动态实例化一个类,增加代码的灵活性。

class Triangle(object):
	def __init__(self,a,b,c):
		self._a = a
		self._b = b
		self._c = c
	@staticmethod
	def is_triangle(a,b,c):
		if a+b>c and a+c>b and b+c>a:
			return True
		else:
			return False
	def perimeter(self):
		return self._a + self._b + self._c
	def area(self):
		half_perimeter = self.perimeter()/2
		return (half_perimeter*(half_perimeter-self._a)*(half_perimeter-self._b)*(half_perimeter-self._c))
def main():
	a, b ,c = 3, 4, 5
	if Triangle.is_triangle(a,b,c):
		triangle = Triangle(a,b,c)
		print('三角形的周长是%.3f' % triangle.perimeter())
		print('三角形的面试时%.3f' % triangle.area())
	else:
		print('三条边不能构成三角形')
if __name__=='__main__':
	main()

对象方法,静态方法,类方法

from time import time, localtime
class Time_Test(object):
	#self是隐藏参数,代表类实例化对象
	def __init__(self,year=2000,month=1,day=1):
		self._year = year
		self._month = month
		self._day = day
	#对象方法
	def time_show(self):
		print('时间是%d年%d月%d日' % (self._year, self._month, self._day))
	#静态方法 不需要self隐藏参数,可以直接用类名调用
	@staticmethod
	def time_valid(year,month,day):
		if year<=2019 and month<=12 and day<=31:
			return True
		else:
			return False
	#类方法 clas作为隐藏参数,代表类本身,可以直接用类名调用
	@classmethod
	def time_now(cls):
		ctime = localtime(time())
		return cls(ctime.tm_year, ctime.tm_mon, ctime.tm_mday)
def main():
	year, month, day =2018, 10, 25
	#静态方法可以直接调用
	if Time_Test.time_valid(year,month,day):
		print('时间可能正确')
		time_string = Time_Test(year,month,day)
		time_string.time_show()
	else:
		print('时间有点不正确')
	#类方法可以直接调用,通过类方法创建对象
	time_current = Time_Test.time_now()
	time_current.time_show()
if __name__=='__main__':
	main()

类之间的关系
is-a关系:继承或泛化关系。比如学生和人,学生和电子产品的关系。子类可以继承父类的属性和方法,除此之外,还可以添加自己都有的属性和方法,所以子类比父类拥有更多的能力,也更特殊,在面向对象编程中可以用子类对象替换父类对象。子类继承父类的方法后,可以重写父类父类已有的方法,从而不同的子类相同的方法有不同的实现方式,叫多态
has-a关系:关联关系。比如部门和员工,汽车和发动机的关系。某个类以成员变量的形式出现在另一个类中,二者是关联关系,比如类A关联与类B,则B体现为A的全局变量,
use-a关系通常称之为依赖,比如司机有一个驾驶的行为(方法),其中(的参数)使用到了汽车,那么司机和汽车的关系就是依赖关系。某个类B以局部变量的形式出现在另一个类A中(类A中方法的参数是B对象,在类A方法中创建了B对象等),二者是依赖关系。

抽象类就是不能被实例化的类,抽象程度高,大部门只定义了方法名,没有方法实现。专门让其他的子类来继承。python中可以通过abc模块的ABCMeta元类和@abstractmethod包装器来达到效果。

class Person(object):
	def __init__(self,name,age):
		self._name = name
		self._age = age
	@property
	def name(self):
		return self._name
	@property
	def age(self):
		return self._age
	@age.setter
	def age(self,value):
		self._age = value
	def watch_tv(self,tv):
		print('%s 喜欢看 %s' % (self._name,tv))
class Student(Person):
	def __init__(self,name,age,grade):
		super().__init__(name,age)
		self._grade = grade
	@property
	def grade(self):
		return self._grade
	@grade.setter
	def grade(self,value):
		self._grade = value
	def study(self,course):
		print('%s年级的%s正在学习%s' % (self._grade,self._name,course))
class Teacher(Person):
	def __init__(self,name,age,title):
		super().__init__(name,age)
		self._title = title
	@property
	def title(self):
		return self._title
	@title.setter
	def title(self,value):
		self._title = value
	def teach(self,course):
		print('%s%s正在学习%s' % (self._title,self._name,course))
def main():
	liWei = Student('LiWei',12,'三')
	niuXiangLin = Teacher('NiuXiangLin',22,'硕士生')
	liWei.study('数据结构')
	niuXiangLin.teach('c语言')		
if __name__=='__main__':
	main()
from abc import ABCMeta,abstractmethod
class Pet(object,metaclass=ABCMeta):
	def __init__(self,name):
		self._name = name
	@property
	def name(self):
		return self._name
	@abstractmethod
	def make_voice(self):
		pass
class Dog(Pet):
	def make_voice(self):
		print('%s : 汪汪汪。。' % self._name)
class Cat(Pet):
	def make_voice(self):
		print('%s: 喵喵喵。。' % self._name)
def main():
	pet = [Dog('元宝'), Cat('凯瑟琳'),Dog('阿黄')]
	for one in pet:
		one.make_voice()
if __name__=='__main__':
	main()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值