类的定义
- 现实世界中事物的描述、定义
- 描述对象包含的数据和特征
- 注意类与对象的区别
类的创建和使用
创建
- 类名使用大驼峰命名方式,但是首字母大写,不适用下划线_
- 实例名和模块名使用小写字母,并在单词之间加下划线_
- 类与类之间使用2个空行分隔
- 类的不同方法之间使用1个空行分隔
- class ClassName():
class Dog(): #类名,大驼峰命名法
'''
模拟狗类动物
'''
def __init__(self, name, age): #构造函数,类的默认方法,前后2个双下划綫与普通方法区分
'''
初始化狗的name和age
:param name:
:param age:
'''
self.name = name
self.age = age
def sit(self):
'''
蹲下动作
:return:
'''
print('{0} is now sitting.'.format(self.name.title()))
def roll_over(self):
'''
打滚动作
:return:
'''
print('{0} rolled over!'.format(self.name.title()))
__init__()
构造函数
- 创建类的实例时,自动调用
- 形参self必不可少,且位于其他形参前面
- 每个与类相关联的方法调用都自动传递self,它是指向实例本身的引用
__del__()
析构函数
- Python中不需要特别使用析构函数
垃圾回收器
- gc模块collect()函数
类的方法
- 必须有self参数
- 调用类的方法是,可以不传递self参数
类的使用(实例化)
- 创建对象的过程称之为类的实例化
- 直接赋值
my_dog = Dog('willie',6)
print('My dog\'s name is {0},and it\'s {1} years old!'.format(my_dog.name,my_dog.age))
my_dog.sit()
my_dog.roll_over()
your_dog = Dog('lucy',3)
print('Your dog\'s name is {0},and it\'s {1} years old!'.format(your_dog.name,your_dog.age))
your_dog.sit()
your_dog.roll_over()
修改类中属性值
- 1.直接修改属性值
- 2.通过方法修改属性值
class Car():
'''
模拟汽车
'''
def __init__(self, make, model, year):
self.make = make
self.model = model
self.year = year
self.odometer_reading = 0 #为属性指定默认值
def get_descriptive_name(self):
'''
输出汽车信息
:return:
'''
return '{0} {1} {2}'.format(self.year,self.make,self.model).title()
def update_odometer(self, mileage):
'''
更新里程数
禁止将里程数回调
'''
if mileage > self.odometer_reading:
self.odometer_reading = mileage
else:
print('You can\'t roll back an odometer!')
def increment_odometer(self, miles):
'''
汽车里程数增加指定的值
禁止将里程数回调,也即禁止增加负数值
:param miles:
:return:
'''
if miles > 0:
self.odometer_reading += miles
else:
print('You can\'t roll back an odometer!')
def read_odometer(self):
'''
打印汽车里程数
'''
print('This car has {0} miles on it'.format(self.odometer_reading))
my_new_car = Car('audi', 'a4', 2016)
print(my_new_car.get_descriptive_name())
my_new_car.read_odometer()
my_new_car.odometer_reading = 23 #通过实例,直接修改属性值
my_new_car.read_odometer()
my_new_car.update_odometer(123) #通过方法1,修改属性值
my_new_car.read_odometer()
my_new_car.increment_odometer(100) #通过方法2,修改属性值
my_new_car.read_odometer()
关于类属性与实例属性
- 在不对实例属性重新赋值的情况下,类属性与实力属性指向同一内存地址
- 使用
__class__.var
调用类属性
class A():
name = 'Leo'
age = 28
def say(self):
self.name = 'bbb'
self.age = 18
print('Hi,{0}'.format(__class__.name)) #调用类属性name
print(A.name)
print(A.age)
print(id(A.name))
print(id(A.age))
a1 = A()
print(a1.name)
print(a1.age)
print(id(a1.name))
print(id(a1.age))
a1.name = 'ccc'
a1.age = 10
print(a1.name)
print(a1.age)
print(id(a1.name))
print(id(a1.age))
a1.say() #
执行结果:
Leo
28
31302744
491811136
Leo
28
31302744
491811136
ccc
10
43679392
491810560
Hi,Leo
类的继承
- 子类继承父类时,会继承父类的所有属性和方法
- 子类也可以定义自己特有的属性和方法
- 父类必须包含在子类当前的文件中,且位于子类前面
- super()特殊函数,也叫超类,代表父类,用于关联子类与父类
- 有时需要在子类中对父类方法进行重写,此时父类中的旧方法会在调用时被忽略
- 当一个类的属性和方法过多时,可以将其中一部分属性与方法分拆出来,定义新的类,然后可以将新类的实例化对象当做属性来赋值
- object类是所有类的父类,也称为基类
class Car():
'''
模拟汽车
'''
def __init__(self, make, model, year):
self.make = make
self.model = model
self.year = year
self.odometer_reading = 0 #为属性'汽车里程数'指定默认值0
def get_descriptive_name(self):
'''
返回汽车信息摘要
:return:
'''
return '{0} {1} {2}'.format(self.year,self.make,self.model).title()
def update_odometer(self, mileage):
'''
更新里程数
禁止将里程数回调
'''
if mileage > self.odometer_reading:
self.odometer_reading = mileage
else:
print('You can\'t roll back an odometer!')
def increment_odometer(self, miles):
'''
汽车里程数增加指定的值
禁止将里程数回调,也即禁止增加负数值
:param miles:
:return:
'''
if miles > 0:
self.odometer_reading += miles
else:
print('You can\'t roll back an odometer!')
def read_odometer(self):
'''
返回汽车里程数
'''
print('This car has {0} miles on it'.format(self.odometer_reading))
def fill_gas_tank(self):
'''
车辆充电/加油信息
:return:
'''
print('Fill gas tank!')
class ElectricCar(Car): #子类ElectricCar继承父类Car
'''
电动汽车
'''
def __init__(self, make, model, year):
'''
初始化父类属性
初始化电动汽车特有属性
:param make:
:param model:
:param year:
'''
super().__init__(make, model, year) #调用父类的方法__init__(),让ElectricCar实例包含Car类的所有属性
self.battery = Battery() #新增属性,此时会生成新的实例Battery,将新的实例作为属性赋值给self.battery,也就是说,每当创建ElectricCar实例,初始化时,会同步创建新的Battery实例
def fill_gas_tank(self): #重写父类的方法fill_gas_tank
'''
电动汽车没有邮箱
:return:
'''
print('This car doesn\'t need a gas tank!')
class Battery():
'''
模拟电动汽车的电瓶
'''
def __init__(self, battery_size = 70):
self.battery_size = battery_size
def describe_battery(self):
print('This car has a {0} -kwh battery.'.format(self.battery_size))
def get_range(self):
'''
返回续航里程
:return:
'''
if self.battery_size == 70:
range = 240
elif self.battery_size == 85:
range = 270
print('This car go approximately {0} miles on a full charge.'.format(range))
my_tesla = ElectricCar('tesla','model s',2016)
print(my_tesla.get_descriptive_name())
my_tesla.fill_gas_tank()
my_tesla.battery.describe_battery()
my_tesla.battery.get_range()
导入类
- 将类存储在模块中,在主程序中导入所需要的模块
- import 导入
- 高效的编程方式,不同的功能存储在不同的模块中
- 导入模块时,先导入标准库,后导入自定义库,之间用空行分隔
import car
my_beetle = car.Car('volkswagen','beetle',2016)
print(my_beetle.get_descriptive_name())
my_beetle.odometer_reading = 23
my_beetle.read_odometer()
my_tesla = car.ElectricCar('tesla','roadster',2016)
print(my_tesla.get_descriptive_name())
my_tesla.battery.describe_battery()
my_tesla.battery.get_range()
类的属性
- 1.私有属性
__
双下划线前缀,私有属性 - 2.公有属性【静态属性|类属性】
没有双下划线前缀,共有属性 - 3.实例属性
有self前缀,实例属性 - 4.内置属性
__dict__
__bases__
__doc__
__module__
class Fruit():
price = 0 #类属性
def __init__(self):
self.color = 'red' #实例属性
zone = 'China' #局部变量,不能被实例化对象调用
__number = 100 #私有属性
class Apple(Fruit):
pass
if __name__ == '__main__':
print(Fruit.price) #返回类属性
apple = Fruit()
print(apple.color) #返回实例属性
#报错 print(apple.zone)
Fruit.price += 10
print(apple.price)
banana = Fruit()
print(banana.price)
#报错 print(banana._Fruit__number)
print(Fruit.__dict__) #Fruit类的内置属性__dict__
print(Fruit.__bases__) #Fruit类的内置属性__bases__
print(Fruit.__module__) #Fruit类的内置属性__module__
print(Fruit.__doc__) #Fruit类的内置属性__doc__
类的方法
类的内置方法
__init__ #初始化对象
__del__ #释放对象
__new__ #生成实例
__str__ #使用print时调用
__getitem__ #获取序列索引key对应的值
__len__ #使用len()时调用
__cmp #比较两个对象
__getattr__ #获取属性值
__setattr__ #设置属性值
__delattr__ #删除属性
__getattribute__ #获取属性值
__gt__ #判断是否大于
__it__ #判断是否小于
__ge__ #判断是否大于等于
__le__ #判断是否小于等于
__eq__ #判断是否等于
__call__ #将实例作为函数调用
类的内置方法实现对象之间的运算
- 对象之间进行关系运算,也叫运算符的重载
- 通过类的内置方法实现,例如
__gt__
等
类方法
- 1.私有方法
__
双下划线前缀,私有方法 - 2.公有方法
没有双下划线前缀,共有方法 - 3.静态方法
@ staticmethod - 4.类方法
@ classmethod
class Fruit():
price = 0
def __init__(self):
self.__color = 'red'
def getColor(self): #公有方法
print(self.__color)
@ staticmethod #@ classmethod 静态方法/类方法
def getPrice():
print(Fruit.price)
def __getPrice():
Fruit.price += 10
print(Fruit.price)
count = staticmethod(__getPrice) #把__getPrice()转换为静态方法,并赋值给count,也即count()为静态方法
if __name__ == '__main__':
apple = Fruit()
apple.getColor()
Fruit.count()
banana = Fruit()
Fruit.count()
Fruit.getPrice()
类方法的动态特性
- 可以将已经定义好的方法,动态添加到类中,称为新的方法
class Fruit():
pass
def add(self):
print('Grow...')
Fruit.grow = add #将新定义的方法add,直接动态加入到Fruit类中,重命名为grow
fruit1 = Fruit()
fruit1.grow() #调用新增加的grow方法
类的嵌套
- Python类中可以再定义类,但是不推荐这么使用,会导致程序难以理解
抽象类
多态性
多重继承
- 导致程序复杂,不易维护
典型案例
class Person():
def __init__(self):
pass
def __setattr__(self, key, value):
print('设置属性:{0}'.format(key))
super().__setattr__(key,value)
print('{0}:{1}'.format(key,value))
p = Person()
print(p.__dict__)
p.age = 18
class Person:
# 实例方法
def eat(self):
print(self)
print("Eating.....")
# 类方法
# 类方法的第一个参数,一般命名为cls,区别于self
@classmethod
def play(cls):
print(cls)
print("Playing.....")
# 静态方法
# 不需要用第一个参数表示自身或者类
@staticmethod
def say():
print("Saying....")
leo = Person()
# 实例方法
leo.eat()
# 类方法
Person.play()
leo.play()
# 静态方法
Person.say()
leo.say()
class Student():
def __init__(self, name):
self._name = name
def __gt__(self, other):
print("{0}比{1}大吗?".format(self._name, other._name))
return self._name > other._name
stu1 = Student("one")
stu2 = Student("two")
print(stu1 > stu2)