Python0801-面向对象(重要)

语言的分类

面向机器

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

面向过程

  • 做一件事情,排出个步骤,第一步干什么,第二步干什么,如果出现情况A,做什么处理,如果出现了情况,做什么处理。
  • 问题规模小,可以步骤化,按部就班处理。
  • 代表,C语言

面向对象OOP

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

面向对象

  • 什么是面向对象呢?
    • 一种认识世界、分析世界的方法论。将万事万物抽象为类。
  • 类Class
    • 类是抽象的概念,是万事万物的抽象,是一类事物的共同特征的集合。
    • 用计算机语言来描述类,就是属性和方法的集合
  • 对象instance、Object
    • 对象是类的具象,是一个实体。
    • 对于我们每个人这个个体,都是抽象概念人类的不同的实体。

面向对象举例

  • 你吃鱼
  • 你,就是对象;
  • 鱼,也是对象;
  • 吃就是动作;
  • 你是具体的人,是具体的对象。你属于人类,人类是个抽象的概念,是无数具体的个体的抽象。
  • 鱼,也是具体的对象,就是你吃的这一条具体的角。这条角属于角类,是无数的鱼抽象出来的概念。
  • 吃,是动作,也是操作,也是方法,这个吃是你的动作,也就是人类具有的方法。如果反过来,鱼吃人。吃就是鱼类的动作了。
  • 吃,这个动作,很多动物都具有的动作,人类和鱼类都属于动物类,而动物类是抽象的概念,是动物都有吃的动作,但是吃法不同而已。
  • 你驾驶车,这个车也是车类的具体的对象(实例),驾驶这个动作是鱼类不具有的,是人类具有的方法。
  • 属性,它是对象状态的抽象,用数据结构来描述。
  • 操作。它是对象行为的抽象,用操作名和实现该操作的方法来庙述。
  • 每个人都有名字、身高、体重等信息,这些信息是个人的属性,但是,这些信息不能保存在人类中,因为它是抽象的概念,不能保留具体的值。
  • 而人类的实例,是具体的人,他可以存储这些具体的属性,而且可以不同人有不同的属性。

面向对象哲学

  • 一切皆对象
  • 对象是数据和操作的封装
  • 对象是独立的,但是对象之间可以相互作用
  • 目前OOP是最接近人类认知的编程范式

面向对象3要素

  • 1.封装
    • 组装:将数据和操作组装到一起。
    • 隐藏数据:对外只暴露一些接口,通过接口访问对象。比如驾驶员使用汽车,不需要了解汽车的构造细节,只需要知道使用什么部件怎么驾驶就行,踩了油门就能跑,可以不了解后面的机动原理。
  • 2.继承
    • 多复用,继承来的就不用自己写了
    • 多继承少修改,OCP(Open-closedPrinciple),使用继承来改变,来体现个性
  • 3.多态
    • 面向对象编程最灵活的地方,动态绑定
  • 人类就是封装,
    • 人类继承自动物类,孩子继承父母特征。分为单一继承、多继承;多态,继承自动物类的人类、猫类的操作”吃“不同。

Python的类

  • 定义
class ClassName:
    语句块
  • 1.必须使用class关键字
  • 2.类名必须使用大驼峰命名
  • 3.类定义完成后,就产生了一个类对象,绑定到了标识符ClassName上

类的举例

class MyClass:
    """A example class"""
    x = 'abc'  # 类属性

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


print(1, MyClass.x)
print(2, MyClass.foo)
print(3, MyClass.__doc__)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 abc
2 <function MyClass.foo at 0x0000016C925F19D8>
3 A example class

类对象及类属性

  • 类对象,类的定义就会生成一个类对象
  • 类的属性,类定义中的变量和类中定义的方法都是类的属性
  • 类变量,上例中×是类My创ass的变量
  • MyClass中,×、foo都是类的属性,doc也是类的属性
  • foo方法是类的属性,如同人类的方法,但是每一个具体的人才能吃东西,也就是说吃是人的实例才能调用的方法。
  • foo是方法对象method不是普通的函数对象function了,它一般要求至少有一个参数。第一个参数可以是self(self只是个惯用标识符,可以换名字),这个参数位置就留给了self
  • self指代当前实例本身
  • 问题
    • 上例中,类是谁?实例是谁?

实例化

a = MyClass()  # 实例化
  • 使用上面的语法,在类对象名称后面加上一个括号,就调用类的实例化方法,完成实例化
tom = Person()
jerry = Person()
  • 上面的tom,jerry都是Person类的实例,通过实例化生成了2个实例
  • 每次实例化后获得的实例,是不同的实例,即使是视同同样的参数实例化,也得到不一样的对象。
  • Python类实例化后,会自动调用init方法。这个方法第一个参数必须留给self,其他参数随意。
init方法
  • MyClass()实际上调用的是init(self)方法,可以不定义,如果没有定义会在实例化后隐式调用。
  • 作用:对实例进行初始化
class MyClass:
    def __init__(self):
        print('init')


print(1, MyClass)  # 不会调用
print(2, MyClass())  # 调用__init__
a = MyClass()  # 调用__init__
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 <class '__main__.MyClass'>
init
2 <__main__.MyClass object at 0x0000017A09B00390>
init
  • 初始化函数可以多个参数,请注意第一个位置必须是self,例如__init__(self, name, age)
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) # 实例化
jerry = Person('Je', 25)
print(tom.name, jerry.age)
jerry.age +=1
print(jerry.age)
jerry.showage()
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Tom 25
26
Je is 26
  • 注意:__init__()方法不能有返回值,也就是只能是None

实例对象instance

  • 类实例化后一定会获得一个对象,就是实例对象
  • 上例中的tom、jerry就是Person类的实例。
  • __init__方法的第参数self就是指代某一个实例。
  • 类实例化后,得到一个实例对象,实例对象会绑定方法,调用方法时采用jerry.showage()的方式。
  • 但是函数签名是showage(self),少传一个参数self吗?
  • 这个self就是jerry,Python会把方法的调用者作为作为第一参数self的实参传入。
  • self.name就是Jerry对象的name,name是保存在了jerry对象上,而不是Person类上。所以,称为实例变量

self举例

class MyClass:
    def __init__(self):
        print('self in init = {}'.format(id(self)))


c = MyClass()  # 会调用__init__
print('c = {}'.format(id(c)))
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
self in init = 1892697973760
c = 1892697973760
  • 上例说明,self就是调用者,就是c对应的实例对象。
  • self这个名字只是一个惯例,它可以修改,但是请不要修改,否则影响代码的可读性
  • 看打印的结果,思考下执行的顺序,为什么?

实例变量和类变量

class Person:
    age = 3
    def __init__(self, name):
        self.name = name


# tom = Person('Tom', 20)  # TypeError: __init__() takes 2 positional arguments but 3 were given
tom = Person('Tom')
jerry = Person('Jerry')

print(1, tom.name, tom.age)
print(2, jerry.name, jerry.age)
print(3, Person.age)
# print(4, Person.name) # AttributeError: type object 'Person' has no attribute 'name'
Person.age = 30
print(5, Person.age, tom.age, jerry.age)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 Tom 3
2 Jerry 3
3 3
5 30 30 30
  • 实例变量是每一个实例自己的变量,是自己独有的;类变量是类的变量,是类的所有实例共享的属性和方法
特殊属性含义
name对象名
class对象的类型
dict对象的属性的字典
qualname类的限定名

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

举例

class Person:
    age = 3

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


print('----class----')
print(1, Person.__class__)
print(2, sorted(Person.__dict__.items()), end='\n\n')  # 属性字典

tom = Person('Tom')
print('----instance tom----')
print(3, tom.__class__)
print(4, sorted(tom.__dict__.items()), end='\n\n')

print("----tom's class----")
print(5, tom.__class__.__name__)
print(6, sorted(tom.__class__.__dict__.items()), end='\n\n')
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
----class----
1 <class 'type'>
2 [('__dict__', <attribute '__dict__' of 'Person' objects>), ('__doc__', None), ('__init__', <function Person.__init__ at 0x0000019B375819D8>), ('__module__', '__main__'), ('__weakref__', <attribute '__weakref__' of 'Person' objects>), ('age', 3)]

----instance tom----
3 <class '__main__.Person'>
4 [('name', 'Tom')]

----tom's class----
5 Person
6 [('__dict__', <attribute '__dict__' of 'Person' objects>), ('__doc__', None), ('__init__', <function Person.__init__ at 0x0000019B375819D8>), ('__module__', '__main__'), ('__weakref__', <attribute '__weakref__' of 'Person' objects>), ('age', 3)]
  • 上例中,可以看到类属性保存在类的__dict__中,实例属性保存在实例的__dict__中,如果从实例访问类的属性,就需要借助__class__找到所属的类。
  • 有了上面知识,再看下面的代码
class Person:
    age = 3
    height = 170

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


tom = Person('Tom')
jerry = Person('Jerry', 20)

Person.age = 30
print(1, Person.age, tom.age, jerry.age)  # 输出什么结果

print(2, Person.height, tom.height, jerry.height)  # 输出什么结果
jerry.height = 175
print(3, Person.height, tom.height, jerry.height)  # 输出什么结果

tom.height += 10
print(4, Person.height, tom.height, jerry.height)  # 输出什么结果

Person.height += 15
print(5, Person.height, tom.height, jerry.height)  # 输出什么结果

Person.weight = 70
print(6, Person.weight, tom.weight, jerry.weight)  # 输出什么结果

print(7, tom.__dict__['height'])
# print(8, tom.__dict__['weight'])  # 可以么?KeyError: 'weight'
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 30 18 20
2 170 170 170
3 170 170 175
4 170 180 175
5 185 180 175
6 70 70 70
7 180
  • 总结
    • 是类的,也是这个类所有实例的,其实例都可以访问到;是实例的,就是这个实例自己的,通过
      类访问不到。
    • 类变量是属于类的变量,这个类的所有实例可以共享这个变量。
  • 实例可以动态的给自己增加一个属性。实例.__dict__[变量名]实例.变量名都可以访问到。
  • 实例的同名变量会隐藏这类变量,或者说是覆盖了这个类变量。
    实例属性的查找顺序
  • 指的是实例使用.来访问属性,会先找自己的__dict__,如果没有,然后通过属性__class__找到自己的类,再去类的__dict__中找
  • 找到自己的类,再去类的__dict__中找
  • 注意,如果实例使用__dict__[变量名]访问变量,将不会按照上面的找顺序找变量了,这是
    指明使用字典的key查找,不是属性查找。
  • 一般来说,类变量使用全大写来命名。

装饰一个类

  • 回顾,什么是高阶函数?什么是装饰器函数?
  • 思考,如何装饰一个类?
  • 需求,为一个类通过装饰,增加一些类属性
# 增加类变量
def add_name1(name, cls):
    cls.NAME = name  # 动态增加类属性


# 改进成装饰器
def add_name(name):
    def wrapper(cls):
        cls.NAME = name
        return cls
    return wrapper


@add_name('Tom')
class Person:
    AGE = 3


print(Person.NAME)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Tom
  • 之所以能够装饰,本质上是为类对象动态的增加了一个属性,而Person这个标识符指向这个类对象。

类方法和静态方法

  • 前面的例子中定义的init等方法,这些方法本身都是类的属性,第一个参数必须是self,而self必须指向一个对象,也就是类必须实例化之后,由实例来调用这个方法。

普通函数

class Person:
    def normal_method():
        print('normal')


# 如何调用
Person.mormal_method()  # 可以么?
Person().normal_method()  # 可以么?

print(Person.__dict__)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
{'__weakref__': <attribute '__weakref__' of 'Person' objects>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__doc__': None, '__module__': '__main__', 'normal_method': <function Person.normal_method at 0x000002159F4B19D8>}
  • Person.normal_method()
    • 可以,因为这个方法只是被Person这个名词空间管理的一个普通的方法,normal_method这是Person的一个属性而已。
  • 由于normal_method在定义的时候没有指定self,所以不能完成实例对象的绑定,不能用Person().normal_method()调用。
  • 注意:虽然语法是对的,但是,没有人这么用,也就是说禁止这么写

类方法

class Person:
    @classmethod
    def class_method(cls):  # cls是什么
        print('class = {0.__name__}({0})'.format(cls))
        cls.HEIGHT = 170


Person.class_method()
print(Person.__dict__)
~~~~~~~~~~~~~~~~~~~~~~~~~
class = Person(<class '__main__.Person'>)
{'__doc__': None, '__module__': '__main__', 'class_method': <classmethod object at 0x0000027724C92400>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, 'HEIGHT': 170}
  • 类方法
    • 在类定义中,使用@classmethod装饰器修饰的方法
    • 必须至少有一个参数,且第一个参数留给了cls,cls指代调用者即类对象自身
    • cls这个标识符可以是任意合法名称,但是为了易读,请不要修改
    • 涌过cls可以直接操作类的属性
    • 注意:无法通过cls操作类的实例。为什么
  • 类方法,类似于C++、Java中的静态方法

静态方法

class Person:
    @classmethod
    def class_method(cls):
        print('class = {0.__name__}({0})'.format(cls))
        cls.HEIGHT = 170


    @staticmethod
    def static_methd():
        print(Person.HEIGHT)


Person.class_method()
Person.static_methd()
print(Person.__dict__)
~~~~~~~~~~~~~~~~~~~~~
class = Person(<class '__main__.Person'>)
170
{'class_method': <classmethod object at 0x000001DC18272400>, 'HEIGHT': 170, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__module__': '__main__', '__doc__': None, 'static_methd': <staticmethod object at 0x000001DC18272320>}
  • 静态方法
    • 在类定义中,使用@staticmethod装饰器修饰的方法
    • 调用时,不会隐式的传入参数
    • 静态方法,只是表明这个方法属于这个名词空间。函数归在一起,方便组织管理。

方法的调用

  • 类可以定义这么多种方法,究竟如何调用他们?
class Person:
    def normal_method():
        print('normal')


    def method(self):
        print("{}'s method".format(self))


    @classmethod
    def class_method(cls):
        print('class = {0.__name__}({0})'.format(cls))
        cls.HEIGHT = 170


    @staticmethod
    def static_methd():
        print(Person.HEIGHT)


print('~~~~类访问~~~~')
print(1, Person.normal_method())
# print(2, Person.method())
print(3, Person.class_method())
print(4, Person.static_methd())
print(5, 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_methd())
print('----jerry----')
jerry = Person()
# print(1, jerry.normal_method())
print(2, jerry.method())
print(3, jerry.class_method())
print(4, jerry.static_methd())
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~类访问~~~~
normal
1 None
class = Person(<class '__main__.Person'>)
3 None
170
4 None
5 {'normal_method': <function Person.normal_method at 0x00000196458619D8>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, 'method': <function Person.method at 0x0000019645861A60>, 'class_method': <classmethod object at 0x000001964586A240>, 'static_methd': <staticmethod object at 0x000001964586A748>, '__module__': '__main__', '__dict__': <attribute '__dict__' of 'Person' objects>, '__doc__': None, 'HEIGHT': 170}
~~~~实例访问~~~~
----tom----
<__main__.Person object at 0x000001964586A860>'s method
2 None
class = Person(<class '__main__.Person'>)
3 None
170
4 None
----jerry----
<__main__.Person object at 0x000001964586A7F0>'s method
2 None
class = Person(<class '__main__.Person'>)
3 None
170
4 None
  • 类几乎可以调用所有内部定义的方法,但是调用普通的方法时会报错,原因是第一参数须是
    类的实例。
  • 实例也几乎可以调所有的方法,普通的函数的调一般不可能出现,因为不允许这么定义。
    类除了普通方法都可以调用,普通方法需要对象的实例作为第一参数。
  • 实例可以调所有类中定义的方法(包括类方法、静态方法),普通方法传入实例宦身,静态方
    法和类方法需要找到实例的类。

访问控制

私有(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 += i


p1 = Person('tom')
p1.growup(20) # 正常的范围
p1.age = 160  # 超过了范围,并绕过了控制逻辑
print(p1.age)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
160
  • 上例,本来是想通过方法控制属性,但是由于属性在外部可以访问,或者说可见,就可以直接绕
    过方法,直接修改这个属性。
  • 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 += i


p1 = Person('tom')
p1.growup(20)  # 正常的范围
print(p1.__age)  # 可以吗
  • 通过实验可以看出,外部已经访问不到__age了,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 += i


    def getage(self):
        return self.__age


print(Person('tom').getage())
~~~~~~~~~~~~~~~~~~~~
18

私有变量的本质

外部访问不到,能够动态增加一个__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 += i


    def getage(self):
        return self.__age


p1 = Person('tom')
p1.growup(20)  # 正常的范围
# print(p1.__age)  # 访问不到
p1.__age = 28
print(1, p1.__age)
print(2, p1.getage())
# 为什么年龄不一样?__age没有覆盖吗?
print(3, p1.__dict__)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 28
2 38
3 {'_Person__age': 38, '__age': 28, 'name': 'tom'}
  • 秘密都在dict中,里面是{‘_Person__age’: 38, ‘__age’: 28, ‘name’: ‘tom’}
  • 私有变量的本质:
    • 类定义的时候,如果声明一个实例变量的时候,使用双下划线,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 += i


    def getage(self):
        return self.__age


p1 = Person('tom')
p1.growup(20)  # 正常的范围
# print(p1.__age)  # 访问不到
p1.__age = 28
print(1, p1.__age)
print(2, p1.getage())
# 为什么年龄不一样?__age没有覆盖吗?
print(3, p1.__dict__)

# 直接修改私有变量
p1._Person__age = 15
print(4, p1.getage())
print(5, p1.__dict__)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 28
2 38
3 {'__age': 28, 'name': 'tom', '_Person__age': 38}
4 15
5 {'__age': 28, 'name': 'tom', '_Person__age': 15}
  • 从上例可以看出,知道了私有变量的新名称,就可以直接从外部访问到,并可以修改它。

保护变量

  • 在变量名前使用一个下划线,称为保护变量。
class Person:
    def __init__(self, name, age=18):
        self.name = name
        self._age = age


tom = Person('Tom')
print(tom._age)
print(tom.__dict__)
~~~~~~~~~~~~~~~~~~~~
18
{'_age': 18, 'name': 'Tom'}
  • 可以看出,这个_age属性根本就没有改变名称,和普通的属性一样,解释器不做任何特殊处理。
  • 这只是开发者共同的约定,看见这种变量,就如同私有变量,不要直接使用。

私有方法

  • 参照保护变量、私有变量,使用单下划线、双下划线命名方法。
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(1, tom._getname())  # 没改名
# print(2, tom.__getage())
print(3, tom.__dict__)
print(4, tom.__class__.__dict__)
print(5, tom._Person__getage())  # 改名了
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 Tom
3 {'name': 'Tom', '_age': 18}
4 {'__doc__': None, '__init__': <function Person.__init__ at 0x0000023A58BB19D8>, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'Person' objects>, '_getname': <function Person._getname at 0x0000023A58BB1A60>, '__dict__': <attribute '__dict__' of 'Person' objects>, '_Person__getage': <function Person.__getage at 0x0000023A58BB1AE8>}
5 18

私有方法的本质

  • 单下划线的方法只是开发者之间的约定,解释器不做任何改变。
  • 双下划线的方法,是私有方法,解释器会改名,改名策略和私有变量相同,类名方法名。
  • 方法变量都在类的dict中可以找到。

私有成员的总结

  • 在Python中使用单下划线或者_双下划线来标识一个成员被保护或者被私有化隐藏起来。
  • 但是,不管使用亻十么样的访问控制,都不能真正的阻止用户修改类的成员。Python中没有绝对的安全的保护成员或者私有成员。
  • 因此。前导的下划线只是一种警告或者提醒。请遵守这个约定。除非真有必要,不要修改或者使
    用保护成员或者私有成员,更不要修改它们。

补丁

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

猴子补丁〔MonkeyPatch)

  • 在运行时,对属性、方法、函数等进行动态替换。
  • 其目的往往是为了通过替换、修改来增强、扩展原有代码的能力。
  • 黑魔法,慎用。

作业

随机整数生成

  • 可以指定一批生成的个数,可以指定数值的范围,可以调整数字的个数
import random

class RandomInt:  # 对象
    def __init__(self, count=10, start=1, stop=100):
        self.count = count
        self.start = start
        self.stop = stop

    def genint(self):
        return [random.randint(self.start, self.stop) for _ in range(self.count)]

class RandomInt2:  # 工具类
    @classmethod
    def genint(cls, count=10, start=1, stop=100):
        return [random.randint(start, stop) for _ in range(count)]

#自己的
import random

class Num:
    def rd(self, number=10, start=0, end=10):
        return [random.randint(start, end) for _ in range(number)]


test = Num()
print(test.rd(5, 2, 4))

打印坐标

  • 使用上题中的类,随机生成20个数字,两两配对形成二维坐标系的坐标,把这些坐标组织起来,并打印输出,
import random

class RandomInt3:
    def __init__(self, count=10, start=1, stop=100):
        self._count = count
        self.start = start
        self.stop = stop
        self._gen = self._generate()

    def _generate(self):
        # 生成器, 无限生成,要多少不在这里处理
        while True:
            yield [random.randint(self.start, self.stop) for _ in range(self._count)]

    def generate(self, count=0):
        if count > 0:
            self._count = count
        # return next(self._gen)
        ret = next(self._gen)
        return ret

ri = RandomInt3()

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def

points = [Point(x, y) for x, y in zip(ri.generate(), ri.generate())]
# points2 = [Point(*v) for v in zip(ri.generate(), ri.generate())]

# print(points, len(points))
for point in points:
    print("{}{}.format(point)")

车辆信息

  • 记录车的品牌mark,颜色color,价格price,速度speed等特征,并实现增加车辆信息、显示全部车辆信息的功能

class Car:  # 你管理车辆的抽象
    id = 0

    @classmethod
    def genid(cls):  # 生成id用函数
        cls.id = cls.id +1

    def __init__(self, mark, speed, color, price=-1, **kwargs):
        self.id = self.genid()
        self.mark = mark
        self.color = color
        self.price = price
        self.__dict__.update(kwargs)
        self.properties = kwargs

    def __repr__(self):
        return "<Car {} "

car1 = Car('Red Flag', 100, 'red')
car2 = Car('audi', 120, 'black')


class CarInfo:  # 车辆信息的管理
    cars = []

    def addcar(self, *cars:Car):
        self.cars.extend(cars)

    def getall(self):
        return self.cars


    # def getcatbyid(self, id):

ci = CarInfo()

实现温度的处理

  • 实现华氏温度和摄氏温度的转换。
  • ℃ = 5 * (℉ - 32) / 9
  • ℉ = 9 * ℃ / 5 +32
  • 完成以上转换后,增加与开始温度的转换,K = ℃ + 273.15
class Temperature:
    def __init__(self, t, unit='c'):
        self._c = None
        self._f = None
        self._k = None

        if unit == 'f':
            self._f = t
            self._c = self.f2c(t)
        elif unit == 'k':
            self._k = t
            self._c = self.k2c(t)
        else:
            self._c =t


    @property
    def c(self):
        return self._c

    @property
    def f(self):
        if self._f is None:
            self._f = self.c2f(self._c)
        return self._f

    @property
    def k(self):
        if self._k is None:
            self._k = self.c2k(self._c)
        return self._k



    @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(cla, k):
        return cls.c2f(cls.k2c(k))

t1 = Temperature.c2k(68)
t2 = Temperature(68, 'f')
[x, ]

模拟购物车购物

class Color:
    RED = 0
    BLUE = 1
    GREEN = 2
    GOLDEN = 3
    BLACK = 4
    OTHER = 1000

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='Huawei', color=Color.GOLDEN, memory='4G')
mycart.additem(mycart)

mycar = Item(mark='Red Flag', color=Color.BLACK, year=2017)
mycart.additem(mycar)

print(mycart.getallitems())
  • 注意,以上代码只是一个非常简答的一个实现,生产环境实现购物车的增删改查,要考虑很多
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值