Object Oriented Python 简明教程
Object Oriented Python - Building Blocks
在本章中,我们将详细讨论面向对象术语和编程概念。类只是实例的一个工厂。这个工厂包含描述如何创建实例的蓝图。实例或对象是根据类构造的。在大多数情况下,我们可以拥有一个类的多个实例。每个实例都有一组属性,这些属性在类中定义,因此特定类的每个实例都应具有相同的属性。
Class Bundles : Behavior and State
一个类可以让你将一个对象的的行为和状态捆绑在一起。观察以下图表以更好地理解 -
在讨论类捆绑时,以下几点值得注意 -
-
单词 behavior 等同于 function - 它是一段执行某些操作(或实现某一行为)的代码
-
单词 state 与 variables 相同——它是类内存储值的一个地方。
-
当我们一起断言类行为和状态时,这意味着类会封装函数和变量。
Classes have methods and attributes
在 Python 中,创建方法定义类行为。方法这个词是面向对象编程中给类内部定义的函数的一个名称。总结一下:
-
Class functions ——是 methods 的同义词
-
Class variables ——是 name attributes. 的同义词
-
Class ——给具有确切行为的实例创建一个蓝图。
-
Object ——类的实例之一,执行类中定义的功能。
-
Type ——指示该实例所属的类
-
Attribute ——任何对象值:object.attribute
-
Method ——类中定义的“可调用属性”
观察以下代码段以作示例——
var = “Hello, John”
print( type (var)) # ‘str’> or <class 'str'>
print(var.upper()) # upper() method is called, HELLO, JOHN
Creation and Instantiation
以下代码展示了如何创建我们的第一个类,然后创建它的实例。
class MyClass(object):
pass
# Create first instance of MyClass
this_obj = MyClass()
print(this_obj)
# Another instance of MyClass
that_obj = MyClass()
print (that_obj)
在此,我们创建了一个称为 MyClass 的类,该类不做任何任务。 MyClass 类中的参数 object 涉及类继承,将在后面的章节中讨论。上面的代码中的 pass 表明,该块是空的,也就是一个空的类定义。
让我们创建一个类 MyClass() 的实例 this_obj 并对其进行打印,如以下所示:
<__main__.MyClass object at 0x03B08E10>
<__main__.MyClass object at 0x0369D390>
在此,我们创建了 MyClass. 的一个实例。十六进制代码是指对象存储的地址。另一个实例指向另一个地址。
现在让我们在类 MyClass() 中定义一个变量,并从该类的实例中获取变量,如下面的代码所示:
class MyClass(object):
var = 9
# Create first instance of MyClass
this_obj = MyClass()
print(this_obj.var)
# Another instance of MyClass
that_obj = MyClass()
print (that_obj.var)
Instance Methods
类中定义的函数称为 method. 实例方法需要一个实例才能调用它,并且不需要装饰器。在创建实例方法时,第一个参数始终为 self. 虽然我们可以用任何其他名称调用它(self),但建议使用 self,因为它是一个命名约定。
class MyClass(object):
var = 9
def firstM(self):
print("hello, World")
obj = MyClass()
print(obj.var)
obj.firstM()
Encapsulation
封装是 OOP 的基本原则之一。OOP 让我们能够隐藏对象的内部工作原理的复杂性,在以下方面对开发人员有利 −
-
简化并使之易于理解,无需了解内部即可使用对象。
-
可以轻松管理任何更改。
面向对象编程严重依赖于封装。术语“封装”和“抽象”(也称为数据隐藏)通常被用作同义词。它们几乎是同义词,因为抽象是通过封装实现的。
封装为我们提供了限制对某些对象组件的访问权限的机制,这意味着对象内部表示不能从对象定义外部看到。通常通过特殊方法 Getters 和 Setters. 来访问这些数据
这些数据存储在实例属性中,可以从类外的任何地方进行操作。为了保护它,只应使用实例方法访问该数据。禁止直接访问。
class MyClass(object):
def setAge(self, num):
self.age = num
def getAge(self):
return self.age
zack = MyClass()
zack.setAge(45)
print(zack.getAge())
zack.setAge("Fourty Five")
print(zack.getAge())
Output
执行上述代码时,可以看到以下输出:
45
Fourty Five
应该使用异常处理结构仅在数据正确有效时存储数据。如上所见,对于 setAge() 方法,没有对用户输入的限制。它可以是字符串、数字或列表。因此,我们需要检查上面的代码以确保存储的正确性。
class MyClass(object):
def setAge(self, num):
self.age = num
def getAge(self):
return self.age
zack = MyClass()
zack.setAge(45)
print(zack.getAge())
zack.setAge("Fourty Five")
print(zack.getAge())
Init Constructor
方法 *init* 会在类对象实例化后立即隐式调用。这将初始化对象。
x = MyClass()
上面显示的这一行代码将创建一个新实例,并将该对象分配给局部变量 x。
实例化操作,即 calling a class object ,创建一个空对象。许多类希望使用对象创建一个实例,该实例定制为特定的初始状态。因此,类可以定义一个名为 “ init ()“ 的特殊方法,如下所示 −
def __init__(self):
self.data = []
Python 在实例化期间调用 init ,定义了一个当类实例化时应该出现的附加属性,该属性可以设置该对象的某些起始值或在实例化时运行所需例程。因此,在此示例中,可以通过以下方法获取一个新的已初始化实例 −
x = MyClass()
方法 init () 可以具有一个或多个参数,来获得更大的灵活性。init 表示初始化,因为它初始化实例的属性。它被称为类的构造器。
class myclass(object):
def __init__(self,aaa, bbb):
self.a = aaa
self.b = bbb
x = myclass(4.5, 3)
print(x.a, x.b)
Class Attributes
类中定义的属性称为“类属性”,而函数中定义的属性称为“实例属性”。在定义时,这些属性没有前缀 self,因为它们是类的属性,而不是特定实例的属性。
类属性可以通过类本身( className.attributeName)以及类的实例(inst.attributeName)来访问。因此,实例既可以访问实例属性,也可以访问类属性。
>>> class myclass():
age = 21
>>> myclass.age
21
>>> x = myclass()
>>> x.age
21
>>>
类属性可以在实例中被覆盖,虽然这并不是一个打破封装的好方法。
Python 中有一个用于查找属性的路径。第一个是在类中定义的方法,然后是其上方的类。
>>> class myclass(object):
classy = 'class value'
>>> dd = myclass()
>>> print (dd.classy) # This should return the string 'class value'
class value
>>>
>>> dd.classy = "Instance Value"
>>> print(dd.classy) # Return the string "Instance Value"
Instance Value
>>>
>>> # This will delete the value set for 'dd.classy' in the instance.
>>> del dd.classy
>>> >>> # Since the overriding attribute was deleted, this will print 'class
value'.
>>> print(dd.classy)
class value
>>>
我们在实例 dd 中覆盖“classy”类属性。覆盖时,Python 解释器会读取覆盖的值。但是一旦新值被“del”删除,覆盖的值便不再存在于该实例中,因此查找将向上一个级别并从类中获取它。
Working with Class and Instance Data
在本节中,让我们了解类数据与实例数据的关系。我们可以将数据存储在类中或实例中。在设计类时,我们需要决定哪些数据属于实例,哪些数据应该存储在总体类中。
实例可以访问类数据。如果我们创建多个实例,那么这些实例既可以访问它们各自的属性值,也可以访问总体类数据。
因此,类数据是所有实例共享的数据。观察下面给出的代码以更好地理解−
class InstanceCounter(object):
count = 0 # class attribute, will be accessible to all instances
def __init__(self, val):
self.val = val
InstanceCounter.count +=1 # Increment the value of class attribute, accessible through class name
# In above line, class ('InstanceCounter') act as an object
def set_val(self, newval):
self.val = newval
def get_val(self):
return self.val
def get_count(self):
return InstanceCounter.count
a = InstanceCounter(9)
b = InstanceCounter(18)
c = InstanceCounter(27)
for obj in (a, b, c):
print ('val of obj: %s' %(obj.get_val())) # Initialized value ( 9, 18, 27)
print ('count: %s' %(obj.get_count())) # always 3