zl程序教程

您现在的位置是:首页 >  后端

当前栏目

转载(Python入门 类class提高篇)

Python入门 提高 转载 Class
2023-09-27 14:25:31 时间

转载于知乎:Python入门 类class提高篇

一、python类中的访问限制(常用)

1、属性的访问限制,Python私有属性

Python类中有很多属性,如果有些属性不希望被外部访问,我们可以属性命名时以双下划线开头(__),该属性不能使用原变量名访问,使属性变为私有的(伪私有)。

但,如果一个属性以"__xxx__"的形式定义,那么它可以被外部访问。以"__xxx__"定义的属性在Python的类中被称为特殊属性,有很多预定义的特殊属性是以“__xxx__”定义,所以我们不要把普通属性用"__xxx__"定义。

以单下划线开头的属性"_xxx"虽然也可以被外部访问,但是,按照习惯,他们不应该被外部访问,遵照编码规范我们也不该在外部访问 _xx 或 __xx 属性。

说明:加双下划线__xx 的属性,可以通过“ _类名__xx ”可以访问到属性的值。

如下圆类Circle的示例,我们将pi属性开头加上双下划线变成私有属性:

 1 class Circle(object):
 2    __pi = 3.14
 3 
 4    def __init__(self, r):
 5        self.r = r
 6 
 7    def area(self):
 8        """
 9 圆的面积
10        """
11        return self.r **2* self.__pi
12 
13 circle1 = Circle(1)
14 print(Circle.__pi)  # 抛出AttributeError异常
15 print(circle1.__pi)  # 抛出AttributeError异常

通过 Circle.__pi 与 circle1.__pi 访问 __pi 时 都会出现 AttributeError 异常,证明访问权限已被控制。

那么是不是我们就不能访问 __pi 变量?

不是,其实还是可以访问 __pi ,可以通过 Circle._Circle__pi 访问到 __pi 属性,为什么能这么访问这里不多讲。

按照编码规范,他们不应该使用Circle._Circle__pi 访问到__pi属性。

 

2、方法的访问限制,Python私有访问

同属性的访问限制,方法的访问限制也是在方法名前加双下划线(__),它也是一种伪私有。

示例:

 1 class Circle(object):
 2    __pi = 3.14
 3 
 4    def __init__(self, r):
 5        self.r = r
 6 
 7    def area(self):
 8        """
 9 圆的面积
10        """
11        return self.r**2 * self.__pi
12 
13    def __girth(self):
14        """
15 圆的周长
16        """
17        return 2*self.r * self.__pi
18 
19 circle1 = Circle(2)
20 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) <= 3999 and int(month) <= 12 and int(day) <= 31

date1 = Date.from_string('2012-05-10')
print(date1.year, date1.month, date1.day)
is_date = Date.is_date_valid('2012-09-18') # 格式正确 返回True

is_date_valid(date_as_string) 只有一个参数,它的运行不会影响类的属性,

注意:@staticmethod修饰方法 is_date_valid(date_as_string)中无实例化参数self或者cls;而@classmethod修饰的方法中有from_string(cls, date_as_string) 类参数cls。

三、Python 的 property使用

property的有两个作用

  • 作为装饰器 @property将类方法转换为类属性(只读)
  • property重新实现一个属性的setter和getter方法

1、@property将类方法转换为只读属性(常用)

使用property的最简单的方法是将它作为装饰器来使用。这可以让你将一个类方法转变成一个类属性。

示例:

class Circle(object):
   __pi = 3.14

   def __init__(self, r):
       self.r = r

   @property
   def pi(self):
       return self.__pi

circle1 = Circle(2)
print(circle1.pi)
circle1.pi=3.14159  # 出现AttributeError异常

上面示例装饰了pi方法,创建实例后我们可以使用circle1.pi 自己获取方法的返回值,而且他只能读不能修改。

2、property重新实现setter和getter方法(少用)

示例1:(用得较少)

class Circle(object):
   __pi = 3.14

   def __init__(self, r):
       self.r = r

   def get_pi(self):
       return self.__pi

   def set_pi(self, pi):
       Circle.__pi = pi

   pi = property(get_pi, set_pi)

circle1 = Circle(2)
circle1.pi = 3.14  # 设置 pi的值
print(circle1.pi)  # 访问 pi的值

正如你所看到的,当我们以这种方式使用属性函数时,它允许pi属性设置并获取值本身而不破坏原有代码。让我们使用属性装饰器来重写这段代码,看看我们是否能得到一个允许设置的属性值。

示例2:(用得比示例1多)

class Circle(object):
   __pi = 3.14

   def __init__(self, r):
       self.r = r

   @property
   def pi(self):
       return self.__pi

   @pi.setter
   def pi(self, pi):
       Circle.__pi = pi

circle1 = Circle(2)
circle1.pi = 3.14  # 设置 pi的值
print(circle1.pi)  # 访问 pi的值

把一个getter方法变成属性,只需要加上@property就可以了,如上此时pi(self)方法,@property本身又创建了另一个装饰器@pi.setter,负责把一个setter方法变成属性赋值,于是,将@pi.setter加到pi(self, pi)上,我们就拥有一个可控的属性操作。

 

REF:

 

Python's Instance, Class, and Static Methods Demystified

Python OOP Tutorial 3: classmethods and staticmethods

正确理解Python中的 @staticmethod@classmethod方法

Python's @classmethod and @staticmethod Explained