【变量】关于单下划线、双下划线开头变量的含义
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了【变量】关于单下划线、双下划线开头变量的含义相关的知识,希望对你有一定的参考价值。
参考技术A 以单下划线(_)表明是标准库的变量双下划线(__) 开头表明是编译器的变量
建议自己在命名的时候不要用下划线开头,避免与标准库中的命名冲突。
Python 用下划线作为变量前缀和后缀指定特殊变量
_xxx 不能用 “from module import *” 导入
__xxx__ 系统定义名字
__xxx 类中的私有变量名
核心风格:避免用下划线作为变量名的开始
因为下划线对解释器有特殊的意义,而且是内建标识符所使用的符号,我们建议程序员避免用下划线作为变量名的开始。
一般来讲,变量名_xxx被看作是“私有的”,在模块或类外不可以使用,当变量是私有的时候,用_xxx 来表示变量是很好的习惯。因为变量名__xxx__对Python 来说有特殊含义,对于普通的变量应当避免这种命名风格。
“单下划线” 开始的成员变量叫做保护变量,意思是只有类对象和子类对象自己能访问到这些变量;
“双下划线” 开始的是私有成员,意思是只有类对象自己能访问,连子类对象也不能访问到这个数据。
以单下划线开头(_foo)的代表不能直接访问的类属性,需通过类提供的接口进行访问,不能用“from xxx import *”而导入;
以双下划线开头的(__foo)代表类的私有成员;
以双下划线开头和结尾的(__foo__)代表python里特殊方法专用的标识,如 __init__()代表类的构造函数。
Python中类的特殊变量
特殊变量
- 类似__xx,以双下划线开头的实例变量名,就变成了一个私有变量(private),只有内部可以访问,外部不能访问;
- 类似__xx__,以双下划线开头,并且以双下划线结尾的,是特殊变量,特殊变量是可以直接访问的,它不是private变量,下面会介绍Python中的常见特殊变量;
- 类似_x,以单下划线开头的实例变量名,这样的变量外部是可以访问的,但是,按照约定俗成的规定,当你看到这样的变量时,意思就是,“虽然我可以被访问,但是请把我视为私有变量,不要随意访问”。
内置函数
- type(),type()函数返回type类型
用法:
import types type(‘abc‘)==types.StringType type(u‘abc‘)==types.UnicodeType type([])==types.ListType type(str)==types.TypeType
最后这种类型叫做TypeType,所有类型本身就是TypeType。
也可以对函数或者类:
- isinstance(),判断一个对象是否属于某个类型
一个例子:
class P(object): pass class C(P): pass p = P() c = C() print isinstance(p, P) print isinstance(c, P) print isinstance(p, C) # False print isinstance(c, C)
如上,子类实例即是父类类型,也是子类类型,但父类实例不属于子类类型。
isinstance()也可以代替type()的作用:
isinstance(‘a‘, str) isinstance(u‘a‘, unicode) isinstance(‘a‘, unicode) #False
- dir(),获取对象的属性和方法列表
- getattr(),获取对象的特定属性
- hasattr(),对象是否存在某个属性
- setattr(),设置对象的属性
用法:
class P(object): name = "cq" def __init__(self, age): self.age = age print hasattr(P, "name") # True print hasattr(P, "age") # False setattr(P, "age", 31) print getattr(P, "name") # cq print getattr(P, "age") # 31
特殊变量
__doc__
定义文档字符串
__dict__
类的属性列表
__class__
__slots__
对类的实例可以动态的绑定属性和方法,如下:
from types import MethodType def set_age(self, age): self.age = age class P(object): pass p = P() p.name = ‘chenqi‘ p.set_age = MethodType(set_age, p, P) p.set_age(31) print p.name print p.age
对一个实例添加的属性(或方法)仅在该实例有效,对其它实例不起作用。
如果想让添加的方法对所有实例都生效,可以绑定到类上:
P.set_age = MethodType(set_age, None, P)
最后,__slots__的作用就是限制对类动态绑定的属性范围,例如:
class P(object): __slots__ = ("name", "age") pass
如上,除了"name"和"age"之外的属性就不能再增加了;
注意:__slots__属性不会继承给子类,仅在当前类生效。
__init__
创建实例的时候,可以调用__init__方法做一些初始化的工作:
class Student(object): def __init__(self, name, score): self.name = name self.score = score def print_score(self): print(‘%s: %s‘ % (self.name, self.score))
与普通的实例方法类似,如果子类不重写__init__,实例化子类时,会自动调用父类的__init__;
如果子类重写了__init__,实例化子类时,则只会调用子类的__init__,此时如果想使用父类的__init__,可以使用super函数,如下:
class P(object): def __init__(self, name, score): self.name = name self.score = name class C(P): def __init__(self, name, score, age): super(C, self).__init__(name, score) self.age = age c = C(‘cq‘, 100, 31)
__new__
注意:__init__是实例创建之后调用的第一个方法,而__new__更像构造函数,它在__init__之前被调用。
另外,__new__方法是一个静态方法,第一参数是cls,__new__方法必须返回创建出来的实例。
例如,用__new__实现单例模式:
class Singleton(object): def __new__(cls): # 关键在于这,每一次实例化的时候,我们都只会返回这同一个instance对象 if not hasattr(cls, ‘instance‘): cls.instance = super(Singleton, cls).__new__(cls) return cls.instance obj1 = Singleton() obj2 = Singleton() obj1.attr1 = ‘value1‘ print obj1.attr1, obj2.attr1 print obj1 is obj2
__del__
类似析构函数。
class NewClass(object): num_count = 0 def __init__(self,name): self.name = name self.__class__.num_count += 1 print name,NewClass.num_count def __del__(self): self.__class__.num_count -= 1 print "Del",self.name,self.__class__.num_count a = NewClass("a") b = NewClass("b") c = NewClass("c") del a del b del c
注意:用del删除一个对象的时候,不一定会调用__del__,只有在对象的引用计数为零时,__del__()才会被执行。
__enter__
__exit__
这两个方法是用于支持with语句的上下文管理器。
例如让文件句柄支持with语法的实现:
class File(object): def __init__(self, file_name, method): self.file_obj = open(file_name, method) def __enter__(self): return self.file_obj def __exit__(self, type, value, traceback): self.file_obj.close() with File(‘demo.txt‘, ‘w‘) as opened_file: opened_file.write(‘Hola!‘)
__iter__
next
如果一个类想被用于for ... in
循环,类似list或tuple那样,就必须实现一个__iter__()
方法,该方法返回一个迭代对象,然后,Python的for循环就会不断调用该迭代对象的next()
方法拿到循环的下一个值,直到遇到StopIteration错误时退出循环。
class Fib(object): def __init__(self): self.a, self.b = 0, 1 # 初始化两个计数器a,b def __iter__(self): return self # 实例本身就是迭代对象,故返回自己 def next(self): self.a, self.b = self.b, self.a + self.b # 计算下一个值 if self.a > 100000: # 退出循环的条件 raise StopIteration(); return self.a # 返回下一个值
__call__
实例可以像函数一样调用。
class Student(object): def __init__(self): self.name = "Michael" def __call__(self): print ‘__call__ called‘ s = Student() s()
注意:callable()函数可用于判断一个对象是否可调用!
__str__,返回用户看到的字符串
__repr__,返回开发者看到的字符串(用于调试)
# test.py class P(object): def __str__(self): return "__str__ called" def __repr__(self): return "__repr__ called" p = P()
可以看下__str__和__repr__的区别:
>>> from test import p >>> p __repr__ called >>> print p __str__ called
__getitem__
__setitem__
__delitem__
支持下标(或切片)操作的函数,
例如:
class Fib(object): def __getitem__(self, n): if isinstance(n, int): a, b = 1, 1 for x in range(n): a, b = b, a + b return a
if isinstance(n, slice): start = n.start stop = n.stop a, b = 1, 1 L = [] for x in range(stop): if x >= start: L.append(a) a, b = b, a + b return L fib = Fib() print fib[10] print fib[0:10]
__getattr__
__getattribute__
__setattr__
__delattr__
支持点操作(即 "对象.属性" 访问方式),
当访问不存在的属性时,才会使用__getattr__ 方法.
class Student(object): def __init__(self): self.name = "Michael" def __getattr__(self, attr): print ‘__getattr__ called‘ if attr==‘score‘: return 99 elif attr==‘name‘: return "Tom" s = Student() print s.score # 99 print s.name # Michael
参考文档:
https://infohost.nmt.edu/tcc/help/pubs/python/web/special-methods.html
以上是关于【变量】关于单下划线、双下划线开头变量的含义的主要内容,如果未能解决你的问题,请参考以下文章