Python面向对象
面向对象3要素
- 封装
组装:将数据和操作组装到一起
隐藏数据:对外只暴露一些接口,通过接口访问对象。 - 继承
多复用,相同功能通过继承来避免重复造轮子
多继承少修改,使用继承来改变特性,体现个性化 - 多态
面向对象编程最灵活的地方,动态绑定。
类的定义
class ClassName:
语句块
必须使用class关键字
类名建议大驼峰
类定义完成后,就产生了一个类对象,绑定到ClassName上
class MyClass:'''A example class'''x = 'abc' # 类属性def foo(self):return 'My Class' # 类方法fooa = MyClass()
类对象及类属性
- 类对象,类的定义就会生成一个类对象
- 类的属性,类定义中的变量和类中定义的方法都是类的属性,如上例
- 类变量,x是MyClass的变量
- MyClass中,x、foo(也可称方法)都是类的属性,doc也是类的属性
- foo是method方法对象,不是普通的函数对象function了,必须至少有一个参数,且第一个参数必须是self。self指代当前示例本身
- a = MyClass()表示实例化,实例化后会得到一个对象,就是实例对象
init方法
MyClass()实际上调用的是init(self)方法,可以不定义,如果没有定义会在实例化后隐式调用,主要作用是对示例进行初始化
class MyClass:def __init__(self):self.name = 'tom'print(self.name)a = MyClass() #会调用__init__
初始化函数可以多个参数,单第一个位置必须是self
注意:init()方法不能有返回值,也就只能是None
实例的特殊属性
实例变量是每一个实例自己的变量,是自己独有的,类变量是类的变量,是类的所有实例共享的属性和方法
__name__:对象名__class__:对象的类型__dict__:对象的属性的字典__qualname__:类的限定名
class Person:x = 'abc'def __init__(self):self.name = 'tom'self.age = 18print(self.name, self.age)def show(self, x, y):self.name = xself.age = yprint(self.name, self.age)a = Person()print(a.__class__, Person.__class__, sep='\n')# a.__class__: <class '__main__.Person'> 实例的__class__为类的方法# Person.__class__: <class 'type'> 类的__class__为类的类型print(a.__class__.__qualname__, Person.__qualname__, sep='\n')# a.__class__.__qualname__:Person 实例本身并没有__qual_name__属性# Person.__qualname__:Person 返回类的限定名print(a.__class__.__name__, Person.__name__, sep='\n')# a.__class__.__name__: Person 实例本身并没有__name__属性# Person.__name__: Person 返回类的名称print(a.__dict__, Person.__dict__, sep='\n')# a.__dict__:{'name': 'tom', 'age': 18} 返回实例的属性# Person.__dict__:{'__module__': '__main__', 'x': 'abc', '__init__': <function Person.__init__ at 0x000001AA057AB840>...} # 返回类属性
总结:
是类的属性,也是这个类所有实例的,所有实例都可以访问到,是实例的,就是这个实例自己的,通过类访问不到
类变量是属于类的变量,这个类的所有实例都可以共享这个变量
实例可以动态的给自己增加一个属性,
实例.__dict__[变量名]和实例.变量名都可以访问到实例的同名变量会隐藏这类变量,或者说覆盖了这个类的变量
实例属性的查找顺利
- 指的是实例使用.来访问属性,会先找自己的
__dict__,如果没有,通过属性class找到自己的类,在去找类的__dict__ - 如果实例使用
__dict__[变量名]访问变量,将不会按照上面的查找顺序找变量了。
- 指的是实例使用.来访问属性,会先找自己的
装饰一个类(不是类装饰器)
def add_name(name):
# 装饰器,增加类的属性
def wapper(cls):
cls.Name = name
return cls
return wapper
@add_name('Tom')
class Person:
age = 18
print(Person.age, Person.Name)
# 本质上是为类对象动态的添加了一个属性,而Person这个标识符指向这个类对象
类方法和静态方法
class Person:
@classmethod
def classs_method(cls):
print('class = {0.__name__} ({0})'.format(cls))
cls.Height = 180
@staticmethod
def static_method(): # 无需传入self或cls参数
print(Person.Height)
Person.classs_method()
print(Person.__dict__)
Person.static_method()
类方法
- 在类定义中,使用@classmethod装饰器修饰的方法
- 至少有一个参数,且第一个参数留给了cls,cls指代调用者即类对象自身
- 通过cls可以直接操作类的属性,但无法通过cls操作类的实例(此时的cls相当于是从模板中复制了一个实体,所以根本不知道类中有多少其他的实例)
静态方法
- 在类定义中使用@staticmethod装饰器修饰的方法
- 调用时,不会隐式传入参数
- 静态方法,只是表明这个方法属于这个名词空间,函数归在一起,方便组织管理
属性装饰器
一般的设计是:把实例的属性保护起来,不让外部直接访问,外部使用getter和setter来读取设置属性
类中变量以__开头,在被访问的时候会被解释器隐藏。如下例中__his就不可直接访问,如需访问需使用_Person__his。
class Person:
def __init__(self, chi, eng, his):
self.__chi = chi
self.__eng = eng
self.__his = his
@property # 装饰器,后面跟的函数名就是以后的属性名,实现的就是getter功能,有了它表示为只读属性
def chiense(self):
return self.__chi
@chiense.setter # 装饰器,与属性名同名,且接受2个参数,第一个是self,第二个是要赋予的值,有了它表示可写
def chinese(self, value):
self.__chi = value
student1 = Person(80, 90, 100)
print(student1.chinese) # getter功能
student1.chinese = 100 # setter功能
print(student1.chinese)
# property装饰器必须在前,stter、deleter装饰器在后
# property装饰器能通过简单的方式,把对方法的操作变成对属性的访问,起到一定的隐藏效果
