python类内的变量分为实例变量和类变量
class Dog:
kind = 'canine' # class variable shared by all instances
def __init__(self, name):
self.name = name # instance variable unique to each instance
>>> d = Dog('Fido')
>>> e = Dog('Buddy')
>>> d.kind # shared by all dogs
'canine'
>>> e.kind # shared by all dogs
'canine'
>>> d.name # unique to d
'Fido'
>>> e.name # unique to e
'Buddy'
如将列表作为类变量,下列中所有的狗共享同一个列表
class Dog:
tricks = [] # mistaken use of a class variable
def __init__(self, name):
self.name = name
def add_trick(self, trick):
self.tricks.append(trick)
>>> d = Dog('Fido')
>>> e = Dog('Buddy')
>>> d.add_trick('roll over')
>>> e.add_trick('play dead')
>>> d.tricks # unexpectedly shared by all dogs
['roll over', 'play dead']
该类正确的设计方式
class Dog:
def __init__(self, name):
self.name = name
self.tricks = [] # creates a new empty list for each dog
def add_trick(self, trick):
self.tricks.append(trick)
>>> d = Dog('Fido')
>>> e = Dog('Buddy')
>>> d.add_trick('roll over')
>>> e.add_trick('play dead')
>>> d.tricks
['roll over']
>>> e.tricks
['play dead']
Note:
- python类中无法强制隐藏数据,(类似于C++中的ptivate属性变量)。以一个下划线开头的命名(如_name)会被处理为API的非公开部分(无论他是一个函数、方法或数据成员)。原理:python提供了name mangling (命名编码),任何形如 __spam 的标识(前面至少两个下划线,后面至多一个),被替代为 _classname__spam ,此语法不关注标识的位置,只要求在类定义内。
- 数据属性会覆盖同名的方法属性。为避免此类错误,可以大写方法名称的首字母,数据属性名称加一个前缀“_"
- 方法的第一个参数被命名为self,仅是一个约定,对于python,self没有任何特殊含义
class my_class:
def func(a): # 可以不加self,但不加self后可读性变弱
print(a)
my_class.func('123')
4.函数定义代码可以定义在类外,也可以将一个函数对象赋值给类中的一个局部变量
def f1(self, x, y):
return min(x, x+y)
class C:
f = f1
def g(self):
return 'hello world'
h = g
5.每个值都是一个对象,因此每个值都有一个类(class)(也称为他的类型type),存储为object.__class__
a = 3
print(a.__class__) # <class 'int'>
继承
class DerivedClassName(BaseClassName):
<statement-1>
.
.
.
<statement-N>
通过表达式引入基类也可
class DerivedClassName(modname.BaseClassName):
<statement-1>
.
.
.
<statement-N>
基类名必须与派生类定义在一个作用域内
Note:Python 中的所有方法本质上都是 虚 方法,即派生类会覆盖基类的方法
在解析派生类的属性引用时,如果在类中找不到请求调用的属性,就搜索基类。如果基类是由别的类派生而来,这个规则会递归的应用上去。
python有两个用于继承的函数:
- 函数
isinstance()
用于检查实例类型:如isinstance(obj, int)
检查obj的类型是不是int或是int派生类的实例 - 函数 issubclass() 用于检查类继承,如
issubclass(bool, int)
为 True,因为 bool 是 int 的子类
多继承
class DerivedClassName(Base1, Base2, Base3):
<statement-1>
.
.
.
<statement-N>
super()可以动态改变解析顺序,使得每个祖先类只调用一次,详见解说
补充
- 一个空的类定义可以实现类似于结构体的功能
class Employee:
pass
john = Employee() # Create an empty employee record
# Fill the fields of the record
john.name = 'John Doe'
john.dept = 'computer lab'
john.salary = 1000
- 异常也可以是类
class B(Exception):
pass
class C(B):
pass
class D(C):
pass
for cls in [B, C, D]:
try:
raise cls()
except D:
print("D")
except C:
print("C")
except B:
print("B")