之前咱们讲过类大致分成两块区域,如下图所示:
J5Nl34.jpg

每个区域详细划分又可以分为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class A:
company_name = '51devops' # 公静态变量(静态字段): 类可以访问,类内部可以访问;
__iphone = '1353333xxxx' # 私有静态变量(私有静态字段):仅类内部可以访问;

def __init__(self,name,age): #特殊方法
self.name = name #对象属性(普通字段)
self.__age = age # 私有对象属性(私有普通字段)
def func1(self): # 普通方法
pass
def __func(self): #私有方法
print(666)

@classmethod # 类方法
def class_func(cls):
""" 定义类方法,至少有一个cls参数 """
print('类方法')

@staticmethod #静态方法
def static_func():
""" 定义静态方法 ,无默认参数"""
print('静态方法')

@property # 属性
def prop(self):
pass

各种情况访问权限

对于每一个类的成员而言都有两种形式:

  • 公有成员,在任何地方都能访问
  • 私有成员,只有在类的内部才能方法

私有成员和公有成员的访问限制不同,下面我们就根据不同情况来说明各种不同的访问权限:

公有静态字段:类可以访问;类内部可以访问;
私有静态字段:仅类内部可以访问;

公有静态属性(字段):

1
2
3
4
5
6
7
8
9
10
11
12
class C:
name = "公有静态字段"
def func(self):
print C.name
class D(C):
def show(self):
print C.name
C.name # 类访问
obj = C()
obj.func() # 类内部可以访问
obj_son = D()
obj_son.show() # 派生类中可以访问

私有静态属性(字段):

1
2
3
4
5
6
7
8
9
10
11
12
13
class C:
__name = "私有静态字段"
def func(self):
print C.__name
class D(C):
def show(self):
print C.__name
C.__name # 不可在外部访问
obj = C()
obj.__name # 不可在外部访问
obj.func() # 类内部可以访问
obj_son = D()
obj_son.show() #不可在子类中可以访问

公有普通字段:对象可以访问;类内部可以访问;派生类中可以访问
私有普通字段:仅类内部可以访问;

公有普通字段:

1
2
3
4
5
6
7
8
9
10
11
12
13
class C:
def __init__(self):
self.foo = "公有字段"
def func(self):
print self.foo  # 类内部访问
class D(C):
def show(self):
print self.foo # 派生类中访问
obj = C()
obj.foo # 通过对象访问
obj.func() # 类内部访问
obj_son = D();
obj_son.show() # 子类中访问

私有普通字段:

1
2
3
4
5
6
7
8
9
10
11
12
13
class C:
def __init__(self):
self.__foo = "私有字段"
def func(self):
print self.foo  # 类内部访问
class D(C):
def show(self):
print self.foo # 子类中访问
obj = C()
obj.__foo # 通过对象访问 ==> 错误
obj.func() # 类内部访问 ==> 正确
obj_son = D();
obj_son.show() # 子类中访问 ==> 错误

公有方法:对象可以访问;类内部可以访问;派生类中可以访问
私有方法:仅类内部可以访问;

公有方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class C:
def __init__(self):
pass
def add(self):
print('in C')
class D(C):
def show(self):
print('in D')
def func(self):
self.show()
obj = D()
obj.show() # 通过对象访问
obj.func() # 类内部访问
obj.add() # 派生类中访问

私有方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class C:
def __init__(self):
pass
def __add(self):
print('in C')
class D(C):
def __show(self):
print('in D')
def func(self):
self.__show()
obj = D()
obj.__show() # 通过不能对象访问
obj.func() # 类内部可以访问
obj.__add() # 派生类中不能访问

总结:

对于这些私有成员来说,他们只能在类的内部使用,不能再类的外部以及派生类中使用.

ps:非要访问私有成员的话,可以通过 对象.类_属性名,但是绝对不允许!!!

为什么可以通过.类__私有成员名访问呢?因为类在创建时,如果遇到了私有成员(包括私有静态字段,私有普通字段,私有方法)它会将其保存在内存时自动在前面加上类名.

双下方法

定义:双下方法是特殊方法,他是解释器提供的 由爽下划线加方法名加双下划线 __方法名__的具有特殊意义的方法,双下方法主要是python源码程序员使用的,我们在开发中尽量不要使用双下方法,但是深入研究双下方法,更有益于我们阅读源码。

调用:不同的双下方法有不同的触发方式,就好比盗墓时触发的机关一样,不知不觉就触发了双下方法,例如:init

len
1
2
3
4
5
6
7
8
9
10
11
12
13
class B:
def __len__(self):
print(666)
b = B()
len(b) # len 一个对象就会触发 __len__方法。
class A:
def __init__(self):
self.a = 1
self.b = 2
def __len__(self):
return len(self.__dict__)
a = A()
print(len(a))
hash
1
2
3
4
5
6
7
8
class A:
def __init__(self):
self.a = 1
self.b = 2
def __hash__(self):
return hash(str(self.a)+str(self.b))
a = A()
print(hash(a))
str

如果一个类中定义了str方法,那么在打印 对象 时,默认输出该方法的返回值。

1
2
3
4
5
6
7
8
class A:
def __init__(self):
pass
def __str__(self):
return '宝元'
a = A()
print(a)
print('%s' % a)
repr

如果一个类中定义了repr方法,那么在repr(对象) 时,默认输出该方法的返回值。

1
2
3
4
5
6
7
8
class A:
def __init__(self):
pass
def __repr__(self):
return '宝元'
a = A()
print(repr(a))
print('%r'%a)
call

对象后面加括号,触发执行。

注:构造方法new的执行是由创建对象触发的,即:对象 = 类名() ;而对于 call 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()

1
2
3
4
5
6
7
class Foo:
def __init__(self):
pass
def __call__(self, *args, **kwargs):
print('__call__')
obj = Foo() # 执行 __init__
obj() # 执行 __call__
del

析构方法,当对象在内存中被释放时,自动触发执行。

注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。

new
1
2
3
4
5
6
7
8
9
class A:
def __init__(self):
self.x = 1
print('in init function')
def __new__(cls, *args, **kwargs):
print('in new function')
return object.__new__(A, *args, **kwargs)
a = A()
print(a.x)

使用new实现单例模式

1
2
3
4
5
6
class A:
__instance = None
def __new__(cls, *args, **kwargs):
if cls.__instance is None:
cls.__instance = object.__new__(cls)
return cls.__instance