4

Python 简明教程 --- 20,Python 类中的属性与方法

 2 years ago
source link: https://codeshellme.github.io/2020/06/python-learn20/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

微信公众号:码农充电站pro

个人主页:https://codeshellme.github.io

与客户保持良好的关系可以使生产率加倍。

—— Larry Bernstain

目录

类中的变量称为属性,类中的函数称为方法

类中的属性分为:

  • 实例属性:对象所有,互不干扰
  • 类属性:类所有,所有对象共享

类中的方法分为:

  • 实例方法:定义中有self 参数
  • 类方法:定义中有cls 参数,使用@classmethod 装饰器
  • 静态方法:定义中即没有self 参数,也没有cls 参数,使用@staticmethod 装饰器

1,实例属性与类属性

类的对象,就是类的一个实例。类的实例属性被对象所有,包含在每个对象之中,不同的对象之间,互不干扰。类的类属性被类所有,被包含在类中,是所有的类对象共享。

一般情况下,实例属性会在__init__ 方法中声明并初始化,并且使用self 来绑定。而类属性是在类作用域中被声明,并且不使用self 来绑定。

例如下面代码中,country 为类属性,__name 为实例属性:

#! /usr/bin/env python3
class People:
country = 'china'
def __init__(self, name):
self.__name = name

访问实例属性时使用对象.属性名的格式,实例属性属于对象各自的,互不影响:

>>> p1 = People('小明')
>>> p2 = People('小美')
>>>
>>> p1.get_name()
>>> p2.get_name()

类属性被所有对象共有,一旦被改变,所有对象获取到的值都会被改变。访问类属性时使用类名.属性名的格式,也可以使用对象.属性名的格式来访问:

>>> People.country # 用`类名.属性名`的格式访问
'CHINA'
>>> p1.country # 用`对象.属性名`的格式访问
'china'
>>> p2.country
'china'
>>>
>>> People.country = 'CHINA' # 类属性的值被改变
>>> p1.country # 每个对象获取到的值也会被改变
'CHINA'
>>> p2.country
'CHINA'

注意,在使用对象.属性名的格式访问对象时,不要以这种格式对类属性进行赋值,否则结果可能不会像你想象的一样:

>>> p1 = People('小明')
>>> p2 = People('小美')
>>> People.country
'china'
>>> p1.country
'china'
>>> p2.country
'china'
>>> p1.country = '中国' # 使用`对象.属性名`的格式对类对象进行赋值
>>> p1.country # 只有 p1.country 被改变
>>> p2.country # p2.country 没有被改变
'china'
>>> People.country # People.country 也没有被改变
'china'

从上面代码中可以看到,在Python 中以对象.属性名格式对类属性进行赋值时,只有p1.country 的值被改变了,p2.countryPeople.country 的值都没有被改变。

实际上,这种情况下,类属性的值并没有被改变,而是对象p1 中多了一个country 实例属性,此后,p1.country 访问的是p1 的实例属性,p1.country对属性country的访问屏蔽了类中的country属性,而p2.countryPeople.country 访问的依然是原来的类属性

所以,类名.属性名对象.属性名的格式都可以访问类属性的值,但尽量避免使用对象.属性名的格式对类属性的值进行赋值,否则可能会发生混乱。

建议:

不管是访问还是改变类属性的值,都只用类名.属性名的格式

2,实例方法,类方法,静态方法

Python 类中有三种方法:

实例方法属于对象,方法中都有一个self 参数(代表对象本身)。实例方法只能由对象调用,不能通过类名访问。实例方法中可以访问实例属性和类属性。

类方法属于类,方法中都有一个cls 参数(代表类本身)。类方法即可以通过类名访问,也可以通过对象访问,类方法中只能访问类属性,不能访问实例属性。

注意:

Python 解释器在构造类与对象时,是先于对象产生的。

因此,类属性与类方法是先于实例属性与实例方法 产生的。

所以当类方法产生时,还没有实例属性,因此,类方法中不能访问实例属性。

静态方法中,没有self 参数,也没有cls 参数。因此,在静态方法中,即不能访问类属性,也不能访问实例属性。静态方法可以使用类名访问,也可以使用对象访问。

在Python 中,定义类方法需要用到装饰器@classmethod,定义静态方法需要用到装饰器@staticmethod

实例方法演示

#! /usr/bin/env python3
class People:
country = 'china'
def __init__(self, name):
self.__name = name
# 实例方法中有self 参数
def instance_method_test(self):
# 在实例方法中访问了实例属性和类属性
print('name:%s country:%s' % (self.__name, People.country))
>>> p = People('小明')
>>> p.instance_method_test()
name:小明 country:china

在实例方法中访问了实例属性__name和类属性country,均可以被访问。

类方法演示

#! /usr/bin/env python3
class People:
country = 'china'
def __init__(self, name):
self.__name = name
# 类方法中都有cls 参数
@classmethod
def class_method_test1(cls):
print('在类方法中访问类属性country:%s' % cls.country)
@classmethod
def class_method_test2(cls):
print('在类方法中访问实例属性__name:%s' % self.__name)
>>> p = People('小明')
>>> p.class_method_test1() # 在类方法中访问类属性,可以
在类方法中访问类属性country:china
>>>
>>> p.class_method_test2() # 在类方法中访问实例属性,出现异常
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/wp/to_beijing/People.py", line 18, in class_method_test2
print('在类方法中访问实例属性__name:%s' % self.__name)
NameError: name 'self' is not defined

从上面代码中可以看到,在类方法中可以访问类属性,但在类方法中访问实例属性,会出现异常。

静态方法演示

#! /usr/bin/env python3
class People:
country = 'china'
def __init__(self, name):
self.__name = name
# 静态方法中即没有self 参数也不没有cls 参数
@staticmethod
def static_method_test1():
print('在静态方法中访问类属性country:%s' % cls.country)
@staticmethod
def static_method_test2():
print('在静态方法中访问实例属性__name:%s' % self.__name)
>>> p = People('小明')
>>> p.static_method_test1() # 在静态方法中访问类属性,出现异常
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/wp/to_beijing/People.py", line 14, in static_method_test1
print('在静态方法中访问类属性country:%s' % cls.country)
NameError: name 'cls' is not defined
>>>
>>> p.static_method_test2() # 在静态方法中访问实例属性,出现异常
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/wp/to_beijing/People.py", line 18, in static_method_test2
print('在静态方法中访问实例属性__name:%s' % self.__name)
NameError: name 'self' is not defined

从上面代码中可以看到,在静态方法中无论访问实例方法还是类方法,都会出现异常。

3,专有方法

我们之前讲到过的魔法方法,即以双下划线__开头且结尾的方法__xxx__,就是专有方法。这些方法都被Python 赋予了特殊的含义,用户可以根据需要,来实现这些方法。

下面我们介绍一些 Python 中常见的专有方法。

__len__ 方法

实现该方法的类的对象,可以用len() 函数计算其长度。

__str__ 方法

实现该方法的类的对象,可以转化为字符串。

__call__ 方法

实现该方法的类的对象,可以像函数一样调用。

__iter__ 方法

实现该方法的类的对象,是可迭代的。

__setitem__ 方法

实现该方法的类的对象,可以用索引的方式进行赋值。

__getitem__ 方法

实现该方法的类的对象,可以用索引的方式进行访问。

__contains__ 方法

实现该方法的类的对象,可以进行in 运算。


__add__ 方法

实现该方法的类的对象,可以进行加+运算。

__sub__ 方法

实现该方法的类的对象,可以进行减-运算。

__mul__ 方法

实现该方法的类的对象,可以进行乘*运算。

__div__ 方法

实现该方法的类的对象,可以进行除/运算。

__pow__ 方法

实现该方法的类的对象,可以进行乘方运算。

__mod__ 方法

实现该方法的类的对象,可以进行取模运算。


__eq__ 方法

实现该方法的类的对象,可以进行相等==比较。

__ne__ 方法

实现该方法的类的对象,可以进行不等于!=比较。

__gt__ 方法

实现该方法的类的对象,可以进行大于>比较。

__ge__ 方法

实现该方法的类的对象,可以进行大于等于>=比较。

__lt__ 方法

实现该方法的类的对象,可以进行小于<比较。

__le__ 方法

实现该方法的类的对象,可以进行小于等于<=比较。


推荐阅读:

Python 简明教程 — 15,Python 函数

Python 简明教程 — 16,Python 高阶函数

Python 简明教程 — 17,Python 模块与包

Python 简明教程 — 18,Python 面向对象

Python 简明教程 — 19,Python 类与对象


欢迎关注作者公众号,获取更多技术干货。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK