Python 变量和函数传参

类变量和实例变量

通过下面的例子说明类变量和实例变量的区别与访问权限说明:当类变量和成员变量前面是__开头时,一种python的约定为不能在外部访问该类变量或者成员变量,因为Python解释器会把该变量前面加上 _Foo(Foo为类名)当做成员变量的名称,但是我们按照这样的方式( _Foo__cls_name )还是可以访问

class Foo(object):                                                                                                                                             
    cls_name = "Python"
    cls_dict = {"age":10}
    _cls_name = "C++"
    _cls_dict = {"age":20}
    __cls_name = "Java"
    __cls_dict = {"age":30}

    def __init__(self):
        self.sel_name = "C" 
        self.sel_dict = {"age":40}
        self._sel_name = "Perl"
        self._sel_dict = {"age":50}
        self.__sel_name = "C#"
        self.__sel_dict = {"age":60}
        print Foo.cls_name
        print Foo.cls_dict
        print Foo._cls_name
        print Foo._cls_dict
        print Foo.__cls_name
        print Foo.__cls_dict
        print self.cls_name
        print self.cls_dict
        print self._cls_name
        print self._cls_dict
        print self.__cls_name
        print self.__cls_dict

        #Error:  Class 'Foo' has no '__sel_dict' member; maybe '_sel_dict'
        #print Foo.sel_name 
        #print Foo.sel_dict
        #print Foo._sel_name
        #print Foo._sel_dict
        #print Foo.__sel_name
        #print Foo.__sel_dict
        print self.sel_name
        print self.sel_dict
        print self._sel_name
        print self._sel_dict
f = Foo()
print Foo.cls_name
print Foo.cls_dict
print Foo._cls_name
print Foo._cls_dict
#Error :type object 'Foo' has no attribute '__cls_name'
#print Foo.__cls_name
#print Foo.__cls_dict

print f.cls_name
print f.cls_dict
print f._cls_name
print f._cls_dict
#Error: 'Foo' object has no attribute '__cls_name'
#print f.__cls_name
#print f.__cls_dict

print Foo._Foo__cls_name
print Foo._Foo__cls_dict
print f._Foo__cls_name
print f._Foo__cls_name

print f.sel_name
print f.sel_dict
print f._sel_name
print f._sel_dict
#Error: 'Foo' object has no attribute '__sel_name'
#print f.__sel_name
#print f.__sel_dict

print f._Foo__sel_name
print f._Foo__sel_dict

尝试修改类变量和成员变量:
结论是当修改了类变量后,后面申明的实例访问的也是改变后的类变量,因为类变量在内存中只会存在一份。然而实例变量作用域为单个实例,它表明每一个实例的变量内存空间不一样。

class Foo(object):                                                                                                                                             

    cls_name = "Python"
    cls_dict = {"age":10}
    _cls_name = "C++"
    _cls_dict = {"age":20}
    __cls_name = "Java"
    __cls_dict = {"age":30}

    def __init__(self):
        self.sel_name = "C" 
        self.sel_dict = {"age":40}
        self._sel_name = "Perl"
        self._sel_dict = {"age":50}
        self.__sel_name = "C#"
        self.__sel_dict = {"age":60}

    def cls_func(self, keys):
        Foo.cls_name = "Python_change"
        Foo.cls_dict[keys] = 100 
        Foo._cls_name = "C++_change"
        Foo._cls_dict[keys] = 200 
        Foo.__cls_name = "Java_change"
        Foo.__cls_dict[keys] = 300 

    def sel_func(self, keys):
        self.sel_name = "Python_sel_change"
        self.sel_dict[keys] = 1000
        self._sel_name = "C++_sel_change"
        self._sel_dict[keys] = 2000
        self.__sel_name = "Java_sel_change"
        self.__sel_dict[keys] = 3000
f = Foo()
f.cls_func("age1")
print Foo.cls_name
print Foo.cls_dict
print Foo._cls_name
print Foo._cls_dict
#Error:type object 'Foo' has no attribute '__cls_name'
#print Foo.__cls_name
#print Foo.__cls_dict
print f.cls_name
print f.cls_dict
print f._cls_name
print f._cls_dict
#Error: 'Foo' object has no attribute '__cls_name'
#print f.__cls_name
#print f.__cls_dict

f2 = Foo()
f2.cls_func("age2")
print f2.cls_name
print f2.cls_dict
print f2._cls_name
print f2._cls_dict
print f2._Foo__cls_name
print f2._Foo__cls_dict

f.sel_func("age1")
print f.sel_name
print f.sel_dict
print f._sel_name
print f._sel_dict
print f._Foo__sel_name
print f._Foo__sel_dict

f2.sel_func("age2")
print f2.sel_name
print f2.sel_dict
print f2._sel_name
print f2._sel_dict
print f2._Foo__sel_name
print f2._Foo__sel_dict
>>Python_change
{'age': 10, 'age1': 100}
C++_change
{'age': 20, 'age1': 200}
Java_change
{'age': 30, 'age1': 300}
Python_change
{'age': 10, 'age1': 100}
C++_change
{'age': 20, 'age1': 200}
Java_change
{'age': 30, 'age1': 300}
Python_change
{'age': 10, 'age2': 100, 'age1': 100}
C++_change
{'age': 20, 'age2': 200, 'age1': 200}
Java_change
{'age': 30, 'age2': 300, 'age1': 300}
Python_sel_change
{'age': 40, 'age1': 1000}
C++_sel_change
{'age': 50, 'age1': 2000}
Java_sel_change
{'age': 60, 'age1': 3000}
Python_sel_change
{'age': 40, 'age2': 1000}
C++_sel_change
{'age': 50, 'age2': 2000}
Java_sel_change
{'age': 60, 'age2': 3000}

当继承父类的类成员变量时,子类继承来可变对象的在子类修改也会影响到父类,因此可以将类成员变量看成是类的父类以及其子类独有的存在,就像类的全局变量:

class A():                                                                                                                                                     
    cls_name = "Python"
    cls_list = [1,2]

class B(A):
    def cls_func(self, age):
        B.cls_list.append(age)

b = B() 
print b.cls_name
print b.cls_list
b.cls_func(3)
print b.cls_list
print A.cls_list
a = A() 
print a.cls_list

>>Python
[1, 2]
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]

函数参数传递

Python 里面的对象分为可变对象和不可变对象
可变对象:list,dict。
不可变对象:int,string,float,tuple。
当函数定义时如果传递的是不可变对象就是值传递,比如:

def func(a):
    a = a + 10
    print a
b = 11
func(b)
print b
>>21
11

以上例子说明b并未被函数修改,说明传递的数据为不可变对象的时候是值传递。
当传递的是可变对象时,就是传递的应用,比如:

def func(list_a):
    list_a.append(10)
    print list_a
l = [1,2,3]
func(l)
print l
>>[1,2,3,10]
[1,2,3,10]

以上例子说明当传递一个可变对象list,并且在函数体内部修改了该可变对象,那么该对象会影响到外部传递的那个list对象。

python中应该避免将可变对象作为函数参数的默认值

在python中函数也是对象,它的参数就是它的成员变量,当你把可变对象当做函数参数的默认值时会导致的问题就是如果你在函数体中有增删查改这个可变对象的代码,那么当你多次调用时会发现这个可变对象是连续变化的。如:

def func(ages=[7, 8], age=None):
    ages.append(age)
    return a
b = func(age=10)
c = func(age=11)
d = func(age=12)
print b
print c
print d
>>[7, 8, 10]
[7, 8, 10, 11]
[7, 8, 10, 11, 12]

你会发现这个函数失去了你想要达到的目的,产生这个现象的原因是func函数的可变对象a只会有一个定义,每次调用它时都会使用这个对象a的引用,那么多次调用该函数就出现了上面的结果。
修改:

def func(a=None, age=None):                                                                                                                                    
    if a is None:
        a = [7, 8]
    a.append(age)
    return a
b = func(age=10)
c = func(age=11)
d = func(age=12)
print b
print c
print d
>>[7, 8, 10]
[7, 8, 11]
[7, 8, 12]