中企动力 > 头条 > 调用python类方法

网站性能检测评分

注:本网站页面html检测工具扫描网站中存在的基本问题,仅供参考。

调用python类方法

Python中七种可调用对象的总结 推广视频课程

img

范峻

关注

除了用户自定义的函数,调用操作符()也可以被用在其它对象上。Python中有7种形式的可调用对象:

用户自定义函数

由def语句或者lambda表达式创建。

内置函数

由C(CPython)实现,如len,time.strftime。

内置方法

由C实现的方法,如dict.get。

方法(Method)

定义在类中的函数。

类

一个类通过__new__方法来创建一个实例,并通过__init__方法初始化之,并最终把实例返回给调用者。由于Python中没有new操作符,所以通过对一个类进行调用来创建这个类的实例。当然,你也可以重载__new__方法来做一些别的事情。

类实例

如果一个类的中定义了__call__方法,那么这个类的实例就可以像函数一样被调用。

Generator函数

使用了yield关键字的函数或者方法,在被调用时,返回一个generator对象。

为了判断一个对象是否是可调用的,可以使用callable()内置函数:

Python“类”之继承 互联网视频课程

img

七年

关注

大家好,今天我们一起聊聊Python“类”之继承,说到这个题目,其实我不是特别喜欢,也纠结了几个小时,“所有官方的教程里面都是继承,可我认为在某些程度上遗传更贴切”,文章的封面也选了好久,最终决定了这张亲子图。正式讲之前,和大家聊聊这些,我想对于内容的理解应该会有所帮助。

首先,我们定义一个animal动物的类(就把自己当Python界的造物主吧,现在你正在创建animal):

接下来想创造dog,dog也会eat和sleep,于是身为造物主的我们偷懒了,“eat和sleep,animal就有,能不能从它那儿继承过来”,当然可以啊,大家请看:

我们猜猜看,会输出什么结果,为什么dog类连初始化函数也没有,这样子可以吗?大家先看运行结果

dog继承了animal遗传给它的eat和sleep方法,并调用了animal的初始化方法,好吧,这么大的恩情,所以理所应当的,dog就是儿子,即子类,animal就是爹,即父类。

创造完dog,于是造物主的我们手又痒痒了,现在着手创建cat吧:

这回,又会有什么输出结果呢?

发现什么没,cat调用的是自己的初始化方法和eat方法,这就像拒绝继承皇位的王子,想靠自己的意志活出不一样的人生。这在Python里,叫做方法重载,也就是子类根据自己的需要,重写父类中的方法。

然后呢,再创造一个会飞的哺乳动物,蝙蝠bat:

bat类继承自animal类和bird类,在Python里,这叫做多重继承,就像小孩继承了父母双方的基因,既聪明又漂亮;bat类还生成自己独特的方法focus,下面我们一起看一下运行结果。

1、继承语法 class 子类名(父类名1,父类名2,...):

2、子类可以创建自己独有的方法

3、方法调用时,子类先在本类中查找调用的方法,找不到才去父类中按次序找,即在父类1中找到了就不去父类2中找了,这一点可以从bat类的初始化方法中看出。

4、子类可以重写继承自父类中的方法,即方法重载,方法调用时,优先调用子类中重载过的方法,比如上述代码中的eat方法。

今天的Python大餐就先到这儿,大家回去好好消化,等着你的会是更美味可口,敬请享用。

Python代码风格:PEP8规则 笔记 行业视频课程

img

许沛菡

关注

Python程序设计的代码风格应该遵循PEP8规则:

一、代码布局

1、缩进:

每级缩进4个空格(不用Tab,更不空格Tab混用)

1、续行应该与其包裹元素对齐,要么使用圆括号、方括号和花括号内的隐式行连接来垂直对齐,要么使用悬挂式缩进对齐。当使用悬挂缩进时,应该考虑到第一行不应该有参数,以及使用缩进以区分自己是续行。

2、缩进4个空格的规则对于续行是可选的。

3、当 if 语句的条件部分长到需要换行写的时候,注意可以在两个字符关键字的连接处(比如 if ),增加一个空格,再增加一个左括号来创造一个4空格缩进的多行条件。这会与 if 语句内同样使用4空格缩进的代码产生视觉冲突。PEP没有明确指明要如何区分i发的条件代码和内嵌代码。可使用的选项包括但不限于下面几种情况:

4、(可以参考下面关于是否在二进制运算符之前或之后截断的讨论)

在多行结构中的大括号/中括号/小括号的右括号可以与内容对齐单独起一行作为最后一行的第一个字符,如:

或者也可以与多行结构的第一行第一个字符对齐,如:

2、Tab还是空格?

空格是被首先推荐的缩进方式。

Tab应该只在现有代码已经使用tab进行缩进的情况下使用,以便和现有代码保持一致。

Python 3不允许再同一个代码块中Tab和空格混合使用。

混合使用制表符和空格缩进的Python2代码应该统一转成空格。

使用命令行运行Python 2时,使用-t选项,会出现非法混用tab和空格的警告。当使用-tt选项时,这些警告会变成错误。强烈推荐使用这些选项!

3、最大行长

每行最大长度79个字符。

对于连续大段的文字(比如文档字符串(docstring)或注释),每行应该被限制在72个字符长度内。

Python标准库比较传统,将行长限制在79个字符以内(文档字符串/注释为72个字符)。

一种推荐的换行方式是利用Python圆括号、方括号和花括号中的隐式续行。长行可以通过在括号内换行来分成多行。应该最好加上反斜杠来区别续行。

有时续行只能使用反斜杠才。例如,较长的多个 with 语句不能采用隐式续行,只能接受反斜杠表示换行:

另一个这样的例子是assert语句。要确保续行的缩进适当。

在二元运算符之前应该换行吗?

遵循数学的传统能产出更多可读性高的代码:

4、空行

顶层函数和类的定义,前后用两个空行隔开。

类里的方法定义用一个空行隔开。

相关的功能组可以用额外的空行(尽量少地)隔开。一堆相关的单行代码之间的空白行可以省略(例如,一组虚拟实现 dummy implementations)。

在函数中使用空行来区分逻辑段(尽量少地)。

Python接受control-L(即^L)换页符作为空格;许多工具把这些字符当作页面分隔符,所以你可以在文件中使用它们来分隔相关段落。请注意,一些编辑器和基于Web的代码阅读器可能无法识别control-L为换页,将在其位置显示另一个字形。

5、源文件编码

Python核心发布版本中的代码总是以UTF-8格式编码(或者在Python2中用ASCII编码)。

使用ASCII(Python 2)或者UTF-8(Python 3)的文件不应该添加编码声明。

在标准库中,只有用作测试目的,或者注释或文档字符串需要提及作者名字而不得不使用非ASCII字符时,才能使用非默认的编码。否则,在字符串文字中包括非ASCII数据时,推荐使用\x, \u, U或N等转义符。

对于Python 3.0及其以后的版本中,标准库遵循以下原则(参见PEP 3131):Python标准库中的所有标识符都必须只采用ASCII编码的标识符,在可行的条件下也应当使用英文词(很多情况下,使用的缩写和技术术语词都不是英文)。此外,字符串文字和注释应该只包括ASCII编码。只有两种例外:

(a) 测试情况下为了测试非ASCII编码的特性

(b) 作者名字。作者名字不是由拉丁字母组成的也必须提供一个拉丁音译名。

鼓励面向全球的开源项目都采用类似的原则。

6、导入

1、imports应该分行写,而不是都写在一行,例如:

这样写也是可以的:

导入(import)始终在文件的顶部,在模块注释和文档字符串之后,在模块全局变量和常量之前。

导入顺序如下:

imports应该按照下面的顺序分组来写:

1、标准库imports

2、相关第三方imports

3、本地应用/库的特定imports

不同组的imports之前用空格隔开。

将任何相关的 __all__ 说明(specification)放在imports之后。

推荐使用绝对(absolute)imports,因为这样通常更易读,在import系统没有正确配置的情况下,也会有更好的表现(或者至少会给出错误信息):

在绝对路径比较长的情况下,也可以使用相对导入:

Python 3中已经禁止隐式的相对导入。

导入类的方法,通常可以这样写:

如果和本地命名的拼写产生了冲突,应当使用绝对导入:

禁止使用通配符导入。

通配符导入(from import *)应该避免,因为它不清楚命名空间有哪些名称存,混淆读者和许多自动化的工具。唯一的例外是重新发布对外的API时可以考虑使用。

7、模块中前后具有双下划线的变量名

像__all__ , __author__ , __version__ 等这样的模块中的变量名(也就是名字里有两个前缀下划线和两个后缀下划线),应该放在文档字符串的后面,以及除from __future__ 之外的import表达式前面。Python要求将来在模块中的导入,必须出现在除文档字符串之外的其他代码之前。

比如:

二、字符串引号

Python中单引号字符串和双引号字符串都是相同的。注意尽量避免在字符串中的反斜杠以提高可读性。

根据PEP 257, 三个引号都使用双引号。

三、表达式和语句中的空格

在下列情况下,避免使用无关的空格:

1、紧跟在小括号,中括号或者大括号后。

2、紧贴在逗号、分号或者冒号之前。

3、然而,冒号在切片中就像二元运算符,在两边应该有相同数量的空格(把它当做优先级最低的操作符)。在扩展的切片操作中,所有的冒号必须有相同的间距。例外情况:当一个切片参数被省略时,空格就被省略了。

4、紧贴在函数参数的左括号之前。

5、紧贴索引或者切片的左括号之前。

6、为了和另一个赋值语句对齐,在赋值运算符附件加多个空格。

其他建议

1、避免在尾部添加空格。因为尾部的空格通常都看不见,会产生混乱:比如,一个反斜杠后面跟一个空格的换行符,不算续行标记。有些编辑器不会保留尾空格,并且很多项目(像CPython)在pre-commit的挂钩调用中会过滤掉尾空格。

总是在二元运算符两边加一个空格:赋值(=),增量赋值(+=,-=),比较(==,,!=,,=,in,not,in,is,is not),布尔(and, or, not)。

如果使用具有不同优先级的运算符,请考虑在具有最低优先级的运算符周围添加空格。有时需要通过自己来判断;但是,不要使用一个以上的空格,并且在二元运算符的两边使用相同数量的空格。

2、在指定函数 关键字参数 或者 默认参数 值的时候,不要在=附近加上空格。

3、功能型注释应该使用冒号的一般性规则,并且在使用 ->的时候要在两边加空格。(参考下面的功能注释得到能够多信息)

4、当给有类型备注的参数赋值的时候,在=两边添加空格(仅针对那种有类型备注和默认值的参数)。

5、复合语句(同一行中的多个语句)通常是不允许的。

6、虽然有时候将小的代码块和 if/for/while 放在同一行没什么问题,多行语句块的情况不要这样用,同样也要避免代码行太长!

四、注释

与代码自相矛盾的注释比没注释更差。修改代码时要优先更新注释!

注释是完整的句子。如果注释是断句,首字母应该大写,除非它是小写字母开头的标识符(永远不要修改标识符的大小写)。

如果注释很短,可以省略末尾的句号。注释块通常由一个或多个段落组成。段落由完整的句子构成且每个句子应该以点号(后面要有两个空格)结束,并注意断词和空格。

非英语国家的程序员请用英语书写你的注释,除非你120%确信代码永远不会被不懂你的语言的人阅读。

1、注释块

注释块通常应用在代码前,并和这些代码有同样的缩进。每行以 '# '(除非它是注释内的缩进文本,注意#后面有空格)。

注释块内的段落用仅包含单个 '#' 的行分割。

2、行内注释

慎用行内注释(Inline Comments) 节俭使用行内注释。 行内注释是和语句在同一行,至少用两个空格和语句分开。行内注释不是必需的,重复罗嗦会使人分心。

不推荐:

但是有时,很有必要:

加了以后对理解代码很有帮助的情况下,关键处才加。

3、文档字符串

文档字符串的标准参见:PEP 257。

为所有公共模块、函数、类和方法书写文档字符串。非公开方法不一定有文档字符串,建议有注释(出现在 def 行之后)来描述这个方法做什么。

更多参考:PEP 257 文档字符串约定。注意结尾的 """ 应该单独成行,例如:

单行的文档字符串,结尾的 """ 在同一行。

4、版本标签

如果你必须在源文件中包含git、Subversion、CVS或RCS crud信息,放置在模块的文档字符串之后,任何其他代码之前,上下各用一个空行:

五、命名规范

Python库的命名约定有点混乱,不可能完全一致。但依然有些普遍推荐的命名规范的。新的模块和包 (包括第三方的框架) 应该遵循这些标准。对不同风格的已有的库,建议保持内部的一致性。

1、最重要的原则

用户可见的API命名应遵循使用约定而不是实现。

2、命名风格

以下是常见的命名方式:

b(单个小写字母)

B(单个大写字母)

lowercase (小写字母)

lower_case_with_underscores (使用下划线分隔的小写字母)

UPPERCASE( 大写字母)

UPPER_CASE_WITH_UNDERSCORES (使用下划线分隔的大写字母)

CapitalizedWords(首字母大写的单词串或驼峰缩写)

注意: 使用大写缩写时,缩写使用大写字母更好。故 HTTPServerError 比 HttpServerError 更好。

mixedCase(不同于首字母大写,第一个单词的首字母小写)

Capitalized_Words_With_Underscores(带下划线,首字母大写,巨丑无比)

还有一种风格使用短前缀分组名字。这在Python中不常用, 但出于完整性提一下。例如,os.stat()返回的元组有st_mode, st_size, st_mtime等等这样的名字(与POSIX系统调用结构体一致)。

X11库的所有公开函数以X开头, Python中通常认为是不必要的,因为属性和方法名有对象作前缀,而函数名有模块名为前缀。

下面讲述首尾有下划线的情况:

_single_leading_underscore:(单前置下划线): 弱内部使用标志。 例如"from M import " 不会导入以下划线开头的对象。

single_trailing_underscore_(单后置下划线): 用于避免与 Python关键词的冲突。 例如:

__double_leading_underscore(双前置下划线): 当用于命名类属性,会触发名字重整。 (在类FooBar中,__boo变成 _FooBar__boo)。

__double_leading_and_trailing_underscore__(双前后下划线):用户名字空间的魔法对象或属性。例如:__init__ , __import__ or __file__,不要自己发明这样的名字。

3、命名约定规范

避免采用的名字:

决不要用字符'l'(小写字母el),'O'(大写字母oh),或 'I'(大写字母eye) 作为单个字符的变量名。一些字体中,这些字符不能与数字1和0区别。用'L' 代替'l'时。

包和模块名:

模块名要简短,全部用小写字母,可使用下划线以提高可读性。包名和模块名类似,但不推荐使用下划线。

模块名对应到文件名,有些文件系统不区分大小写且截短长名字,在 Unix上不是问题,但当把代码迁移到 Mac、Windows 或 DOS 上时,就可能是个问题。当然随着系统的演进,这个问题已经不是经常出现。

另外有些模块底层用C或C++ 书写,并有对应的高层Python模块,C/C++模块名有一个前置下划线 (如:_socket)。

类名:

遵循CapWord。

接口需要文档化并且可以调用时,可能使用函数的命名规则。

注意大部分内置的名字是单个单词(或两个),CapWord只适用于异常名称和内置的常量。

异常名:

如果确实是错误,需要在类名添加后缀 "Error"。

全局变量名:

变量尽量只用于模块内部,约定类似函数。

对设计为通过 "from M import " 来使用的模块,应采用 __all__ 机制来防止导入全局变量;或者为全局变量加一个前置下划线。

函数名:

函数名应该为小写,必要时可用下划线分隔单词以增加可读性。 mixedCase(混合大小写)仅被允许用于兼容性考虑(如: threading.py)。

函数和方法的参数:

实例方法第一个参数是 'self'。

类方法第一个参数是 'cls'。

如果函数的参数名与保留关键字冲突,通常在参数名后加一个下划线。

方法名和实例变量:

同函数命名规则。

非公开方法和实例变量增加一个前置下划线。

为避免与子类命名冲突,采用两个前置下划线来触发重整。类Foo属性名为__a, 不能以 Foo.__a访问。(执著的用户还是可以通过Foo._Foo__a。) 通常双前置下划线仅被用来避免与基类的属性发生命名冲突。

常量:

<...

Python面向对象,类和对象类和实例,类实例静态方法的区别 行业视频课程

img

巴兰基利亚

关注

说一下,对python面向对象的理解,并说明面向对象的三个特点。

1.面向对象是一种编程思想,符合人们的思考习惯,把执行者变为指挥者

把复杂的事情简单化,如果想完成意见事情,找到具有这样功能的对象

如果能找到,调用这个对象的功能,完成这件事情,如果找不到,创建

具有这样功能的对象,再调用完成这件事情。

2.面向对象是一种编程思想,是将数据封装到对象内部,通过对象的方法

来操作数据,通过对象和对象之间的相互的调用配合来完成整个功能的

过程。

面向对象的特点:封装:将有一定功能的代码封装起来,使用时调用即可、继承:将公共的属性和方法放在父类中,自己自考虑特有的属性和方法。多态:程序运行过程中,根据执行条件的不同,动态执行不同的操作代码的过程称为运行时多态。

1. 简答

1) 类对象和实例对象的区别

类对象就是类本身,当遇见类的时候,就会创建新的命名空间,命名空间

包含所有类变量和方法定义的名称。

实例对象就是通过类对象创建出来的实例(类对象实例化之后返回的

就是实例对象),用来存储实例属性和存储实例对象的引用。

2) 类属性和实例属性的区别

类属性:定义在类内部,方法外边,属于所有类对象和所有实例对象

调用:类对象.属性 = 值

实例属性:通过init初始化的变量和实例对象创建出来的属性

调用:实例对象.属性

3) 类方法和实例方法和静态方法的区别

类方法:必须有一个参数,这个参数表示为当前类对象,一般为cls,在

方法的头部加上@classmethod

实例方法:必须有一个参数,表示当前实例对象,一般是self

静态方法:普通函数的格式,不需要强制要求传递参数,在方法的头部

加上注释@staticmethod一般用于实例对象、类对象无关的

内容。

十分钟学python类,类的特殊方法 流量视频课程

img

向晓啸

关注

探究更多的类属性,在一些初学者的教程中,一般很少见。我之所以要在这里也将这部分奉献出来,就是因为本教程是“From Beginner to Master”。当然,不是学习了类的更多属性就能达到 Master 水平,但是这是通往 Master 的一步,虽然在初级应用中,本节乃至于后面关于类的属性用的不很多,但是,这一步迈出去,你就会在实践中有一个印象,以后需要用到了,知道有这一步,会对项目有帮助的。俗话说“艺不压身”。

__dict__

读者是否思考过一个问题:类或者实例属性,在 Python 中是怎么存储的?或者为什么修改或者增加、删除属性,我们能不能控制这些属性?

用 dir() 来查看一下,发现不管是类还是实例,都有很多属性,这在前面已经反复出现,有点见怪不怪了。不过,这里我们要看一个属性:__dict__,因为它是一个保存秘密的东西:对象的属性。

为了便于观察,我将上面的显示结果进行了换行,每个键值对一行。

对于类 Spring 的__dict__属性,可以发现,有一个键'season',这就是这个类的属性;其值就是类属性的数据。

用这两种方式都能得到类属性的值。或者说 Spring.__dict__['season'] 就是访问类属性。下面将这个类实例化,再看看它的实例属性:

实例属性的__dict__是空的。有点奇怪?不奇怪,接着看:

这个其实是指向了类属性中的 Spring.season,至此,我们其实还没有建立任何实例属性呢。下面就建立一个实例属性:

>>> s.season = "the spring of instance"

>>>s.__dict__

{'season': 'the spring of instance'}

这样,实例属性里面就不空了。这时候建立的实例属性和上面的那个 s.season 只不过重名,并且把它“遮盖”了。这句好是不是熟悉?因为在讲述“实例属性”和“类属性”的时候就提到了。现在读者肯定理解更深入了。

此时,那个类属性如何?我们看看:

Spring 的类属性没有受到实例属性的影响。

按照前面的讲述类属性和实例熟悉的操作,如果这时候将前面的实例属性删除,会不会回到实例属性s.__dict__为空呢?

果然打回原形。

当然,你可以定义其它名称的实例属性,它一样被存储到__dict__属性里面:

诚然,这样做仅仅是更改了实例的__dict__内容,对 Spring.__dict__无任何影响,也就是说通过 Spring.lang 或者 Spring.__dict__['lang'] 是得不到上述结果的。

那么,如果这样操作,会怎样呢?

在类的__dict__被更改了,类属性中增加了一个'flower'属性。但是,实例的__dict__中如何?

没有被修改。我也是这么想的,哈哈。你此前这这么觉得吗?然而,还能这样:

这个读者是否能解释?其实又回到了前面第一个出现 s.season 上面了。

通过上面探讨,是不是基本理解了实例和类的__dict__,并且也看到了属性的变化特点。特别是,这些属性都是可以动态变化的,就是你可以随时修改和增删。

属性如此,方法呢?下面就看看方法(类中的函数)。

结果跟前面讨论属性差不多,方法 tree 也在__dict__里面呢。

又跟前面一样。虽然建立了实例,但是在实例的__dict__中没有方法。接下来,执行:

在类(3)中有一部分内容阐述“数据流转”,其中有一张图,其中非常明确显示出,当用上面方式执行方法的时候,实例 t 与 self 建立了对应关系,两者是一个外一个内。在方法中 self.x = x,将 x 的值给了 self.x,也就是实例应该拥有了这么一个属性。

果然如此。这也印证了实例 t 和 self 的关系,即实例方法(t.tree('xiangzhangshu'))的第一个参数(self,但没有写出来)绑定实例 t,透过 self.x 来设定值,即给 t.__dict__添加属性值。

换一个角度:

这回方法中没有将 x 赋值给 self 的属性,而是直接 return,结果是:

是不是理解更深入了?

现在需要对 Python 中一个观点:“一切皆对象”,再深入领悟。以上不管是类还是的实例的属性和方法,都是符合 object.attribute 格式,并且属性类似。

当你看到这里的时候,要么明白了类和实例的__dict__的特点,要么就糊涂了。糊涂也不要紧,再将上面的重复一遍,特别是自己要敲一敲有关代码。(建议一个最好的方法:用两个显示器,一个显示器看本教程,另外一个显示器敲代码。事半功倍的效果。)

需要说明,我们对__dict__的探讨还留有一个尾巴:属性搜索路径。这个留在后面讲述。

不管是类还是实例,其属性都能随意增加。这点在有时候不是一件好事情,或许在某些时候你不希望别人增加属性。有办法吗?当然有,请继续学习。

__slots__

首先声明,__slots__能够限制属性的定义,但是这不是它存在终极目标,它存在的终极目标更应该是一个在编程中非常重要的方面:优化内存使用。

仔细看看 dir() 的结果,还有__dict__属性吗?没有了,的确没有了。也就是说__slots__把__dict__挤出去了,它进入了类的属性。

这里可以看出,类 Spring 有且仅有两个属性。

实例化之后,实例的__slots__与类的完全一样,这跟前面的__dict__大不一样了。

通过类,先赋予一个属性值。然后,检验一下实例能否修改这个属性:

看来,我们的意图不能达成,报错信息中显示,tree 这个属性是只读的,不能修改了。

因为前面已经通过类给这个属性赋值了。不能用实例属性来修改。只能:

用类属性修改。但是对于没有用类属性赋值的,可以通过实例属性:

但此时:

实例属性的值并没有传回到类属性,你也可以理解为新建立了一个同名的实例属性。如果再给类属性赋值,那么就会这样了:

当然,此时在给 t.flower 重新赋值,就会爆出跟前面一样的错误了。

这里试图给实例新增一个属性,也失败了。

看来__slots__已经把实例属性牢牢地管控了起来,但更本质是的是优化了内存。诚然,这种优化会在大量的实例时候显出效果。

详解 Python 方法之类方法 & 静态方法 流量视频课程

img

惜筠

关注

写在之前

这几天的阅读量蜜汁低,是什么原因我也没搞清楚,如果你们觉得我哪里写的有问题,或者是哪里不好,欢迎后台或者微信告知我,先行谢过。

昨天的文章 详解类方法之绑定方法与非绑定方法 中写了方法中的绑定方法和非绑定方法,今天我们继续来学习剩下的「类方法」和「静态方法」。

类方法 & 静态方法

在开始之前,先让我们来看下面一段代码:

class Sample:language = "C++"def__init__(self): self.language = "python"defget_class_attr(cls):return cls.languageif __name__ == "__main__": print("sample.language:",Sample.language) r = get_class_attr(Sample) print("get class attribute:",r) f = Sample() print("instance attribute:",f.language)

上述代码在类 Sample 中,定义了一个属性 language = “C++”,这个是「类属性」;在初始化方法中,又定义了 self.language = “python”,这个是「实例属性」。

知道了这个,我们然后来分析一下函数 get_class_attr(cls),在这个函数中参数用的是 cls,从函数体来看,要求它引用的对象应该具有属性 language,这说明,不是随随便便哪个对象都可以。很巧的是在前面定义的类 Sample 中就有 language 这个属性,于是在调用这个函数的时候,就直接将该类对象作为方法 get_class_attr() 的参数。

Sample.language 是要得到类属性的值,get_class_attr(Sample) 所返回的就是类 Sample 的属性 Sample.language 的值,所以对于上述例子来说,前面两个 print() 函数打印的结果应该是一样的。

f = Sample() 则是创建了一个实例,然后通过 f.language 访问实例属性。所以对于上述的代码的运行结果如下所示:

sample.language:C++getclassattribute:C++instanceattribute:python

不知道经过我上述的解释你是否明白了,如果没明白,建议你再仔细对比一下上述的运行结果和分析的过程。

在上述的例子中,比较特殊的函数应该是 get_class_attr(cls),它是写在类的外面的,然而这个函数又只能调用前面写的那个类对象,因为不是所有对象都有那个特别的 language 属性,这种函数写在外面不利于后期的维护,我们应该避免这种情况的发生,而避免的方法就是把函数和类写在一起,所以就有了下面这种写法:

classsample:language = "C++"def__init__(self): self.language = "python" @classmethoddefget_class_attr(cls):return cls.languageif __name__ == "__main__": print("sample.language:",sample.language) r = sample.get_class_attr() print("get class attribute:",r) f = sample() print("instance attribute:",f.language) print("instance get_class_str:",f.get_class_attr())

在上面这个修改的代码中,出现了 @classmethod,这是一个装饰器,我们在函数的那部分讲到过。这里需要我们注意的是,@classmethod 所装饰的方法的参数中,第一个参数不是 self,这个和我们常规认识中的类的方法有所区别。这里使用了参数 cls,这是习惯的写法,当然用其它的也可以。让我们来看一下运行的结果:

sample.language:C++getclassattribute:C++instanceattribute:pythoninstanceget_class_str:C++

通过上面的运行结果我们可以看到,不管是通过类还是实例来执行 get_class_attr() 得到的结果都是类属性的值,这说明装饰器 @classmethod 所装饰的方法,它的参数 cls 引用的对象是类对象 Sample。

至此,「类方法」 的定义就出来了:类方法,就是在类里面定义的方法。该方法由装饰器 @classmethod 装饰,其第一个参数 cls 引用的是这个类对象,即将类本身作为作为引用对象传到这个方法里。

知道了类方法以后,我们可以用同样的思路理解另一个方法 「静态方法」,我们还是先来看一段代码:

import randomdefjudge(n):num = random.randint(1,100)return num - n > 0classSample:def__init__(self,name):self.name = namedefget_name(self,age):if judge(age):returnself.nameelse:return"the name is stupid"if __name__ == "__main__": s = Sample('rocky') name = s.get_name(23) print(name)

先看一下上面的代码,类 Sample 里面使用了外面的函数 judge(n),这种类和函数的关系也是因为相互关联,所以后期的程序维护可能会出问题,于是为了便于维护,我们同样对程序进行了修改:

import randomclassSample:def__init__(self,name):self.name = namedefget_name(self,age):ifself.judge(age):returnself.nameelse:return"the name is stupid"@staticmethoddefjudge(n): num = random.randint(1,100)return num - n > 0if __name__ == "__main__": s = Sample('rocky') name = s.get_name(23) print(name)

同样是经过修改优化,将原来在类外面的函数放到了类里面。但是这不是简单的移动,还要在函数的前面加上 @staticmethod 装饰器,并且要注意的是,虽然这个函数在类的里面,但是跟别的方法是不一样的,它的第一个参数也不是 self,当我们要使用它的时候,可以通过实例调用,比如 self.judge(n),也可以通过类调用这个方法,比如 sample.select(n)。

从上面的程序可以看出,尽管 judge(n) 位于类里面,但它确实一个独立的方法,与类本身没有关系,仅仅是为了免除前面所说的后期维护上的麻烦。但是它也有存在的道理,上面的例子就是一个典型的说明。

所以「静态方法」的定义也就出来了:在类的作用域里面,前面必须要加上一个 @staticmethod 装饰器,我们将这种方法命名为静态方法。

写在之后

方法是类的重要组成部分,本章所讲的类方法和静态方法让我们在使用类的时候有了更加便利的工具。

「方法」的这一块到这里就补充完了,之后我们将继续学习 OOP 的剩下两个特征:「多态」和「封装」,敬请期待。

如果你觉得本篇文章让你有所收获,欢迎点赞转发,你的支持是对我码字最大的动力,分享永远在路上,我们一起加油。

The end。

干货!Python入门基础之面向对象二:类和实例、方法 营销视频课程

img

绿柏

关注

前面

一篇

文章我介绍了python面向对象的基本知识,链接在最下面。初步解释了面向对象和面向对象的优点,今天就开始正式用代码来展现面向对象。

1、利用class创建类

Python中,创建类的语句是如下所示

先解释一下,class后面跟的是类名,括号里面是基类(也成为父类)python3中默认继承object。里面的函数称为方法(注意,严格来说,python中,位于类里面的def语句才能被称为方法,而在类外面定义的def只能被称为函数)。示例如下

2、定义类的属性,

我们讲了类是有属性的,那么如何定义类的属性,有以下两种种:

1、 直接在类里面定义,这里属性是位于类的变量空间里面,整个类中可以直接访问。

2、 在构造函数里面定义,这是对象的属性,访问时要通过self访问。

3、构造函数__init__

类是由属性构成的,当我们在定义一个类的时候,我们需要对类的属性进行设置,这时候就用到了构造函数:__init__(self,[……]),我们在构造函数中的参数是赋值给self,因为在oop中,self就是实例对象,name、age、weight变成了状态信息。

我们接上面说为什么它继承object,通过dir()我们可以打印出他的属性,发现他继承了很多方法,在后面的使用中会比较方便。(这里涉及到了新式类和老式类的问题,在python3中全都是新式类,新式类更加强大)。

4、访问控制

Python不像Java中有明确的访问控制方法,说白了就是没有访问控制。不过有一套约定俗成的方法:全靠自觉

变量名前面无下划线,可以公开访问。

变量名前面带有一个下划线:类的私有属性。

变量名前面带有两个下划线:部分私有属性,类里面可以访问,实例化之后不能直接访问。

再说一遍:全靠自觉!其实它们无论怎样都是可以访问的。这样只是代码规范,方便以后的代码维护。

5、定义类的方法

函数和方法的区别:前面我讲过,python在类中的def才能被称为方法,因为函数和方法的区别就是它们是否依附于一个类。函数直接通过函数名调用,方法通过类实例化调用,方法是类的一个属性。

方法的访问控制和类的属性一样,也是没有,定义方法也就差不多,如下:

绑定方法:

你们可能注意到了,每个方法中 都有self,这个self是绑定类的,表示函数是类的属性。

self 变量用于在类实例方法中引用方法所绑定的实例。因为方法的实例在任何方法调用中总是作为第一个参数传递的,self 被选中用来代表实例。你必须在方法声明中放上 self(你可能已经注意到了这点),但可以在方法中不使用实例(self)。如果你的方法中没有用到 self , 那么请考虑创建一个常规函数,除非你有特别的原因。毕竟,你的方法代码没有使用实例,没有与类关联其功能,这使得它看起来更像一个常规函数。在其它面向对象语言中,self 可能被称为 this。

方法装饰器:

@classmenthod类方法,调用的时候用类名,不是先生成对象,由对象调用

@property像访问属性一样调用方法,就是指不用加括号了。

如下:我在上面的那个类里面加了两个方法,用了这两个修饰器。

使用方法如下:

上一篇:Python 入门基础之面向对象过程-面向过程概述

下一篇介绍类的继承、运算符重载(钩子)等。欢迎关注。

python面向对象之类属性和类方法的使用和实例 推广视频课程

img

波莉

关注

类属性和类方法

目标

类的结构 类属性和实例属性 类方法和静态方法

01. 类的结构

1.1 术语 —— 实例

1. 使用面相对象开发,第 1 步 是设计 类

2. 使用 类名() 创建对象,创建对象 的动作有两步:

1) 在内存中为对象 分配空间

2) 调用初始化方法 `__init__` 为 对象初始化

3. 对象创建后,内存 中就有了一个对象的 实实在在 的存在 —— 实例

因此,通常也会把:

1. 创建出来的 对象 叫做 类 的 实例

2. 创建对象的 动作 叫做 实例化

3. 对象的属性 叫做 实例属性

4. 对象调用的方法 叫做 实例方法

在程序执行时:

1. 对象各自拥有自己的 实例属性

2. 调用对象方法,可以通过 `self.`

访问自己的属性

调用自己的方法

结论

每一个对象 都有自己 独立的内存空间,保存各自不同的属性

多个对象的方法,在内存中只有一份,在调用方法时,需要把对象的引用 传递到方法内部

1.2 类是一个特殊的对象

> `Python` 中 一切皆对象:

> `class AAA:` 定义的类属于 类对象

> `obj1 = AAA()` 属于 实例对象

在程序运行时,类 同样 会被加载到内存

在 `Python` 中,类 是一个特殊的对象 —— 类对象

在程序运行时,类对象 在内存中 只有一份,使用 一个类 可以创建出 很多个对象实例

除了封装 实例 的 属性 和 方法外,类对象 还可以拥有自己的 属性 和 方法

1. 类属性

2. 类方法

通过 类名. 的方式可以 访问类的属性 或者 调用类的方法

02. 类属性和实例属性

2.1 概念和使用

类属性 就是给 类对象 中定义的 属性

通常用来记录 与这个类相关 的特征

类属性 不会用于记录 具体对象的特征

示例需求

定义一个 工具类

每件工具都有自己的 `name`

需求 —— 知道使用这个类,创建了多少个工具对象?

```python

class Tool(object):

使用赋值语句,定义类属性,记录创建工具对象的总数

count = 0

def __init__(self, name):

self.name = name

针对类属性做一个计数+1

Tool.count += 1

创建工具对象

tool1 = Tool("斧头")

tool2 = Tool("榔头")

tool3 = Tool("铁锹")

知道使用 Tool 类到底创建了多少个对象?

print("现在创建了 %d 个工具" % Tool.count)

2.2 属性的获取机制(科普)

在 `Python` 中 属性的获取 存在一个 向上查找机制

因此,要访问类属性有两种方式:

1. 类名.类属性

2. 对象.类属性 (不推荐)

注意

如果使用 `对象.类属性 = 值` 赋值语句,只会 给对象添加一个属性,而不会影响到 类属性的值

03. 类方法和静态方法

3.1 类方法

类属性 就是针对 类对象 定义的属性

使用 赋值语句 在 `class` 关键字下方可以定义 类属性

类属性 用于记录 与这个类相关 的特征

类方法 就是针对 类对象 定义的方法

在 类方法 内部可以直接访问 类属性 或者调用其他的 类方法

语法如下

```python

@classmethod

def 类方法名(cls):

pass

```

类方法需要用 修饰器 `@classmethod` 来标识,告诉解释器这是一个类方法

类方法的 第一个参数 应该是 `cls`

由 哪一个类 调用的方法,方法内的 `cls` 就是 哪一个类的引用

这个参数和 实例方法 的第一个参数是 `self` 类似

提示 使用其他名称也可以,不过习惯使用 `cls`

3. 通过 类名. 调用 类方法,调用方法时,不需要传递 `cls` 参数

4. 在方法内部

可以通过 `cls.` 访问类的属性

也可以通过 `cls.` 调用其他的类方法

示例需求

定义一个 工具类

每件工具都有自己的 `name`

需求 —— 在 类 封装一个 `show_tool_count` 的类方法,输出使用当前这个类,创建的对象个数

```python

@classmethod

def show_tool_count(cls):

"""显示工具对象的总数"""

print("工具对象的总数 %d" % cls.count)

```

> 在类方法内部,可以直接使用 `cls` 访问 类属性 或者 调用类方法

3.2 静态方法

在开发时,如果需要在 类 中封装一个方法,这个方法:

既 不需要 访问 实例属性 或者调用 实例方法

也 不需要 访问 类属性 或者调用 类方法

这个时候,可以把这个方法封装成一个 静态方法

语法如下

```python

@staticmethod

def 静态方法名():

pass

```

静态方法 需要用 修饰器 `@staticmethod` 来标识,告诉解释器这是一个静态方法

通过 类名. 调用 静态方法

```python

class Dog(object):

狗对象计数

dog_count = 0

@staticmethod

def run():

不需要访问实例属性也不需要访问类属性的方法

print("狗在跑...")

def __init__(self, name):

self.name = name

```

3.3 方法综合案例

需求

1. 设计一个 `Game` 类

2. 属性:

定义一个 类属性 `top_score` 记录游戏的 历史最高分

定义一个 实例属性 `player_name` 记录 当前游戏的玩家姓名

3. 方法:

静态方法 `show_help` 显示游戏帮助信息

类方法 `show_top_score` 显示历史最高分

实例方法 `start_game` 开始当前玩家的游戏

4. 主程序步骤

1) 查看帮助信息

2) 查看历史最高分

3) 创建游戏对象,开始游戏

案例小结

1. 实例方法 —— 方法内部需要访问 实例属性

实例方法 内部可以使用 类名. 访问类属性

2. 类方法 —— 方法内部 只 需要访问 类属性

3. 静态方法 —— 方法内部,不需要访问 实例属性 和 类属性

提问

如果方法内部 即需要访问 实例属性,又需要访问 类属性,应该定义成什么方法?

答案

应该定义 实例方法

因为,类只有一个,在 实例方法 内部可以使用 类名. 访问类属性

```python

class Game(object):

游戏最高分,类属性

top_score = 0

@staticmethod

def show_help():

print("帮助信息:让僵尸走进房间")

@classmethod

def show_top_score(cls):

print("游戏最高分是 %d" % cls.top_score)

def __init__(self, player_name):

self.player_name = player_name

def start_game(self):

print("[%s] 开始游戏..." % self.player_name)

使用类名.修改历史最高分

Game.top_score = 999

1. 查看游戏帮助

Game.show_help()

2. 查看游戏最高分

Game.show_top_score()

3. 创建游戏对象,开始游戏

game = Game("小明")

game.start_game()

4. 游戏结束,查看游戏最高分

Game.show_top_score()

``

img

在线咨询

建站在线咨询

img

微信咨询

扫一扫添加
动力姐姐微信

img
img

TOP