面向对象的程序设计(Object Oriented Programming, OOP)的一个关键性的观念就是将数据以及对数据的操作封装在一起, 组成一个相互依存、不可分割的整体, 即对象Object 。 对于相同的类型的对象抽象后得到共同的特征 就形成了类Class。
内置的数据类型列表,字典,元组等等都是类, 学习python必须熟悉了解类,下面从相关的概念出发,对类做一些梳理。
1 属性和方法
类就是把数据以及对数据的操作方法放在一起, 数据无非就是变量, 对数据的操作方法无非就是函数。 把这两种统称为类的成员;而函数称为成员方法 ,变量称为成员属性 。
2 实例属性和类属性
成员属性分为 实例属性和类属性,
- 实例属性一般指在构造函数__init__ 中定义的,定义和使用时必须以self作为前缀
- 类属性是在类中所有方法之外定义的变量
实例属性是由实例决定的, 不同的实例可以是不同的实例属性; 而类属性是全局的,每个实例的类属性都相同;(实例属性与类属性的关系 像 局部变量与全局变量的关系)
class Car:
price = 10000 # 这是类属性, 定义在所有方法之外
def __init__(self, c):
self.color = c # 这是实例属性
由于类属性是全局的, 所以通过类.属性 和 实例.属性 都可以访问, 而实例属性只可以通过实例.属性 访问
car1 = Car('red') #创建一个对象, 也叫做类的实例化 ,从人类 到具体的 “张三”
Car.price #类.属性访问
>>>10000
car1.price #实例.属性访问
>>>10000
Car.color
>>>AttributeError: type object 'Car' has no attribute 'color' # 实例属性不可以通过 类.属性 访问
car1.color
>>>'red'
isinstance(car1, Car) # 查看一个对象是否为某个类的实例
>>> True
在类定义完成之后, python 可以动态的 新增或者修改成员 ,如下
Car.company = "Volkswagen" # 增加成员属性
Car.price = 11111 # 修改成员属性
def setSpeed(self, s):
self.speed = s
import types
Car.setSpeed = types.MethodType(setSpeed, car1) # 增加成员方法
方法和函数的区别在于, 方法一般指与实例相关的函数, 调用方法时, 实例本身会作为第一个参数传递, 所以在增加成员方法时, 要调用 types.MethodType() 将函数转化为方法, 然后才能添加到类。
属性
属性和方法一个是变量一个是函数,调用的时候差一个括号, 也可以将方法属性化, 不加括号就能以调用
class Car:
price = 10000
def __init__(self, c):
self.color = c
def showcolor1(self):
return self.color
@property # 属性装饰器
def showcolor2(self):
return self.color
car = Car('red')
car.price # 访问属性
>>>10000
car.showcolor1() # 调用方法
>>>'red'
car.showcolor2 # 方法属性化
>>>'red'
dir(class_name)查看类中方法和属性, help(class.method) 查看方法说明
dir(car)
['__class__',
'__delattr__',
'__dict__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__gt__',
'__hash__',
'__init__',
'__init_subclass__',
'__le__',
'__lt__',
'__module__',
'__ne__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__',
'__weakref__',
'color',
'price',
'showcolor1',
'showcolor2']
3 共有成员 与 私有成员
为了数据的保密性,需要为某些变量设定成私密属性,使得从类的外部不可以直接方法, 即私有成员; 与之相对的即公有成员。
- __x ,python 中双下划线开头的即为私有成员
- _x,单下划线开头为保护成员, 不可以使用import 导入, 只有类内部或者子类可以使用
- x , 两边都用下划线的为特殊成员。
class Car:
__price = 10000
def __init__(self, c):
self.color = c
car = Car('red')
Car.__price
AttributeError: type object 'Car' has no attribute '__price'
car.__price
AttributeError: type object 'Car' has no attribute '__price' # 不管是实例还是类都不能访问私有成员
但是为了程序的测试和调试, python提供了一种方法可以在类外部访问私有成员, “实例._类__私有属性”
car = Car('red')
car._Car__price
>>>10000 # 可以访问
4 公有方法、私有方法、静态方法、类方法
公有方法和私有方法都属于实例(第一个参数是self), 每个实例都有自己的公有方法和私有方法, 但私有方法不可以通过 实例.私有方法直接调用,只能在内部调用(或者通过python的特殊方式调用)。
class Car:
def __init__(self, c):
self.color = c
def __show(self): # 私有方法
print(self.color)
def setColor(self, newcolor): # 公有方法
self.color = newcolor
self.__show()
car1 = Car('red')
car1.__show()
>>>AttributeError: 'Car' object has no attribute '__show'
car1.setColor("bule")
>>>bule
可以看到对于私有方法__show() ,从外部调用时它给你藏着掖着, 骗你说没有, 但是类内部公有方法setColor()可以通过 self.__show() 调用。
静态方法和类方法可以通过类名和实例名调用, 但不能直接访问实例成员,只能访问类成员,都是总体的方法。
class Car:
price = 10000
def __init__(self, c):
self.color = c # 这是实例属性
@classmethod #类方法修饰器
def showprice(cls):
print(cls.price)
@staticmethod # 静态方法修饰器
def sayhello():
print('hello')
car1 = Car('red')
car1.showprice()
car1.sayhello()
>>>10000
>>>hello
注意: 类方法和静态方法属于是不依赖于实例的, 不可以调用实例成员
运算符重载
为什么int 类的加法和列表的加法都是同样的符号“+” ,但运算方法却不同,这就是运算符的重载,对于同一个运算符,对于不同的类定义的计算方法。
例如,对于Car类,将两辆车“+”定义为其价格之和,重载__add__
class Car:
def __init__(self, color, money):
self.color = color
self.money = money
def __add__(self, anothercar):
if isinstance(anothercar, Car):
return self.money + anothercar.money
else : print('this is nor a car ')
car1 = Car("red", 10000)
car2 = Car("bule",10000)
car1 + car2
>>>20000
继承
继承是为了复用而设计的,当需要一个新类时, 如果新类是某个设计好的类的子类, 那么直接调用设计好的类不失为一个机智高效的方法,分别称为子类和父类。 这种行为就是继承。
比如现在需要一个 大众汽车类,可以继承Car类功能,
class Volkswagen(Car):
def setmodel(self, m):
self.model = m
car3 = Volkswagen( 'yellow', 100)
car3.color
>>>'yellow'
car3.money
>>>100 # 继承了负类的成员
car3.setmodel('迈腾')
>>>car3.model
'迈腾'
查看一个类的子类 可以用 issubclass(son, father) .或者 class.__bases__查看其父类。
issubclass(Volkswagen, Car)
True
Volkswagen.__bases__
(__main__.Car,)