Python/类

维基教科书,自由的教学读本
跳到导航 跳到搜索

概述[编辑]

class ClassName(Base1, Base2, Base3):
   """Class documentation""" 
   def __init__(self,參數):
       語句
   def funcName(self,參數): #self 不是 python 關鍵字,把它換成其它名字也是表示類實例
       語句
       localVar = value0
       self.DataMember = value1
       self.__privateDataMember2 = value2
   dataMember1 = value    # A class attribute, not an instance one
   <statement-N>

super() 函數用於調用父類(超類)的一個方法。也可以用父类名来访问其一个方法。

类的字典(Class Dictionar): vars(instanceName) 或者instanceName.__dict__ # instance attributes as a dictionary

类属性可以用类名或者实例名加上属性名来访问。如果修改 <class instance>.<Class member> 的值,这实际上是(覆盖)创建了同名的实例属性。

在外部访问一个不存在的实例属性,这自动增加这个实例属性。用del关键字可以删除实例属性。这叫做动态类结构(Dynamic Class Structure)

类的特殊方法[编辑]

  • __init__ : 初始化函数,在生成对象时调用
  • __del__ : 析构函数,释放对象时使用
  • __repr__ : 直接输入instanceName再回车时输出一个字符串。
  • __str__: print(instanceName)时输出一个字符串。
  • __len__: 获得长度
  • __enter__ 与 __exit__ :专用于with语句
  • __new__:Metaclass构造函数
属性运算符重载函数
函数 间接形式 直接形式
__getattr__ getattr(A, B) A.B
__setattr__ setattr(A, B, C) A.B = C
__delattr__ delattr(A, B) del A.B

操作符重载,各个操作数必须都是该类的实例。带有赋值操作符如果没有重载,默认调用相应的双元运算符,结果值赋给自身这个名字。

二元运算符重载函数
函数 运算符
__add__ A + B
__sub__ A - B
__mul__ A * B
__truediv__ A / B
__floordiv__ A // B
__mod__ A % B
__pow__ A ** B
__and__ A & B
__or__ A | B
__xor__ A ^ B
__eq__ A == B
__ne__ A != B
__gt__ A > B
__lt__ A < B
__ge__ A >= B
__le__ A <= B
__lshift__ A << B
__rshift__ A >> B
__contains__ A in B
A not in B
酉运算符重载函数
函数 运算符
__pos__ +A
__neg__ -A
__inv__ ~A
__abs__ abs(A)
__len__ len(A)
元素项的索引与切片运算符重载函数
函数 运算符
__getitem__ C[i]
__setitem__ C[i] = v
__delitem__ del C[i]
__getslice__ C[s:e]
__setslice__ C[s:e] = v
__delslice__ del C[s:e]
其它重载函数
函数 运算符
__cmp__ cmp(x, y)
__hash__ hash(x)
__nonzero__ bool(x)
__call__ instanceName(params)
__iter__ iter(x)
__reversed__ reversed(x) (2.6+)
__divmod__ divmod(x, y)
__int__ int(x)
__long__ long(x)
__float__ float(x)
__complex__ complex(x)
__hex__ hex(x)
__oct__ oct(x)
__index__
__copy__ copy.copy(x)
__deepcopy__ copy.deepcopy(x)
__sizeof__ sys.getsizeof(x) (2.6+)
__trunc__ math.trunc(x) (2.6+)
__format__ format(x, ...) (2.6+)

综合示例[编辑]

import math
class MyComplex:
  """A complex number"""       # Class documentation
  classvar = 0.0               # A class attribute, not an instance one
  def phase(self):             # A method
    return math.atan2(self.imaginary, self.real)
  def __init__(self):          # A constructor
    """A constructor"""
    self.real = 0.0            # An instance attribute
    self.imaginary = 0.0
c1 = MyComplex()
c1.real = 3.14                 # No access protection
c1.imaginary = 2.71
phase = c1.phase()             # Method call
c1.undeclared = 9.99           # Add an instance attribute
del c1.undeclared              # Delete an instance attribute

print vars(c1)                 # Attributes as a dictionary
vars(c1)["undeclared2"] = 7.77 # Write access to an attribute
print c1.undeclared2           # 7.77, indeed

MyComplex.classvar = 1         # Class attribute access
print c1.classvar == 1         # True; class attribute access, not an instance one
print "classvar" in vars(c1)   # False
c1.classvar = -1               # An instance attribute overshadowing the class one
MyComplex.classvar = 2         # Class attribute access
print c1.classvar == -1        # True; instance attribute acccess
print "classvar" in vars(c1)   # True

class MyComplex2(MyComplex):   # Class derivation or inheritance
  def __init__(self, re = 0, im = 0):
    self.real = re             # A constructor with multiple arguments with defaults
    self.imaginary = im
  def phase(self):
    print "Derived phase"
    return MyComplex.phase(self) # Call to a base class; "super"
c3 = MyComplex2()
c4 = MyComplex2(1, 1)
c4.phase()                     # Call to the method in the derived class

class Record: pass             # Class as a record/struct with arbitrary attributes
record = Record()
record.name = "Joe"
record.surname = "Hoe"

新风格类[编辑]

从python 2.2开始支持新风格类(new-style class)。Python 3已经都是新风格类了,即使是按照老风格写的代码。

Classic Class:

>>> class ClassicFoo:
...     def __init__(self):
...         pass

New Style Class:

>>> class NewStyleFoo(object):
...     def __init__(self):
...         pass

属性[编辑]

属性(Property)是有getter与setter方法。

>>> class SpamWithProperties(object):
...     def __init__(self):
...         self.__egg = "MyEgg"
...     def get_egg(self):
...         return self.__egg
...     def set_egg(self, egg):
...         self.__egg = egg
...     egg = property(get_egg, set_egg)

>>> sp = SpamWithProperties()
>>> sp.egg
'MyEgg'
>>> sp.egg = "Eggs With Spam"
>>> sp.egg
'Eggs With Spam'
>>>

从Python 2.6开始有@property decorator:

>>> class SpamWithProperties(object):
...     def __init__(self):
...         self.__egg = "MyEgg"
...     @property
...     def egg(self):
...         return self.__egg
...     @egg.setter
...     def egg(self, egg):
...         self.__egg = egg

静态方法[编辑]

>>> class StaticSpam(object):
...     def StaticNoSpam():
...         print "You can't have have the spam, spam, eggs and spam without any spam... that's disgusting"
...     NoSpam = staticmethod(StaticNoSpam)

>>> StaticSpam.NoSpam()
You can't have have the spam, spam, eggs and spam without any spam... that's disgusting

或使用函数decorator @staticmethod

>>> class StaticSpam(object):
...     @staticmethod
...     def StaticNoSpam():
...         print "You can't have have the spam, spam, eggs and spam without any spam... that's disgusting"

菱形继承的方法搜索顺序[编辑]

Python 2.2开始,多继承中父类的搜索顺序是广度优先MRO(Method Resolution Order),称为C3算法。这样的新式类有__mro__属性,可以打印出父类搜索顺序。

最佳实践[编辑]

建议像C++那样使用类。使用<class>.<member>语法,代替__dict__。

封装[编辑]

所有的私有(属性或方法),都是在变量左边加双下划线。所有的私有,都不能在类的外部使用。父类的私有属性可以被子类调用吗? 不可以。

Python 其实没有真正的隐藏机制,双下画线只是 Python 的一个小技巧,Python 会“偷偷”地改变以双下画线开头的方法名,会在这些方法名前添加单下画线和类名。因此上面的 __method1() 方法其实可以按_className__method1方式调用(通常并不推荐这么干)。

Doc Strings[编辑]

鼓励使用

运行时增加方法[编辑]

增加给类[编辑]

class Spam:
  def __init__(self):
    self.myeggs = 5

def cook(self):
  print "cooking %s eggs" % self.myeggs

Spam.cook = cook   #add the function to the class Spam
eggs = Spam()      #NOW create a new instance of Spam
eggs.cook()        #and we are ready to cook!

This will output

cooking 5 eggs

增加给实例[编辑]

class Spam:
  def __init__(self):
    self.myeggs = 5

eggs = Spam()

def cook(self):
  print "cooking %s eggs" % self.myeggs

import types
f = types.MethodType(cook, eggs, Spam)
eggs.cook = f

eggs.cook()

输出为:

cooking 5 eggs

使用一个函数[编辑]

写一个函数来实现给类实例增加方法:

def attach_method(fxn, instance, myclass):
  f = types.MethodType(fxn, instance, myclass)
  setattr(instance, fxn.__name__, f)
attach_method(cook, eggs, Spam)

在函数add_method中不能写instance.fxn = f因为它增加了一次函数调用fxn到这个实例