python的_xxx, __xxx, __xxx__区别
_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__()
的一点注意事项
推荐阅读
-
linux上的mysql报Table'xxx'doesn'texist的错误解决方法_MySQL
-
怎的提取“xxx,订单号123”里面的123呢
-
Python中lambda的用法及其与def的区别解析
-
启动Tomcat报错Unsupported major.minor version xxx的解决方法
-
浅谈Python2.6和Python3.0中八进制数字表示的区别
-
Python中%r和%s的详解及区别
-
python中单引号和双引号的区别作用(python转义引号用法)
-
mysql sql语句优化(sql和python的区别讲解)
-
python追加写入文件操作方法(python列表和数组的区别)
-
python中单引号和双引号的区别作用(python转义引号用法)