赞
踩
目录
用于描述复杂的对象,包含很多属性和方法。
类(Class):某一些有共同特征的对象的抽象,是某种概念。
对象(Object):也称为实例(instance),是具体存在的实体,每个实体具备一定的特征。对象之间有相同点也有不同点。
零到多个成员变量...
零到多个执行语句...
零到多个成员方法...
- # 第一个面向对象程序,定义人类:一个关于人的类
- class Person:
- ''' 定义一个人 '''
- def __init__(self,name,age=0):
- ''' 构造方法,定义与生俱来的两个属性,姓名和年龄 '''
- self.name = name
- self.age = age
- def birthday(self):
- ''' 定义实例方法,过生日 ''' # 定义一个实例方法
- self.age += 1
- print('%s%d岁啦,生日快乐!!!' % (self.name, self.age))
- def open_mouth(self):
- ''' 张嘴 '''
- print('%s张嘴。' % self.name)
- def chew(self):
- ''' 咀嚼 '''
- print('%s嚼一嚼。' % self.name)
- def eat(self):
- ''' 吃饭 ''' # 定义一个实例方法,依赖其他方法
- self.open_mouth() # 在类定义中调用其它的方法,使用self.xxx的方式
- self.chew()
-
-
- a = Person('张三') # 使用构造方法,由于第一个self参数自动绑定,只需传入后面的参数
-
- a.name
- a.age
- a.birthday() # 调用过生日方法,第一个参数自动绑定,不需要传参了
- a.birthday()
- a.age
- a.eat()
- # python中,也可以用 类.方法(对象) 的方式来调用方法,就是看着啰嗦
- Person.chew(a)
- # 实例变量的动态增删改
- # 增
- a.nickname = '小明'
- print(a.nickname)
- # 改
- a.nickname = '小麻'
- print(a.nickname)
- # 删
- # del a.nickname
- print(a.nickname) # 删除之后,这个成员变量不存在了,会报错
-
- # 类变量的动态增删改
- # 增
- Person.charactor = '勇敢'
- print(Person.charactor)
- print(a.charactor) # 每个实例都能够调用类变量
- # 改
- Person.charactor = '智慧'
- print(Person.charactor)
- print(a.charactor)
- # 删
- # del Person.charactor
- print(Person.charactor)
- class Student(Person):
- ''' 定义类:学生,继承 “人”这个类别 '''
- def __init__(self,name,age=0,school='北师大'):
- ''' 初始化一个“学生” '''
- Person.__init__(self,name,age) # 先使用基类的初始化方法
- self.school = school # 在此基础上添加
- def gotoschool(self): # 新增一个成员方法
- ''' 上学函数 '''
- print('%s去%s上学啦!' % (self.name, self.school))
- b = Student('韩梅梅')
- b.gotoschool()
- class Mosquito:
- '''
- 蚊子类。目前我们只关心蚊子的行为,不关心具体的蚊子,所以没有构造方法。这个类不会产生实例对象。
- '''
- # 使用@classmethod修饰类方法,自动绑定第一个参数,也就是当前类cls
- @classmethod
- def fly(cls):
- '''
- 飞行方法,蚊子都会飞。
- '''
- print('这个类是会飞的: ', cls)
-
- # 使用@staticmethod修饰静态方法
- @staticmethod
- def sting(p):
- '''
- 叮咬方法,我们关心谁被蚊子叮了,并不关心叮人的具体是哪只蚊子。这个方法的参数是人类对象。
- '''
- print(p.name + '被蚊子叮了。')
- Mosquito.sting(a)
- Mosquito.fly()
1)在前面,加上权限检查,数据合理性与一致性检查,等必要的前处理。
2)在后面,加上记录日志,保存结果,统计绘图,等必要的后处理。
3)适用于前后处理可以通用,中间的函数算法可以灵活替换的场景。
4)可以使用*args代替不定个数的参数,增加装饰器的通用性。
- def pre_post(func):
- '''
- 用装饰器实现通用的前后处理 '''
- def pre_post_f(*args):
- '''
- 实际进行前后处理操作的函数 '''
- # 用一句话代替前后处理过程
- print('前处理......')
- f = func(*args)
- print('后处理......')
- # 内层函数的返回值为func的返回值
- return f
- # 外层函数,把包装好的内层函数作为返回值
- return pre_post_f
-
- # 用通用前后处理函数来包装一个求平均值的函数
- @pre_post
- def mymean(x):
- return sum(x)/len(x)
- # 运行mymean函数,实际上运行的是含有前后处理的,用 pre_post包装好了的函数
- x = list(range(10))
- print(mymean(x))
- # 中国城市信息列表
- class City:
- # 定义类变量
- country = 'China' # 中国城市
- num_of_cities = 0 # 城市总数
- def __init__(self, name, lon, lat, postcode):
- self.name = name
- self.lon = lon
- self.lat = lat
- self.postcode = postcode
- City.num_of_cities += 1
- def print_city(self):
- # 使用类变量一定要带上类名,下面这句话会报错
- # print('Country: %s' % contry)
- # 下面这些是正确的
- print('Country: %s' % City.country)
- print('Total number of cities: %d' % City.num_of_cities)
- print('City name: %s' % self.name)
- print('Longitude: %7.3f' % self.lon)
- print('Latitude: %7.3f' % self.lat)
- print('Post code: %d' % self.postcode)
- BJ = City('北京',116.408,39.904,100000)
- BJ.print_city()
- SH = City('上海',121.445,31.213,200000)
- SH.print_city()
- GZ = City('广州',113.265,23.108,510000)
- GZ.print_city()
- # 访问类变量
- # 通过类访问
- print(City.country)
- # 通过类修改
- City.country = '中国'
- print(City.country)
- # 通过实例访问
- print(BJ.country)
- # 通过实例修改
- BJ.country = 'BJ中国' # 通过实例BJ修改
- # 从类中访问,发现类变量没有被改过!
- print(City.country)
- # 从实例BJ中访问,发现被改了
- print(BJ.country)
- # 从其它实例中访问,发现还是没有被修改
- print(SH.country)
- # 通过dir发现BJ中新建了一个实例变量,也叫country!
- dir(BJ)
面向对象的三大特征:封装(Encapsulation)、继承和多态。
封装指的是将对象的状态信息隐藏在内部,不允许外部直接访问。通过该类提供的方法,完成数据完整性、一致性、权限检查等操作后才允许访问和修改。
以双下划线__开头的是隐藏变量和方法。
类变量、类方法、实例变量、实例方法,都是可以隐藏的。也可以通过“作弊”的方式访问到隐藏变量和方法。但是非常不推荐这样做!
- # 中国城市信息列表,使用封装来增加安全性
- class City:
- # 定义类变量,所有的类变量都是隐藏变量
- # 中国城市
- __country = 'China'
- # 城市总数
- __num_of_cities = 0
- def __num_plusone():
- ''' 隐藏方法,让城市的总数加一。 '''
- City.__num_of_cities += 1
- def __init__(self, name, lon, lat, postcode):
- ''' 构造方法,所有的实例变量都是隐藏变量。 '''
- self.__name = name
- self.__lon = lon
- self.__lat = lat
- self.__postcode = postcode
- City.__num_plusone()
-
- def print_city(self):
- ''' 把实例对象和类的信息打印出来。 '''
- print('Country: %s' % City.__country)
- print('Total number of cities: %d' % City.__num_of_cities)
- print('City name: %s' % self.__name)
- print('Longitude: %7.3f' % self.__lon)
- print('Latitude: %7.3f' % self.__lat)
- print('Post code: %d' % self.__postcode)
- # 读取类和对象的属性
- def get_name(self):
- return self.__name
- def get_lat(self):
- return self.__lat
- def get_lon(self):
- return self.__lon
- def get_coordinate(self):
- return self.__lat, self.__lon
- def get_postcode(self):
- return self.__postcode
- def get_country():
- return City.__country
- def get_num_of_cities():
- return City.num_of_cities
- # 没有写入方法,对象一旦创建就不能修改,类的属性只能通过内部的方法修改
看起来python的隐藏方法是有效的。然而,事实上python并没有真正的隐藏机制,它只是把被隐藏的变量给改了名字。
用_类名__变量或方法名的方式,可以访问到被隐藏的东西。但是平时不建议这样做。
- # 创建一些对象
- BJ = City('北京',116.408,39.904,100000)
- BJ.print_city()
-
- SH = City('上海',121.445,31.213,200000)
- SH.print_city()
-
- GZ = City('广州',113.265,23.108,510000)
- GZ.print_city()
- # 直接访问实例变量和类变量,会报错,隐藏变量从类定义的外部,既不能读也不能写
- #print(City.country)
- print(BJ.__name)
- # 通过get方法间接访问类变量和实例变量
- print(City.get_country())
- print(BJ.get_name())
- # 作弊式访问隐藏变量
- print(BJ._City__name)
- # 作弊式修改隐藏变量
- BJ._City__name = 'Beijing'
- print(BJ._City__name)
property()函数的语法格式如下:
property(fget = None, fset = None, fdel = None, doc = None)
- # 中国城市信息列表,使用property定义属性
- class City:
- # 定义类变量,所有的类变量都是隐藏变量
- # 中国城市
- __country = 'China'
- # 城市总数
- __num_of_cities = 0
- def __num_plusone():
- ''' 隐藏方法,让城市的总数加一。 '''
- City.__num_of_cities += 1
- def __init__(self, name, lon, lat, postcode):
- ''' 构造方法,所有的实例变量都是隐藏变量。 '''
- self.__name = name
- self.__lon = lon
- self.__lat = lat
- self.__postcode = postcode
- City.__num_plusone()
-
- def print_city(self):
- ''' 把实例对象和类的信息打印出来。 '''
- print('Country: %s' % City.__country)
- print('Total number of cities: %d' % City.__num_of_cities)
- print('City name: %s' % self.__name)
- print('Longitude: %7.3f' % self.__lon)
- print('Latitude: %7.3f' % self.__lat)
- print('Post code: %d' % self.__postcode)
- # 读取类和对象的属性
- def get_name(self):
- return self.__name
- def get_lat(self):
- return self.__lat
- def get_lon(self):
- return self.__lon
- def get_coordinate(self):
- return self.__lat, self.__lon
- def get_postcode(self):
- return self.__postcode
- def get_country():
- return City.__country
- def get_num_of_cities():
- return City.num_of_cities
-
-
- # 写入对象的属性(类的属性不能直接写)
- def set_name(self, name):
- self.__name = name
- def set_lat(self, lat):
- self.__lat = lat
- def set_lon(self, lon):
- self.__lon = lon
- def set_coordinate(self, coordinate):
- self.__lat, self.__lon = coordinate
- def set_postcode(self, postcode):
- self.__postcode = postcode
-
- # 定义coordinate属性的删除操作
- def del_coordinate(self):
- self.__lat, self.__lon = 0, 0
-
- # 用property定义属性
- coordinate = property(get_coordinate, set_coordinate, del_coordinate, \
- '城市的经纬度坐标,北纬在前,东经在后,南和西方向为负值')
-
- # 创建一些对象
- BJ = City('北京',116.408,39.904,100000)
- BJ.print_city()
-
- SH = City('上海',121.445,31.213,200000)
- SH.print_city()
-
- GZ = City('广州',113.265,23.108,510000)
- GZ.print_city()
- # 访问coordinate的说明文档
- help(City.coordinate)
- # 访问coordinate的说明文档,也可以直接取得成员的__doc__字符串
- print(City.coordinate.__doc__)
- # 访问coordinate属性
- print(BJ.coordinate)
- # 事实上是通过get方法访问的
- # 直接对coordinate属性赋值
- BJ.coordinate = 39, 116
- print(BJ.coordinate)
- # 事实上是通过set方法修改的,是安全的
- # 直接访问隐藏的属性,例如lat,还是不行的
- print(BJ.__lat)
- # 通过get方法访问lat,确认lat也被修改了
- print(BJ.get_lat())
- # 多重继承例子
- # 定义飞机类
- class Plane:
- def __init__(self, name, speed = 2000):
- self.name = name
- self.speed = speed # 飞行速度
- def fly(self):
- print('%s是飞机,可以飞!' % self.name)
- # 定义武器类
- class Weapon:
- def __init__(self, name, attack_p = 500):
- self.name = name
- self.attack_p = attack_p # 攻击力点数
- def fire(self):
- print('%s是武器,开火!!!' % self.name)
- # 定义战斗机类,继承飞机和武器
- class Fighter(Plane, Weapon):
- pass # 什么都不做,先看看里面有什么
- # 定义战斗机类Fighter的实例
- f = Fighter('歼20')
- # 看看里面有什么
- print(f.name)
- print(f.speed)
- #print(f.attack_p) # 攻击力属性丢了!
- f.fly()
- f.fire()
- # 重写父类方法例子
- class Aircraft():
- ''' 飞行器,包括热气球、飞艇、各种固定翼和旋翼飞机。在大气层内飞行。 '''
- def __init__(self, name, maxspeed = 100):
- self.name = name
- self.maxspeed = maxspeed # 飞行速度
- def fly(self):
- print('%s是飞行器(aircraft),可以在大气层内飞行。' % self.name)
- class Plane(Aircraft):
- ''' 固定翼飞行器(Fixed-wing aeroplane),一般简称为飞机(plane),利用固定的机翼产生的升力在大气层内飞行。 '''
- def fly(self): # 重写父类的方法
- print('%s是固定翼飞行器(Fixed-wing aeroplane),利用固定的机翼产生的升力在大气层内飞行。' % self.name)
- class Helicopter(Aircraft):
- ''' 直升飞机(Helicopter),利用旋转的机翼产生的升力在大气层内飞行。 '''
- def fly(self): # 重写父类的方法
- print('%s直升飞机(Helicopter),利用旋转的机翼产生的升力在大气层内飞行。' % self.name)
- # 定义固定翼飞机和直升飞机的实例
- a = Plane('C919')
- a.fly()
- b = Helicopter('直20')
- b.fly()
有时候我们需要在子类中调用被重写的方法,只需要指定父类的名字就可以了。这个时候需要显示的给它传入self参数。
- # 定义战斗机类,与之前不同的是,这次不使用多重继承,同时测试调用被重写的父类方法
- class Fighter(Plane):
- def __init__(self, name, maxspeed = 2000, attack_p = 500):
- self.name = name
- self.maxspeed = maxspeed # 飞行速度
- self.attack_p = attack_p # 攻击力点数
- # 添加新的方法:开火
- def fire(self):
- print('%s是武器,开火!!!' % self.name)
- # 重写父类方法
- def fly(self):
- # 首先调用父类的同名方法,注意要给这个方法传入self参数
- Plane.fly(self)
- # 后面是新添加的内容
- print('%s是战斗机,可以高速飞行。' % self.name)
- # 定义一个实例,看看fly方法执行的结果如何
- c = Fighter('歼20')
- c.fly()
- # 定义战斗机类,使用super函数
- class Fighter(Plane):
- def __init__(self, name, maxspeed = 2000, attack_p = 500):
- # 使用super函数调用父类的构造方法
- super().__init__(name, maxspeed)
- self.attack_p = attack_p # 攻击力点数
- # 添加新的方法:开火
- def fire(self):
- print('%s是武器,开火!!!' % self.name)
- # 重写父类方法
- def fly(self):
- # 使用super函数调用父类的方法
- super().fly()
- # 后面是新添加的内容
- print('%s是战斗机,可以高速飞行。' % self.name)
-
- # 定义一个实例,看看fly方法执行的结果如何,和上面是一样的
- c = Fighter('歼20')
- c.fly()
-
- # 看看super函数的帮助,发现它其实是super类的构造方法
- help(super)
- # 定义实例
- a = Plane('C919')
- a.fly()
- # 同一个变量,换一个类
- a = Helicopter('直20')
- a.fly()
- # 再换一个类,同样是执行fly方法,执行方式不同
- a = Fighter('歼20')
- a.fly()
- # 用issubclass检测类的继承关系
- # Fighter是Plane的子类
- print(issubclass(Fighter,Plane))
- # Fighter不是Helicopter的子类
- print(issubclass(Fighter,Helicopter))
- # 使用元组作为第二个参数,只要符合其中一个就是True
- print(issubclass(Fighter,(Plane,Helicopter)))
-
-
- # 用isinstance检测类和对象的关系
- a = Fighter('歼20')
- # 是Fighter对象吗?
- print(isinstance(a,Fighter))
- # 是Plane对象吗?
- print(isinstance(a,Plane))
- # 是Helicopter对象吗?
- print(isinstance(a,Helicopter))
- # 使用元组作为第二个参数,只要符合其中一个就是True
- print(isinstance(a,(Plane,Helicopter)))
- # 定义枚举类,一年四季
- import enum
- S = enum.Enum('Season',('spring','summer','fall','winter'))
- # 访问枚举类
- # 打印成员
- print(S.spring)
- # 打印成员的name属性
- print(S.spring.name)
- # 打印成员的value属性
- print(S.spring.value)
- # 通过变量名来访问成员(注意是用方括号,类似于访问字典类型)
- print(S['spring'])
- # 通过枚举值来访问成员(注意是用圆括号,编号从1开始,不是从0开始!)
- print(S(1))
- # 枚举类自带的__members__属性,将枚举类转换为字典(有序字典)
- print(S.__members__)
- class Season(enum.Enum):
- # 为序列指定value值
- spring = '春'
- summer = '夏'
- fall = '秋'
- winter = '冬'
- def info(self):
- print('这是一个代表季节%s的枚举' % self.value)
- # 通过成员名访问
- print(Season['spring'])
- # 通过枚举值来访问
- print(Season('春'))
- # 使用info方法
- Season['summer'].info()
- # 使用__members__遍历有序字典
- for name, member in Season.__members__.items():
- print(name, ':', member, ',', member.value)
-
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。