面向对象。面向对象两个重要概念:类(class)和实例(Instance)。
而‘对象’是面向对象的核心,在一个类class里可以找到多个对象
我们要知道类(class)是一个抽象话的概念,例如学生,老师,男人,女人,超级英雄。
而实例是根据类传教出来的具体对象,(比如说女人有很多,但是你的“对象”只要一个)
每个在同一类的对象都有相同的方法,但是各自数据会有些许不同。(像每个学生高矮胖瘦,肤色年龄等。但是他们都是学生都学习,吃饭...)
(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)
我们以超级英雄为例子,做如下操作:
class Hero(): #创建一个类,没有任何属性
pass
#创建Hero类里的一个实例
iron = Hero()
#运行iron得到<__main__.Hero object at 0x036D9B10>他是指向Hero的实例
#现在Hero 里面是没有任何东西的,我们可以通过如下方法添加进去
iron.name = 'ironman' #给iron绑定一个name的属性,属性值是ironman
iron.name = 'ironman22222' #如果name属性已经有了,就会改变其原属性
print(iron.name) #这样会得到ironman
(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)
#由于类可以起模板左右,即每个人都有名字性别身高体重等,所以在创建某类的时候可以把这一类必有的属性绑定上去
#通过定义一个__init__的方法可以在创建类的时候导入属性,这样得到的实例就必须有该属性。
class Hero(object):
def __init__(self,name,skill): #我们将超级英雄的名字和技能导入
self.name = name
self.skill = skill
关于self,我在廖雪峰大师看到如下的解释
#==注意到__init__方法的第一个参数永远是self,表示创建的实例本身,
#==因此,在__init__方法内部,就可以把各种属性绑定到self,因为self就指向创建的实例本身。
#==有了__init__方法,在创建实例的时候,就不能传入空的参数了,必须传入与__init__方法匹配的参数,
#==但self不需要传,Python解释器自己会把实例变量传进去:...所以
iron = Hero('ironman','IonCannon') #IonCannon就是离子炮...
print(iron.name) #得到ironman
print(iron.skill) #得到IonCannon
(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)
#面向对象编程的一个重要特点就是数据封装。在上面的Hero类中,每个实例就拥有各自的name和skill这些数据。
#但是,既然Hero实例本身就拥有这些数据,要访问这些数据,就没有必要从外面的函数去访问,
#可以直接在Hero类的内部定义访问数据的函数,这样,就把“数据”给封装起来了。
#这些封装数据的函数是和Hero类本身是关联起来的,我们称之为类的方法:
class Hero(object):
def __init__(self,name,skill): #我们将超级英雄的名字和技能导入
self.name = name
self.skill = skill
def print_name(self):
print('这个超级英雄的名字是:%s'%self.name)
iron = Hero('Ironman','IonCannon')
iron.print_name()
结果就是我们在创建对象的时候只要吧属性(名字和技能)导入
要调用的时候直接调用class内部的函数就可以了,即在内部定义了某些函数(功能)
就是这些数据和逻辑被封装起来,可以直接调用
init():在创建一个对象的时候默认被调用,不需要手动调用,init(self),默认一个参数名字为self,不需要开发者传递
(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)
下面是关于魔方方法(Magic Method),可以选择性不看啦~~~~~~~~~~~~
(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)(●ˇ∀ˇ●)
对了关于这个init...就是Python中一个很酷炫的名字==>魔法方法(Magic Method)
是指被下划线包围的方法或所能调用的方法的统称,这些方法在特殊情况下被调用,没有调用他的必要
构造方法. __init__一个对象被构建好之后会自定调用该方法
__init__这个方法在上面的例子里已经使用,我再做拙略的归纳如下
'''
- - Python中所有的类都直接或间接继承object
- object中有init()和str()方法
- object中的这两个方法大部分时间和我们使用时的需求不匹配
- 我们可以根据自己的需求对方法体进行更改,这就叫做重写
- 更多内容在明天的知识点继承中
- 重写方法使用总结:
- 当两个关联的类,出现了相同的函数名,在调用该函数时,先在本类中找,
- 如果有,调用
- 如果没有,在去父类找,如果有调用,
- 如果没有,去基类,找不到报错
我们可以在Python语言参考手册中的“Data Model”一章列出了83个特殊方法的名字,其中47个用于实现算术运算、位运算和比较操作
(https://docs.python.org/3/reference/datamodel.html) 下面有几个常用的,其他的等有时间了慢慢看吧~~
1.__init__
在创建实例(by __new__())之后调用,但在将其返回给调用者之前调用。参数是传递给类构造函数表达式的参数。如果基类具有__init__() 方法,则派生类的__init__()方法(如果有)必须显式调用它以确保正确初始化实例的基类部分; 例如:super().__init__([args...])。
因为__new__()并且__init__()在构造对象(__new__()创建对象和__init__()自定义对象)时一起工作,所以不会None返回任何非值__init__(); 这样做会导致TypeError在运行时引发。
2.__new__
被调用以创建类cls的新实例。 __new__()是一个静态方法(特殊的,因此您不需要声明它),它将请求实例的类作为其第一个参数。其余参数是传递给对象构造函数表达式的参数(对类的调用)。返回值__new__()应该是新的对象实例(通常是cls的实例)。
典型的实现通过__new__()使用 适当的参数调用超类的方法然后在返回之前根据需要修改新创建的实例来创建类的新实例。super().__new__(cls[, ...])
如果__new__()返回cls的实例,那么__init__()将调用新实例的 方法,其中 self是新实例,其余参数与传递给它的相同。__init__(self[, ...])__new__()
如果__new__()不返回cls的实例,则__init__()不会调用新实例的 方法。
__new__()主要用于允许不可变类型的子类(如int,str或tuple)自定义实例创建。它也通常在自定义元类中重写,以自定义类创建。
3.__del__
在实例即将被销毁时调用。这也称为终结器或(不正确地)析构函数。如果基类具有 __del__()方法,则派生类的__del__()方法(如果有)必须显式调用它以确保正确删除实例的基类部分。
有可能(尽管不推荐!)__del__()方法通过创建对它的新引用来推迟实例的销毁。这称为物体复活。它是依赖于实现的,无论__del__()是在复活的对象即将被摧毁时第二次被调用; 当前的CPython实现只调用一次。
无法保证__del__()在解释器退出时仍然存在的对象调用方法。
注意 del x不直接调用x.__del__()- 前者将引用计数减x1,后者仅在x引用计数达到零时调用
object.__repr__(自我)
由repr()内置函数调用以计算对象的“官方”字符串表示。如果可能的话,这应该看起来像一个有效的Python表达式,可用于重新创建具有相同值的对象(给定适当的环境)。如果无法做到这一点,则应返回表单的字符串。返回值必须是字符串对象。如果类定义 但未定义,则在需要该类的实例的“非正式”字符串表示时也使用。<...some useful description...>__repr__()__str__()__repr__()
这通常用于调试,因此表示信息丰富且明确是很重要的。
4.object.__str__(自我)
由str(object)内置函数调用 format()并print()计算对象的“非正式”或可打印的字符串表示形式。返回值必须是 字符串对象。
这种方法的不同之处在于object.__repr__()没有期望__str__()返回有效的Python表达式:可以使用更方便或简洁的表示。
内置类型object 调用定义的默认实现object.__repr__()。
5.object.__bytes__(自我)
由字节调用以计算对象的字节串表示。这应该返回一个bytes对象。
6.object.__format__(self,format_spec )
由format()内置函数调用,并通过扩展,评估格式化的字符串文字和str.format()方法,以生成对象的“格式化”字符串表示。的format_spec参数是包含所期望的格式选项的描述的字符串。format_spec参数的解释取决于实现的类型__format__(),但是大多数类会将格式化委托给其中一个内置类型,或者使用类似的格式化选项语法。
更多关于format的可以查阅https://docs.python.org/3/library/string.html#formatspec
7.__add__()
类似的还有__sub__()、__mul__()、__mod__()等,相当于实现了运算符重载,特别是要对用户自定义的类型定义一些操作集合时这些魔术方法十分常用
...还有更多更多的奥秘,位来的日子里慢慢探索吧~~