candy 发表于 2018-8-3 12:24:47

Python基础:Python类(真累~)

  类的声明:
  一、类的属性
  (私有属性和公有属性)
  (类属性)
  二、类的方法
  (构造方法、析构方法、自定义方法、特殊成员方法)
  (静态方法、类方法、类属性)
  三、类的继承
  (方法和属性的继承,方法的重构)
  (抽象类,多重继承)
  四、类的多态
  (实现接口的重用)
  五、类的特殊装饰
  (@staticmethod、@classmethod、@property)
  六、类的来源和原类(metaclass)
  七、反射

[*]  类的声明
  使用class声明类,建议类名单词首字母大写。
  “新式类”和“经典类”的区分在Python 3之后就已经不存在,在Python 3.x之后的版本,因为所有的类都派生自内置类型object(即使没有显示的继承object类型),即所有的类都是“新式类”。
  新式类:
class Management(object):  

  
    def add():
  
      pass
  经典类:
class Management:  
    pass

[*]  类的属性
  类的属性就是类定义的变量值。
  公有属性:在类里直接定义的属性,它在类名下面直接定义。
  调用:1、类中调用:类名.属性名 ,更改原公有属性值
  2、实例调用:实例.属性名
class Management(object):  
    num = 10
  

  
    def add(self):
  
      Management.num +=10            # 类中调用公有属性并更改值,num=11
  
      pass
  

  
s1 = Management()
  
s2 = Management()
  

  
# 第一种情况:s1实例中调用公有属性,s2实例没有调用公有属性
  
s1.num +=1
  
Management.num += 2
  
"""
  
<结果>
  
s1不变,s2和Management都改变了
  
s1_num:11   s2_num:12   Manage_num:12
  
&quot;&quot;&quot;
  

  
# 第二种情况:先调用s1实例公有属性,再通过S1调用add更改,然后再使用类更改
  
s1.num +=1
  
s1.add()
  
Management.num += 2
  
&quot;&quot;&quot;
  
<结果>
  
先调用的s1实例num依然不变,s2和Management都被修改了
  
s1_num:11   s2_num:22   Manage_num:22
  

  
&quot;&quot;&quot;
  问题:为什么修改num的值以后,实例s1和实例s2会有不同的结果呢 ?
  因为公有属性查找的顺序是:先找实例的公有属性,没找到再找类里的公有属性
  可以这样理解:Management相当于一个微信群,num是群里发的一张照片,S1和S2是群里面的两个人。
  情况1:S1把照片存到本地,P了个双眼皮,S2说太难看了,我也不会P图,不保存。这个时候发照片的Management说我也觉得难看,把图撤回,重新发了一个P的图。S2就只能保存最新的图片。
  情况2:S1找到Management说你的图太丑了,重新改一下吧,Management说好!撤回图片修改了~
  私有属性:加两个下划线,__membername,编译的时候自动加上类名,变成_classname__membername,这种技术叫变量名压缩(mangling),以达到外部不能调用的目的。实际使用_classname__membername是可以调用的,但是不符合规定。标准方法是通过定义函数来获取。
class Classname(object):  
'''this is a demo!'''
  
def __init__(self):
  
self.__membername = 88
  

  
def read_membername(self):            # 标准的外部访问方法,使用函数来读取私有属性。
  
return self.__membername
  

  
s= Classname()
  
print(s._Classname__membername)
  
print(s.read_membername())
  
'''
  
<结果>
  
88
  
88
  
------像下面的调用,会出现AttributeError错误------
  
print(s.__membername)
  
'''
  类属性:类自带的属性,需要注意的是实例化的类属性,和原类的类属性不同。用上面的例子作演示。
属性作用示例结果__doc__类的文档字符串print(s.__doc__)  print(Classname.__doc__)
  this is a demo!
  this is a demo!
__dict__类的属性组成的字典print(s.__dict__)  print(Classname.__dict__)
  {'_Classname__membername': 88}
  {'__init__':, '__module__': '__main__', '__doc__': '\nthis is a demo!\n', 'read_membername':}
__name__类的名字(字符串)##不能用于实例print(s.__name__ )  print(Classname.__name__ )
  Classname
__bases__类的所有父类组成的元组#不能用于实例print(s.__bases__)  print(Classname.__bases__)
  (,)为什么没有值?可能是编译器问题
__module__类所属的模块print(s.__module__)  print(Classname.__module__)
__main__  __main__
__class__类对象的类型print(s.__class__)  print(Classname.__class__)
待测__slots__  限定类属性,在类属性位置定义
  未在slots定义的属性都是非法属性
__slots__.('name','age','sexy')使用'name','age','sexy'的以外属性会报错

[*]  类的方法
  类的方法就是类里面定义的函数。类的构造方法、析构方法、自定义类方法、静态方法、类方法、属性方法、特殊成员方法。
  构造方法:__init__
  实例化类的时候就会运行的函数。希望初始化的参数放置在init下面。(个人觉得,这个初始化参数可以是一切对象!)
class A(object):  
def instense(self):
  
print(&quot;init obj A&quot;)
  

  
class B(object):
  
def __init__(self, para):
  
self.init_para = para
  
self.obj_A = A()
  
self.num = 1
  

  
def show(self):
  
print(self.init_para)
  
self.obj_A.instense()
  
print(self.num)
  
haha = B(&quot;this is para&quot;)
  
haha.show()
  

  

  
----------
  
this is para
  

  
init obj A
  

  
1
  析构方法:
  __del__:销毁实例时,方法才会执行。
class Hello(object):  
    def __del__(self):
  
      print(&quot;你删除了实例&quot;)
  
# 在python上测试
  
instance = Hello()
  
del instance
  
# 当然也可以使用实例调用,但没有这么用的~~
  
instance.__del__()
  自定义方法:
  除去类中自带的以_下划线开头的函数,在类中定义一个函数,实现相应的功能。
class Person(object):  
    def __init__(self,person_name, person_age)
  静态方法:
  @staticmethod,不需要访问类里的任何参数。所带的参数都是从外部传入的。
class Person(object):  
    def __init__(self,person_name, person_age):
  
      self.name = person_name
  
      self.age = person_age
  

  
    @staticmethod
  
    def info(country):
  
      print(country)
  类方法:
  @classmethod,第一个参数必须是类属性。
class Person(object):  
    country = &quot;china&quot;
  
    def __init__(self,person_name, person_age):
  
      self.name = person_name
  
      self.age = person_age
  

  
    @classmethod
  
    def info(country):
  
      print(country)
  属性方法:
  @property把一个函数变成一个静态属性
  直接调用函数名字,不需要加括号,就能获取到函数返回值。一般用在不注重过程,只要结果的情况!
class Person(object):  
    country = &quot;china&quot;
  
    def __init__(self,person_name, person_age):
  
      self.name = person_name
  
      self.age = person_age
  

  
    @property
  
    def health_point(self):
  
      print(&quot;HP:【{}】&quot;.format(self.age*2))
  
      return self.age*2
  

  
P = Person(&quot;laowang&quot;,23)
  
P.health_point                # 不需要括号,看起来完全是一个属性,这就是属性方法
  

  
'''上面的类属性只是只读的,即然是叫属性,那么只读就显得太LOW了'''
  类属性装饰器@property,装饰以后,函数就有:赋值setter\销毁deleter两个方法。
class Person(object):  
    country = &quot;china&quot;
  
    def __init__(self,person_name, person_age):
  
      self.name = person_name
  
      self.age = person_age
  

  
    @property
  
    def health_point(self):
  
      self.age = self.age*2
  
      print(&quot;HP:【{}】&quot;.format(self.age))
  
      return self.age
  

  
    @health_point.setter                  # 增加了一个赋值方法
  
    def health_point(self, add):
  
      self.age = add
  

  
    @health_point.deleter                   # 增加了一个销毁属性的方法
  
    def health_point(self):
  
      del self.age
  

  
P = Person(&quot;laowang&quot;, 33)
  
print(P.health_point)
  

  
P.health_point = 22                        # 给health.point赋值
  
print(P.health_point)
  

  
del P.health_point                         # 销毁属性
  特殊成员方法:
方法作用示例结果__call__  默认未定义
  类实例化后,调用实例运行的方法
  p = Person()
  p()
  Person是类名
  实例p没有调用函数,加()运行call方法
__str__  默认未定义,定义时必须有返回值
  定义时,打印实例,输入str返回值
  p = Person()
  print (p)
  Person是类名
  打印实例p,运行str方法,打印返回值
__getitem__用于索引操作,如字典。获取数据  p = Person()
  p['name']
自动运行getitem__setitem__用于索引操作,如字典。赋值  p = Person()
  p['name'] = 'David'
自动运行setitem__delitem__用于索引操作,如字典。删除数据  p = Person()
  del p['name']
自动运行delitem__new__  类实例化时,执行__new__,并且会阻止
  init运行,可以在new里调用init
p = Person()参照例子二__len__待续__cmp__待续'''例子一call\str\getitem\setitem\delitem方法'''  
class Person(object):
  
def __call__(self):
  
print(&quot;print call&quot;)
  

  
def __str__(self):
  
print(&quot;print str:&quot;,end='')
  
return &quot;1&quot;
  

  
def __getitem__(self,key):
  
print(&quot;getitem:&quot;,key)
  

  
def __setitem__(self,key,value):
  
print('setitem:',key,value)
  

  
def __delitem__(self,key):
  
print('delitem:',key)
  

  
p = Person()
  
p()
  
print(p)
  
print('-----------')
  
get = p['name']
  
p['name'] = 'David'
  
del p['name']
'''例子二:__new__/__init__'''  
class Person(object):
  

  
def __init__(self):
  

  
print('this is init!')
  

  

  
def __new__(self):                  # __new__会阻断__init__执行,要想执行,需要写init方法
  

  
print(&quot;this is new!&quot;)
  

  
self.__init__(self)      # 如果去掉这一行,init不能执行
  

  
p = Person()
  类的来源和元类:
  http://blog.jobbole.com/21351/中文版详细解答。下面写一个自己理解的简版的。
  首先,类也是对象,可以:
  1)   你可以将它赋值给一个变量
  2)   你可以拷贝它
  3)   你可以为它增加属性
  4)   你可以将它作为函数参数进行传递
  类也是是由type()这个函数创建的,type是类的类,类的爹。学名叫元类!
  也许有人会问那为啥type()能查看到数据类型呢?
  可能你会注意到,type的结果前是class。。。因为数据类型在Python中都是类定义的,这也说明了,为什么数字,字符等等全是对象。
  type格式:
  type(类名,(父类元组),{属性和方法的字典}),父类元组可以没有;后面两个典省略时,默认值为None。
'''一言不合就上例子'''  

  
Person = type('Person',(),{'country':'china'})
  

  
print(Person.country)
  

  
# 带继承Person类的用法
  
def run():                  # 定义函数,把run传给Action的leg方法。
  
    print('running...')
  

  
Action = type('Action',(Person,),{'leg':run})
  

  
print(Action.country)
  
Action.leg()
  metaclass:
  创建类的时候,使用metaclass,python就会使用指定的元类创建类。找不到则使用type创建。
class MyType(type):  
    def __init__(self,*args,**kwargs):
  

  
      print(&quot;Mytype __init__&quot;,*args,**kwargs)
  

  
    def __call__(self, *args, **kwargs):
  
      print(&quot;Mytype __call__&quot;, *args, **kwargs)
  
      obj = self.__new__(self)
  
      print(&quot;obj &quot;,obj,*args, **kwargs)
  
      print(self)
  
      self.__init__(obj,*args, **kwargs)
  
      return obj
  

  
    def __new__(cls, *args, **kwargs):
  
      print(&quot;Mytype __new__&quot;,*args,**kwargs)
  
      return type.__new__(cls, *args, **kwargs)
  

  
print('here...')
  
class Foo(object,metaclass=MyType):
  
    def __init__(self,name):
  
      self.name = name
  

  
      print(&quot;Foo __init__&quot;)
  

  
    def __new__(cls, *args, **kwargs):
  
      print(&quot;Foo __new__&quot;,cls, *args, **kwargs)
  
      return object.__new__(cls)
  

  
f = Foo(&quot;Alex&quot;)
  
print(&quot;f&quot;,f)
  
print(&quot;fname&quot;,f.name)

[*]  类的继承
  代码重用。
  Python3中类有单继承和多继承,其中多继承与Python2的继承顺序不同。
  子类方法与父类重名,子类方法会覆盖父类
  单继承:
'''一言不合就上例子'''  

  
class Person(object):
  
    def __init__(self,person_name):
  
      self.name = person_name
  
    def info(self):
  
      print(&quot;this is personal info:\nname:{}&quot;.format(self.name))
  

  
class Action(Person):
  
    def __init__(self,person_name):
  
    '''父类析构函数有两种继承方法'''
  
      super(Action, self).__init__(person_name)   # 方法一
  
      # Person.__init__(self, person_name)          # 方法二
  

  
    def run(self):
  
      print(&quot;{} is running...&quot;.format(self.name))
  

  
a = Action('Alex')
  
a.run()                            # 继承了Person的属性。
  
a.info()                           # 继承了Person的方法。
  多重继承:
  不能同时继承两父亲类和爷爷类比如B继承A,C继承时就不能同时写A和B,只写B就可以了。
class ROOT(object):  
    def __init__(self):
  
      print(&quot;this is root&quot;)
  
    def action(self):
  
      print(&quot;ROOT is action...&quot;)
  

  

  
class A(ROOT):
  
    def __init__(self):
  
      super(A, self).__init__()
  
      print ('init A...')
  
    def action(self):
  
      print(&quot;A is action...&quot;)
  

  
class B(ROOT):
  
    def __init__(self):
  
      super(B, self).__init__()
  
      print ('init B...')
  
    def action(self):
  
      print(&quot;B is action...&quot;)
  

  
class C(A):
  
    def __init__(self):
  
      super(C, self).__init__()
  
      print ('init C...')
  
    def action(self):
  
      print(&quot;C is action...&quot;)
  

  
class D(B,C):
  
    def __init__(self):
  
      super(D, self).__init__()
  
      print ('init D...')
  
    def action(self):
  
      print(&quot;D is action...&quot;)
  

  
d = D()
  要理解继承的顺序,因为当方法重名时,顺序靠后的方法覆盖前面的方法。
  类的继承关系:                D(A,B)实例化时候的继承先后顺序:先找B(及其父类),再找C(及其父类)
      


[*]  类的多态
  多态就是同一个父类的方法,不同子类继承可以进行不同的改写,实现多种不同的功能。
  任何依赖父类作为参数的函数或者方法都可以不加修改地正常运行,原因就在于多态。
'''接着上面的例子'''  

  
# 定义一个函数,把ROOT类传进里面
  

  
def who_action(class_name):
  
    class_name.action()
  

  
who_action(ROOT())
  
who_action(D())
  
who_action(A())
页: [1]
查看完整版本: Python基础:Python类(真累~)