类的详解

面向对象是一种编程方式,此编程方式的实现是基于对类和对象的使用。
类是一个模板,模板中包装了多个“函数”供使用(可以讲多函数中公用的变量封装到对象中)。
对象,根据模板创建的实例(即对象),实例用于调用被包装在类中的函数。类是对象的定义 ,而实例是“ 真正的实物”,它存放了类中所定义的对象的具体信息。
面向对象三大特性:封装、继承和多态。

1、类的定义:

1、使用 class 语句来创建一个新类,class 之后为类的名称并以冒号结尾:

class ClassName:'类的帮助信息'   #类文档字符串class_suite    #类体#类的帮助信息可以通过ClassName.__doc__查看。
#class_suite 由类成员,方法,数据属性组成。
#!/usr/bin/python
# -*- coding: UTF-8 -*-
class Employee:'所有员工的基类'empCount = 0def __init__(self, name, salary):self.name = nameself.salary = salaryEmployee.empCount += 1def displayCount(self):print "Total Employee %d" % Employee.empCountdef displayEmployee(self):print "Name : ", self.name,  ", Salary: ", self.salary#empCount 变量是一个类变量,它的值将在这个类的所有实例之间共享。你可以在内部类或外部类使用 Employee.empCount 访问。
#第一种方法__init__()方法是一种特殊的方法,被称为类的构造函数或初始化方法,当创建了这个类的实例时就会调用该方法
#self 代表类的实例,self 在定义类的方法时是必须有的,虽然在调用时不必传入相应的参数。
实例

2、self代表类的实例,而非类。类的方法与普通的函数只有一个特别的区别——它们必须有一个额外的第一个参数名称, 按照惯例它的名称是 self。

class Test:def prt(self):print(self)print(self.__class__)t = Test()
t.prt()'''
以上实例执行结果为:
<__main__.Test instance at 0x10d066878>
__main__.Test从执行结果可以很明显的看出,self 代表的是类的实例,代表当前对象的地址,而 self.__class__ 则指向类。
'''#self 不是 python 关键字,我们把他换成 runoob 也是可以正常执行的:
class Test:def prt(runoob):print(runoob)print(runoob.__class__)
t = Test()
t.prt()'''
以上实例执行结果为:
<__main__.Test instance at 0x10d066878>
__main__.Test
'''
self
''' 创建实例对象
实例化类其他编程语言中一般用关键字 new,但是在 Python 中并没有这个关键字,类的实例化类似函数调用方式。
以下使用类的名称 Employee 来实例化,并通过 __init__ 方法接收参数。'''#"创建 Employee 类的第一个对象"
emp1 = Employee("Zara", 2000)
#"创建 Employee 类的第二个对象"
emp2 = Employee("Manni", 5000)''' 访问属性
您可以使用点号 . 来访问对象的属性。使用如下类的名称访问类变量:'''emp1.displayEmployee()
emp2.displayEmployee()
print "Total Employee %d" % Employee.empCount''' 可以使用以下函数的方式来访问属性:
getattr(obj, name[, default]) : 访问对象的属性。
hasattr(obj,name) : 检查是否存在一个属性。
setattr(obj,name,value) : 设置一个属性。如果属性不存在,会创建一个新属性。
delattr(obj, name) : 删除属性。'''
属性访问

2、类的成员

1、字段包括:普通字段和静态字段,他们在定义和使用中有所区别,而最本质的区别是内存中保存的位置不同。普通字段属于对象,静态字段属于类。

#coding=utf-8
class Province:# 静态字段country = '中国'def __init__(self, name):# 普通字段self.name = name
# 直接访问普通字段
obj = Province('河北省')
print(obj.name)
# 直接访问静态字段
print(Province.country)'''
由上述代码可以看出【普通字段需要通过对象来访问】【静态字段通过类访问】,在使用上可以看出普通字段和静态字段的归属是不同的。其静态字段在内存中只保存一份,普通字段在每个对象中都要保存一份。
应用场景: 通过类创建对象时,如果每个对象都具有相同的字段,那么就使用静态字段。
'''
字段

2、类的方法包括实例方法、类方法、静态方法。

class Foo(object):  def test(self)://定义了实例方法  print("object")  @classmethod  def test2(clss)://定义了类方法  print("class")  @staticmethod  def test3()://定义了静态方法  print("static")  
方法
#coding=utf-8
class Apple:def fun1(self):return 'normal'@staticmethoddef fun2():return 'staticmethod'@classmethoddef fun3(cls):return 'classmethod'
print Apple.fun1
print Apple.fun2
print Apple.fun3
print "-"*80apple = Apple()
print apple.fun1
print apple.fun2
print apple.fun3
print "-"*80apple1 = Apple()
print apple1.fun1
print apple1.fun2
print apple1.fun3'''
输出结果:
1、<unbound method Apple.fun1>
2、<function fun2 at 0x00000000022FC4A8>
3、<bound method classobj.fun3 of <class __main__.Apple at 0x0000000001E7C768>>
4、----------------------------------------------------------------------------
5、<bound method Apple.fun1 of <__main__.Apple instance at 0x00000000022FAE08>>
6、<function fun2 at 0x00000000022FC4A8>
7、<bound method classobj.fun3 of <class __main__.Apple at 0x0000000001E7C768>>
8、----------------------------------------------------------------------------
9、 <bound method Apple.fun1 of <__main__.Apple instance at 0x00000000022FAE48>>
10、<function fun2 at 0x00000000022FC4A8>
11、<bound method classobj.fun3 of <class __main__.Apple at 0x0000000001E7C768>>
--------------------- ------------------------------------------------------
''''''
解析:
1、普通方法传入的第一个参数必须是self(当然也可以不用self,官方要求尽量用self),self是指实例对象本身;
2、静态方法无需传参;
3、类方法传入的第一个参数必须是class,是指类本身。
对比结果1,5,9行: 
fun1通过class调用时,它是未绑定的方法,而实例化apple和apple1之后,它属于绑定的方法,且实例化后的apple和apple1内存地址不同,因为它们属于不同的实例对象。
对比结果2,6,10行: 
静态方法fun2通过class调用或者通过实例化后的对象调用,是没有任何区别的,全部都是指向同一块内存地址。可以简单的理解成静态方法与类或者实例没有任何关系,一旦调用后,它的内存地址即确定。
对比结果3,7,11行: 
类方法fun3通过class调用或者通过实例化后的对象调用,是没有任何区别的,全部都是指向同一块内存地址。为什么?因为实例化对象apple和apple1调用类方法fun3传入的第一个参数是类本身Apple,也就是说apple.fun3 = apple1.fun3 = Apple.fun3。区别总结:
1、静态方法装饰器下定义的方法属于函数(function);
2、类方法装饰器下定义的方法属于方法(method);
3、静态方法无需传入任何参数;
4、类方法传入的第一个参数必须是class本身cls;
5、静态方法与类方法一旦被调用,内存地址即确定。通过类调用和通过实例化对象调用的结果完全一样。
6、三种方法从不同层次上来对方法进行了描述:实例方法针对的是实例,类方法针对的是类,他们都可以继承和重新定义,而静态方法则不能继承,可以认为是全局函数
'''
实例解析

3、如果你已经了解Python类中的方法,那么属性就非常简单了,因为Python中的属性其实是普通方法的变种。

#coding=utf-8
# ############### 定义 ###############
class Foo:def func(self):pass# 定义属性
    @propertydef prop(self):pass
# ############### 调用 ###############
foo_obj = Foo()
foo_obj.func()
foo_obj.prop   #调用属性'''
由属性的定义和调用要注意一下几点:
定义时,在普通方法的基础上添加 @property 装饰器;
定义时,属性仅有一个self参数
调用时,无需括号方法:foo_obj.func()属性:foo_obj.prop
注意:属性存在意义是:访问属性时可以制造出和访问字段完全相同的假象属性由方法变种而来,如果Python中没有属性,方法完全可以代替其功能
'''
属性

属性的两种定义方式
属性的定义有两种方式:
装饰器 即:在方法上应用装饰器
静态字段 即:在类中定义值为property对象的静态字段

'''
装饰器方式
装饰器方式:在类的普通方法上应用@property装饰器
我们知道Python中的类有经典类和新式类,新式类的属性比经典类的属性丰富。( 如果类继object,那么该类是新式类 )
经典类,具有一种@property装饰器(如上一步实例)
'''# ############### 定义 ###############    
class Goods:@propertydef price(self):return "wupeiqi"
# ############### 调用 ###############
obj = Goods()
result = obj.price  # 自动执行 @property 修饰的 price 方法,并获取方法的返回值#新式类,具有三种@property装饰器
# ############### 定义 ###############
class Goods(object):@propertydef price(self):print '@property'@price.setterdef price(self, value):print '@price.setter'@price.deleterdef price(self):print '@price.deleter'
# ############### 调用 ###############
obj = Goods()
obj.price      # 自动执行 @property 修饰的 price 方法,并获取方法的返回值
obj.price= 123 # 自动执行 @price.setter修饰的price方法,并将123赋值给方法的参数
del obj.price  # 自动执行 @price.deleter 修饰的 price 方法'''
注:经典类中的属性只有一种访问方式,其对应被 @property 修饰的方法新式类中的属性有三种访问方式,并分别对应了三个被@property、@方法名.setter、@方法名.deleter修饰的方法
由于新式类中具有三种访问方式,我们可以根据他们几个属性的访问特点,分别将三个方法定义为对同一个属性:获取、修改、删除
'''
装饰器方式
#静态字段方式,创建值为property对象的静态字段
#当使用静态字段的方式创建属性时,经典类和新式类无区别class Foo:def get_bar(self):return 'good'BAR = property(get_bar)
obj = Foo()
reuslt = obj.BAR        # 自动调用get_bar方法,并获取方法的返回值
print result'''
property的构造方法中有个四个参数
第一个参数是方法名,调用 对象.属性 时自动触发执行方法
第二个参数是方法名,调用 对象.属性 = XXX 时自动触发执行方法
第三个参数是方法名,调用 del 对象.属性 时自动触发执行方法
第四个参数是字符串,调用 对象.属性.__doc__ ,此参数是该属性的描述信息
'''
静态字段方式

 3、新式类和旧式类

# -*- coding: utf-8 -*-
# 经典类或者旧试类
class A:pass
a = A()# 新式类
class B(object):pass
b = B()# python2不支持
# print(A.__class__)
print(a.__class__)
print(type(A))
print(type(a))# python2
# __main__.A
# <type 'classobj'>
# <type 'instance'># python3
# <class 'type'>
# <class '__main__.A'>
# <class 'type'>
# <class '__main__.A'>print(B.__class__)
print(b.__class__)
print(type(B))
print(type(b))# python2
# <type 'type'>
# <class '__main__.B'>
# <type 'type'>
# <class '__main__.B'># python3
# <class 'type'>
# <class '__main__.B'>
# <class 'type'>
# <class '__main__.B'># 旧式类的实现不够好,类是类,实例是实例,类的类型是classobj,实例的类型是instance,两者的联系只在于__class__,
# 这和内置对象是不同的,int对象的类型就是int,同时int()返回的也是int类型的对象,内置对象和自定义对象不同就对代码统一实现带来很大困难。
#
# 新式类
#
# 1. 所有类的类型都是type
# 2. 所有类调用的结果都是构造,返回这个类的实例
# 3. 所有类都是object的子类
# 4. 新式类不仅可以用旧类调用父类的方法,也可以用super方法。
View Code

 4、类的私有成员

1):单下划线_开头:只是告诉别人这是私有属性,外部依然可以访问更改
2):双下划线__开头:外部不可通过实例化对象.属性名来访问或者更改
实际将其转化为了_类名_属性名,只是在内部将变量名修改了,我们仍让可以通过._类名_属性名访问

>>>class Test():
>>>    a = 100
>>>Test.__dict__
Out[3]: {'__doc__': None, '__module__': '__main__', 'a': 100}>>>class Test():
>>>    __a = 100
>>>Test.__dict__
Out[5]: {'_Test__a': 100, '__doc__': None, '__module__': '__main__'}
>>>Test._Test__a
Out[6]: 100
实例

私有成员和公有成员的访问限制不同:
1) 静态字段
公有静态字段:类可以访问;类内部可以访问;派生类中可以访问
私有静态字段:仅类内部可以访问;
2) 普通字段
公有普通字段:对象可以访问;类内部可以访问;派生类中可以访问
私有普通字段:仅类内部可以访问;
注意:如果想要强制访问私有字段,可以通过【对象._类名__私有字段明】访问(如:obj._C__foo),不建议强制访问私有成员。方法、属性的访问于上述方式相似,即:私有成员只能在类内部使用

5、类成员的修改

1、修改类的对象(实例)属性

#coding=utf-8
class Test(object):a = 100def __init__(self):pass
t1 = Test()
t2 = Test()
#1.通过实例对象t1修改类属性的值
print("修改前:t1.a = %d, t2.a = %d, Test.a = %d"%(t1.a, t2.a, Test.a))
t1.a += 100
print("修改后:t1.a = %d, t2.a = %d, Test.a = %d"%(t1.a, t2.a, Test.a))'''
输出:
修改前:t1.a = 100, t2.a = 100, Test.a = 100 
修改后:t1.a = 200, t2.a = 100, Test.a = 100
'''
View Code

很明显,我们通过实例对象修改类属性的值,并没有在全局范围奏效,它只是对t1对象的实例属性修改了,实际上并没有对本身定义的类属性和其它的对象的属性造成变动。

2、修改类的属性:

class Test(object):a = 100def __init__(self):pass
t1 = Test()
t2 = Test()
#1.通过类名修改类属性的值
print("修改前:t1.a = %d, t2.a = %d, Test.a = %d"%(t1.a, t2.a, Test.a))
Test.a += 100
print("修改后:t1.a = %d, t2.a = %d, Test.a = %d"%(t1.a, t2.a, Test.a))'''
输出: 
修改前:t1.a = 100, t2.a = 100, Test.a = 100 
修改后:t1.a = 200, t2.a = 200, Test.a = 200
'''
View Code

通过类名修改的类属性,在全局范围奏效,也就是说确实修改了类属性的值,在实例对象中我们看到属性值全部被修改。

6、类的内置特殊成员

#coding=utf-8
class Province:"""Genius is thing but labor and diligence!"""country = 'China'def __init__(self, name, count):self.name = nameself.count = countdef func(self, *args, **kwargs):city="New"print 'func'
obj = Province('HeBei',10000)   # 自动执行类中的 __init__ 方法
print obj      
'''
#__init__构造方法,通过类创建对象时,自动触发执行。输出:
<__main__.Province instance at 0x0000000003989108>
'''
__init__
#coding=utf-8
class Province:"""Genius is thing but labor and diligence!"""country = 'China'def __init__(self, name, count):self.name = nameself.count = countdef func(self, *args, **kwargs):city="New"print 'func'def __del__(self):          #当对象在内存中被释放时,自动触发执行。pass
obj = Province('HeBei',10000)   
print obj      
'''
#__del__析构方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。输出:
<__main__.Province instance at 0x0000000003989108>
'''
__del__
#coding=utf-8
class Province:"""Genius is thing but labor and diligence!"""country = 'China'def __init__(self, name, count):self.name = nameself.count = countdef func(self, *args, **kwargs):city="New"print 'func'def __del__(self):passdef __call__(self):print "__call__"
obj = Province('HeBei',10000)   
print obj()             #对象后面加括号,触发执行。
'''
#__call__构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()输出:
__call__
None
'''
__call__
#coding=utf-8
class Province:"""Genius is thing but labor and diligence!"""country = 'China'def __init__(self, name, count):self.name = nameself.count = countdef func(self, *args, **kwargs):city="New"print 'func'def __del__(self):passdef __call__(self):print "__call__"def __str__(self):return("__str__")
obj = Province('HeBei',10000)   
print obj    '''
#__str__如果一个类中定义了__str__方法,那么在打印对象时,默认输出该方法的返回值。输出:
__str__
'''
__str__
#用于迭代器,之所以列表、字典、元组可以进行for循环,是因为类型内部定义了 __iter__。
#a)第一步
class Foo(object):pass
obj = Foo()
for i in obj:print i
# 报错:TypeError: 'Foo' object is not iterable#b)    第二步
#!/usr/bin/env python
# -*- coding:utf-8 -*-
class Foo(object):   def __iter__(self):pass
obj = Foo()
for i in obj:print i
# 报错:TypeError: iter() returned non-iterator of type 'NoneType'#c)    第三步
#!/usr/bin/env python
# -*- coding:utf-8 -*-
class Foo(object):def __init__(self, sq):self.sq = sqdef __iter__(self):return iter(self.sq)
obj = Foo([11,22,33,44])
for i in obj:
print i#d)For循环语法内部
#!/usr/bin/env python
# -*- coding:utf-8 -*-
obj = iter([11,22,33,44])
while True:val = obj.next()print val
__iter__
#coding=utf-8
class Foo(object):def __getitem__(self, key):print('__getitem__', key)def __setitem__(self, key, value):# print('__setitem__', key, value)self.key = keyself.value = valueprint(key,value)return self.keydef __delitem__(self, key):print('__delitem__', key)obj =Foo()
result = obj['k1']       # 自动触发执行 __getitem__
obj['k3']='xxxxxx'      # 自动触发执行 __setitem__
del obj['k1']               # 自动触发执行 __delitem__
__getitem__、__setitem__、__delitem__
#该三个方法用于分片操作,如:列表。
#!/usr/bin/env python
# -*- coding:utf-8 -*-
class Foo(object):def __getslice__(self, i, j):print '__getslice__',i,jdef __setslice__(self, i, j, sequence):print '__setslice__',i,jdef __delslice__(self, i, j):print '__delslice__',i,j
obj = Foo()
obj[-1:1]                               # 自动触发执行 __getslice__
obj[0:1] = [11,22,33,44]      # 自动触发执行 __setslice__
del obj[0:2]                          # 自动触发执行 __delslice__
__getslice__、__setslice__、__delslice__
'''
__new__()在Python :类里面的构造方法init()负责将类的实例化,而在init()调用之前,new()决定是否要使用该init()方法,
因为new()可以调用其他类的构造方法或者直接返回别的对象来作为本类 的实例。
如果将类比喻为工厂,那么init()方法则是该工厂的生产工人,init()方法接受的初始化参 数则是生产所需原料,init()方法会按照方法中的语句负责将原料加工成实例以供工厂出货。而 new()则是生产部经理,new()方法可以决定是否将原料提供给该生产部工人,同时它还决定着出 货产品是否为该生产部的产品,因为这名经理可以借该工厂的名义向客户出售完全不是该工厂的产品。
new()方法的特性:
new()方法是在类准备将自身实例化时调用。
new()方法始终都是类的静态方法,即使没有被加上静态方法装饰器。
''''''
通常来说,新式类开始实例化时,new()方法会返回cls(cls指代当前类)的实例,然后该类的 init()方法作为构造方法会接收这个实例(即self)作为自己的第一个参数,然后依次传入new ()方法中接收的位置参数和命名参数。
注意:如果new()没有返回cls(即当前类)的实例,那么当前类的init()方法是不会被调用 的。
如果new()返回其他类(新式类或经典类均可)的实例,那么只会调用被返回的那个类的构造方 法。
'''
class Foo(object):def __init__(self, *args, **kwargs):passdef __new__(cls, *args, **kwargs):return object.__new__(Stranger, *args, **kwargs) #重写Foo类的new方法,返回Stranger类的实例class Stranger(object):passfoo = Foo()
print(type(foo)) #结果显示foo其实是Stranger类的实例 <class '__main__.Stranger'>#链接:https://blog.csdn.net/Four_Infinite/article/details/52798919#__init__与__new__的先后执行顺序
class Test(object):def __init__(self,name):self.name = nameprint "hey"def __new__(cls, *args, **kwargs):print "hello"return object.__new__(cls, *args, **kwargs)
f = Test("study")'''
输出:hellohey
'''
__new__
#阅读以下代码:
class Foo(object):def __init__(self):pass 
obj = Foo()   # obj是通过Foo类实例化的对象'''
上述代码中,obj 是通过 Foo 类实例化的对象,其实,不仅 obj 是一个对象,Foo类本身也是一个对象,因为在Python中一切事物都是对象。如果按照一切事物都是对象的理论:obj对象是通过执行Foo类的构造方法创建,那么Foo类对象应该也是通过执行某个类的 构造方法 创建。
print type(obj) # 输出:<class '__main__.Foo'>     表示,obj 对象由Foo类创建
print type(Foo) # 输出:<type 'type'>              表示,Foo类对象由 type 类创建
所以,obj对象是Foo类的一个实例,Foo类对象是 type 类的一个实例,即:Foo类对象 是通过type类的构造方法创建。
'''#那么,创建类就可以有两种方式:
#a)    普通方式
class Foo(object):def func(self):print 'hello wupeiqi'
#b)    特殊方式(type类的构造函数)
def func(self):print 'hello wupeiqi'
Foo = type('Foo',(object,), {'func': func})
#type第一个参数:类名
#type第二个参数:当前类的基类
#type第三个参数:类的成员'''
==》 类 是由 type 类实例化产生
那么问题来了,类默认是由 type 类实例化产生,type类中如何实现的创建类?类又是如何创建对象?答:类中有一个属性 __metaclass__,其用来表示该类由 谁 来实例化创建,所以,我们可以为 __metaclass__ 设置一个type类的派生类,从而查看 类 创建的过程。
'''
__metaclass__
'''
__new__ is the method called before __init__
It's the function that actually creates the object and returns it.
__init__ only initialize the object passed as a parameter.
We rarely use __new__, except when we want to control how the object
is created.
For a metaclass, the object created is a class. And since we want to 
customize it, we need to override __new__.
We can also do something by overriding __init__ to get customized initialization
process as well.
Advanced usage involves override __call__, but we won't talk about this here.'''
#链接:https://www.jianshu.com/p/224ffcb8e73e
#链接:https://www.jianshu.com/p/14b8ebf93b73
__new__ and __init__
class Test(type):pass
class Name(object):__metaclass__ = Testf = Name()
print type(f)
print type(Name)
print type(Test)'''
输出:<class '__main__.Name'><class '__main__.Test'><type 'type'>
'''class Test(type):def __init__(self,*args,**kwargs):super(Test,self).__init__(*args,**kwargs)def test(self,name):return name
class Name(object):__metaclass__ = Testdef __init__(self,what):self.what = whatdef sayhi(self):return self.whatf = Name("cat")
print type(f)
print type(Name)
print type(Test)'''
输出:<class '__main__.Name'><class '__main__.Test'><type 'type'>
'''
__metaclass__2
class Fo():passclass FFo(object):passprint type(Fo)
print type(type(Fo))
print type(FFo)'''
输出:<type 'classobj'><type 'type'><type 'type'>
'''
新旧类的type类型区别

 

#__doc__表示类的描述信息
#__module__表示当前操作的对象在那个模块,类定义所在的模块(类的全名是'__main__.className',如果类位于一个导入模块mymod中,那么className.__module__ 等于 mymod)
#__class__表示当前操作的对象的类是什么
#__name__表示类名
#__bases__类的所有父类构成元素(包含了一个由所有父类组成的元组)
#__dict__表示类或对象中的所有成员(包含一个字典,由类的数据属性组成)。

#coding=utf-8
class Province:"""Genius is thing but labor and diligence!"""country = 'China'def __init__(self, name, count):self.name = nameself.count = countdef func(self, *args, **kwargs):city="New"print 'func'
print Province.__doc__
print Province.__module__
#print Province.__class__    #AttributeError: class Province has no attribute '__class__'
print Province.__name__
print Province.__bases__
print Province.__dict__'''
#__doc__表示类的描述信息
#__module__表示当前操作的对象在那个模块,类定义所在的模块(类的全名是'__main__.className',如果类位于一个导入模块mymod中,那么className.__module__ 等于 mymod)
#__class__表示当前操作的对象的类是什么
#__name__表示类名
#__bases__类的所有父类构成元素(包含了一个由所有父类组成的元组)
#__dict__表示类的属性(包含一个字典,由类的数据属性组成)输出:
Genius is thing but labor and diligence!
__main__
Province
()
{'country': 'China', '__module__': '__main__', 'func': <function func at 0x000000000329C358>, '__doc__': 'Genius is thing but labor and diligence!', '__init__': <function __init__ at 0x000000000329C2E8>}'''
类的特殊成员
#coding=utf-8
class Province:"""Genius is thing but labor and diligence!"""country = 'China'def __init__(self, name, count):self.name = nameself.count = countdef func(self, *args, **kwargs):city="New"print 'func'
obj = Province('HeBei',10000)
print obj.__doc__ 
print obj.__module__
print obj.__class__  
#print obj.__name__    #AttributeError: Province instance has no attribute '__name__'  
#print obj.__bases__   #AttributeError: Province instance has no attribute '__bases__'
print obj.__dict__'''
#__doc__表示类的描述信息
#__module__表示当前操作的对象在那个模块,类定义所在的模块(类的全名是'__main__.className',如果类位于一个导入模块mymod中,那么className.__module__ 等于 mymod)
#__class__表示当前操作的对象的类是什么
#__name__表示类名
#__bases__类的所有父类构成元素(包含了一个由所有父类组成的元组)
#__dict__表示类的属性(包含一个字典,由类的数据属性组成)输出:
Genius is thing but labor and diligence!
__main__
__main__.Province
{'count': 10000, 'name': 'HeBei'}
'''
类的实例特殊成员

7、类的继承

面向对象编程 (OOP) 语言的一个主要功能就是“继承”。继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。

'''
通过继承创建的新类称为“子类”或“派生类”,被继承的类称为“基类”、“父类”或“超类”,继承的过程,就是从一般到特殊的过程。在某些 OOP 语言中,一个子类可以继承多个基类。但是一般情况下,一个子类只能有一个基类,要实现多重继承,可以通过多级继承来实现。继承概念的实现方式主要有2类:实现继承、接口继承。
实现继承是指使用基类的属性和方法而无需额外编码的能力。
接口继承是指仅使用属性和方法的名称、但是子类必须提供实现的能力(子类重构爹类方法)。
在考虑使用继承时,有一点需要注意,那就是两个类之间的关系应该是“属于”关系。例如,Employee 是一个人,Manager 也是一个人,因此这两个类都可以继承 Person 类。但是 Leg 类却不能继承 Person 类,因为腿并不是一个人。OO开发范式大致为:划分对象→抽象类→将类组织成为层次化结构(继承和合成) →用类与实例进行设计和实现几个阶段。
'''
#coding=utf-8class Person(object):   # 定义一个父类def talk(self):    # 父类中的方法print("person is talking....")  class Chinese(Person):    # 定义一个子类, 继承Person类def walk(self):      # 在子类中定义其自身的方法print('is walking...')c = Chinese()
c.talk()      # 调用继承的Person类的方法
c.walk()     # 调用本身的方法'''
# 输出
person is talking....
is walking...
'''
View Code
"""
如果我们要给实例 c 传参,我们就要使用到构造函数,那么构造函数该如何继承,同时子类中又如何定义自己的属性?
继承类的构造方法:1.经典类的写法: 父类名称.__init__(self,参数1,参数2,...)2. 新式类的写法:super(子类,self).__init__(参数1,参数2,....)
"""#coding=utf-8
class Person(object):def __init__(self, name, age):self.name = nameself.age = ageself.weight = 'weight'def talk(self):print("person is talking....")class Chinese(Person):def __init__(self, name, age, language):  # 先继承,在重构Person.__init__(self, name, age)  #继承父类的构造方法,也可以写成:super(Chinese,self).__init__(name,age)self.language = language    # 定义类的本身属性def walk(self):print('is walking...')class American(Person):pass
c = Chinese('bigberg', 22, 'Chinese')
构造函数的继承
class Person(object): def __init__(self, name, age):self.name = nameself.age = ageself.weight = 'weight'def talk(self):print("person is talking....")class Chinese(Person):def __init__(self, name, age, language): Person.__init__(self, name, age) self.language = languageprint(self.name, self.age, self.weight, self.language)def talk(self):  # 子类 重构方法print('%s is speaking chinese' % self.name)def walk(self):print('is walking...')c = Chinese('bigberg', 22, 'Chinese')
c.talk()'''
# 输出
bigberg 22 weight Chinese
bigberg is speaking chinese
'''
父类方法的重写

8、类的多态

多态是面向对象的重要特性,简单点说:“一个接口,多种实现”,指一个基类中派生出了不同的子类,且每个子类在继承了同样的方法名的同时又对父类的方法做了不同的实现,这就是同一种事物表现出的多种形态。

"""
编程其实就是一个将具体世界进行抽象化的过程,多态就是抽象化的一种体现,把一系列具体事物的共同点抽象出来, 再通过这个抽象的事物, 与不同的具体事物进行对话,对不同类的对象发出相同的消息将会有不同的行为。 
多态允许将子类的对象当作父类的对象使用,某父类型的引用指向其子类型的对象,调用的方法是该子类型的方法。这里引用和调用方法的代码编译前就已经决定了,而引用所指向的对象可以在运行期间动态绑定。
"""
#一个抽象类具有多个子类,就是多种形态。多态依赖于继承,没有继承就没有多态。class Animal(object):def __init__(self, name, age):self.name = nameself.age = agepassclass Dog(Animal):def __init__(self, name, age, breed):super(Dog, self).__init__(name, age)self.breed = breedpassclass Cat(Animal):def __init__(self, name, age, breed):super(Cat, self).__init__(name, age)self.breed = breedpass#我们定义了一个 Animal类,又定义了其两个子类 :Dog 和 Cat。这两个子类就表示了Animal这个类的多种形态。
View Code

多态性是指具有不同功能的函数可以使用相同的函数名,这样就可以用一个函数名调用不同内容的函数。在面向对象方法中一般是这样表述多态性:向不同的对象发送同一条消息,不同的对象在接收时会产生不同的行为(即方法)。也就是说,每个对象可以用自己的方式去响应共同的消息。所谓消息,就是调用函数,不同的行为就是指不同的实现,即执行不同的函数。

9、对象销毁(垃圾回收)

要保持追踪内存中的对象,Python使用了引用计数这一简单技术。也就是说Python内部记录着所有使用中的对象 各有多少引用。一个内部跟踪变量,称为引用计数器。每个对象各有多少个引用,简称引用计数。当对象被创建时,就创建了一个引用计数,当这个对象不再需要时,也就是说,这个对象的引用计数变为0时,它被垃圾回收。(并不是100%这样)

链接:https://www.cnblogs.com/bigberg/p/7591463.html

转载于:https://www.cnblogs.com/windyrainy/p/10654862.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/394412.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

leetcode279. 完全平方数(动态规划)

给定正整数 n&#xff0c;找到若干个完全平方数&#xff08;比如 1, 4, 9, 16, …&#xff09;使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。 示例 1: 输入: n 12 输出: 3 解释: 12 4 4 4. 解题思路 数组含义&#xff1a;dp[i]数字i对应组成和的完全平方…

什么情况不能办理房产抵押贷款 房产抵押贷能贷多少?

所谓房产抵押贷款是指以自己或亲友的房产作为抵押物向贷款机构申请贷款&#xff0c;款项可用于企业经营、买房、买车、装修及其他用途的融资方式。但是有些情况是规定不能申请房产抵押贷款的&#xff0c;而且贷款的数额是有限的&#xff0c;不是想贷多少就多少。那么&#xff0…

Android RecyclerView 二级列表实现

Android RecyclerView 二级列表实现

2数据库表增加一个字段_14个实用的数据库设计技巧!

1. 原始单据与实体之间的关系可以是一对一、一对多、多对多的关系。在一般情况下&#xff0c;它们是一对一的关系&#xff1a;即一张原始单据对应且只对应一个实体。在特殊情况下&#xff0c;它们可能是一对多或多对一的关系&#xff0c;即一张原始单证对应多个实体&#xff0c…

错误: 找不到或无法加载主类 helloworld_全面剖析虚拟机类加载机制

1.引言java源文件经过编译后生成字节码class文件&#xff0c;需要经过虚拟机加载并转换成汇编指令才能执行&#xff0c;那么虚拟机是如何一步步加载这些class文件的对于java程序员是完全透明的&#xff0c;本文尝试全面分析jvm类加载机制。2.思考开始之前我们来简单思考一下&am…

nginx反向代理和shiro权限校验产生的404问题

问题描述: 我们的项目A&#xff08;以下简称A&#xff09;用了shiro做权限校验&#xff0c;nginx做反向代理&#xff0c;在另一个项目B&#xff08;以下简称B&#xff09;中点击某个A的链接时实现单点登录并会跳转到该路径。跳转到原路径的时候nginx报了404。出现404之后再次点…

android 揭示动画_如何使用意图揭示函数名称使代码更好

android 揭示动画Discover Functional JavaScript was named one of the best new Functional Programming books by BookAuthority!“发现功能JavaScript”被BookAuthority评为最佳新功能编程书籍之一 &#xff01; Code is a way to communicate with developers reading it…

200道物理学难题——038蚱蜢跃树

转载于:https://www.cnblogs.com/hanford/p/6168514.html

(转)dp动态规划分类详解

dp动态规划分类详解 转自&#xff1a;http://blog.csdn.NET/cc_again/article/details/25866971 动态规划一直是ACM竞赛中的重点&#xff0c;同时又是难点&#xff0c;因为该算法时间效率高&#xff0c;代码量少&#xff0c;多元性强&#xff0c;主要考察思维能力、建模抽象能力…

strcmp可以比较数组么_大家都用过百度云,但你面试过百度云么

作者&#xff1a;黄小斜百度研发面经百度智能云软件研发工程师百度智能云研发岗好像是做控制台方面的组一面&#xff1a;1自我介绍&#xff0c;项目2 static关键字有什么用&#xff0c;static修饰不同东西时有什么作用&#xff0c;内部类用static修饰和不用static修饰有何区别。…

leetcode785. 判断二分图(dfs和bfs染色)

给定一个无向图graph&#xff0c;当这个图为二分图时返回true。 如果我们能将一个图的节点集合分割成两个独立的子集A和B&#xff0c;并使图中的每一条边的两个节点一个来自A集合&#xff0c;一个来自B集合&#xff0c;我们就将这个图称为二分图。 graph将会以邻接表方式给出…

bdd cucumber_如何使用BDD构建坚如磐石的Ruby on Rails应用

bdd cucumberby Marko Anastasov通过Marko Anastasov 如何使用BDD构建坚如磐石的Ruby on Rails应用 (How to build rock-solid Ruby on Rails apps with BDD) 了解通过行为驱动开发来构建可持续Web应用程序的最佳实践。 (Learn best practices for building sustainable web a…

go kegg_KEGG分析及可视化

上一篇推文中我们解释了GO富集分析及可视化&#xff08;GO富集分析及可视化&#xff09;&#xff0c;除了GO富集分析&#xff0c;我们经常在paper中看到KEGG分析&#xff0c;KEGG是什么呢&#xff0c;Kyoto Encyclopedia of Genes and Genomes&#xff0c;京都基因和基因组百科…

IntelliJ IDEA注册码

IntelliJ IDEA注册码 http://idea.lanyus.com/ 1.导航栏下 2.help下 3.register点击 4.单选Activation code 5.粘贴注册码 转载于:https://www.cnblogs.com/YUJIE666/p/10662561.html

单词本.

offset 偏移量 charset字符集 str 代表String字符串 IgnoreCase忽略大小写 Object 对象 argument 参数 if and only if:当且仅当 value:值 specified:指定 Parameters:参数 iterator:迭代器 invoke:调用 variable:变量 resolved:解决 sequnence 序列 default:默认转载于:http…

leetcode931. 下降路径最小和(动态规划)

给定一个方形整数数组 A&#xff0c;我们想要得到通过 A 的下降路径的最小和。 下降路径可以从第一行中的任何元素开始&#xff0c;并从每一行中选择一个元素。在下一行选择的元素和当前行所选元素最多相隔一列。 示例&#xff1a; 输入&#xff1a;[[1,2,3],[4,5,6],[7,8,9…

lvm使用

注&#xff1a;新添加的硬盘&#xff0c;如果没有分区&#xff0c;可以直接使用pvcreate进行创建&#xff0c;然后用vgextend进行扩展如果新添加的硬盘经过分区&#xff0c;则要把需要扩展的分区修改为8e格式&#xff0c;则进行扩展以上内容实测~相关概念&#xff1a;pv:物理卷…

python django用户登录系统_Django实现用户注册登录

学习Django中&#xff1a;试着着写一个用户注册登录系统&#xff0c;开始搞事情 O(∩_∩)O哈哈~Ubuntupython 2.7.12Django 1.10.4IDE&#xff1a;PycharmBootstrap(其实没怎么用~~)新建项目&#xff1a;(我是直接用pycharm直接生成的)使用终端&#xff1a;(创建项目)django-ad…

ubantu 添加防火墙策略_ubuntu安装防火墙并策略配置

1、安装ubuntu防火墙sudo apt-get install ufw启用sudo ufw enablesudo ufw default deny作用&#xff1a;开启了防火墙并随系统启动同时关闭所有外部对本机的访问(本机访问外部正常)。关闭sudo ufw disable查看防火墙状态sudo ufw status2、开启/禁用相应端口或服务举例sudo u…

如何使用React Native构建嵌套的抽屉菜单

by Dhruvdutt Jadhav由Dhruvdutt Jadhav 如何使用React Native构建嵌套的抽屉菜单 (How to build a nested drawer menu with React Native) Screen space is a precious commodity on mobile. The drawer menu (or “hamburger menu”) is one of the most popular navigatio…