Python 3.7.x 介绍-6类

Posted Joey-Zhang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python 3.7.x 介绍-6类相关的知识,希望对你有一定的参考价值。

类提供了将数据和功能捆绑在一起的方法。 创建新类会创建一种新类型的对象,从而允许创建该类型的新实例。 每个类实例都可以附加属性以保持其状态。 类实例还可以具有用于修改其状态的方法(由其类定义)。 与其他编程语言相比,Python的类机制添加了具有最少新语法和语义的类。 它是C ++和Modula-3中的类机制的混合体。 Python类提供面向对象编程的所有标准功能与C ++和Modula-3不同,内置类型可以用作用户扩展的基类。 此外,与C ++一样,大多数具有特殊语法(算术运算符,下标等)的内置运算符都可以重新定义为类实例。(重载)

1. 命名和对象

对象具有特性,多个名称(在多个范围内)可以绑定到同一个对象。 这在其他语言中称为别名。

2. Python 作用域(范围)和命名空间

在介绍类之前,我首先要告诉你一些Python的范围规则。类定义对命名空间有一些巧妙的技巧,你需要知道范围和命名空间如何工作才能完全理解处理机制。
命名空间是从名称到对象的映射。大多数名称空间当前都是作为Python Dict字典映射实现的,但这通常不会明示(性能除外),并且可能在将来发生变化。
顺便说一下,我对word后面的任何名称使用word属性 - 例如,在表达式z.real中,real是对象z的属性。
命名空间是在不同时刻创建的,具有不同的生命周期。 包含内置名称的命名空间是在Python解释器启动时创建的,永远不会被删除。 读入模块定义时,将创建模块的全局命名空间.
调用函数时会创建函数的本地名称空间,并在函数返回或引发函数内未处理的异常时删除。
范围是Python程序的文本区域,可直接访问命名空间。
如果名称声明为全局,则所有引用和赋值将直接转到包含模块全局名称的中间作用域。要重新绑定在最内层范围之外找到的变量,可以使用非本地语句;
Python的一个特殊之处在于 - 如果没有全局语句生效 - 对名称的赋值总是进入最内层范围。
全局声明可用于表明特定变量存在于全局范围内,应该在那里调用;非本地语句表明特定变量存在于封闭范围内,应该在那里调用。

例子

def scope_test():
    def do_local():
        spam = "local spam"

    def do_nonlocal():
        nonlocal spam
        spam = "nonlocal spam"

    def do_global():
        global spam
        spam = "global spam"

    spam = "test spam"
    do_local()
    print("After local assignment:", spam)
    do_nonlocal()
    print("After nonlocal assignment:", spam)
    do_global()
    print("After global assignment:", spam)

scope_test()
print("In global scope:", spam)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
After local assignment: test spam
After nonlocal assignment: nonlocal spam
After global assignment: nonlocal spam
In global scope: global spam

3.A First Look at Classes

类引入了一些新语法,三种新对象类型和一些新语义。

类定义和语法

class ClassName:
    <statement-1>
    .
    .
    .
    <statement-N>

输入类定义时,将创建一个新的命名空间,并将其用作本地范围 - 因此,对局部变量的所有赋值都将进入此新命名空间。

类对象
类对象支持两种操作:属性引用和实例化。 属性引用使用Python中所有属性引用使用的标准语法:obj.name

class MyClass:
    """A simple example class"""
    i = 12345

    def f(self):
        return 'hello world'

然后MyClass.i和MyClass.f是有效的属性引用,分别返回一个整数和一个函数对象。
类实例化使用函数表示法.

x = MyClass()

实例化操作 (“calling” a class object) 创建一个空对象.

def __init__(self):
    self.data = []
1
2
>>> class Complex:
...     def __init__(self, realpart, imagpart):
...         self.r = realpart
...         self.i = imagpart
...
>>> x = Complex(3.0, -4.5)
>>> x.r, x.i
(3.0, -4.5)

实例对象
现在我们可以用实例对象做什么?实例对象理解的唯一操作是属性引用。
方法对象
通常,绑定后立即调用方法:

x.f()

类的实例变量
一般来说,实例变量用于每个实例的唯一数据,而类变量用于所有类实例共享的属性和方法:

class Dog:

    kind = 'canine'         # class variable shared by all instances

    def __init__(self, name):
        self.name = name    # instance variable unique to each instance

>>> d = Dog('Fido')
>>> e = Dog('Buddy')
>>> d.kind                  # shared by all dogs
'canine'
>>> e.kind                  # shared by all dogs
'canine'
>>> d.name                  # unique to d
'Fido'
>>> e.name                  # unique to e
'Buddy'

4.Random Remarks

数据属性覆盖具有相同名称的方法属性; 为了避免可能导致大型程序中难以发现的错误的意外名称冲突,使用某种最小化冲突机会的约定是明智的。 可能的约定包括大写方法名称,使用小的唯一字符串(可能只是下划线)为数据属性名称添加前缀,或者使用动词作为数据属性的方法和名词。 作为类属性的任何函数对象都为该类的实例定义了一个方法。 函数定义不必在文本中包含在类定义中:将函数对象赋值给类中的局部变量也是可以的。 例如:

# Function defined outside the class
def f1(self, x, y):
    return min(x, x+y)

class C:
    f = f1

    def g(self):
        return 'hello world'

    h = g

5.继承

class DerivedClassName(BaseClassName):
    <statement-1>
    .
    .
    .
    <statement-N>

必须在包含派生类定义的作用域中定义名称BaseClassName。 代替基类名称,也允许使用其他任意表达式。 这是很有用,例如,在另一个模块中定义基类时:
派生类定义的执行与基类的执行相同。 构造类对象时,会记住基类。 这用于解析属性引用:如果在类中找不到请求的属性,则搜索继续查找基类。 如果基类本身是从其他类派生的,则递归应用此规则。
Python有两个内置函数可以继承:
a. 使用isinstance()来检查实例的类型:只有当obj.class是int或从int派生的某个类时,isinstance(obj,int)才为True
多继承
Python也支持多重继承的形式。具有多个基类的类定义如下所示:

class DerivedClassName(Base1, Base2, Base3):
    <statement-1>
    .
    .
    .
    <statement-N>

6.私有变量

Python中不存在除对象内部之外无法访问的私有“实例变量”。 但是,大多数Python代码都遵循一个约定:前缀为下划线的名称(例如_spam)应被视为API的非公共部分(无论是函数,方法还是数据成员)。

7. Odds and Ends

有时,使用类似于Pascal“record”或C“struct”的数据类型是很有用的,将一些命名数据项捆绑在一起。一个空的类定义可以很好地完成:

class Employee:
    pass

john = Employee()  # Create an empty employee record

# Fill the fields of the record
john.name = 'John Doe'
john.dept = 'computer lab'
john.salary = 1000

8. Iterators

到目前为止,您可能已经注意到大多数容器对象都可以使用for语句循环:

for element in [1, 2, 3]:
    print(element)
for element in (1, 2, 3):
    print(element)
for key in 'one':1, 'two':2:
    print(key)
for char in "123":
    print(char)
for line in open("myfile.txt"):
    print(line, end='')

9. 生成器

生成器是一个用于创建迭代器的简单而强大的工具。 它们像常规函数一样编写,但只要想要返回数据就使用yield语句。 每次调用next()时,生成器就会从它停止的地方恢复(它会记住所有数据值以及上次执行的语句)。 一个例子表明,生成器很容易创建:

def reverse(data):
    for index in range(len(data)-1, -1, -1):
        yield data[index]
>>>
>>> for char in reverse('golf'):
...     print(char)
...
f
l
o
g

10.生成器表达式

一些简单的生成器可以使用类似于列表推导的语法简洁地编码为表达式,但使用括号而不是方括号。 这些表达式适用于通过封闭函数立即使用生成器的情况。

>>> sum(i*i for i in range(10))                 # sum of squares
285

>>> xvec = [10, 20, 30]
>>> yvec = [7, 5, 3]
>>> sum(x*y for x,y in zip(xvec, yvec))         # dot product
260

>>> from math import pi, sin
>>> sine_table = x: sin(x*pi/180) for x in range(0, 91)

>>> unique_words = set(word  for line in page  for word in line.split())

>>> valedictorian = max((student.gpa, student.name) for student in graduates)

>>> data = 'golf'
>>> list(data[i] for i in range(len(data)-1, -1, -1))
['f', 'l', 'o', 'g']

以上是关于Python 3.7.x 介绍-6类的主要内容,如果未能解决你的问题,请参考以下文章

Python 3.7.x 介绍-7 标准库

Python 3.7.x Notes-6 Classes

Python 3.7.x 介绍-8 标准库 2

Python 3.7.x 介绍-8 标准库 2

Python 3.7.x 介绍-5 错误和异常处理

Python 3.7.x 介绍 -4 输入和输出