您的位置:首页 > 编程语言 > Python开发

python的_xxx, __xxx, __xxx__区别

2017-05-18 14:55 127 查看

_xxx

弱“内部使用”标识

如:”from M import *”,将不导入所有以下划线开头的对象,包括包、模块、成员。

表明该方法或属性不应该去调用

Python中不存在真正的私有方法。为了实现类似于c++中私有方法,可以在类的方法或属性前加一个“_”单下划线,意味着该方法或属性不应该去调用,它并不属于API。

xxx_

只是为了避免与python关键字的命名冲突

__xxx

伪私有方法

class A(object):
def __init__(self):
self.name = 'A'
def __method(self):
print("I'm a method in A")

a = A()
a.__method()


输出:

AttributeError: 'A' object has no attribute '__method'


虽然看上去在像是私有函数,在外部无法访问,但是其实python只是简单地给
__method()
改了下名字,仍然可以这样访问:

a._A__method()


输出:

I'm a method in A


了解了这么一个改名的机制,再看下面这个例子:

class BaseClass(object):
def __init__(self):
self.name = 'Base'
def __method(self):
print("I'm Base")
def method(self):
self.__method()

class SubClass(BaseClass):
def __init__(self):
super(SubClass, self).__init__()
self.name = 'Sub'
def __method(self):  # 覆写父类__method()
print("I'm Sub")
def method(self):    # 覆写父类method()
self.__method()

sub = SubClass()
sub.method()


此时的输出为:

I'm Sub


没问题,子类覆写了父类的
method()
方法,因此输出是”Sub”。如果不覆写:

class SubClass(BaseClass):
def __init__(self):
super(SubClass, self).__init__()
self.name = 'Sub'
def __method(self):  # 覆写父类__method()
print("I'm Sub")
#def method(self):     没有覆写父类method()
#    self.__method()


调用
sub.method()
时,输出:

I'm Base


可以发现,子类调用的是从父类继承下来的
method()
方法,从而调用的自然是父类的
__method__()


其实如果从改名的角度来思考,很容易理解。

在写每个类代码的时候,虽然我们写的都是:

def method(self):
self.__method()


但是BaseClass直接把代码改成了:

def method(self):
self._BaseClass__method()


对应着SubClass:

def method(self):
self._SubClass__method()


而继承可以理解成,如果子类没有覆写,则复制父类的代码下来。因而就出现了,调用
sub.method()
时,其实是调用了父类的
_BaseClass__method()
,输出
BaseClass的情况。


为了加强继承的复制代码与改名机制的理解,我又写了如下代码

class BaseClass(object):
def __init__(self):
self.name = 'Base'
def __method(self):
print("I'm Base")
def method(self): self._BaseClass__method()
self._SubClass__method()

base = BaseClass()
base.method()


输出为:

I'm Base
AttributeError: 'BaseClass' object has no attribute '_SubClass__method'


对于父类来说,它的类方法只有
_BaseClass__method()
,因此调用
_SubClass__method()
时报错。

接着,运行如下代码:

class BaseClass(object):
def __init__(self):
self.name = 'Base'
def __method(self):
print("I'm Base")
def method(self): self._BaseClass__method()
self._SubClass__method()

class SubClass(BaseClass):
def __init__(self):
super(SubClass, self).__init__()
self.name = 'Sub'
def __method(self):
print("I'm Sub")

sub = SubClass()
sub.method()


输出:

I'm Base
I'm Sub


对子类来说,继承的时候首先复制了父类的代码,因此父类的
method()
方法自然就被复制下来。然而,虽然父类的
__method()
方法和子类的
__method()
方法名字一样,但是由于改名机制的存在,其实两个函数的名字并不同,因此并不存在覆写的情况,而是SubClass不仅自己定义了一个
_SubClass__method()
,同时复制了父类的
_BaseClass__method()
。所以这里调用时输出是上面这样而不会报错。

__xxx__

“魔术”对象或属性

许多特殊的代码会调用对应的魔术方法。下面是总结的部分我遇到过的魔术方法:

__init__()

这个很常见,就是创建一个类的实例的时候会调用,相当于构造函数。

__call__()

如果一个类实现了这个函数,那么这个类就是“可调用对象”,可以通过如下方式调用:

class C:
def __call__(self, name):
print(name)

c = C()
c('Hello!')  # 会调用__call__()方法


输出:

Hello!


__getitem__()

class C:
def __init__(self):
self.list = [1,2,3,4,5]

def __getitem__(self, item):
return self.list[item]

c = C()

for i in range(5):
print(c[i]) # 会调用__getitem__()方法


__iter__()
__next__()

之所以把这两个放在一起,是因为我见到的这两个是在迭代器操作的时候同时出现的。直接看代码:

class IterDemo:
def __iter__(self):
print('__iter__() is called')
return NextDemo()   # 需要返回一个实现了__next__()方法的类的对象

class NextDemo:
def __next__(self):
print('__next__() is called')

iterDemo = IterDemo()

nextDemo = iter(iterDemo)   # 调用iterDemo.__iter__()方法
next(nextDemo)              # 调用nextDemo.__next__()方法


__setattr__()

用在类内给成员变量赋值。

class C:
def __init__(self):
self.a = 1        #调用一次__setattr__()

def __setattr__(self, key, value):
dict = self.__dict__
dict[key] = value
print("__setattr__ !")

def modify(self,new_a):
self.a = new_a    #调用一次__setattr__()

c = C()
c.modify(2)


输出:

__setattr__ !
__setattr__ !


参考:

Python下划线与命名规范

python
_
__
__xx__
的区别


pytorch学习笔记(四):输入流水线(input pipeline)

Python3关与迭代器next()使用为
__next__()
的一点注意事项
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  python 继承