1. 面向对象
类似于c++/c#/java等高级语言,python从设计之初就已经是一门面向对象的语言,正因为如此,在python中创建一个类和对象是很容易的。关于面向对象的思想及基础,此处不再赘述。
2. 类对象
(1) 类变量
:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外
。类变量通常不作为实例变量使用。有的书本也称之为类属性
。
类属性引用使用和 python 中所有的属性引用一样的标准语法:实例对象.name
或 类名.name
# 创建一个类
class student:
num = 101
def test(self):
print('HelloWorld.')
s = student() # 实例化类
print(s.num) # 引用类属性(通过实例化对象)
print(student.num) # 引用类属性(通过类名)
s.test() # 引用类的方法
类变量在整个实例化的对象中是公用的,怎么理解???
# 相信看了此demo, 就明白了.
class Animal:
age = 12
def setAge(self, Age):
self.age = Age
def show(self):
print("age is:>", self.age)
Animal().show()
a = Animal()
a.setAge(13)
a.show()
a.setAge(14)
a.show()
a.show()
print(Animal.age)
(2) 实例变量
: 在类的声明中,属性是用变量来表示的,这种变量就称为实例变量,实例变量就是一个用 self 修饰的变量
。 有的书本也称之为类属性
。
# self.num, self.name就是实例变量
class Animal:
def __init__(self, num, name):
self.num = num
self.name = name
def show(self):
print(self.num, self.name)
Animal(101, 'Cat').show()
# 101 Cat
3. 构造函数__init__()
类有一个名为 __init__()
的特殊方法(构造函数),该方法在类实例化时会自动调用。
class student:
def __init__(self):
print("实例化类时将调用类的构造函数.")
student() # 实例化类时将自动调用类的构造函数
3. 类的属性
(1)
类的公有属性
可以在任何地方被类对象所调用
。
class animal:
num = 101
print(animal().num)
(2)
类的私有属性
__attrs:两个下划线开头
,声明该属性为私有,不能在类的外部被使用或直接访问
。只能在类内部进行调用(self.__attrs)
。
class animal:
__num = 101
def test(self):
print(self.__num)
self.__print()
def __print(self):
print(self.__num)
animal().test()
print(animal().__num) # 错误
4. 类的普通方法
(0)
默认有个self参数,且只能被对象调用。
(1)
在类的内部,使用 def 关键字来定义一个方法,与一般函数定义不同,类方法必须包含参数 self, 且为第一个参数,self 代表的是类的实例
。(static函数除外, c++中的static函数中也不能出现this)
self实际上就是实例对象本身, 该参数名一般约定为self.(相当于c++/c#/java当中的this)
通过它来传递实例的属性和方法.(也可以传类的属性和方法)
(2)
调用形式:实例对象.普通函数()
。
(3)
类的公有方法
可以在任何地方被对象调用
。
# 类方法的必须有一个额外参数, 约定为self
# test()就是一个类方法, 并且是public类型的, 可以在任何地方被对象调用
class animal:
def test(self):
print('HelloWorld.')
animal().test()
(4)
类的私有方法
__method
:两个下划线开头
,声明该方法为私有方法,只能在类的内部调用
(self.__method()),不能在类的外部调用
。
class animal:
def __printInfo(self):
print('这是私有方法, 只能在类的内部被调用.')
def test(self):
self.__printInfo()
animal().test()
# animal().__printInfo() # 错误
(5)
类的专有方法
__init__
:构造函数,在生成对象时调用
__del__
:析构函数,释放对象时使用
__repr__
:打印,转换
__setitem__
:按照索引赋值
__getitem__
:按照索引获取值
__len__
:按照索引获取值
__cmp__
:比较运算
__call__
:函数调用
__add__
:加运算
__sub__
:减运算
__mul__
:乘运算
__truediv
:除运算
__mod__
:求余运算
__pow__
:乘方
5. 类的静态方法
(1)
可用staticmethod()将类方法包装成静态函数;
(2)
也可以用@staticmethod装饰器定义一个 静态函数;
(3)
static函数与一般方法不同,不包含参数self
;
(4)
static函数中不能出现self,就好比C++中的static函数中不能出现this一样;
(5)
static函数的调用:类名.静态函数()
或者 实例对象.静态函数()
;
class StaticClass:
def call():
print('call static method1 <call()>.')
# 将call()包装成静态函数
call = staticmethod(call)
# 使用@staticmethod定义静态函数
@staticmethod
def say():
print('call static method2 <say()>.')
# 通过实例对象访问静态函数
StaticClass().call()
StaticClass.say()
# 通过类名访问静态函数
StaticClass.call()
StaticClass.say()
6. 类方法
(1)
默认有个 cls 参数,可以被类和对象调用,需要加上 @classmethod 装饰器
。函数的第一个参数表示类本身
且该参数一般约定为cls, 通过它来传递类的属性和方法(不能传实例的属性和方法)
(2)
调用方法:实例.类方法()
或 类名.类方法()
。
# demo1
class ClassMethod:
@classmethod
def test(cls):
print('调用类方法.')
ClassMethod().test() # 通过实例调用类方法
ClassMethod.test() # 通过类名调用类方法
# demo2:cls的使用
class Student:
addr = "SuZhou"
@classmethod
def ClassMethod(cls):
print('call classMethod.')
# 类方法中调用类属性 和 类方法(通过类名)
@classmethod
def ClassMethodExtend(cls):
Student.addr = "JiangSu"
print(Student.addr)
Student.ClassMethod()
print("call ClassMethodExtend.")
# 类方法中调用类属性 和 类方法(通过参数cls)
@classmethod
def ClassMethodExtendEx(cls):
cls.addr = "ZhongGuo"
print('cls.addr:> ', cls.addr)
cls.ClassMethod()
Student.ClassMethodExtend()
Student.ClassMethodExtendEx()
print(Student.addr)
7. 类的静态方法和类方法异同
类方法 和 静态方法 都可以通过类名和实例进行调用。
类方法 和 静态方法 都是属于类级方法。
[a]. 类变量
:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外
。类变量通常不作为实例变量使用。有的书本也称作类属性
。
[b]. 实例变量
:在类的声明中,属性是用变量来表示的,这种变量就称为实例变量,实例变量就是一个用self修饰的变量
。有的书本也称为实例属性
。
[c]. 实例方法
:就是类的普通方法。
(1)
类方法
a.
类方法中只能使用 类属性和类方法,不能使用实例属性和实例方法(普通方法),因为不具备self
;
b.
类方法中也可以调用 静态方法;
(2)
静态方法
a.
实例属性和实例方法都不能使用(因为不具备self
),但是可以类属性和类方法;
8. 单继承
python 同样支持类的继承,如果一种语言不支持继承,类就没有什么意义。
派生类的定义格式
:
class DerivedClassName(BaseClassName):
<statement-1>
.
.
.
<statement-N>
子类(派生类 DerivedClassName)会继承父类(基类 BaseClassName)的属性和方法。
BaseClassName(实例中的基类名)必须与派生类定义在一个作用域内
。除了类,还可以用表达式,基类定义在另一个模块中时这一点非常有用:
class DerivedClassName(modname.BaseClassName):
# 基类
class People:
__weight = 0
def __hello(self):
print('HelloWorld')
def __init__(self, name, age, weight):
self.name = name
self.age = age
self.__weight = weight
def speak(self):
print("[father] %s say:> i am %d years old." % (self.name, self.age))
# 派生类
class Student(People):
def __init__(self, name, age, weight, grade):
# 调用父类的构造函数
People.__init__(self, name, age, weight)
# 初始化实例变量
self.grade = grade
# 覆盖父类的方法
def speak(self):
print("[son] %s say:> i am %d years old and i am in %d grade." % (self.name, self.age, self.grade))
# 父类的私有属性和私有方法不会被继承
def test(self):
print(self.weight)
self.__hello()
Student('Ken', 30, 60, 6).speak()
Student('Tom', 10, 10, 4).test() # 错误
9. 多继承
python同样有限的支持多继承形式。
多继承的类定义格式
:
class DerivedClassName(Base1, Base2, Base3):
<statement-1>
.
.
.
<statement-N>
需要注意圆括号中父类的顺序,若是父类中有相同的方法名,而在子类使用时未指定,python从左至右搜索,即方法在子类中未找到时,从左到右依次查找父类中是否包含方法。
class Father:
def __init__(self, ear, eye):
self.ear = ear
self.eye = eye
def test(self):
print('test() in father.')
class Mother:
def __init__(self, hair, sing):
self.hair = hair
self.sing = sing
def test(self):
print('test() in mother.')
class Son(Father, Mother):
def __init__(self, ear, eye, hair, sing, eat):
# 调用父类的构造函数
Father.__init__(self, ear, eye)
# 调用基类的构造函数
Mother.__init__(self, hair, sing)
# 初始化实例变量
self.eat = eat
def show(self):
print(self.ear, self.eye, self.hair, self.sing, self.eat)
def test(self):
print('test() in son.')
s = Son('Big-ear', 'little-eye', 'black-hair', 'good-sing', 'eat-pig')
s.show()
s.test() # test(), 如果子类中不存在此方法, 那么python将会从左至右查找其基类中是否包含此方法
10. 方法重写
如果你的父类方法的功能不能满足你的需求,你可以在子类重写你父类的方法
。
class Parent(object):
def __init__(self):
self.parent = 'I am parent.'
def bar(self, message):
print("%s from Parent." % message)
class Child(Parent):
def __init__(self):
super(Child, self).__init__()
# 重写(覆盖)基类的方法
def bar(self, message):
print("%s from Son." % message)
child = Child()
child.bar('HelloWorld~~~')
11. 运算符重载
python同样支持运算符重载,我们可以对类的专有方法进行重载。
class Vector:
def __init__(self, aa, bb):
self.a = aa
self.b = bb
# 对类的专有方法__str__进行重载
def __str__(self):
return 'Vector(%d, %d).' % (self.a, self.b)
# 对类的专有方法__add__进行
def __add__(self, other):
return Vector(self.a + other.a, self.b + other.b)
v1 = Vector(2, 10)
v2 = Vector(5, -2)
print(v1 + v2)
12. super()函数
super() 函数是用于调用父类(超类)的一个方法
。
super() 是用来解决多重继承问题的
,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及到查找顺序(MRO)、重复调用(钻石继承)等种种问题。
格式:
super(type[, object-or-type])
type:类。
object-or-type:类, 一般是self。
Python3.x 和 Python2.x 的一个区别是: python3 可以使用直接使用 super().xxx 代替 super(Class, self).xxx。
# 1. python3写法
class A:
def __init__(self):
pass
def add(self, x):
print(x ** 3)
def test(self):
print('I am father.')
class B(A):
def __init__(self):
super().__init__()
def add(self, x):
super().add(x) # 调用父类的add()
B().add(2) # 8
# 2. python2写法
class A(object): # python2.x记得继承object
def add(self, x):
print(x + 1)
class B(A):
def add(self, x):
super(B, self).add(x)
B().add(9) # 10
# 3. demo
class Parent(object):
def __init__(self):
self.parent = 'I am parent.'
def bar(self, message):
print("%s from Parent." % message)
class Child(Parent):
def __init__(self):
super(Child, self).__init__()
def bar(self, message):
super(Child, self).bar(message) # 调用基类的bar()函数
print("%s from Son." % message)
child = Child()
super(Child, child).bar('HelloWorld@@@') # 调用基类的bar()函数