1、语言的分类

1)面向机器

抽象成机器指令,机器容易理解。代表:汇编语言。

2)面向过程

做一件事,排除步骤,第一步做什么,第二步做什么,如果出现A问题,做什么处理,出现b问题,做什么处理。问题规模小,步骤化,按部就班处理。  代表:c语言。

(按照步骤进行处理的。)

面向对象和面向过程的差异(一步一步的走,都有谁做or抽象成为不同的类,谁能做。)

编程是多范式的,面向对象只是一种范式。

3)面向对象ocp

随着计算机需要解决的问题规模扩大,情况越来越复杂,需要很多人,很多部门协作,面向过程编程太不适合了。代表:c++  java  python等

三要素:封装,父类有的,子类直接继承,多继承少修改,

继承是为了多复用。单一继承、多继承。Mixin技术

2、面向对象

1)定义    (是一种认识世界,分析世界的方法论,用类来表现实实在在的对象。)

c语言是面向过程的,Python和Java是面向对象的。(大型项目的话利用类抽象)面向对象一种是抽象的,一种是具体的。

一种认识世界、分析世界的方法论,将万事万物抽象为类。

2)类class

类是抽象的概念,是万事万物的抽象,是一类实物的共同特征的集合。

用计算机语言来描述类,就是属性和方法的集合。

3)对象instance、object

对象是类的巨象,是一个实体。

对于每个人这个个体,都是抽象概念人类的不同的实体。

(你吃鱼,你就是对象。鱼,也是对象;吃是动作。你是具体的人,是具体的动作。你属于人类,人类是个抽象的概念,是无数具体的个体的抽象。鱼也是具体的对象,就是说你吃的是一条具体的鱼,这条鱼属于鱼类,是无数的鱼抽象出来的概念。)

(吃,是具体的动作,也是操作,也是方法,这个吃是你的动作,也就是人类具有的方法,如果说的是鱼吃人,吃就是鱼类的动作了)

(吃是个动作,许多动物都具有的动作,人类和鱼类都属于动物类,而动物类是抽象的概念,是动物都有吃的动作,但是吃法不同而已)

(驾驶车,这个车也是车类的具体的对象(实例),驾驶这个动作是鱼类不具有的,是人类具有的方法。)

4)属性

是对象状态的抽象,用数据结构来描述。

5)操作

他是对象行为的抽象,用操作名和实现该操作方法的描述。

(每个人都有名字,身高,体重等信息,这些信息都是个人的属性,但是,这些信息不能保存在人类中,因为他是抽象的概念,不能保留具体的值。)

(而人类的实例,就是具体的人,他可以存储这些具体的特性,而且可以不同的人有不同的属性)

6)哲学

一切皆对象

对象是数据和操作的封装

对象是独立的,但是对象之间可以相互作用。

目前oop是最接近人类认知的编程范式。

3、面向对象3要素****

1)封装

*组装:将数据和操作组装到一起。

*对外只是暴露一些接口,通过接口访问对象。(可供操作的属性,暴漏的属性)

2)继承

*多复用,继承来的就不用自己写了。(用到父类已经做好的实现和操作,在自己内部无需实现了,相同的就不写了,写自己独有的特点。)

*多继承少修改,ocp(open-closed princile),使用继承来改变,来体现个性。(父类的基础上少修改)。

3)多态

*面向对象编程最灵活的地方,动态绑定。

人类就是封装:

人类继承自动物类,孩子继承父母的特征,分为单一继承、多继承;

多态,继承自动物类的人类,猫类的操作吃的不同。

(类对象)类的定义

(类的对象)类的实例。

4、Python的类

1)定义

Class  ClassName:

语句块                    (放属性和方法,实例的属性。实例化过程。)

(1)必须使用class关键字。

(2)类名必须是用大驼峰命名。

(3)类定义完成后,就产生了一个类对象,绑定了标示符ClassName上。

(4)举例

class MyClass:

    """A example class"""

   
x = 1  #  类属性



    def foo(self):   #类属性foo,也是方法

        return " My Class"



print(MyClass.x)

print(MyClass.foo)

print(MyClass.foo(1))

print(MyClass.__doc__)

No1 print:   1

No2 print:   <function MyClass.foo at 0x0000002E421852F0>  (说是个函数类在某个地址里面)

No3 print:  My Class

No4 print:  A example class

类属性

(标示符就是一个属性)

5、类对象及类属性

1)类对象

类的定义就会产生一个类对象。

2)类属性

类定义中的变量和类中定义的方法都是类的属性。

3)类变量

上类中的x是类MyClass的变量。

(加括号调用方法,不加是调用的属性。)

4)总结

MyClass中  x、foo都是类的属性。

foo方法都是类的属性,如同吃是人类的方法。但是每个具体的人才能吃东西,也就说吃人的实例才能调用的方法。

foo 是方法对象method,不是普通的函数对象function了,他一般要求至少有一个参数。第一个参数可以是self(self是标示符),这个参数位置就留给了self

6、类的实例

调用MyClass().Show()     (new函数和init函数都调用了)  带有self的都是方法。

调用 a = MyClass()

背后是要进行绑定的。

前后都有下划线的称为魔术方法。初始化方法。

7、实例化

a = MyClass()

1)         定义方法:

使用上面的语法,在类对象名称后面加上一个括号,就是调用类的实例化方法,完成实例化。实例化就是真正创建一个该类的对象(实例)。

tom = MyClass()

Jerry = MyClass()

tom /jerry都是MyClass的实例,通过实例化生成了2个实例。

每次实例化后获得实例,是不同的实例,即使是使用同样的参数实例化,也得到不同的对象。

Python类实例化后,会自动调用__init__,这个方法第一个参数都必须留给self,其它参数随意。

2)__init__

3)MyClass()实际上调用的是__init__(self)方法,可以不定义,如果没有定义会在实例化后隐式调用。

作用:对实例进行初始化(self当前对象的本身)。实例带初始化。

初始化函数可以多个参数,第一个参数位置必须是self。

__init__()方法不能有返回值,也就是只能是None。

class MyClass:

    """A example class"""

   
x = 1  #  类属性



    def foo(self):   #类属性foo,也是方法

        return " My Class"



# print(MyClass)    #不会被调用

print(MyClass())    #会调用

a = MyClass()     #  会被调用。。结果和2一样。

print(a)

No1  print:不会被调用

No2 print :<__main__.MyClass object at 0x0000001101903908>

No2 print :<__main__.MyClass object at 0x0000001101903908>

class Person:

    def __init__(self,name,age):

        self.name = name

        self.age = age



    def showage(self):

        print('{} is {}'.format(self.name,self.age))



tom = Person('Tom',20)

cat = Person('cat',12)

tom.showage()                   #  Tom is 20

cat.showage()                   #   cat is 12

print(tom.name,cat.name)        #    Tom cat

cat.age += 1

print(cat.age)                   #   13

cat.showage()                   #   cat is 13

每次实例化后都会生成不同的对象。(id地址不同)

8、实例对象instance

1)类实例化后一定会获得一个对象,就是实例对象。

tom  cat 就是Person类的实例。

__init__ 方法的第一参数self就是指代某一实例。

类实例化后,得到一个实例对象,实例对象都会绑定方法,调用时采用tom.showage()的方式。函数签名是showage(self)。这个self就是tom,python中会把方法的调用者作为第一参数self作为实参传入。

Self,name就是tom对象的name,name是保存在tom对象上面,而不是Person的类上面,所有称为实例变量。

2)         Self 实例化。

class MyClass:

    def __init__(self):

        print('self in init = {}'.format(id(self)))



c = MyClass()

print('c = {}'.format(id(c)))

self in init = 583263140104

c = 583263140104

Self就是调用者,就是c对应的实例对象。

Self这个名字只是一个惯例,可以修改,最好不要修改,影响可读性。

9、实例变量和类变量

class Person:

    age = 3

    def __init__(self,name):

        self.name = name



tom = Person('tom')

cat = Person('cat')



print(tom.name,tom.age)

print(cat.name,cat.age)

print(Person.age)

Person.age = 30

print(Person.age,tom.age,cat.age)

tom 3

cat 3

3

30 30 30

实例变量是每一个实例自己的变量,是自己独有的。类变量是累的变量,是类的所有实例共享和使用的方法。

特殊属性

含义

__name__

对象名

__class__

对象的模型

__dict__

对象的属性的字典

__qualname__

类的限定名

Python中每一种对象都拥有不同的属性,函数、类、都是对象,类的实例也是对象。

class Person:

    age = 3

    def __init__(self,name):

        self.name = name



print('class-----------')

print(Person.__class__)

print(sorted(Person.__dict__.items()),end='\n\n')



tom = Person('tom')

print('----instance tom ----')

print(tom.__class__)

print(sorted(tom.__dict__.items()),end='\n\n')



print('-----tom class------')

print(tom.__class__.__name__)

print(sorted(tom.__class__.__dict__.items()),end= '\n\n')

class-----------

<class 'type'>

[('__dict__', <attribute '__dict__' of 'Person' objects>), ('__doc__', None), ('__init__', <function Person.__init__ at 0x000000FD0DFF52F0>), ('__module__', '__main__'), ('__weakref__', <attribute '__weakref__' of 'Person' objects>), ('age', 3)]

----instance tom ----

<class '__main__.Person'>

[('name', 'tom')]

-----tom class------

Person

[('__dict__', <attribute '__dict__' of 'Person' objects>), ('__doc__', None), ('__init__', <function Person.__init__ at 0x000000FD0DFF52F0>), ('__module__', '__main__'), ('__weakref__', <attribute '__weakref__' of 'Person' objects>), ('age', 3)]

class Person:

    age = 3

    hight = 170



    def __init__(self,name,age=18):

        self.name = name

        self.age = age



tom = Person('tom')

cat = Person('cat',20)



Person.age = 30

print(Person.age,tom.age,cat.age)



print(Person.hight,tom.hight,cat.hight)

cat.hight = 175

print(Person.hight,tom.hight,cat.hight)

tom.hight +=10

print(Person.hight,tom.hight,cat.hight)



Person.hight +=15

print(Person.hight,tom.hight,cat.hight)



Person.weight = 70

print(Person.weight,tom.weight,cat.weight)



print(tom.__dict__['hight'])

# print(tom.__dict__['weight'])  不可执行,因为后来定义的字典内没有

30 18 20

170 170 170

170 170 175

170 180 175

185 180 175

70 70 70

180

总结:

是类的,也就是这个类的所有实例,其实例都可以访问的到,是实例的,就是这个实例自己,通过类访问不到。

类变量是属于类的变量,这个类的所有实例可以共享这个变量。

实例可以动态的给自己增加一个属性。实例.__dict__,如果没有,然后通过属性__class__找到自己的类,再去类的__dict__中找。

注意,如果实例使用__dict__[变量名]访问变量,将不会按照上面的顺序查找变量了,这是指明使用字典的key查找,不是属性来查找。

一般来说,类变量使用全部大写来命名。

特殊属性

实例的字典里面放的是和self有关的信息,类字典里面放的是类的信息,类的字典的items。

属性访问的:的找自己的找不到自己的找类的。

字典访问的:指定的是自己的字典。

赋值即定义,定义属性。

Person().normal()实例调用。必须传参数。不用。

Person.normal()类调用。

10、装饰一个类

def add_name(cls):

    cls.NAME = name

    return cls



@add_name('tom')

class Person:

    AGE = 3
def add_name(name):

    def wrapper(cls):

        cls.NAME = name

        return cls

    return wrapper



@add_name('tom')

class Person:

    AGE = 3

11、类方法和静态方法。

__init__等方法,这些方法的本身都是类的属性,第一个参数必须是self,而self必须指向一个对象,也就是类必须实例化以后,由实例来调用这个方法。

1)普通函数:

class Person:

    def normal_method():

        print('normal')

# Person.normal_method()   #可以调用

# Person().normal_method()   #不可以调用



print(Person.__dict__)

Person.normal_method()

可以被调用,因为这个方法只是被Person这个名词空间管理的一个普通方法,normal只是一个属性而已。

由于normal_method在定义的时候没有指定self。所以不能完成实例对象的banding,不能用,Person().Normal_method()绑定。  虽然语法对的,但是禁止这么写。

2)类方法

class Person:

    @classmethod

    def class_method(cls):

        print('class={0.__name__}({0})'.format(cls))

        cls.HIGHT = 170



Person.class_method()

print(Person.__dict__)

class=Person(<class '__main__.Person'>)

{'__module__': '__main__', 'class_method': <classmethod object at 0x000000C59D4A3908>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None, 'HIGHT': 170}

(1)在类定义中,使用@clasmethod装饰器修饰的方法,

(2)必须至少有一个参数,且第一个参数留给了cls,cls指代调用者即类对象自身。

(3)cls这个标示符可以是任意合法名称,但是为了易读,不建议修改。

(4)通过cls可以直接操作类的属性。

(3)静态方法。

class Person:

    @classmethod

    def class_method(cls):

        print('class={0.__name__}({0})'.format(cls))

        cls.HIGHT = 170



    @staticmethod

    def static_method():

        print(Person.HIGHT)



Person.class_method()

Person.static_method()

print(Person.__dict__)

class=Person(<class '__main__.Person'>)

170

{'__module__': '__main__', 'class_method': <classmethod object at 0x000000E7C4993908>, 'static_method': <staticmethod object at 0x000000E7C49938D0>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None, 'HIGHT': 170}

(1)staticmethod 静态方法

(2)不需要传参。

(3)在类定义中,使用@staticmethod装饰器修饰的方法。

(4)调用时不会隐身传入参数,静态方法,只是表明这个方法属于这个名词空间,函数归在一起,方便管理。

12、方法的调用

class Person:

    def normal_method():

        print('normal')



    def method(self):

        print('{} method'.format(self))



    @classmethod

    def class_method(cls):

        print('class={0.__name__}({0})'.format(cls))

        cls.HIGHT = 170



    @staticmethod

    def static_method():

        print(Person.HIGHT)



print('---类访问---')

print(1,Person.normal_method())    #  可以调用,返回None。

# print(2,Person.method())    #不可以被调用,必须传入参数,一个self

print(3,Person.class_method())   ##返回None

print(4,Person.static_method())   #返回None

print(Person.__dict__)

print('实例访问')

print('tom')

tom = Person()

# print(1,tom.normal_method())   #不能调用,报错 需要参数

print(2,tom.method())      #可以

print(3,tom.class_method())  #可以

print(4,tom.static_method())   #可以

总结:

类几乎可以调用所有内部定义的方法,但是调用普通方法的时候会报错,原因是第一参数必须是类的实例。

实例几乎可以调用所有,普通的函数的调用一般不可能出现,因为不允许定义。

类除了普通方法都可以调用,普通方法需要对象的实例作为第一参数。

实例可以调用所有类中定义的方法,(静态,类方法),普通方法传入实例本身,静态方法和类方法需要找到实例的类。

13、访问控制

1)私有属性(private)

class Person:

    def __init__(self,name,age=18):

        self.name = name

        self.age = age



    def growup(self,i=1):   #控制逻辑

        if i>0 and i <150:

            self.age +=1

p1 = Person('tom')

p1.growup(20)

p1.age =160

print(p1.age)

想通过方法来控制属性,但是由于属性在外部可以访问,就直接绕过方法,直接修改属性。私有属性则解决了这个问题。

私有属性:

使用双下划线开头的属性名。就是私有属性。

class Person:

    def __init__(self,name,age=18):

        self.name = name

        self.__age = age



    def growup(self,i=1):   #控制逻辑

        if i>0 and i <150:

            self.__age +=1

p1 = Person('tom')

p1.growup(20)

# p1.age =160

print(p1.__age)

print(p1.__age)

AttributeError: 'Person' object has no attribute '__age'

访问不到 __age ..

class Person:

    def __init__(self,name,age=18):

        self.name = name

        self.__age = age



    def growup(self,i=1):   #控制逻辑

        if i>0 and i <150:

            self.__age += 1



    def getage(self):

        return self.__age

p1 = Person('tom')

print(p1.getage())

Print 19

2)私有属性的本质,

外部访问不到,能够动态增加一个__age?

class Person:

    def __init__(self,name,age=18):

        self.name = name

        self.__age = age



    def growup(self,i=1):   #控制逻辑

        if i>0 and i <150:

            self.__age += 1



    def getage(self):

        return self.__age

p1 = Person('tom')

p1.__age =28

print(p1.__age)

# print(p1.getage())

年龄没有被覆盖,全部存在__dict__的字典里面了。

私有变量本质:

类定义的是,如果生命一个实例变量的时候,使用双下划线,python的解释器就会将其改名,转换为_类名__变量名 的名称了,所以用原来的名字访问不到了。

class Person:

    def __init__(self,name,age=18):

        self.name = name

        self.__age = age



    def growup(self,i=1):   #控制逻辑

        if i>0 and i <150:

            self.__age += 1



    def getage(self):

        return self.__age

p1 = Person('tom')

p1.__age =28

print(p1.__age)

# print(p1.getage())



p1._Person__age =15

print(p1.getage())

print(p1.__dict__)

28

15

{'name': 'tom', '_Person__age': 15, '__age': 28}

##

3)保护变量

在变量名前面使用一个下划线,称为保护变量。

class Person:

    def __init__(self,name,age = 18):

        self.name = name

        self._age = age



       

tom = Person('tom')

print(tom._age)

print(tom.__dict__)

18

{'name': 'tom', '_age': 18}

_age属性没有改变名称,和普通属性一样,解释器不做任何处理,只是开发者共同的约定,看见这样的变量,就如同私有变量,不直接使用。

4)私有方法

参展保护变量,私有变量,使用单下划线,双下划线命名方法。

class Person:

    def __init__(self,name,age =18):

        self.name = name

        self._age = age



    def _getname(self):

        return self.name



    def __getage(self):

        return self._age



tom = Person('tom')

print(tom._getname())    ##没改名

# print(tom.__getage())    ##m没有次属性

print(tom.__dict__)

print(tom.__class__.__dict__)

print(tom._Person__getage())   #改名了

tom

{'name': 'tom', '_age': 18}

{'__module__': '__main__', '__init__': <function Person.__init__ at 0x000000F1ECDB52F0>, '_getname': <function Person._getname at 0x000000F1ECDB5620>, '_Person__getage': <function Person.__getage at 0x000000F1ECDB56A8>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}

18

5)私有方法的本质

当下划线的方法只是开发者之间的约定,解释器不做任何改变

双下划线的方法,是私有方法,解释器会改名,改名策略和私有变量相同,_类名__昂发名。

方法变量都在类的 __dict__ 里面可以找到。

6)私有成员总结;

在python中使用_单下划线或者_双下划线来标示一个成员被保护或者被私有化隐藏起来,但是不管使用什么样的访问控制,都不能真正的组织用户修改类的成员,python中没有决定的安全环保成员或者私有成员。

因此,前道的下划线只是一种警告或者提醒,要遵守这个约定,除非有必要,否则不能修好或者使用保护成员或者私有成员,更不能修改。

14、属性装饰器

一般很好的设计是:把实例的属性保护起来,不让外部直接访问,外部使用getter读取属性和setter方法设置属性。

class Person:

    def __init__(self,name,age=18):

        self.name = name

        self.__age =age



    @property

    def age(self):

        return self.__age

    @age.setter

    def age(self,age):

        self.__age = age



tom = Person('tom')

print(tom.age)

tom.age = 20

print(tom.age)

使用property装饰器的时候,三个方法必须同名。

Property装饰器:

后面跟的函数名就是以后的属性名,他就是getter,这个必须有,有了它至少有了只读属性。

Setter装饰器

与属性名同名,且接受两个参数,第一个是self,第二个是将要赋值的值,有了它,属性可写。

Deleter装饰器

可以控制是否删除属性,很少用。

Property装饰器必须在前,setter  和  delter装饰器在后面。

Property装饰器能通过简单的方式,吧对方法的操作变成对属性的访问,并起到了一定的隐藏效果。

其它写法:

class Person:

    def __init__(self,name,age =20):

        self.name = name

        self.__age = age



    def getage(self):

        return self.__age



    def setage(self,age):

        self.__age =age



    def delage(self):

        del  self.__age

        print('del')



    age = property(getage,setage,delage,'age property')



tom = Person('tom')

print(tom.age)

tom.age = 25

del tom.age
class Person:

    def __init__(self,name,age=20):

        self.name =name

        self.__age = age



    age = property(lambda self:self.__age)



tom = Person('tom')

print(tom.age)

可读、可写。

15、补丁。

可以通过修改或者替换类的成员。使用着调用的方式没有改变,但是,类提供的功能可以已经改变。

猴子补丁:

在运行时,对属性,方法,函数等进行动态替换。

其目的是为了替换,修改来增强,扩展原有的代码的能力。

慎重使用。

上例中,假设Person类和get_score方法是从数据库中拿数据,但是测试的时候不方便。

使用猴子补丁的方法,替换了get_score方法,返回模拟的数据。

16、对象的销毁。

__del__ 方法,称为析构函数(方法)

作用:销毁类的时候调用,以释放占用的资源,其中就放些清理资源的代码。比如释放链接。

这个方法不能让对象真正的小虎,只是对象销毁的时候会自动调用它。

使用del的语句删除实例,引用计数减1,当引用计数为0时候,会idong调用__del__方法。

import time



class Person:

    def __init__(self,name,age=18):

        self.name = name

        self.__age = age



    def __del__(self):

        print('delete{}'.format(self.name))





def test():

    tom = Person('tom')

    tom.__del__()

    tom.__del__()

    tom.__del__()

    print('=======')

    tom1 = tom

    tom3 = tom1

    print(1,'del')

    del tom

    time.sleep(3)



    print(2,'del')

    del tom3

    time.sleep(3)

    print('-----')



    del tom3

    time.sleep(3)

    print('........')

test()

由于垃圾回收对象销毁时候,才会真正清理对象,还会再之间自动调用__del__ 方法。除非知道自己的目的,否则不会手动清理;不会手动调用这个方法。

17、方法重载。

Python没有重载,不需要重载

Python中,方法(函数)定义中,形参非常灵活,不需要指定类型(就算指定了也只是说明一个说明而非约束,),形参个数也不固定(可变参数),一个函数的定义可以实现很多种不同形式实参的调用,所哟python不需要方法重载。

或者说python本身就是实现了其他语言的重载。

18、封装:

面向对象的三要素之一,封装。

封装:

将数据和操作组织到类中,即属性和方法。

将数据隐藏起来,给使用者提供操作(方法),使用者通过操作就可以获取或者修改数据。

Getter和setter。

通过控制访问,暴漏给适当的数据和操作给用户,该隐藏的隐藏起来,例如保护成员或者私有成员。

19、习题:

1)随机整数生成类

##初步代码:

import random





class Ran:



    def __init__(self,start=0,end=100,length=10):

        self.start = start

        self.end  = end

        self.length = length



    def array(self):

        lst=  [random.randint(self.start,self.end)for i in range(self.length)]

        print(lst)



j = Ran()

j.length=5

j.array()

###第二步改进控制打印长度的

import random





class Ran:



    def __init__(self,start=0,end=100,length=10):

        self.start = start

        self.end  = end

        self.length = length



    def array(self,length=0):

        length = self.length if length<=0 else length

        lst=  [random.randint(self.start,self.end)for i in range(length)]

        print(lst)



j = Ran()

j.array(20)

####三,利用工具实现的方式

import random

class Ran:

    @classmethod

    def array(cls,start = 1,end =100,length =10):

        return [random.randint(start,end)for _ in range(length)]



a = Ran()

print(a.array())

###利用生成器

import random





class Ran:



    def __init__(self,start=0,end=100,length=10):

        self.start = start

        self.end  = end

        self.length = length

        self._gen = self._array()



    def _array(self):

        while True:

            yield random.randint(self.start,self.end)



    def array(self,length=0):

        if length <= 0:

            return [next(self._gen)for _ in range(self.length)]

        else:

            return [next(self._gen)for i in range(length)]



j = Ran()

print(j.array(20))

print(j.array())
import random





class Ran:



    def __init__(self,start=0,end=100,length=10):

        self.start = start

        self.end  = end

        self.length = length

        self._gen = self._array()



    def _array(self):

        while True:

            yield [random.randint(self.start,self.end)for _ in range(self.length)]



    def array(self,length=0):

        if length > 0:

            self.length = length

        return next(self._gen)



j = Ran()

print(j.array(20))

print(j.array())

2)利用上次的随机数生成20次,两两组和,打印坐标。

import random





class Ran:

    def __init__(self,start=0,end=100,count=20):

        self.start = start

        self.end= end

        self.count = count





    def array(self,count=0):

        count = self.count if count<=0 else count

        lst = [random.randint(self.start,self.end)for i in range(count)]

        return lst



a = Ran()

a.array()



class Point:

    def __init__(self,x,y):

        self.x = x

        self.y = y



# points = zip(a.array(),a.array())

# for x in points:

#     print(x)

points = [Point(x,y)for x,y in zip(a.array(),a.array())]

for p in points:

    print('{}:{}'.format(p.x,p.y))

3)车辆信息

class Car:



    def __init__(self, mark, color, price, speed, **kwargs):



        # self.id = genid

        self.mark = mark

        self.color = color

        self.price = price

        self.speed = speed

        self.__dict__.update(kwargs)



class CarInfo:

    cars = []

    def addcar(self,car:Car):

        self.cars.append(car)



    def getall(self):

        return self.cars



c1 = CarInfo()

car = Car('audi','red',100,100)

c1.addcar(car)

print(c1.getall())

4、实现温度的处理。

class Temp:

    def __init__(self,t,unit='c'):

        self._c = None

        self._f = None

        self._k =None

        #都先转换为摄氏温度,然后以后访问调用计算其他的温度的值

        if unit == 'k':

            self._k = t

            self._c = self.k2c(t)

        elif unit == 'f':

            pass

        else:

            self._c = t



    @property

    def c(self):

        return self._c



    @property

    def k(self):

        pass



    @property

    def f(self):

        pass

    #温度转换

    @classmethod

    def c2f(cls,c):

        return 9*c/5 +32



    @classmethod

    def f2c(cls,f):

        return 5*(f-32)/9



    @classmethod

    def c2k(cls,c):

        return c +273.15



    @classmethod

    def k2c(cls,k):

        return k -273.15



    @classmethod

    def f2k(cls,f):

        return cls.c2k(cls.f2c(f))



    @classmethod

    def k2f(cls,k):

        return cls.c2f(cls.k2c(k))



print(Temp.c2f(40))

print(Temp.c2k(40))

print(Temp.f2c(40))

print(Temp.k2c(40))

print(Temp.k2f(40))

print(Temp.f2k(40))



t = Temp(37)

print(t.c,t.k,t.f)

5、模拟购物车购物

class Item:

    def __init__(self,**kwargs):

        self.__spec = kwargs



    def __repr__(self):

        return str(sorted(self.__spec.items()))



class Cart:

    def __init__(self):

        self.items = []



    def additem(self,item:Item):

        self.items.append(item)



    def getallitems(self):

        return self.items



mycart = Cart()

myphone = Item(mark='apple',menory='4G')

mycart.additem(myphone)

print(mycart.getallitems())

一、类的继承

1、概念;

1)面向对象的三要素之一,继承inheritance

人类和猫类都是继承动物类。

个体继承自父母,继承了父母的一部分特征,但也可以有自己的个性。

在面向对象的世界中,从父类中继承,就可以直接拥有父类的属性和方法,这个可以减少代码,增加多复用,子类可以定义自己的属性和方法。

class Animal:

    def shout(self):

        print('Animal shouts')



class Cat:

    def shout(self):

        print('Cat shouts')



class Dog:

    def shout(self):

        print('Dog shouts')



a = Animal()

a.shout()



c = Cat()

c.shout()



d = Dog()

d.shout()

Animal shouts

Cat shouts

Dog shouts

上面的例子的类虽然有关系,但是定义时候并没有建立这种关系,而是各自完成定义。。

class Animal:

    def __init__(self,name):

        self._name = name



    def shout(self):

        print('{} shouts'.format(self.__class__.__name__))



    @property

    def name(self):

        return self._name



a = Animal('monster')

a.shout()



class Cat(Animal):

    pass



cat = Cat('garfield')

cat.shout()



class Dog(Animal):

    pass



dog = Dog('ahuang')

dog.shout()

print(dog.name)

上例可以看出,通过继承,猫类,狗类,直接继承了父类的属性和方法。

2)继承

Class cat(Animal)这种形式就是从父类继承,括号中写继承的类的列表。

继承可以让子类从父类获取特征(属性和方法)

父类Animal 就是cat的父类,也称为基类,超类。

子类

Cat 就是Animal的子类,也成为派生类。

2、定义

格式:

Class 子类名(基类1,[基类2,...........]):

语句块

如果类定义的时候,没有基类列表,等同于继承自object,在python3种,object类是所有对象的根基类。

Class  A:

Pass

#等价于

Class  A(object):

Pass

Python支持多继承,继承也可以多级。

查看继承的特殊属性和方法:

特殊属性和方法

含义

举例

__base__

类的基类

__bases__

类的基类元组

__mro__

显示方法查找顺序,基类的元组

mro()方法

同上

Int.mro()

__subclasses__()

类的子类列表

Int.__subclasses__()

3、继承中的访问控制

class Animal:

    __COUNT = 100

    HEIGHT = 0



    def __init__(self,age,weight,height):

        self.__COUNT += 1

        self.age = age

        self.__weight = weight

        self.HEIGHT = height



    def eat(self):

        print('{}eat'.format(self.__class__.__name__))



    def __getweight(self):

        print(self.__weight)



    @classmethod

    def showcount1(cls):

        print(cls.__COUNT)



    @classmethod

    def __showcount2(cls):

        print(cls.__COUNT)



    def showcount3(self):

        print(self.__COUNT)



class Cat(Animal):

    NAME = 'CAT'

    __COUNT = 200



# c = Cat()     函数参数错误,传参错误。

c = Cat(3,5,15)

c.eat()    ##cat eat

print(c.HEIGHT)   ##15

# print(c.__COUNT) ##私有不可访问

# c.__getweight()   #私有不可访问

c.showcount1()    #100因为__是改名的,在实例的类找不到,所以利用继承的。

# c.__showcount2()  #不可以,私有的不能访问

c.showcount3()   #101

print(c.NAME)   # CAT



print('{}'.format(Animal.__dict__))

print('{}'.format(Cat.__dict__))

print(c.__dict__)

print(c.__class__.mro())

后四个print

1/{'_Animal__getweight': <function Animal.__getweight at 0x000000D34976B0D0>, '__dict__': <attribute '__dict__' of 'Animal' objects>, 'HEIGHT': 0, '__weakref__': <attribute '__weakref__' of 'Animal' objects>, 'showcount3': <function Animal.showcount3 at 0x000000D34976B268>, 'showcount1': <classmethod object at 0x000000D349769748>, 'eat': <function Animal.eat at 0x000000D349764BF8>, '_Animal__COUNT': 100, '__module__': '__main__', '__init__': <function Animal.__init__ at 0x000000D349764D08>, '_Animal__showcount2': <classmethod object at 0x000000D349769780>, '__doc__': None}

2/{'NAME': 'CAT', '__module__': '__main__', '_Cat__COUNT': 200, '__doc__': None}

3/{'_Animal__COUNT': 101, 'HEIGHT': 15, '_Animal__weight': 5, 'age': 3}

4/[<class '__main__.Cat'>, <class '__main__.Animal'>, <class 'object'>]

从父类继承,自己没有的,就到父类中去找。

私有的都是不可以访问的,但是本质上依然是改了名字放在这个属性的类的__dict__ 中,知道这个新名称就可以直接找到这个隐藏的变量。

(类外部是不会被访问的,私有属性,内部可以。)

继承顺序:实例,自己的类,父类。继承类;

总结:

继承时候,公有的,子类和实例都可以随意访问,私有成员被隐藏,子类和实例不可直接访问,当私有变量所在的类内的方法都可以访问这个私有变量。

属性查找顺序:

实例的__dict__>>    类__dict__如果有继承==〉父类__dict__.

dir()来查看继承属性。

4、方法的重写、覆盖override

class Animal:

    def shout(self):

        print('Animal shouts')



class Cat(Animal):

    #覆盖了父类的方法

    def shout(self):

        print('miao')

a = Animal()

a.shout()

c =Cat()

c.shout()



print(a.__dict__)

print(c.__dict__)

print(Animal.__dict__)

print(Cat.__dict__)

{}

{}

{'__dict__': <attribute '__dict__' of 'Animal' objects>, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'Animal' objects>, '__doc__': None, 'shout': <function Animal.shout at 0x000000E832DF4D08>}

{'__module__': '__main__', '__doc__': None, 'shout': <function Cat.shout at 0x000000E832DF4BF8>}

class Animal:

    def shout(self):

        print('Animal shouts')



class Cat(Animal):

    #覆盖了父类的方法

    def shout(self):

        print('miao')

    #覆盖本身的方法,调用父类的方法

    def shout(self):

        print(super())

        print(super(Cat,self))

        super().shout()

        super(Cat,self).shout()   #等价于super()

        # self.__class__.__bases__.shout(self)

a = Animal()

a.shout()

c =Cat()

c.shout()



print(a.__dict__)

print(c.__dict__)

print(Animal.__dict__)

print(Cat.__dict__)

Animal shouts

<super: <class 'Cat'>, <Cat object>>

<super: <class 'Cat'>, <Cat object>>

Animal shouts

Animal shouts

{}

{}

{'__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'Animal' objects>, 'shout': <function Animal.shout at 0x0000001852BD4D08>, '__doc__': None, '__dict__': <attribute '__dict__' of 'Animal' objects>}

{'__module__': '__main__', '__doc__': None, 'shout': <function Cat.shout at 0x0000001852BDB0D0>}

Super()可以访问到父类的属性。

class Animal:



    @classmethod

    def class_method(cls):

        print('class_method_animal')



    @staticmethod

    def static_method():

        print('statice_method_animal')



class Cat(Animal):

    @classmethod

    def class_method(cls):

        print('class_method_cat')



    @staticmethod

    def static_method():

        print('statice_method_animal')



c = Cat()

c.class_method()

c.static_method()

class_method_cat

statice_method_animal

这些都可以进行被覆盖,原因是字典的搜索顺序。

5、继承中的初始化

上图中类B定义时候生命继承自类A,则在类B中__base__中是可以看到A的

但是这是和调用类A的构造方法是两回事。

如果B中调用了A的构造方法,就可以拥有父类的属性了。

class A:

    def __init__(self,a,b=1):

        self.a = a

        self.__b = b



class B(A):

    def __init__(self,b,c):

        A.__init__(self,b + c,b -c )

        self.b = b

        self.c = c



    def printv(self):

        print(self.b)

        print(self.a)

f = B(4,5)

print(f.__dict__)

print(f.__class__.__bases__)

f.printv()

{'c': 5, 'a': 9, '_A__b': -1, 'b': 4}

(<class '__main__.A'>,)

4

9在B中调用了父类的__init__函数。  如果父类中定义了__init__,子类中就应该调用他。

如果利用自动调用父类的__init__方法呢。

class A:

    def __init__(self):

        self.a1 = 'a1'

        self.__a2 = 'a2'



class B:

    pass

b =B()

print(b.__dict__)

子类没有自己的属性和方法,直接继承。。。会自动调用的。

此种类型不会自动调用,需要手动处理调用:

class A:

    def __init__(self):

        self.a1 = 'a1'

        self.__a2 = 'a2'

        print('Ainit')

class B(A):

    def __init__(self):

        self.b1 ='b1'

        print('B init')

b =B()

print(b.__dict__)

B init

{'b1': 'b1'}

正确初始化。

class A:

    def __init__(self,age):

        print('Ainit')

        self.age = age



    def show(self):

        print(self.age)



class B(A):

    def __init__(self,age,weight):



        print('Binit')

        self.age = age +1

        self.weight = weight

        super().__init__(age)

b = B(10,5)

b.show()

调用父类的__init__方法,出现在不同的位置,导致出现的结果不同。

class A:

    def __init__(self,age):

        print('Ainit')

        self.__age = age



    def show(self):

        print(self.__age)



class B(A):

    def __init__(self,age,weight):



        print('Binit')

        self.__age = age +1

        self.__weight = weight

        super().__init__(age)

b = B(10,5)

b.show()

打印出10,原因在__dict__,父类A的show方法中__age h会被解释为_A__age因此显示的就是10,而不是11.

自己私有的属性,就该自己读取和修改,不要借助其他类的方法,即使是父类或者派生类。

继承中的初始化

(继承加覆盖就是多态。)

二、多继承

1、Python不同的版本的类

Python2.2之前是没有共同祖先的,之后,引入object的类,他是所有类的共同 的祖先object。

Python2中为了兼容,分为古典类(旧式类)和新式类。

Python3中全部都是新式类。

新式类都是继承自object的,新式类可以使用super。

2、Ocp原则

多用继承,少用修改。

继承的用途,增强基类,实现多态。

多态:

在面向对象中,父类,子类通过继承联系在一起,如果通过一套方法,就可以实现不同的表现,就是多态。

一个类继承自多个类就是多继承,他将会有多个类的特征。

3、多继承弊端

多继承很好的模拟了世界,因为事物很少是单一继承的,但是舍弃简单,必然引入复杂性,带来了冲突。

如同一个孩子继承了来自父母双方的特征,那么到底眼睛像爸爸还是妈妈呢,孩子究竟该谁多一点呢。

多继承的实现会导致编译器设计的复杂度增加,所以很多语言舍弃了类的多继承。

C++支持多继承,JAVA也舍弃了多继承。

Java中,一个类可以实现多个接口,一个接口也可以继承多个解耦,Java的接口很纯粹,只是方法的生命。继承者必须实现这些方法,就具有了这些能力,就能干什么。

多继承可能会带来二义性,例如,猫和狗都继承自动物类,现在如果一个类多继承了猫和狗类,猫和狗都有shout方法,子类究竟继承谁的shout呢。

解决的方案。

实现多继承的语言,要解决二义性,深度优先或者广度优先。

4、Python多继承实现。

Class ClassName(基类列表)

类体

左图是多继承,右图是单一继承。

多继承带来路径选择问题,究竟继承哪个父类的特征呢。

Python使用MRO(method resolution order)解决基类搜索顺序问题。

历史原因:MRO有三个搜索算法:

经典算法,按照定义从左到右,深度优先策略,2.2之前左图的MRO是MYclass dbaca

新式算法,经典算法的升级,重复的是只保留最后一个,2.2左图的mro是myclassd,b,c,a,object

C3算法,在类被创建出来的时候,就计算出一个MRO有序列表,2.3之后,Python3唯一支持的算法。

左图中MRO是myclass,d,b,c,a,object的列表。

C3算法解决了多继承的二义性。

5、多继承的缺点

当类很多,继承复杂的情况下,继承路径太多,很难说清什么样的继承路径。

Python语法是允许很多继承的,但Python代码是解释执行的,只有执行到的时候,才会发现错误。

团队协作开发,如果引入多继承,name代码将会不可控。

不管编程语言是否支持多继承,都应避免使用多继承。

6、Mixin类                  (继承加覆盖等于多态。)

类有下面的继承关系。

本质上是:多继承的来实现,体现的是组合的设计模式。

文档Document类是其他所有文档类的抽象基类;

Word PDF类是Document的子类。

为document子类提供打印能力:

方法:

1)在Document中提供print方法。

class Document:

    def __init__(self,content):

        self.content = content

   

    def print(self):

        raise NotImplementedError()

   

class Word(Document):pass

class Pdf(Document):pass

基类提供的方法不应该具体实现,因为他未必适合子类的打印,子类中需要覆盖重写。

Print是一种能力 ——打印功能,不是所有的Document的子类都需要,所有,从这个角度出发,会有问题的。

2)需要打印的子类上增加。

如果在现有子类上直接增加,违反了OCP原则,所以应该继承后增加。

##3采用多继承形式。

class Printable:

    def print(self):

        print(self.content)



class Document:

    def __init__(self,content):

        self.content = content



class Word(Document):pass

class Pdf(Document):pass



class PrintableWord(Printable,Word):pass

print(PrintableWord.__dict__)

print(PrintableWord.mro())



pw = PrintableWord('test str')

pw.print()

{'__doc__': None, '__module__': '__main__'}

[<class '__main__.PrintableWord'>, <class '__main__.Printable'>, <class '__main__.Word'>, <class '__main__.Document'>, <class 'object'>]

test str

应用于网络,文档应该具备序列化的能力,类上就应该实现序列化。

可序列化还分为使用pickle,json,messagepack等

发现,类可能太多了,继承的方式很好。

功能太多,A需要几样功能,B需要几样功能,很繁琐。

3)装饰器。

使用装饰器增强一个类,把功能给类附加上去,那个类需要他,就去装饰他。

class Document:

    def __init__(self,content):

        self.content = content



class Word(Document):pass

class Pdf(Document):pass







def printable(cls):

    cls.print = lambda self: print(self.content)

    return lcs



@printable  #printableWord=printable(printableword)

class PrintableWord(Word):pass



a = PrintableWord()

a.print('ls')
class Document:

    def __init__(self,content):

        self.content = content



class Word(Document):pass

class Pdf(Document):pass







def printable(cls):

    def _print(self):

        print(self.content)

    cls.print = _print

    return cls

 

@printable  #printableWord=printable(printableword)

class PrintableWord(Word):pass



a = PrintableWord()

a.print('ls')

优点:简单方便,在需要的地方动态增加,直接使用装饰器。

4)Mixin

class Document:

    def __init__(self,content):

        self.content = content



class Word(Document):pass

class Pdf(Document):pass



class PrintableMixin:

    def print(self):

        print(self.content,'Mixin')



class PrintableWord(PrintableMixin,Word):pass

print(PrintableWordMixin.__dict__)

print(PrintableWordMixin.mro())



def printable(cls):

    def _print(self):

        print(self.content)

    cls.print = _print

    return cls



@printable  #printableWord=printable(printableword)

class PrintableWord(Word):pass



pw = PrintableWord('test str')

pw.print()

6、Mixin类(混合)   实现的是组合。解决的是应该的是缺少什么样的功能。场景和使用范围是不一样的。不出现除了功能以外的属性方法等。(组合模式)

Mixin本质上就是多继承。

Mixin体现的是一种组合的设计模式。

Mixin体现在mro中。

在面向对象的设计中,一个复杂的类,往往需要很多功能,而这些功能来自不同的类提供,需要好多类组合在一起。设计角度说多组合,少继承。

Mixin类的使用原则。

不应该显示的出现__init__初始化方法。

通常不能单独工作,因为他是准备混入别的类中的功能的实现。

Mixin类的祖先类应该是Mixin类。

使用时候,Mixin类通常在继承列表的第一个位置,class PrintableWord(PrintableMixin,Word):pass

人是具体的实例,必须进行实例化。登录网站,先抽象用户类,每个用户是独立的个体,每个人操作都是不同的。利用面向过程是难以实现的。

Mixin类和装饰器

这两种方式都可以使用,看个人喜好。

如果还需要继承就使用Mixin类的方式。

Python中面向对象的概念的更多相关文章

  1. python 中面向对象的概念

    原文 域和作用空间 本地域,函数域(nonlocal)和 全局域(global) def scope_test(): def do_local(): spam = "local spam&q ...

  2. Python中面向对象的概念(科普)

    面向对象(OOP)基本概念 面向对象编程 —— Object Oriented Programming 简写 OOP 目标 了解 面向对象 基本概念 01. 面向对象基本概念 我们之前学习的编程方式就 ...

  3. 『Python题库 - 简答题』 Python中的基本概念 (121道)

    ## 『Python题库 - 简答题』 Python中的基本概念 1. Python和Java.PHP.C.C#.C++等其他语言的对比? 2. 简述解释型和编译型编程语言? 3. 代码中要修改不可变 ...

  4. python中面向对象_类_对象的概念与定义

    1. 面向对象的概念,面向对象是一种编程思想. 是对现实世界中一类事物的抽象,在编程中可以理解为是一种建立现实世界事物的模型 2.  面向对象和面向过程的区别: 面向过程关注的是完成工作的步骤. 面向 ...

  5. python 中面向对象编程的几个概念

    Python super() 函数 super() 函数是用于调用父类(超类)的一个方法. super 是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会 ...

  6. python中面向对象

    一.Python经典类与新类 经典类:如果没有直接或间接的子类化一个对象,也就是说如果没有指定一个父类,或者是如果子类化的基本类没有父类,那么就定义了经典类: class classics: 'def ...

  7. python中面向对象元类的自定义用法

    面向对象中的常用方法 1.instance 和 issubclass instance :判断两个对象是不是一类 issubclass :判断某个类是不是另一个类的子类 #两个常用方法的使用 clas ...

  8. python 中面向对象编程简单总结2

    1.python中继承的特点: (1)总是从一个类继承,默认为object类 (2)不要忘记调用super.__init__方法来初始化父类的方法 def __init__(self,args): s ...

  9. Python中面向对象初识到进阶

    面向对象初识到进阶 # 面向对象结构: # class 类名: # def __init__(self,参数1,参数2): # self.对象的属性1 = 参数1 # self.对象的属性2 = 参数 ...

随机推荐

  1. CPU饥饿与线程饥饿

    线程饥饿: 进程无法得到资源,(cpu或者io资源或者别的什么资源),所以无法进行下去 比如说读者写者问题,如果读者优先,那么写者可能会饿死. 又比如操作系统概念的一道习题. 用broadcast可能 ...

  2. Gym - 101981D Country Meow(模拟退火)题解

    题意: 给\(n\)个三维点,问最小覆盖球的半径. 思路: 模拟退火. 代码: #include<set> #include<map> #include<cmath> ...

  3. CNN可视化技术总结(三)--类可视化

    CNN可视化技术总结(一)-特征图可视化 CNN可视化技术总结(二)--卷积核可视化 导言: 前面我们介绍了两种可视化方法,特征图可视化和卷积核可视化,这两种方法在论文中都比较常见,这两种更多的是用于 ...

  4. Adobe DreamWeaver CC 快捷键

    1 1 ADOBE DREAMWEAVER CC Shortcuts: DREAMWEAVER CC DOCUMENT EDITING SHORTCUTS Select Dreamweaver > ...

  5. cursor CSS属性定义鼠标指针悬浮在元素上时的外观。

    1 1 cursor CSS属性定义鼠标指针悬浮在元素上时的外观. https://developer.mozilla.org/zh-CN/docs/Web/CSS/cursor 概述 cursor  ...

  6. js 深入原理讲解系列-Promise

    js 深入原理讲解系列-Promise 能看懂这一题你就掌握了 js Promise 的核心原理 不要专业的术语,说人话,讲明白! Q: 输出下面 console.log 的正确的顺序? const ...

  7. SwiftUI All In One

    SwiftUI All In One SwiftUI SwiftUI is an innovative, exceptionally simple way to build user interfac ...

  8. how to publish a dart package using Github Actions?

    how to publish a dart package using Github Actions? dart package flutter package Github Actions publ ...

  9. vue & components & props & methods & callback

    vue & components & props & methods & callback demo solution 1 & props & data ...

  10. c++ 使用PID获取可执行文件路径

    注意看备注 https://docs.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-getmodulefilenameexa #includ ...