在面向对象的术语中,类当X
扩展类Y
时,则Y
称为该等超级/父/基类,X
称为子类/子/派生类。这里需要注意的一点是,只有数据字段和非专用的方法才能被子类访问。私有数据字段和方法只能在类中访问。
1,创建³³首先了一个名为Date
的类,并将该对象作为参数传递,object
是由Python中提供的内置类。创建³³之后了另一个名为time
的类,并将Date
类称为参数。通过这个调用,可以访问Date
类中的所有数据和属性。正因为如此,的创建³³ Time
类对象tm
中父电子杂志类中get_date
方法。
2,在Python中的中,类的构造函数用于创建对象(实例),并为属性赋值。
子类的构造函数总是调用父类的构造函数来初始化父类中的属性的值,然后它开始为其属性赋值。
3,在Python中的中,类的构造函数用于创建对象(实例),并为属性赋值。
子类的构造函数总是调用父类的构造函数来初始化父类中的属性的值,然后它开始为其属性赋值。
class Animal(object):
def __init__(self, name):
self.name = name
def eat(self, food):
print('%s is eating %s , '%(self.name, food))
class Dog(Animal):
def fetch(self, thing):
print('%s goes after the %s !'%(self.name, thing))
class Cat(Animal):
def swatstring(self):
print('%s shreds the string! ' % (self.name))
d = Dog('Ranger')
c = Cat("Meow")
d.fetch("ball");
c.swatstring()
d.eat("Dog food")
c.eat("Cat food")
## 调用一个没有的定义的方法
#d.swatstring()
在上面的例子中,我们看到如何父类中的属性或方法,以便所有的子类或子类都会从父类继承那些属性。
如果一个子类尝尝从另一个子类继承方法或数据,那么它将通过一个错误,就像看到当狗类尝试调用cat
类有swatstring()
方法时,它会抛出一个错误(AttributeError
)。
我们用之前的继承示例理解多态的概念,并在两个子类中添加一个名为show_affection
的常用方法 -
从这个例子可以看到,它指的是一种设计,其中不同类型的对象可以以相同的方式处理,或者更具体地说,两个或更多的类使用相同的名称或通用接口,因为同样的方法(下面的示例中的show_affection
)用任何一种类型的对象调用
4,重载
在Python中,当子类包含一个覆盖超类方法的方法时,也可以通过调用超类方法 -
Super(Subclass, self).method
而不是self.method
。
继承构造函数
从前面的继承示例中看到,__init__
位于父类中,因为子类 - Dog
或Cat
没有__init__
方法.Python使用继承属性查找来查找动物类中的__init__
。
当我们创建子类时,首先它会查找dog
类中的__init__
方法,如果它找不到它,则查找父类Animal
,并在那里找到并在那里调用它。
因此,当类设计变得复杂时,可能希望初始化一个实例,
首先通过父类构造函数然后通过子类构造函数处理它。
import random
class Animal(object):
def __init__(self, name):
self.name = name
class Dog(Animal):
def __init__(self, name):
super(Dog, self).__init__(name)
self.breed = random.choice(['Doberman', 'German shepherd', 'Beagle'])
def fetch(self, thing):
print('%s goes after the %s !'%(self.name, thing))
d = Dog('黑皮')
print(d.name)
print(d.breed)
结论
-
__init__
与任何其他方法一样; 它可以被继承 -
如果一个类没有
__init__
构造函数,巨蟒将检查其父类查找。 -
只要找到一个有
__init__
构造函数,巨蟒就会调用它并停止查找 -
可以使用
super()
函数来调用父类中的方法。 -
可能想要在父类以及子类进行初始化。
总结如下 -
-
任何类都可以从多个类继承
-
搜索继承类时,巨蟒通常使用“深度优先”顺序。
-
但是,当两个类从同一个类继承时,巨蟒将从该MRO中消除该类的第一次出现
装饰器,静态和类方法
函数(或方法)由def
语句创建³³³³。
虽然方法的工作方式与函数完全相同,除了方法第一个参数是实例对象的一点。
我们可以根据行为方式来分类方法
- 简单的方法 - 在类的外部定义。该函数可以通过提供实例参数来访问类属性:
def outside_func(():
蟒蛇
- 实例方法 -
def func(self,)
蟒蛇
- 类方法 - 如果需要使用类属性
@classmethod def cfunc(cls,)
蟒蛇
- 静态方法 - 没有关于该类的任何信息
@staticmethod def sfoo()
蟒蛇
到目前为止,我们已经看到了实例方法,下面来了解其他两种方法。
类方法
@classmethod
装饰器是一个内置的函数装饰器,它通过调用它的类或作为第一个参数调用的实例的类。评估结果会影响函数定义。
语法
class C(object):
@classmethod
def fun(cls, arg1, arg2, ...):
....
fun: function that needs to be converted into a class method
returns: a class method for function
蟒蛇
他们有权访问此cls
参数,它不能修改对象实例状态。
- 它受到类的约束,而不是类的对象。
- 类方法仍然可以修改适用于类的所有实例的类状态。
2.静态方法
静态方法既不接受自己也不接受cls(class)
参数,但可以自由接受任意数量的其他参数。
语法
class C(object):
@staticmethod
def fun(arg1, arg2, ...):
...
returns: a static method for function funself.
蟒蛇
- 静态方法既不能修改对象状态,也不能修改类的状态。
- 受限于可以访问的数据。
什么时候使用
- 通常使用类方法来创建工厂方法。工厂方法返回不同用例的类对象(类似于构造函数)。
- 通常使用静态方法来创建实用函数。
如图1所示,还有一种把数据和功能结合起来,用称为对象的东西包裹起来组织程序的方法。
类和对象是面向对象编程的两个主要方面。类创建一个新类型,而对象这个类的实例。这类似于你有一个int
类型的变量,这存储整数的变量是int
类的实例(对象)。
类的方法与普通的函数只有一个特别的区别-它们必须有一个额外的第一个参数名称,但是调用在这个方法的时候你不。为这个参数赋值,Python中会提供这个值这个特别的变量指对象本身,按照惯例它的名称是self
。
可以注意到存储对象的计算机内存地址也打印了出来。这个地址在你的计算机上会是另外一个值,因为Python中可以在任何空位存储对象。
在Python中的类中有很多方法的名字有特殊的重要意义。我们现在学习将__init__
方法的意义。
__init__
方法在类的一个对象被建立时,马上运行。这个方法可以用来对你的对象做一些你希望的初始化。注意,这个名称的开始和结尾都是双下划线。
这里,把我们__init__
方法定义为取一个参数name
(以及普通的参数self
)。这个在__init__
里,我们只是创建一个新的域,也称为name
。注意它们是两个不同的变量,尽管它们有相同的名字。点号使我们能够区分它们。
最重要的是,没有我们专门调用__init__
方法,只是在创建一个类的新实例的时候,把参数包括在圆括号内跟在类名后面,传递从而给__init__
方法。这是这种方法的重要之处。
现在,能够我们在我们的方法中使用self.name
域。在这sayHi
方法中得到了验证。
当子类和父类都存在相同的run()
方法时,我们说,子类的run()
覆盖了父类的run()
,在代码运行的时候,总是会调用子类的run()
。这样,我们就获得了继承的另一个好处:多态。
要理解什么是多态,我们首先要对数据类型再作一点说明。当我们定义一个class的时候,我们实际上就定义了一种数据类型。我们定义的数据类型和Python自带的数据类型,比如str、list、dict没什么两样
a = list() # a是list类型
b = Animal() # b是Animal类型
c = Dog() # c是Dog类型
Dog
可以看成Animal
,但Animal
不可以看成Dog
。
要理解多态的好处,我们还需要再编写一个函数,这个函数接受一个Animal
类型的变量:
def run_twice(animal):
animal.run()
animal.run()
多态的好处就是,当我们需要传入Dog
、Cat
、Tortoise
……时,我们只需要接收Animal
类型就可以了,因为Dog
、Cat
、Tortoise
……都是Animal
类型,然后,按照Animal
类型进行操作即可。由于Animal
类型有run()
方法,因此,传入的任意类型,只要是Animal
类或者子类,就会自动调用实际类型的run()
方法,这就是多态的意思:
对于Python这样的动态语言来说,则不一定需要传入Animal
类型。我们只需要保证传入的对象有一个run()
方法就可以了:
class Timer(object):
def run(self):
print('Start...')
继承可以把父类的所有功能都直接拿过来,这样就不必重零做起,子类只需要新增自己特有的方法,也可以把父类不适合的方法覆盖重写。
动态语言的鸭子类型特点决定了继承不像静态语言那样是必须的。
类的方法与普通的函数只有一个特别的区别——它们必须有一个额外的 第一个参数名称
按照惯例它的名称是 self
#!/usr/bin/python
# -*- coding: UTF-8 -*-
class Employee:
'''所有员工的基类'''
empCount = 0
def __init__(self, name, salary):
self.name = name
self.salary = salary
Employee.empCount += 1
def displayCount(self):
print "Total Employee %d" % Employee.empCount
def displayEmployee(self):
print "Name : ", self.name, ", Salary: ", self.salary
其中
-
empCount 变量是一个类变量,它的值将在这个类的所有实例之间共享
可以在内部类或外部类使用 Employee.empCount 访问
-
init() 是一个特殊的方法,被称为类的构造函数或初始化方法,当创建了这个类的实例时就会调用该方法
-
self 代表类的实例,self 在定义类的方法时是必须有的,虽然在调用时不必传入相应的参数
self 代表类的实例,而非类
类的方法与普通的函数只有一个特别的区别——它们必须有一个额外的 第一个参数名称
按照惯例它的名称是 self
我们已经创建好了一个类 Employee
,如果要创建这个类的实例,只需要使用 类名+() 即可
就像调用函数一样
类的实例会通过 __init__()
方法接受参数
垃圾回收机制不仅针对引用计数为 0 的对象,同样也可以处理循环引用的情况
循环引用指的是,两个对象相互引用,但是没有其他变量引用他们
这种情况下,仅使用引用计数是不够的
Python 的垃圾收集器实际上是一个引用计数器和一个循环垃圾收集器
作为引用计数的补充, 垃圾收集器也会留心被分配的总量很大 ( 及未通过引用计数销毁的那些 ) 的对象
在这种情况下, 解释器会暂停下来, 试图清理所有未引用的循环
# -*- coding: UTF-8 -*-
class Point:
def __init__( self, x=0, y=0):
self.x = x
self.y = y
def __del__(self):
class_name = self.__class__.__name__
print class_name, "销毁"