python TabError 不报错 python attributeerror str_类属性

在Python类中,有属性和方法。外部代码可以直接通过实例来访问修改。

如果需要让内部的属性不被外部访问到,在属性变量前面加上2个下划线:“__”。

在python中,实例的变量名如果是由2个下划线开头的,就代表这是一个私有变量:只有内部可以访问,外部不许直接通过类或者实例访问。

class F:
   __name = "xurui"

f = F()
f.__name
F.__name 

# 报错
AttributeError: type object 'F' has no attribute '__name'

虽然说外部访问不了一个内部私有属性,但是可以通过类中方法间接的访问、修改。比如类内部方法get_name和set_name:

class F:
   __name = "xurui"   
             
   def get_name(self):
       return self.__name,self


   def set_name(self,name):
       self.__name = name
       return self.__name,self

f = F() # 类中self,都是f这实例对象.
res = f.getName()
print(res,f)
result = f.setName("zhangsan")
print(result,f)

结果:
('xurui', <__main__.F object at 0x0000000000BAA048>) <__main__.F object at 0x0000000000BAA048>
('zhangsan', <__main__.F object at 0x0000000000BAA048>) <__main__.F object at 0x0000000000BAA048>

双下划线开头的私有属性,是不是一定不能从外部访问呢?

其实不是的:

python中2个有趣的现象,外部变量遮蔽类中的变量。

从实例中访问类属性必须要谨慎。

和通常python变量一样,任何对实例属性的赋值都会创建一个实例属性(如果实例属性不存在的话),并且对其赋值。

但是,如果类属性中存在同名的属性,就是产生前面所说的有趣的副作用。

python3.x依旧存在这个情况,下面上代码:

class Foo:
   x = 10

f = Foo()
print("原始数据 通过实例访问:{},通过类访问:{}".format(f.x,Foo.x))

f.x = f.x+10
print("f.x增加10后 通过实例访问:{},通过类访问:{}".format(f.x,Foo.x))

del f.x
print("del干掉f.x后 通过实例访问:{},通过类访问:{}".format(f.x,Foo.x))
# 说明
# 代码创建了一个f.x新的实例属性,它覆盖了对类属性的引用
# 然而, 类属性本身没有受到影响, 仍然存在类域中,还可以通过类属性来访问到
# 给一个与类属性同名的实例属性赋值,我们会有效的遮蔽类属性
# 一旦我们删除了这个实例属性,类属性又重现天日.

结果:
原始数据 通过实例访问:10,通过类访问:10
f.x增加10后 通过实例访问:20,通过类访问:10
del干掉f.x后 通过实例访问:10,通过类访问:10
class Foo:
   x = {"k1" : 10}

f = Foo()
print("原始数据 通过实例访问:{},通过类访问:{}".format(f.x,Foo.x))

f.x["k1"] = 20
print("f.x值变20后 通过实例访问:{},通过类访问:{}".format(f.x,Foo.x))

del f.x
print("del干掉f.x后 通过实例访问:{},通过类访问:{}".format(f.x,Foo.x))

结果:
Traceback (most recent call last):
AttributeError: x

原始数据 通过实例访问:{'k1': 10}, 通过类访问:{'k1': 10}
f.x值变20后 通过实例访问:{'k1': 20}, 通过类访问:{'k1': 20}

为什么下面的dict类型的就会del报错呢??

原因在于:
Python是由C写成的CPython。

C语言中,并没有字符串这个概念:C中叫做字符数组,存储在内存中,是一块连续的空间,不可修改,任何修改字符数组的行为,都会在不影响原始的字符数组下,创建产生一个新的字符数组。

而dict就不一样了,它在内存中存储,是一系列非连续的内存空间,可以在原来的基础上修改,所以,第二个例子中del f.x就会报错。