python面向对象和面向过程

编程范式

面向对象

面向过程

面向过程编程

Procedural programming uses a list of instructions to tell the computer what to do step-by-step.
面向过程编程依赖 - 你猜到了- procedures,一个procedure包含一组要被进行计算的步骤, 面向过程又被称为top-down languages, 就是程序从上到下一步步执行,一步步从上到下,从头到尾的解决问题 。基本设计思路就是程序一开始是要着手解决一个大的问题,然后把一个大问题分解成很多个小问题或子过程,这些子过程再执行的过程再继续分解直到小问题足够简单到可以在一个小步骤范围内解决。

举个典型的面向过程的例子, 数据库备份, 分三步,连接数据库,备份数据库,测试备份文件可用性。

代码如下

def db_conn():
    print("connecting db...")
 
 
def db_backup(dbname):
    print("导出数据库...",dbname)
    print("将备份文件打包,移至相应目录...")
 
def db_backup_test():
    print("将备份文件导入测试库,看导入是否成功")
 
 
def main():
    db_conn()
    db_backup('my_db')
    db_backup_test()
 
 
 
if __name__ == '__main__':
    main()

  

这样做的问题也是显而易见的,就是如果你要对程序进行修改,对你修改的那部分有依赖的各个部分你都也要跟着修改, 举个例子,如果程序开头你设置了一个变量值 为1 , 但如果其它子过程依赖这个值 为1的变量才能正常运行,那如果你改了这个变量,那这个子过程你也要修改,假如又有一个其它子程序依赖这个子过程 , 那就会发生一连串的影响,随着程序越来越大, 这种编程方式的维护难度会越来越高。
所以我们一般认为, 如果你只是写一些简单的脚本,去做一些一次性任务,用面向过程的方式是极好的,但如果你要处理的任务是复杂的,且需要不断迭代和维护 的, 那还是用面向对象最方便了。

面向对象编程

优点

1.因为它可以使程序的维护和扩展变得更简单,并且可以大大提高程序开发效率

2.基于面向对象的程序可以使它人更加容易理解你的代码逻辑,从而使团队开发变得更从容。

特性

Class 类
一个类即是对一类拥有相同属性的对象的抽象、蓝图、原型。在类中定义了这些对象的都具备的属性(variables(data))、共同的方法

Object 对象
一个对象即是一个类的实例化后实例,一个类必须经过实例化后方可在程序中调用,一个类可以实例化多个对象,每个对象亦可以有不同的属性,就像人类是指所有人,每个人是指具体的对象,人与人之前有共性,亦有不同

Encapsulation 封装
在类中对数据的赋值、内部调用对外部用户是透明的,这使类变成了一个胶囊或容器,里面包含着类的数据和方法

Inheritance 继承
一个类可以派生出子类,在这个父类里定义的属性、方法自动被子类继承

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

特性1:数据封装

封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。

特性2:继承

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

通过继承创建的新类称为“子类”或“派生类”。

被继承的类称为“基类”、“父类”或“超类”。

要实现继承,可以通过“继承”(Inheritance)和“组合”(Composition)来实现。

继承概念的实现方式主要有2类:实现继承、接口继承。

Ø 实现继承是指使用基类的属性和方法而无需额外编码的能力;

Ø 接口继承是指仅使用属性和方法的名称、但是子类必须提供实现的能力(子类重构爹类方法);

特性3:多态

多态的作用,就是为了类在继承和派生的时候,保证使用“家谱”中任一类的实例的某一属性时的正确调用。

访问限制

在Class内部,可以有属性和方法,而外部代码可以通过直接调用实例变量的方法来操作数据,这样,就隐藏了内部的复杂逻辑。

  1. 私有属性1,不能直接访问,属性的名称前加上两个下划线__,在Python中,实例的变量名如果以__开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问。
  2. 私有属性2,可以直接访问,以一个下划线开头的实例变量名,比如_name,这样的实例变量外部是可以访问的,但是,按照约定俗成的规定,当你看到这样的变量时,意思就是,“虽然我可以被访问,但是,请把我视为私有变量,不要随意访问”。
class Student(object):

    def __init__(self, name, score):
        self.__name = name
        self.__score = score

    def get_scort(self):
        return self.__name

    def print_score(self):
        print('%s: %s' % (self.__name, self.__score))

bart = Student('Bart Simpson', 59)
#正常访问私有属性的方法
print(bart.get_scort())
#直接访问私有属性1会报错,AttributeError: 'Student' object has no attribute '__name'
print(bart.__name)
#私有属性1直接访问需要使用_classname__name
print(bart._Student__name)

类属性和实例属性

例子1:每创建一个实例,实例会复制一份类属性。对于类属性是列表和字典,共享内存。

class people(object):
    count = 0
    list1 = []
    def __init__(self, name, age):
        self.name = name
        self.age = age

person1 = people("Tom", 12)
person1.count += 1
person1.list1.append(person1.name)
print(person1.count)
print(person1.list1)

person2 = people("Jack", 13)
person2.list1.append(person2.name)
print(person2.count)
print(person2.list1)

#输出结果
1
['Tom']
0
['Tom', 'Jack']

例子2:实例属性和类属性相同,会屏蔽掉类属性

class people(object):
    name = "chinese"
    def __init__(self, name, age):
        self.name = name
        self.age = age

person1 = people("Tom", 12)
print("person1.name:", person1.name)
print("people.name:", people.name)

类的内置函数

_init_()

例如,构造函数每次创建实例时调用

class Dog(object):

    def __init__(self, name, dog_type):
        self.name = name
        self.type = dog_type
d = Dog("Lichuang","京巴")

_del_()

例如,析构函数在主动调用del删除变量或程序结束时调用

#例子1,程序结束调用
class people(object):
    name = "chinese"
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def __del__(self):
        print("%s is killed" %self.name)


person1 = people("Tom", 12)
print("person1.name:", person1.name)

person2 = people("Jack", 10)
print("person1.name:", person1.name)

#输出结果
person1.name: Tom
person1.name: Tom
Tom is killed
Jack is killed

#例子2,主动调用del调用
class people(object):
    name = "chinese"
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def __del__(self):
        print("%s is killed" %self.name)


person1 = people("Tom", 12)
print("person1.name:", person1.name)

person2 = people("Jack", 10)
print("person1.name:", person1.name)
del person2

#输出结果
person1.name: Tom
person1.name: Tom
Jack is killed
Tom is killed

_doc_

__doc__表示类的描述信息

class Foo:
    '''
    萨瓦迪卡
    '''
    def a(self):
        pass

f = Foo()
print(f.__doc__)

#输出结果
萨瓦迪卡

_module__ 和 _class__

_module_ 表示当前操作的对象在那个模块

_class_ 表示当前操作的对象的类是什么

#class_type.py
from __doc__ import Foo

f = Foo()
print(f.__module__)
print(f.__class__)

#__doc__py
class Foo:
    '''
    萨瓦迪卡
    '''
    def a(self):
        pass
if __name__ == "__main__":
    f = Foo()
    print(f.__doc__)

_str_ ,_repr_

如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值。

#默认情况下
class Foo:

    def a(self):
        pass

if __name__ == "__main__":
    f = Foo()
    print(f)
#输出结果
<__main__.Foo object at 0x000001E9CCA61F28>

#配置了__str__()
class Foo:

    def a(self):
        pass
    def __str__(self):
        return "hello"
if __name__ == "__main__":
    f = Foo()
    print(f)
#输出结果
hello

直接显示变量调用__repr__()

>>> s = Student('Michael')
>>> s
<__main__.Student object at 0x109afb310>

#修改函数为__repr__
class Student(object):
    def __init__(self, name):
        self.name = name
    def __str__(self):
        return 'Student object (name=%s)' % self.name
    __repr__ = __str__

_getitem_,_setitem_,_delitem_

用于索引操作,如字典。以上分别表示获取、设置、删除数据

class Foo(object):
 
    def __getitem__(self, key):
        print('__getitem__',key)
 
    def __setitem__(self, key, value):
        print('__setitem__',key,value)
 
    def __delitem__(self, key):
        print('__delitem__',key)
 
obj = Foo()
 
result = obj['k1']      # 自动触发执行 __getitem__
obj['k2'] = 'alex'   # 自动触发执行 __setitem__
del obj['k1']

_dict_

查看类或对象中的所有成员  

对类调用__dict__返回所有属性变量(不包括实例变量)

对对象调用__dict__返回实例变量

class Foo:
    n = 100
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __call__(self, *args, **kwargs):
        print(*args)


if __name__ == "__main__":
    f = Foo("Tom", 100)
    print(f.__dict__)
    print(Foo.__dict__)

_call_

调用对象,在对象后面加括号则可

class Foo:

    def a(self):
        pass
    def __call__(self, *args, **kwargs):
        print(*args)
if __name__ == "__main__":
    f = Foo()
    f(1, 2, 3)

_slots_

限制实例的属性,比如,只允许对Student实例添加nameage属性。

class Student(object):
    __slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称
    
>>> s = Student() # 创建新的实例
>>> s.name = 'Michael' # 绑定属性'name'
>>> s.age = 25 # 绑定属性'age'
>>> s.score = 99 # 绑定属性'score'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute 'score'
    
#使用__slots__要注意,__slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的:
>>> class GraduateStudent(Student):
...     pass
...
>>> g = GraduateStudent()
>>> g.score = 9999

高级编程

高级特性:多重继承、定制类、元类等概念。

新式类和经典类

#经典类
class A:
    def __init__(self):
        self.n = 'A'
#新式类
class A(object):
    def __init__(self):
        self.n = 'A'
        
python2     
经典类:深度优先
新式类:广度优先

python3
都是广度优先

静态方法

通过@staticmethod装饰器即可把其装饰的方法变为一个静态方法

静态方法是不可以访问实例变量或类变量的,一个不能访问实例变量和类变量的方法,其实相当于跟类本身已经没什么关系了,它与类唯一的关联就是需要通过类名来调用这个方法

class a:
    def __init__(self):
        self.n = 'A'
    @staticmethod
    def printn(self):
        print(self.n)

A = a()
A.printn()
#TypeError: printn() missing 1 required positional argument: 'self'

解决办法:

1.将删除self的参数

2.传递对象参数

类方法

类方法通过@classmethod装饰器实现

类方法和普通方法的区别是, 类方法只能访问类变量,不能访问实例变量

class a:
    n = 100
    def __init__(self):
        self.n = 'A'
    @classmethod
    def printclassn(self):
        print(self.n)

A = a()
A.printclassn()
#输出结果
100

属性方法

属性方法的作用就是通过@property把一个方法变成一个静态属性

意义:对传递的参数进行判断是否符合要求

class Dog(object):
    def __init__(self):
        self.__cute = 0
    @property
    def cute(self):
        if self.__cute == 0:
            print("little cute")
        else:
            print("very cute")
    @cute.setter
    def cute(self, n):
        self.__cute = n
        print(self.__cute)
    @cute.deleter
    def cute(self):
        del self.__cute
        print("had del cute")

d = Dog()
d.cute
d.cute = 1
d.cute
del d.cute
d.cute

#输出结果。因为已经del了,再次访问会出错
little cute
Traceback (most recent call last):
1
very cute
  File "C:/Users/Phoenix/PycharmProjects/test/属性方法.py", line 24, in <module>
had del cute
    d.cute
  File "C:/Users/Phoenix/PycharmProjects/test/属性方法.py", line 6, in cute
    if self.__cute == 0:
AttributeError: 'Dog' object has no attribute '_Dog__cute

多重继承

MixIn

在设计类的继承关系时,通常,主线都是单一继承下来的,例如,Ostrich继承自Bird。但是,如果需要“混入”额外的功能,通过多重继承就可以实现,比如,让Ostrich除了继承自Bird外,再同时继承Runnable。这种设计通常称之为MixIn。

Python自带的很多库也使用了MixIn。举个例子,Python自带了TCPServerUDPServer这两类网络服务,而要同时服务多个用户就必须使用多进程或多线程模型,这两种模型由ForkingMixInThreadingMixIn提供。通过组合,我们就可以创造出合适的服务来。

例子1:继承类按顺序继承,E---->C---->D---->A,其中C和D继承A

class A(object):
    def __init__(self):
        print("A")

class B(object):
    def __init__(self):
        print("B")

class C(A):
    pass
    # def __init__(self):
    #     print("C")

class D(A):
    def __init__(self):
        print("D")

class E(C, D):
    # def __init__(self):
    #     print("E")
    pass
e = E()
#输出结果
C

例子2:继承类按顺序继承,E---->C---->A---->D---->B,其中C和D分别继承A,B

class A(object):
    # pass
    def __init__(self):
        print("A")

class B(object):
    def __init__(self):
        print("B")

class C(A):
    pass
    # def __init__(self):
    #     print("C")

class D(B):
    def __init__(self):
        print("D")

class E(C, D):
    # def __init__(self):
    #     print("E")
    pass
e = E()
#输出结果
A

反射

通过字符串映射或修改程序运行时的状态、属性、方法, 有以下4个方法

class Foo(object):
 
    def __init__(self):
        self.name = 'wupeiqi'
 
    def func(self):
        return 'func'
 
obj = Foo()
 
# #### 检查是否含有成员 ####
hasattr(obj, 'name')
hasattr(obj, 'func')
 
# #### 获取成员 ####
getattr(obj, 'name')
getattr(obj, 'func')
 
# #### 设置成员 ####
setattr(obj, 'age', 18)
setattr(obj, 'show', lambda num: num + 1)
 
# #### 删除成员 ####
delattr(obj, 'name')
delattr(obj, 'func')

特殊类

枚举类

定义常量时,一个办法是用大写变量通过整数来定义

好处是简单,缺点是类型是int,并且仍然是变量。

更好的方法是为这样的枚举类型定义一个class类型,然后,每个常量都是class的一个唯一实例。

#例子1,遍历枚举类
from enum import Enum

Month = Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May',
                       'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))

#默认value是从1开始
for i, v in Month._member_map_.items():
    print(i, v, v.value)

#例子2,定义枚举类
#unique当定义的value重复时会报错

from enum import Enum, unique
@unique
class weekday(Enum):
    Monday = 1
    Tuesday = 2
    Wedsday = 3
    Thursday = 4
    Friday = 5
    Saturday = 6
    Sunday = 7
day1 = weekday.Friday
print(day1, day1.value)

元类

type()

1.type()动态创建类

创建类的两种方法:

1.直接用class定义一个类

2.用type创建一个类

例如:

#用class定义类
class hello(object):
    def hello(self):
        print("hello")

h = hello()
h.hello()

#用type创建类
#参数1,类名
#参数2,继承的父类
#参数3,类的方法
#返回值,新创建的类的内存地址
def Hello(self):
    print("Hello")

Hello = type('Hello', (object,), dict(Hello=Hello))
h = Hello()
h.Hello()

2.metaclass控制类的创建行为

当我们定义了类以后,就可以根据这个类创建出实例,所以:先定义类,然后创建实例。

但是如果我们想创建出类呢?那就必须根据metaclass创建出类,所以:先定义metaclass,然后创建类。

连接起来就是:先定义metaclass,就可以创建类,最后创建实例。

metaclass允许你创建类或者修改类。换句话说,你可以把类看成是metaclass创建出来的“实例”。

__new__()方法接收到的参数依次是:

  1. 当前准备创建的类的对象;
  2. 类的名字;
  3. 类继承的父类集合;
  4. 类的方法集合。

例子,ORM全称“Object Relational Mapping”,即对象-关系映射,就是把关系数据库的一行映射为一个对象,也就是一个类对应一个表,这样,写代码更简单,不用直接操作SQL语句。

实际过程:

ModelMetaclass中,一共做了几件事情:

  1. 排除掉对Model类的修改;
  2. 在当前类(比如User)中查找定义的类的所有属性,如果找到一个Field属性,就把它保存到一个__mappings__的dict中,同时从类属性中删除该Field属性,否则,容易造成运行时错误(实例的属性会遮盖类的同名属性);
  3. 把表名保存到__table__中,这里简化为表名默认为类名。
#元类
class ModelMetaclass(type):

    def __new__(cls, name, bases, attrs):
        if name=='Model':
            return type.__new__(cls, name, bases, attrs)
        print('Found model: %s' % name)
        mappings = dict()
        for k, v in attrs.items():
            if isinstance(v, Field):
                print('Found mapping: %s ==> %s' % (k, v))
                mappings[k] = v
        for k in mappings.keys():
            attrs.pop(k)
        attrs['__mappings__'] = mappings # 保存属性和列的映射关系
        attrs['__table__'] = name # 假设表名和类名一致
        return type.__new__(cls, name, bases, attrs)
#基类
class Model(dict, metaclass=ModelMetaclass):

    def __init__(self, **kw):
        super(Model, self).__init__(**kw)

    def __getattr__(self, key):
        try:
            return self[key]
        except KeyError:
            raise AttributeError(r"'Model' object has no attribute '%s'" % key)

    def __setattr__(self, key, value):
        self[key] = value

    def save(self):
        fields = []
        params = []
        args = []
        for k, v in self.__mappings__.items():
            fields.append(v.name)
            params.append('?')
            args.append(getattr(self, k, None))
        sql = 'insert into %s (%s) values (%s)' % (self.__table__, ','.join(fields), ','.join(params))
        print('SQL: %s' % sql)
        print('ARGS: %s' % str(args))
#Field类
class Field(object):

    def __init__(self, name, column_type):
        self.name = name
        self.column_type = column_type

    def __str__(self):
        return '<%s:%s>' % (self.__class__.__name__, self.name)
    
#Field派生类
class StringField(Field):

    def __init__(self, name):
        super(StringField, self).__init__(name, 'varchar(100)')

class IntegerField(Field):

    def __init__(self, name):
        super(IntegerField, self).__init__(name, 'bigint')

#User类
class User(Model):
    # 定义类的属性到列的映射:
    id = IntegerField('id')
    name = StringField('username')
    email = StringField('email')
    password = StringField('password')

# 创建一个实例:
u = User(id=12345, name='Michael', email='test@orm.org', password='my-pwd')
# 保存到数据库:
u.save()
原文地址:https://www.cnblogs.com/akiz/p/11144287.html