一、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则可以不传递任何参数
1、@classmethod 类方法
类方法,我们不用通过实例化类就能访问的方法。而且@classmethod 装饰的方法不能使用实例属性,只能是类属性。它主要使用在和类进行交互,但不和其实例进行交互的函数方法上。
下面,我们要写一个只在类中运行而不在实例中运行的方法。
简单示例,读取私有化类属性数据,如下:
class Circle(object):
__pi = 3.14
def __init__(self, r):
self.r = r
@classmethod
def pi(cls):
return cls.__pi
def area(self):
"""圆的面积"""
return self.r ** 2 * self.__pi
print(Circle.pi()) # 没有实例化 能直接访问pi() 方法
circle1 = Circle(2)
print(circle1.pi()) # 也可以通过实例访问pi()方法Circle类下的pi()方法被 @classmethod 装饰后,我们能通过Circle.pi() 直接运行方法,不用实例化类。
示例:重构构造__init__() 方法应用, 格式化创建时间实例
class Date(object):
day = 0
month = 0
year = 0
def __init__(self, year=0, month=0, day=0):
self.day = day
self.month = month
self.year = year
@classmethod
def from_string(cls, date_as_string):
year, month, day = date_as_string.split('-')
date = cls(year, month, day)
return date
date1 = Date.from_string('2017-10-17') # 直接使用固定格式的字符串就能创建Date的实例
print(date1.year, date1.month, date1.day)from_string 返回的是Date类的实例,所以我们可以通过from_string 实例化类。
注意:from_string(cls, date_as_string)中cls表示的是类,它和self类实例有一定的差别。类方法中都是使用cls,实例方法中使用self。
2、@staticmethod 静态方法
@staticmethod 和@classmethod非常的相似,但是@staticmethod 不强制要求传递参数(它做的事与类方法或实例方法一样)。
@staticmethod使用在有些和类相关函数,但不使用该类或者该类的实例。如更改环境变量、修改其他类的属性等。
一句话@staticmethod 修饰的方法是放在类外的函数,我们为了方便将他移动到了类里面,它对类的运行无影响。
示例:
class Date(object):
day = 0
month = 0
year = 0
def __init__(self, year=0, month=0, day=0):
self.day = day
self.month = month
self.year = year
@classmethod
def from_string(cls, date_as_string):
year, month, day = date_as_string.split('-')
date = cls(year, month, day)
return date
@staticmethod
def is_date_valid(date_as_string):
"""用来校验日期的格式是否正确"""
year, month, day = date_as_string.split('-')
return int(year) <&#61; 3999 and int(month) <&#61; 12 and int(day) <&#61; 31
date1 &#61; Date.from_string(&#39;2012-05-10&#39;)
print(date1.year, date1.month, date1.day)
is_date &#61; Date.is_date_valid(&#39;2012-09-18&#39;) # 格式正确 返回True
is_date_valid(date_as_string) 只有一个参数&#xff0c;它的运行不会影响类的属性&#xff0c;注意&#xff1a;&#64;staticmethod修饰方法 is_date_valid(date_as_string)中无实例化参数self或者cls&#xff1b;而&#64;classmethod修饰的方法中有from_string(cls, date_as_string) 类参数cls。
三、Python 的 property 使用
property 的有两个作用作为装饰器 &#64;property 将类方法转换为类属性&#xff08;只读&#xff09;
property 重新实现一个属性的 setter 和 getter 方法
1、&#64;property 将类方法转换为只读属性&#xff08;常用&#xff09;
使用 property 的最简单的方法是将它作为装饰器来使用。这可以让你将一个类方法转变成一个类属性。
示例&#xff1a;
class Circle(object):
__pi &#61; 3.14
def __init__(self, r):
self.r &#61; r
&#64;property
def pi(self):
return self.__pi
circle1 &#61; Circle(2)
print(circle1.pi)
circle1.pi&#61;3.14159 # 出现AttributeError异常上面示例装饰了pi方法&#xff0c;创建实例后我们可以使用circle1.pi 自己获取方法的返回值&#xff0c;而且他只能读不能修改。
2、property 重新实现 setter 和 getter 方法&#xff08;少用&#xff09;
示例1&#xff1a;&#xff08;用得较少&#xff09;
class Circle(object):
__pi &#61; 3.14
def __init__(self, r):
self.r &#61; r
def get_pi(self):
return self.__pi
def set_pi(self, pi):
Circle.__pi &#61; pi
pi &#61; property(get_pi, set_pi)
circle1 &#61; Circle(2)
circle1.pi &#61; 3.14 # 设置 pi的值
print(circle1.pi) # 访问 pi的值正如你所看到的&#xff0c;当我们以这种方式使用属性函数时&#xff0c;它允许pi属性设置并获取值本身而不破坏原有代码。让我们使用属性装饰器来重写这段代码&#xff0c;看看我们是否能得到一个允许设置的属性值。
示例2&#xff1a;&#xff08;用得比示例1多&#xff09;
class Circle(object):
__pi &#61; 3.14
def __init__(self, r):
self.r &#61; r
&#64;property
def pi(self):
return self.__pi
&#64;pi.setter
def pi(self, pi):
Circle.__pi &#61; pi
circle1 &#61; Circle(2)
circle1.pi &#61; 3.14 # 设置 pi的值
print(circle1.pi) # 访问 pi的值
把一个方法变成属性&#xff0c;只需要加上 &#64;property 就可以了&#xff0c;如上此时 pi(self) 方法&#xff0c;&#64;property 本身又创建了另一个装饰器 &#64;pi.setter&#xff0c;负责用 setter 方法给属性赋值&#xff0c;于是&#xff0c;将&#64;pi.setter加到 pi(self, pi) 上&#xff0c;我们就拥有一个可控的属性操作。
Python 类入门
2020年4月15日 第一次修改&#xff0c;内容优化