Python标准内置函数(61-66)

1.61  函数sum()

在Python程序中,使用函数sum()的语法格式如下所示。

sum(iterable[, start])
  1. iterable:可迭代对象,例如列表。
  2. start:指定相加的参数,如果没有设置这个值则默认为0。

函数rsum()的功能是将start以及iterable的元素从左向右相加并,iterable的元素通常是数字,start值不允许是一个字符串。对于某些使用情况,有很好的替代sum()的方法。连接字符串序列的首选快速方法是调用''.join(sequence)。要以扩展精度添加浮点值,请使用math.fsum()。要连接一系列可迭代对象,请使用itertools.chain()。

例如在下面的实例文件sum.py中,演示了使用函数sum()实现求和运算的过程。

#对可迭代类型进行求和。要求:① 接收对象是可迭代类型。② 可迭代对象所有元素类型是数值型。

#传入可迭代对象

print(sum((1,2,3,4)))

print(sum([1,2,3,4]))

print(sum(range(10)))

# 元素类型必须是数值型

print(sum((1.5,1.5,3.5,4.5)))

print(sum((complex(1,-1),complex(2,-2))))

#sum((1,2,3,'4'))#运行这行会出错,因为‘4’不是值类型



#可以传入一个可选参数start,表示求和前的初始化值,如果传入空的可迭代数据类型,则返回初始值。

print(sum((1,2,3,4),2))

print(sum((1,2,3,4),-10))

# 传入空可迭代对象,直接返回初始值

print(sum([],2))

执行后会输出:

10

10

45

1.0

(3-3j)

12

0

2

1.62  函数super()

在Python程序中,使用函数super()的语法格式如下所示。

super([type[, object-or-type]])
  1. type:类;
  2. object-or-type:类,一般是self。

函数super()是调用父类(超类)的一个方法,能够返回一个代理对象,它委托方法给父类或者type的同级类,这对于访问类中被覆盖的继承方法很有用。除了跳过type本身之外,搜索顺序与getattr()所使用的顺序相同。

参数type的__mro__属性列出getattr()和super()使用的方法解析顺序。该属性是动态的,并且可以在继承层次结构更新时更改。如果省略第二个参数object-or-type,则返回的super对象是未绑定的。如果第二个参数object-or-type是一个对象,则isinstance(obj, type)必须为真。如果第二个参数object-or-type是类型,则issubclass(type2, type)必须为真(这对类方法很有用)。

函数super()有两种典型的使用情况,具体说明如下所示:

  1. 在具有单继承的类层次结构中,可以使用super来引用父类,而不必明确命名它们,从而使代码更易于维护。这种使用非常类似于在其他编程语言中super的使用。
  2. 在动态执行环境中支持协同多继承。这种使用情况是Python独有的,在静态编译语言或仅支持单继承的语言中找不到。这使得可以实现“菱形图”,其中多个基类实现相同的方法。良好的设计指出此方法在每种情况下具有相同的调用顺序(因为调用的顺序在运行时确定,因为该顺序适应类层次结构中的更改,并且因为该顺序可以包括在运行时之前未知的兄弟类)。

注意:函数super()是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及到查找顺序(MRO)、重复调用(钻石继承)等种种问题。其中MRO是类的方法解析顺序表, 其实也就是继承父类方法时的顺序表。

函数super()只实现显式点分属性查找的绑定过程,例如super().__getitem__(name)。函数super()只通过实现自己的__getattribute__()方法来实现这一点,以便以支持协同多继承需要的以可预测的顺序搜索类。因此,super()没有定义隐式的查找语句或操作,例如super()[name]。如果不是零个参数的形式,super()在方法内部使用时没有任何限制。如果两个参数的形式指定准确的参数,就能进行正确的引用。零个参数的形式只在类定义中工作,因为编译器填充必要的细节以正确检索正在定义的类,原理类似访问当前实例的普通方法。

另外读者需要注意,Python3.x 和 Python1.x的一个重要区别是,Python 3 可以直接使用 super().xxx 代替 super(Class, self).xxx

为什么要引入super呢?在最早之前,在子类(B)中调用父类(A)的方法采用的方式如下:

#定义父类A

>>> class A(object):

    def __init__(self):

        print('A.__init__')



#实例化A       

>>> a = A()

A.__init__



# 定义子类B,继承A,在B的__init__ 方法中调用A的__init__方法

>>> class B(A):

    def __init__(self):

        print('B.__init__')

        A.__init__(self)



 #实例化B

>>> b = B()

B.__init__

A.__init__

假设现在要新定义一个类(A1),并更改继承关系(B->A改成B->A1),则需要所有类中做如下所示的代码修改:

#定义新的父类A1

>>> class A1(object):

    def __init__(self):

        print('A1.__init__')



#更改继承关系B->A改成B->A1

>>> class B(A1):

    def __init__(self):

        print('B.__init__')

        A1.__init__(self)



#能正确调用新的父类A1的__init__方法

>>> b = B()

B.__init__

A1.__init__



#假设忘了修改A.__init__(self)

>>> class B(A1):

    def __init__(self):

        print('B.__init__')

        A.__init__(self)

     

#则还是调用了A的__init__方法

>>> b = B()

B.__init__

A.__init__

在引入super之后,不需要显示指定父类的类名,这样增强了程序的可维护性:

#B->A 改用super方式调用父类方法

>>> class B(A):

    def __init__(self):

        print('B.__init__')

        super().__init__()



#能正确调用父类方法

>>> b = B()

B.__init__

A.__init__



#更改继承关系B->A改成B->A1,调用父类方法方式不用修改

>>> class B(A1):

    def __init__(self):

        print('B.__init__')

        super().__init__()



#也能正确调用父类方法

>>> b = B()

B.__init__

A1.__init__

在Python程序中,不带任何参数的super等效于super(类名,self),这一特性多用于单继承关系的子类中。例如下面的演示过程。

#super不带参数

>>> class B(A1):

    def __init__(self):

        print('B.__init__')

        super().__init__()



#能正确调用父类方法

>>> b = B()

B.__init__

A1.__init__



#super带两个参数(类名,self)

>>> class B(A1):

    def __init__(self):

        print('B.__init__')

        super(B,self).__init__()



#也能正确调用父类方法

>>> b = B()

B.__init__

A1.__init__

如果函数super()的第2个参数不传入,则表示代理对象不绑定继承关系。例如下面的演示过程。

#super第2个参数不传入,生成代理对象不绑定继承关系

>>> class B(A1):

    def __init__(self):

        print('B.__init__')

        super(B).__init__()



#super(B).__init__()方法执行时不会调用父类方法

>>> b = B()

B.__init__

如果函数super()的第2个参数是一个对象,则对象必须是第1个参数指定类型的实例,此种关系多用于多层继承关系的子类中。例如下面的演示过程。

#定义父类A

>>> class A(object):

    def __init__(self):

        print('A.__init__')



#定义子类B,继承A,__init__中调用父类的__init__方法

>>> class B(A):

    def __init__(self):

        print('B.__init__')

        super().__init__()



#定义子类C,继承B,__init__中调用父类的__init__方法       

>>> class C(B):

    def __init__(self):

        print('C.__init__')

        super().__init__()



#实例化C时,执行C的__init__方法,调用直接父类B的__init__方法,又进一步调用间接父类A的__init__方法

>>> c = C()

C.__init__

B.__init__

A.__init__



#重新定义子类C,继承关系不变,调用父类方法__init__时改用super(B,self)

>>> class C(B):

    def __init__(self):

        print('C.__init__')

        super(B,self).__init__()



#实例化C时,执行C的__init__方法,super(B,self)代理找到B的父类A,将self转换成B的实例,直接调用了A的__init__方法,跳过了调用B的__init__方法

>>> c = C()

C.__init__

A.__init__



#定义一个新类D

>>> class D(object):

    def __init__(self):

        print('D.__init__')



#重新定义C,继承关系不变,调用父类方法__init__时改用super(D,self)

>>> class C(B):

    def __init__(self):

        print('C.__init__')

        super(D,self).__init__()



#实例化C时,执行C的__init__方法,super(D,self)代理找到D的父类object,将self转换成D的实例,因为D和C无继承关系,self

无法转换成D的实例所以报错

>>> c= C()

C.__init__

Traceback (most recent call last):

  File "<pyshell#14>", line 1, in <module>

    c= C()

  File "<pyshell#13>", line 4, in __init__

    super(D,self).__init__()

TypeError: super(type, obj): obj must be an instance or subtype of type

如果函数super()的第2个参数时一个类型,则类型必须是第1个参数指定类型的子类,此种关系多用于多层继承关系的子类中,适用于类方法。例如下面的演示过程。

#定义父类A,并定义有一个类方法sayHello

>>> class A(object):

    @classmethod

    def sayHello(cls):

        print('A.sayHello')



# 定义子类B,继承A,重写类方法sayHello,在其中调用父类的sayHello方法

>>> class B(A):

    @classmethod

    def sayHello(cls):

        print('B.sayHello')

        super().sayHello()



# 定义子类C,继承B,重写类方法sayHello,在其中调用父类的sayHello方法

>>> class C(B):

    @classmethod

    def sayHello(cls):

        print('C.sayHello')

        super().sayHello()



#调用C的类方法sayHello,其调用C的直接父类B的类方法sayHello,调用时B的sayHello方法又调用B的直接父类A的类方法sayHello

>>> C.sayHello()

C.sayHello

B.sayHello

A.sayHello



#重新定义类C,继承关系不变,使用super(C,C)的方式调用父类方法

>>> class C(B):

    @classmethod

    def sayHello(cls):

        print('C.sayHello')

        super(C,C).sayHello()



#调用C的类方法sayHello,super(C,C)代理对象,找到C的直接父类B,然后调用C的直接父类B的类方法sayHello,调用时B的sayHello方法又调用B的直接父类A的类方法sayHello

>>> C.sayHello()

C.sayHello

B.sayHello

A.sayHello



#重新定义类C,继承关系不变,使用super(B,C)的方式调用父类方法

>>> class C(B):

    @classmethod

    def sayHello(cls):

        print('C.sayHello')

        super(B,C).sayHello()



#调用C的类方法sayHello,super(B,C)代理对象,找到B的直接父类A,然后调用B的直接父类A的类方法sayHello,中间不会调用B的sayHello方法

>>> C.sayHello()

C.sayHello

A.sayHello



#定义一个新类D,和A、B、C无继承关系

>>> class D(object):

    @classmethod

    def sayHello(cls):

        print('D.sayHello')



#重新定义类C,继承关系不变,使用super(D,C)的方式调用父类方法

>>> class C(B):

    @classmethod

    def sayHello(cls):

        print('C.sayHello')

        super(D,C).sayHello()



#调用C的类方法sayHello,super(D,C)代理对象,找到B的直接父类object,然后将C转换成D类,转换失败调用出错

>>> C.sayHello()

C.sayHello

Traceback (most recent call last):

  File "<pyshell#81>", line 1, in <module>

    C.sayHello()

  File "<pyshell#80>", line 5, in sayHello

    super(D,C).sayHello()

TypeError: super(type, obj): obj must be an instance or subtype of type

 

例如在下面的实例文件super.py中,演示了使用函数super()用父类中方法的过程。

class FooParent(object):

    def __init__(self):

        self.parent = 'I\'m the parent.'

        print ('Parent')

   

    def bar(self,message):

        print ("%s from Parent" % message)



class FooChild(FooParent):

    def __init__(self):

        # super(FooChild,self) 首先找到 FooChild 的父类(就是类 FooParent),然后把类B的对象 FooChild 转换为类 FooParent 的对象

        super(FooChild,self).__init__()   

        print ('Child')

       

    def bar(self,message):

        super(FooChild, self).bar(message)

        print ('Child bar fuction')

        print (self.parent)



if __name__ == '__main__':

    fooChild = FooChild()

fooChild.bar('HelloWorld')

执行后会输出:

Parent

Child

HelloWorld from Parent

Child bar fuction

I'm the parent.

1.63  函数type()

在Python程序中,使用函数type()的语法格式如下所示。

class type(object)

class type(name, bases, dict)
  1. name:类的名称;
  2. bases:基类的元组;
  3. dict:字典,类内定义的命名空间变量。

当函数type()只有一个参数object时,返回object的类型。返回值是一个类型对象,通常与object.__class__返回的对象相同。例如在下面的实例文件type.py中,演示了函数type()只有一个参数时的使用过程。

# 一个参数实例

print(type(1))

print(type('toppr'))

print(type([2]))

print(type({0:'zero'}))

x = 1

print(type( x ) == int)    # 判断类型是否相等



#定义类型A

class A:

    name = 'defined in A'



#创建类型A实例a

a = A()



#a.__class__属性

print(a.__class__)

#type(a)返回a的类型

print(type(a))



#测试类型

print(type(a) == A)

执行后会输出:

<class 'int'>

<class 'str'>

<class 'list'>

<class 'dict'>

True

<class '__main__.A'>

<class '__main__.A'>

True

函数type()的另一种使用方式是传入3个参数,将使用3个参数来创建一个新的类型。其中第一个参数name将用作新的类型的类名称,即类型的__name__属性;第二个参数是一个元组类型,其元素的类型均为类类型,将用作新创建类型的基类,即类型的__bases__属性;第三个参数dict是一个字典,包含了新创建类的主体定义,即其值将复制到类型的__dict__属性中。例如在下面的实例文件type1.py中,演示了函数type()有3个参数时的使用过程。

# 三个参数

class X(object):

     a = 1



X = type('X', (object,), dict(a=1))  # 产生一个新的类型 X

print(X)



#定义类型A,含有属性InfoA

class A(object):

    InfoA = 'some thing defined in A'



#定义类型B,含有属性InfoB

class B(object):

    InfoB = 'some thing defined in B'



#定义类型C,含有属性InfoC

class C(A,B):

    InfoC = 'some thing defined in C'



#使用type函数创建类型D,含有属性InfoD

D = type('D',(A,B),dict(InfoD='some thing defined in D'))



#C、D的类型

print(C)

print(D)

#分别创建类型C、类型D的实例

c = C()

d = D()



#分别输出实例c、实例b的属性

print((c.InfoA,c.InfoB,c.InfoC))

print((d.InfoA,d.InfoB,d.InfoD))

执行后会输出:

<class '__main__.X'>

<class '__main__.C'>

<class '__main__.D'>

('some thing defined in A', 'some thing defined in B', 'some thing defined in C')

('some thing defined in A', 'some thing defined in B', 'some thing defined in D')

在Python程序中,虽然可以通过type()函数检测一个对象是否是某个类型的实例,但是更推荐使用isinstance函数,因为isinstance函数考虑了父类子类间继承关系。例如下面的演示过程。

#定义类型B,继承A

>>> class B(A):

    age = 2



#创建类型B的实例b

>>> b = B()



#使用type函数测试b是否是类型A,返回False

>>> type(b) == A

False



#使用isinstance函数测试b是否类型A,返回True

>>> isinstance(b,A)

True

1.64  函数vars()

在Python程序中,使用函数vars()的语法格式如下所示。

vars([object])

函数vars()的功能是返回参数对象object的属性和属性值的字典对象。例如在下面的实例文件vars.py中,演示了函数vars()参数是模块、类、类实例或者定义了__dict__属性对象的过程。

import time

print(vars(time))

#作用于类

print(vars(slice))

#作用于类实例

class a(object):

    pass



print(a.__dict__)

print(vars(a))

a.name = 'Kim'

print(a.__dict__)

print(vars(a))

执行后会输出:

{'__name__': 'time', '__doc__': 'This module provides various functions to manipulate time values.\n\nThere are two standard representations of time.  One is the number\nof seconds since the Epoch, in UTC (a.k.a. GMT).  It may be an integer\nor a floating point number (to represent fractions of seconds).\nThe Epoch is system-defined; on Unix, it is generally January 1st, 1970.\nThe actual value can be retrieved by calling gmtime(0).\n\nThe other representation is a tuple of 9 integers giving local time.\nThe tuple items are:\n  year (including century, e.g. 1998)\n  month (1-12)\n  day (1-31)\n  hours (0-23)\n  minutes (0-59)\n  seconds (0-59)\n  weekday (0-6, Monday is 0)\n  Julian day (day in the year, 1-366)\n  DST (Daylight Savings Time) flag (-1, 0 or 1)\nIf the DST flag is 0, the time is given in the regular time zone;\nif it is 1, the time is given in the DST time zone;\nif it is -1, mktime() should guess based on the date and time.\n\nVariables:\n\ntimezone -- difference in seconds between UTC and local standard time\naltzone -- difference in  seconds between UTC and local DST time\ndaylight -- whether local time should reflect DST\ntzname -- tuple of (standard time zone name, DST time zone name)\n\nFunctions:\n\ntime() -- return current time in seconds since the Epoch as a float\nclock() -- return CPU time since process start as a float\nsleep() -- delay for a number of seconds given as a float\ngmtime() -- convert seconds since Epoch to UTC tuple\nlocaltime() -- convert seconds since Epoch to local time tuple\nasctime() -- convert time tuple to string\nctime() -- convert time in seconds to string\nmktime() -- convert local time tuple to seconds since Epoch\nstrftime() -- convert time tuple to string according to format specification\nstrptime() -- parse string to time tuple according to format specification\ntzset() -- change the local timezone', '__package__': '', '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': ModuleSpec(name='time', loader=<class '_frozen_importlib.BuiltinImporter'>, origin='built-in'), 'time': <built-in function time>, 'clock': <built-in function clock>, 'sleep': <built-in function sleep>, 'gmtime': <built-in function gmtime>, 'localtime': <built-in function localtime>, 'asctime': <built-in function asctime>, 'ctime': <built-in function ctime>, 'mktime': <built-in function mktime>, 'strftime': <built-in function strftime>, 'strptime': <built-in function strptime>, 'monotonic': <built-in function monotonic>, 'process_time': <built-in function process_time>, 'perf_counter': <built-in function perf_counter>, 'get_clock_info': <built-in function get_clock_info>, 'timezone': -28800, 'altzone': -32400, 'daylight': 0, 'tzname': ('Öйú±ê׼ʱ¼ä', 'ÖйúÏÄÁîʱ'), '_STRUCT_TM_ITEMS': 11, 'struct_time': <class 'time.struct_time'>}

{'__repr__': <slot wrapper '__repr__' of 'slice' objects>, '__hash__': None, '__getattribute__': <slot wrapper '__getattribute__' of 'slice' objects>, '__lt__': <slot wrapper '__lt__' of 'slice' objects>, '__le__': <slot wrapper '__le__' of 'slice' objects>, '__eq__': <slot wrapper '__eq__' of 'slice' objects>, '__ne__': <slot wrapper '__ne__' of 'slice' objects>, '__gt__': <slot wrapper '__gt__' of 'slice' objects>, '__ge__': <slot wrapper '__ge__' of 'slice' objects>, '__new__': <built-in method __new__ of type object at 0x000000005CBE3F80>, 'indices': <method 'indices' of 'slice' objects>, '__reduce__': <method '__reduce__' of 'slice' objects>, 'start': <member 'start' of 'slice' objects>, 'stop': <member 'stop' of 'slice' objects>, 'step': <member 'step' of 'slice' objects>, '__doc__': 'slice(stop)\nslice(start, stop[, step])\n\nCreate a slice object.  This is used for extended slicing (e.g. a[0:10:2]).'}

{'__module__': '__main__', '__dict__': <attribute '__dict__' of 'a' objects>, '__weakref__': <attribute '__weakref__' of 'a' objects>, '__doc__': None}

{'__module__': '__main__', '__dict__': <attribute '__dict__' of 'a' objects>, '__weakref__': <attribute '__weakref__' of 'a' objects>, '__doc__': None}

{'__module__': '__main__', '__dict__': <attribute '__dict__' of 'a' objects>, '__weakref__': <attribute '__weakref__' of 'a' objects>, '__doc__': None, 'name': 'Kim'}

{'__module__': '__main__', '__dict__': <attribute '__dict__' of 'a' objects>, '__weakref__': <attribute '__weakref__' of 'a' objects>, '__doc__': None, 'name': 'Kim'}

当函数vars()不接收参数时,其功能和locals()函数一样,能够返回当前作用域内的局部变量。例如在下面的实例文件vars1.py中,演示了函数vars()不接收参数时的过程。

#不带参数功能和locals函数一样

v1 = vars()

l1 = locals()

print(v1)

print(l1)

执行后会输出:

{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000019B066C6BA8>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'vars1.py', '__cached__': None, 'v1': {...}, 'l1': {...}}

{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000019B066C6BA8>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'vars1.py', '__cached__': None, 'v1': {...}, 'l1': {...}}

1.65  函数zip()

在Python程序中,使用函数zip()的语法格式如下所示。

zip([iterable, ...])

参数iterabl表示一个或多个迭代器,函数zip()的功能是将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同,利用 * 号操作符,可以将元组解压为列表。

例如在下面的实例文件zip.py中,演示了使用函数zip()将元素打包成元组的过程。

a = [1,2,3]

b = [4,5,6]

c = [4,5,6,7,8]

zipped = zip(a,b)    # 打包为元组的列表

print(list(zip(a,c)))             # 元素个数与最短的列表一致

print(list(zip(*zipped)))         # 与 zip 相反,可理解为解压,返回二维矩阵式



#如果传入的迭代器长度不一致,最短长度的迭代器迭代结束后停止聚合。

x = [1,2,3] #长度3

y = [4,5,6,7,8] #长度5

print(list(zip(x,y)))# 取最小长度3

#如果只传入一个迭代器,则返回的单个元素元组的迭代器。

print(list(zip([1,2,3])))

# 如果不传入参数,则返回空的迭代器。

print(list(zip()))

# zip(*[iter(s)]*n)等效于调用zip(iter(s),iter(s),...,iter(s))。

x = [1,2,3]

print(list(zip(*[x]*3)))

print(list(zip(x,x,x)))

x2, y2 = zip(*zip(x, y))

print(x == list(x2) and y == list(y2))

执行后会输出:

[(1, 4), (2, 5), (3, 6)]

[(1, 2, 3), (4, 5, 6)]

[(1, 4), (2, 5), (3, 6)]

[(1,), (2,), (3,)]

[]

[(1, 1, 1), (2, 2, 2), (3, 3, 3)]

[(1, 1, 1), (2, 2, 2), (3, 3, 3)]

False

1.66  函数__import__()

在Python程序中,使用函数__import__()的语法格式如下所示。

__import__(name[, globals[, locals[, fromlist[, level]]]])

参数name表示模块名,函数__import__()的功能是动态加载指定的类和函数。如果一个模块经常变化,就可以使用函数__import__()实现动态载入功能。函数__import__(module)相当于import module语句,例如在下面的实例中演示了函数__import__()的这一用法。

首先定义两个文件mian.py和index.py,将两个文件在同一目录下。其中文件index.py的具体实现代码如下所示。

print ('index')



def sayHello():

    print('hello index')



def sayHelloZhCn():

    print('你好 index')

文件mian.py的具体实现代码如下所示。

print ('main')



index = __import__('index')

dir(index)

index.sayHello()

index.sayHelloZhCn()

执行文件main.py,可以通过函数__import__()动态加载文件index.py,__import__()返回的模块也是index模块。执行后会输出:

main

index

hello index

你好 index

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农三叔

感谢鼓励

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值