python基础:class 类
类是模板,而实例时根据该模板创建的对象。
类就是是字面意思的种类,它是相似特征的抽象,也就是说将具有相似特征的东西,聚集在一起通过其相似的特征抽象成一个特定的类。
以猫咪为例,猫咪都具有肉垫和肉食为主这两个特征,根据这两个特征抽象出猫类,每个猫的肉垫颜色可以不同,那么肉垫颜色就可以作为猫实例的属性;而不同肉垫颜色的猫都是肉食为主,那么主肉食就作为这一类的属性,从而定义出了一个类~猫。
一、Python中类的定义和实例的创建
在爬虫中,类通过class关键字定义,语法格式如下:
class name_of_class(object): pass #在此处添加属性和方法
注意:定义了通常都会继承object类,也可以不继承,两者区别不大,但是没有继承object类使用多继承时可能出现问题。(具体什么问题,我也不知道)
有了名为name of class的类,就可以通过其创建出具体的实例,例如:
class_1 = name_of_class()
class_2 = name_of_class()
二、python类中的实例属性和类属性
类的属性是用来表明这个类是什么的。
类的属性又分为实例属性和类属性两种:1)实例属性:用来区分不同实例;2)类属性:每个实例的共有属性;
(1)实例属性
类的属性都是用来指明这个类“是什么”,实例属性是用来区分每个实例不同的基础。
创建名为猫的类,都具有肉垫这一通用属性,为两只猫分别添加肉垫属性并赋予不同颜色:
class cat(object): pass cat1 = cat() cat2 = cat() cat1.Meat_pad = "black" # 使用实例名.属性名来访问属性 cat2.Meat_pad = "pink"
在定义cat类时,可以为cat类添加一个特殊的 __init__()方法:当创建实例时,__init__()方法呗自动调用来为创建的实例增加实例属性:
class cat(object):#创建cat类 def __init__(self,c):#初始化一c属性,self为类下所有方法的必要参数 self.c = c #表示给将要创建的实例赋予属性c赋值
相应的,创建实例时就必须要提供除self以外的参数
cat1 = cat('black') cat2 = cat('pink')
print(cat1.c)
print(cat2.c)
注意:实例名.属性名 cat1.c 访问属性,是我们上面cat类__init__() 方法中 self.c 的 c 这个实例属性名,而不是__init__(self, c)方法中的 c参数名,如下更加容易理解:
class Circle(object): # 创建Circle类 def __init__(self, C): # 约定成俗这里应该使用c,它与self.c中的c同名 self.c = C cat1 = cat('BLACK') print(circle1.c) #我们访问的是小写c
self 代表类的实例,是通过类创建的实例 (注意,在定义类时这个实例我们还没有创建,它表示的我们使用类时创建的那个实例)
(2) 类属性
绑定在实例上的属性不会影响其他实例,但类本身也是一个对象,如果在类上绑定属性,则所有实例都可以访问该类的属性,并且所有实例访问的类属性都是同一个!!!实例属性每个实例各自拥有,互相独立,而类属性有且只有一份。
圆周率π为圆的共有属性,我们可以在Circle类添加pi这个类属性,如下:
class Circle(object): pi = 3.14 # 类属性 def __init__(self, r): self.r = r circle1 = Circle(1) circle2 = Circle(2) print('----未修改前-----') print('pi=\t', Circle.pi) print('circle1.pi=\t', circle1.pi) # 3.14 print('circle2.pi=\t', circle2.pi) # 3.14 print('----通过类名修改后-----') Circle.pi = 3.14159 # 通过类名修改类属性,所有实例的类属性被改变 print('pi=\t', Circle.pi) # 3.14159 print('circle1.pi=\t', circle1.pi) # 3.14159 print('circle2.pi=\t', circle2.pi) # 3.14159 print('----通过circle1实例名修改后-----') circle1.pi=3.14111 # 实际上这里是给circle1创建了一个与类属性同名的实例属性 print('pi=\t', Circle.pi) # 3.14159 print('circle1.pi=\t', circle1.pi) # 实例属性的访问优先级比类属性高,所以是3.14111 print('circle2.pi=\t', circle2.pi) # 3.14159 print('----删除circle1实例属性pi-----')
----未修改前-----
pi= 3.14
circle1.pi= 3.14
circle2.pi= 3.14
----通过类名修改后-----
pi= 3.14159
circle1.pi= 3.14159
circle2.pi= 3.14159
----通过circle1实例名修改后-----
pi= 3.14159
circle1.pi= 3.14111
circle2.pi= 3.14159
仔细观察我们通过类创建的实例修改的类属性后,通过其他实例访问类属性他的值还是没有改变。其实是通过实例修改类属性是给实例创建了一个与类属性同名的实例属性而已,实例属性访问优先级比类属性高,所以我们访问时优先访问实例属性,它将屏蔽掉对类属性的访问。
三 Python类的实例方法
方法是用来表明这个类是用来做什么的.
在类的内部,使用def关键字来定义方法,与一般函数定义不同,类方法必须第一个参数为self,self代表的是类的实例(即你还未创建类的实例),其他参数和普通函数完全一样.
如下我们给圆类 Circle 添加求面积的方法 get_area :
class Circle(object): pi = 3.14 # 类属性 def __init__(self, r): self.r = r # 实例属性 def get_area(self): """ 圆的面积 """ # return self.r**2 * Circle.pi # 通过实例修改pi的值对面积无影响,这个pi为类属性的值 return self.r**2 * self.pi # 通过实例修改pi的值对面积我们圆的面积就会改变 circle1 = Circle(1) print(circle1.get_area()) # 调用方法 self不需要传入参数,不要忘记方法后的括号 输出 3.14
注意:示例中的 get_area(self) 就是一个方法,它的第一个参数是 self 。__init__(self, name)其实也可看做是一个特殊的实例方法。
在方法的内部需要调用实例属性采用 "self.属性名 " 调用。示例中 get_area(self) 对于 pi 属性的引用 Circle.pi 与 self.pi 存在一定区别。
Circle.pi 使用的是类属性 pi,我们通过创建的实例去修改 pi 的值对它无影响。self.pi 为实例的 pi 值,我们通过创建的实例去修改 pi 的值时,由于使用 self.pi 调用的是实例属性,所以 self.pi 是修改后的值。
四 python类中的访问限制
1.属性的访问限制,python的私有属性
Python 类中如果有属性不希望被外部访问,我们可以在属性命名时以双下划线开头( __ ),那么该属性就不能使用原变量名访问,使得该属性变为本类私有的(伪私有)。
但,如果一个属性以"__xxx__"的形式定义,那么它可以被外部访问。
以"__xxx__"定义的属性在 Python 的类中是特殊属性,有很多预定义的特殊属性都是以“__xxx__”定义,所以我们不要把普通属性用"__xxx__" 定义。
以单下划线开头的属性"_xxx",虽然也可以被外部访问,但,按照习惯,他们不应该被外部访问,遵照编码规范我们也不该在外部访问 _xx 或 __xx 属性。
补充说明:加双下划线__xx 的属性,可以通过“ _类名__xx ”可以访问到属性的值。
如下圆类Circle的示例,我们将pi属性开头加上双下划线变成私有属性:
class Circle(object): __pi = 3.14 def __init__(self, r): self.r = r def area(self): """ 圆的面积 """ return self.r **2* self.__pi circle1 = Circle(1) print(Circle.__pi) # 抛出AttributeError异常 print(circle1.__pi) # 抛出AttributeError异常
通过 Circle.__pi 与 circle1.__pi 访问 __pi 时 都会出现 AttributeError 异常,证明访问权限已被控制。
那么是不是我们就不能访问 __pi 变量?
不是,其实还是可以访问 __pi ,可以通过 Circle._Circle__pi 访问到 __pi 属性,为什么能这么访问这里不多讲,他与python的机制有关。
按照编码规范,他们不应该使用Circle._Circle__pi 访问到__pi属性。
2.方法的访问限制,python私有访问
同属性的访问限制,方法的访问限制也是在方法名前加双下划线 ( __ ),它也是一种伪私有。
class Circle(object): __pi = 3.14 def __init__(self, r): self.r = r def area(self): """ 圆的面积 """ return self.r**2 * self.__pi def __girth(self): """ 圆的周长 """ return 2*self.r * self.__pi circle1 = Circle(2) print(circle1.__girth()) # 抛出AttributeError异常
同属性控制,方法需要访问被限制的方法也是 _类名__xx 如 circle1._Circle__girth()。
四 Python类中的@classmethod、@staticmethod 装饰方法(比较难,需要理解)
@classmethod 用来修饰方法。使用在实例化前与类进行交互,但不和其实例进行交互的函数方法上。
@staticmethod 用来修饰类的静态方法。使用在有些与类相关函数,但不使用该类或该类的实例。如更改环境变量、修改其他类的属性等。
两者最明显的区别,classmethod 必须使用类的对象作为第一个参数,而staticmethod则可以不传递任何参数

浙公网安备 33010602011771号