📅  最后修改于: 2021-01-04 04:41:32             🧑  作者: Mango
在本章中,我们将详细讨论面向对象的术语和编程概念。类只是实例的工厂。该工厂包含描述如何制作实例的蓝图。从类构造实例或对象。在大多数情况下,一个类可以有多个实例。每个实例都有一组属性,并且这些属性是在类中定义的,因此特定类的每个实例都应具有相同的属性。
一个类可以让您将对象的行为和状态捆绑在一起。观察下图以更好地理解-
讨论类包时,以下几点值得注意:
“行为”一词与“函数”相同–它是一段代码(执行某项行为(或实现某种行为))
状态一词与变量相同–它是在类中存储值的地方。
当我们声明一个类的行为并一起声明状态时,这意味着一个类将函数和变量打包在一起。
在Python,创建方法定义了类行为。 “方法”一词是给在类中定义的函数的OOP名称。总结-
类函数-是方法的同义词
类变量-是名称属性的同义词。
类-具有确切行为的实例的蓝图。
对象-类的实例之一,执行在类中定义的功能。
类型-表示实例所属的类
属性-任何对象值:object.attribute
方法-类中定义的“可调用属性”
观察以下代码,例如-
var = “Hello, John”
print( type (var)) # ‘str’> or
print(var.upper()) # upper() method is called, HELLO, JOHN
以下代码显示了如何创建我们的第一个类,然后创建其实例。
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类中的参数对象涉及类继承,将在后面的章节中进行讨论。上面的代码中的pass表示此块为空,即它是一个空的类定义。
让我们创建MyClass()类的实例this_obj并将其打印出来,如下所示:
<__main__.myclass object="" at="">
<__main__.myclass object="" at="">
在这里,我们创建了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)
执行上面给出的代码时,您可以观察到以下输出:
9
9
实例知道是从哪个类实例化的,因此从实例请求属性时,实例将查找属性和类。这称为属性查找。
类中定义的函数称为方法。实例方法需要一个实例才能调用它,并且不需要装饰器。创建实例方法时,第一个参数始终是self。尽管我们可以用其他任何名称来称呼它(自我),但还是建议使用自我,因为这是命名约定。
class MyClass(object):
var = 9
def firstM(self):
print("hello, World")
obj = MyClass()
print(obj.var)
obj.firstM()
执行上面给出的代码时,您可以观察到以下输出:
9
hello, World
注意,在上面的程序中,我们定义了一个以self为参数的方法。但是我们无法调用该方法,因为我们尚未对其声明任何参数。
class MyClass(object):
def firstM(self):
print("hello, World")
print(self)
obj = MyClass()
obj.firstM()
print(obj)
执行上面给出的代码时,您可以观察到以下输出:
hello, World
<__main__.myclass object="" at="">
<__main__.myclass object="" at="">
封装是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())
执行上面给出的代码时,您可以观察到以下输出:
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 __方法,这将初始化该对象。
x = MyClass()
上面显示的代码行将创建一个新实例,并将此对象分配给局部变量x。
实例化操作(即调用类对象)将创建一个空对象。许多类喜欢创建具有定制为特定初始状态的实例的对象。因此,一个类可以定义一个名为’__init __()’的特殊方法,如下所示:
def __init__(self):
self.data = []
Python在实例化期间调用__init__来定义在实例化类时应该出现的附加属性,该类可能正在为该对象设置一些初始值或运行实例化所需的例程。因此,在此示例中,可以通过以下方式获取新的初始化实例:
x = MyClass()
__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)
4.5 3
在类中定义的属性称为“类属性”,在函数定义的属性称为“实例属性”。在定义时,这些属性不以自身为前缀,因为它们是类的属性,而不是特定实例的属性。
可以通过类本身(className.attributeName)以及类实例(inst.attributeName)来访问类属性。因此,实例可以访问实例属性以及类属性。
>>> class myclass():
age = 21
>>> myclass.age
21
>>> x = myclass()
>>> x.age
21
>>>
即使不是破坏封装的好方法,也可以在实例中覆盖class属性。
在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”删除了新值,该替换值就不再存在于实例中,因此,查找将向上一个级别并从类中获取它。
在本节中,让我们了解类数据与实例数据之间的关系。我们可以将数据存储在类或实例中。在设计类时,我们决定哪些数据属于实例,哪些数据应存储到整个类中。
实例可以访问类数据。如果我们创建多个实例,则这些实例可以访问其各自的属性值以及整体类数据。
因此,类数据是在所有实例之间共享的数据。遵守下面给出的代码以更好地理解-
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
val of obj: 9
count: 3
val of obj: 18
count: 3
val of obj: 27
count: 3
简而言之,类属性对于类的所有实例都是相同的,而实例属性对于每个实例都是特定的。对于两个不同的实例,我们将具有两个不同的实例属性。
class myClass:
class_attribute = 99
def class_method(self):
self.instance_attribute = 'I am instance attribute'
print (myClass.__dict__)
执行上面给出的代码时,您可以观察到以下输出:
{'__module__': '__main__', 'class_attribute': 99, 'class_method': , '__dict__': , '__weakref__': , '__doc__': None}
实例属性myClass .__ dict__如图所示-
>>> a = myClass()
>>> a.class_method()
>>> print(a.__dict__)
{'instance_attribute': 'I am instance attribute'}