python类:class创建、数据⽅法属性及访问控制详解在Python中,可以通过class关键字定义⾃⼰的类,然后通过⾃定义的类对象类创建实例对象。
python中创建类
创建⼀个Student的类,并且实现了这个类的初始化函数”__init__”:
class Student(object):
count = 0
books = []
def __init__(self, name):
self.name = name
接下来就通过上⾯的Student类来看看Python中类的相关内容。
类构造和初始化
”__init__”和”__new__”的联系和差别
下⾯先通过⼀段代码看看这两个⽅法的调⽤顺序:
class A(object):
def __init__(self,*args, **kwargs):
print "init %s" %self.__class__
def __new__(cls,*args, **kwargs):
print "new %s" %cls
return object.__new__(cls, *args, **kwargs)
a = A()
从代码的输出可以看到,当通过类实例化⼀个对象的时候,”__new__”⽅法⾸先被调⽤,然后是”__init__”⽅法。
⼀般来说,”__init__”和”__new__”函数都会有下⾯的形式:
def__init__(self,*args,**kwargs):
# func_suite
def__new__(cls,*args,**kwargs):
# func_suite
returnobj
对于”__new__”和”__init__”可以概括为:
•“__new__”⽅法在Python中是真正的构造⽅法(创建并返回实例),通过这个⽅法可以产⽣⼀个”cls”对应的实例对象,所以说”__new__”⽅法⼀定要有返回
•对于”__init__”⽅法,是⼀个初始化的⽅法,”self”代表由类产⽣出来的实例对象,”__init__”将对这个对象进⾏相应的初始化操作
__new__特性
“__new__”是在新式类中新出现的⽅法,它有以下⾏为特性:
•“__new__” ⽅法是在类实例化对象时第⼀个调⽤的⽅法,将返回实例对象
•“__new__” ⽅法始终都是类的静态⽅法(即第⼀个参数为cls),即使没有被加上静态⽅法装饰器
•第⼀个参数cls是当前正在实例化的类,如果要得到当前类的实例,应当在当前类中的 “__new__” ⽅法语句中调⽤当前类的⽗类的” __new__” ⽅法
对于上⾯的第三点,如果当前类是直接继承⾃ object,那当前类的 “__new__” ⽅法返回的对象应该为:
def __new__(cls, *args, **kwargs):
# func_suite
return object.__new__(cls, *args, **kwargs)
重写__new__
如果(新式)类中没有重写”__new__”⽅法,Python默认是调⽤该类的直接⽗类的”__new__”⽅法来构造该类的实例,如果该类的⽗类也没有重写”__new__”,那么将⼀直按照同样的规则追溯⾄object的”__n
ew__”⽅法,因为object是所有新式类的基类。
⽽如果新式类中重写了”__new__”⽅法,那么可以选择任意⼀个其他的新式类(必须是新式类,只有新式类有”__new__”,因为所有新式类都是从object派⽣)的”__new__”⽅法来创建实例,包括这个新式类的所有前代类和后代类,只要它们不会造成递归死循环。
看⼀段例⼦代码:
classFoo(object):
def__new__(cls,*args,**kwargs):
obj=object.__new__(cls,*args,**kwargs)
# 这⾥的object.__new__(cls, *args, **kwargs)  等价于
# super(Foo, cls).__new__(cls, *args, **kwargs)
# object.__new__(Foo, *args, **kwargs)
# Bar.__new__(cls, *args, **kwargs)
# Student.__new__(cls, *args, **kwargs),即使Student跟Foo没有关系,也是允许的,因为Student是从object派⽣的新式类
# 在任何新式类,不能调⽤⾃⾝的“__new__”来创建实例,因为这会造成死循环
# 所以要避免return Foo.__new__(cls, *args, **kwargs)或return cls.__new__(cls, *args, **kwargs)
print"Call __new__ for %s"%obj.__class__
returnobj
classBar(Foo):
def__new__(cls,*args,**kwargs):
obj=object.__new__(cls,*args,**kwargs)
print"Call __new__ for %s"%obj.__class__
returnobj
classStudent(object):
# Student没有“__new__”⽅法,那么会⾃动调⽤其⽗类的“__new__”⽅法来创建实例,即会⾃动调⽤ object.__new__(cls)
pass
classCar(object):
def__new__(cls,*args,**kwargs):
# 可以选择⽤Bar来创建实例
obj=object.__new__(Bar,*args,**kwargs)
print"Call __new__ for %s"%obj.__class__
returnobj
foo=Foo()
bar=Bar()
car=Car()
代码的输出为:
__init__的调⽤
“__new__”决定是否要使⽤该类的”__init__”⽅法,因为”__new__” 可以调⽤其他类的构造⽅法或者直接返回别的类创建的对象来作为本类的实例。
通常来说,新式类开始实例化时,”__new__”⽅法会返回cls(cls指代当前类)的实例,然后调⽤该类的”__init__”⽅法作为初始化⽅法,该⽅法接收这个实例(即self)作为⾃⼰的第⼀个参数,然后依次传⼊”__new__”⽅法中接收的位置参数和命名参数。
但是,如果”__new__”没有返回cls(即当前类)的实例,那么当前类的”__init__”⽅法是不会被调⽤的。
例⼦:
class A(object):
def __init__(self, *args, **kwargs):
print "Call __init__ from %s" %self.__class__
def __new__(cls, *args, **kwargs):
obj = object.__new__(cls, *args, **kwargs)
print "Call __new__ for %s" %obj.__class__
return obj
class B(object):
def __init__(self, *args, **kwargs):python的类怎么输出printf
print "Call __init__ from %s" %self.__class__
def __new__(cls, *args, **kwargs):
obj = object.__new__(A, *args, **kwargs)
print "Call __new__ for %s" %obj.__class__
return obj
b = B()
print type(b)
代码中,在B的”__new__”⽅法中,通过”obj = object.__new__(A, *args, **kwargs)”创建了⼀个A的实例,在这种情况下,B 的”__init__”函数就不会被调⽤到。
派⽣不可变类型
关于”__new__”⽅法还有⼀个重要的⽤途就是⽤来派⽣不可变类型。
例如,Python中float是不可变类型,如果想要从float中派⽣⼀个⼦类,就要实现”__new__”⽅法:
classRound2Float(float):
def__new__(cls,num):
num=round(num,2)
#return super(Round2Float, cls).__new__(cls, num)
returnfloat.__new__(Round2Float,num)
f=Round2Float(4.14159)
printf
代码中从float派⽣出了⼀个Round2Float类,该类的实例就是保留⼩数点后两位的浮点数。
通过内建函数dir(),或者访问类的字典属性__dict__,这两种⽅式都可以查看类有哪些属性。
数据属性
类数据属性和实例数据属性
在上⾯的Student类中,”count”"books”"name”和”age”都被称为类的数据属性,但是它们⼜分为类数据属性和实例数据属性。
类变量紧接在类名后⾯定义,相当于java和c++的static变量
实例变量在__init__⾥定义,相当于java和c++的普通变量
>>> class test:
count = 0;类变量
def __init__(self, c):
self.__class__.count = self.__class__.count + 1;
>>> a = test(3)
>>> a.count
3
>>> unt
1
对于类数据属性和实例数据属性,可以总结为:
1.类数据属性属于类本⾝,可以通过类名进⾏访问/修改
2.类数据属性也可以被类的所有实例访问/修改
3.在类定义之后,可以通过类名动态添加类数据属性,新增的类属性也被类和所有实例共有
4.实例数据属性只能通过实例访问
5.在实例⽣成后,还可以动态添加实例数据属性,但是这些实例数据属性只属于该实例
特殊的类属性
对于所有的类,都有⼀组特殊的属性:
类属性含义
__name__类的名字(字符串)
__doc__类的⽂档字符串
__bases__类的所有⽗类组成的元组
__dict__类的属性组成的字典
__module__类所属的模块
__class__类对象的类型
Note:⽂档字符串对于类,函数/⽅法,以及模块来说是唯⼀的,也就是说__doc__属性是不能从⽗类中继承来的。属性隐藏
从上⾯的介绍了解到,类数据属性属于类本⾝,被所有该类的实例共享;并且,通过实例可以去访问/修改类属性。但是,在通过实例中访问类属性的时候⼀定要谨慎,因为可能出现属性”隐藏”的情况。
继续使⽤上⾯的Student类,来看看属性隐藏:
wilber = Student("Wilber", 28)
print "unt unt: ", unt unt
print "unt unt: ", unt unt
print Student.__dict__
print wilber.__dict__
unt
print "unt unt: ", unt unt
print
print "unt unt: ", unt unt
print Student.__dict__
print wilber.__dict__
unt
print
print "Student.books is wilber.books: ", Student.books is wilber.books
wilber.books = ["C#", "Python"]
print "Student.books is wilber.books: ", Student.books is wilber.books
print Student.__dict__
print wilber.__dict__
del wilber.books
print "Student.books is wilber.books: ", Student.books is wilber.books
print
wilber.books.append("CSS")
print "Student.books is wilber.books: ", Student.books is wilber.books
print Student.__dict__
print wilber.__dict__
代码的输出为:
分析⼀下上⾯代码的输出:
•对于不可变类型的类属性unt,可以通过实例wilber进⾏访问,并且”unt unt”
•当通过实例赋值/修改count属性的时候,都将为实例wilber新建⼀个count实例属性,这时,”unt is not
•当通过”unt”语句删除实例的count属性后,再次成为”unt unt”
•同样对于可变类型的类属性Student.books,可以通过实例wilber进⾏访问,并且”Student. books is wilber. books”
•当通过实例赋值books属性的时候,都将为实例wilber新建⼀个books实例属性,这时,”Student. Books is not wilber. books”•当通过”del wilber. books”语句删除实例的books属性后,再次成为”Student. books is wilber. books”
•当通过实例修改books属性的时候,将修改wilber.books指向的内存地址(即Student.books),此时,”Student. Books is wilber. books”
Note: 虽然通过实例可以访问类属性,但是,不建议这么做,最好还是通过类名来访问类属性,从⽽避免属性隐藏带来的不必要⿇烦。
⽅法
在⼀个类中,可能出现三种⽅法,实例⽅法、静态⽅法和类⽅法,下⾯来看看三种⽅法的不同。
实例⽅法
实例⽅法的第⼀个参数必须是”self”,”self”类似于C++中的”this”。
实例⽅法只能通过类实例进⾏调⽤,这时候”self”就代表这个类实例本⾝。通过”self”可以直接访问实例的属性。
类⽅法
类⽅法以cls作为第⼀个参数,cls表⽰类本⾝,定义时使⽤@classmethod装饰器。通过cls可以访问类的相关属性。
class Student(object):
'''
this is a Student class
'''
count = 0
books = []
def __init__(self, name, age):
self.name = name
self.age = age
@classmethod
def printClassInfo(cls):
print cls.__name__

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。