面向对象高级

一、 特性

特性是指的property.

property这个词的翻译一直都有问题, 很多人把它翻译为属性, 其实是不恰当和不准确的. 在这里翻译成特性是为了和属性区别开来.

属性是指的attribute, 我们以前学习的实例变量和类变量是attribute, 所以也可以叫做实例属性和类属性.


property(特性)到底是个什么东西?

我们前面学习类属性和实例属性的时候知道, 访问他们的时候就可以直接获取到这些属性的值.

而特性可以看成一种特殊的属性, 为什么呢?

但从访问方式来看, 特性和属性看不出来差别, 但是特性实际上会经过计算之后再返回值. 所以每一个特性都始终与一个方法相关联.


1.1 定义特性

定义特性和定义实例方法类似, 只需要另外在方法上面添加一个内置装饰器:@property

访问特性和访问实例变量完全一样, 不需要使用添加括号去调用.


import math

class Circle:
def __init__(self, r):
self.r = r @property
def area(self):
"""
定义特性 这个特性是计算出来圆的面积
:return:
"""
return math.pi * (self.r ** 2) c = Circle(10) print(c.area)


很明显, 特性背后的本质是一个方法的存在, 所以你不可能在外面去修改这个特性的值!

试图修改特性的值只会抛出一个异常.

c.area = 100


1.2 使用特性的设计哲学

这种特性使用方式遵循所谓的 统一访问原则.

实际上, 定义一个类总是保持接口的统一总是好的.

有了特性, 把访问属性和访问方法统一了, 都像在访问属性一样, 省得去考虑到底什么时候需要添加括号,什么时候不用添加括号.


1.3 特性的拦截操作

python 还提供了设置和删除属性.

通过给方法添加其他内置装饰器来实现

设置:@特性名.setter

删除:@特性名.deleter

class Student:
def __init__(self, name):
self._name = name # name 是特性了, 所以用实例变量存储特性的值的是换个变量名!!! @property
def name(self):
return self._name @name.setter
def name(self, name):
if type(name) is str and len(name) > 2:
self._name = name
else:
print("你提供的值" + str(name) + "不合法!") @name.deleter
def name(self):
print("对不起, name 不允许删除") s = Student("李四")
print(s.name) s.name = "彩霞"
print(s.name) s.name = "张三"
print(s.name) del s.name

二、三大特性之一-封装性

面向对象的三大特征:封装, 继承, 多态

2.1什么是封装性

	1.封装是面向对象编程的一大特点
2.面向对象编程的第一步,就是讲属性和方法封装到一个抽象的类中
3.外界使用类创建对象,然后让对象调用方法
4.对象方法的细节都被封装在类的内部

在类中定义属性, 定义方法就是在封装数据和代码.

2.2 私有化属性

首先先明确一点, python 不能真正的对属性(和方法)进行私有, 因为 python 没有想 java 那样的private可用.

python 提供的"私有", 是为了怕在编程的过程中对对象属性不小心"误伤"提供的一种保护机制! 这种级别的私有稍微只要知道了规则, 是很容易访问到所谓的私有属性或方法的.


2.2.1 为什么需要私有

封装和保护数据的需要.

默认情况下, 类的所有属性和方法都是公共的, 也就意味着对他们的访问没有做任何的限制.

意味着, 在基类中定义的所有内容都可以都会被派生类继承, 并可从派生类内部进行访问.

在面向对象的应用程序设计中, 我们通常不希望这种行为, 因为他们暴露基类的内部实现, 可能导致派生类中的使用的私有名称与基类中使用的相同的私有名称发生冲突.

属性或方法私有后就可以避免这种问题!


2.2.2 "私有"机制

为了解决前面说的问题, python 提供了一种叫做名称改写(name mangling)的机制

如果给属性或者方法命名的时候, 使用两个下划线开头(__)的属性和方法名会自动变形为_类名__方法名, 这样就避免了在基础中命名冲突的问题.

class Student:
def __init__(self):
pass def __say(self):
print("我是私有方法你信吗?") s = Student() s.__say() # 双下划线开头的方法已经被形变, 此处访问不到


s._Student__say()


2.2.3 不是真正的私有

尽管这种方案隐藏了数据, 但是并没有提供严格的机制来限制对私有属性和方法的访问.

虽然这种机制好像多了一层处理, 但是这种变形是发生在类的定义期间, 并不会在方法执行期间发生, 所以并没有添加额外的开销.

2.2.4 不同的声音

有部分人认为这种使用双__的机制好辣鸡, 写两个下划线影响效率. 他们使用一个下划线, 并把这个作为一个约定.

好吧, 你喜欢哪种呢?

三、面向对象三大特性-继承性(Inheritance)

这一节我们来学习面向的对象的再一个特征: 继承

3.1继承性的概念

继承(extends)是创建新类的一种机制, 目的是专门使用和修改先有类的行为.

原有类称为超类(super class), 基类(base class)或父类.

新类称为子类或派生类.

通过继承创建类时, 所创建的类将继承其基类所有的属性和方法, 派生类也可以重新定义任何这些属性和方法, 并添加自己的新属性和方法

3.2 继承性的意义

继承实现代码的重用,相同的代码不需要重复的编写

从子类的角度来看,避免了重复的代码。(子类继承父类后,子类可以直接使用父类的属性和方法)

从父类的角度来看,子类扩展了父类的功能。(因为子类也是一个特殊的父类)

  1. 子类可以直接访问父类的属性和方法。
  2. 子类可以新增自己的属性和方法。
  3. 子类可以重写父类的方法。

3.3 继承的语法和具体实现

继承的语法如下:

class 父类名:
pass class 子类名(父类名):
pass

3.3.1最简单的继承

python 的继承是在类名的后面添加括号, 然后在括号中声明要继承的父类.

class Father:
def speak(self):
print("我是父类中的 speak 方法") # Son继承 Father 类
class Son(Father):
pass s = Son()
s.speak()

说明:

  1. 从字面上我们看到Son没有定义任何的方法, 但是由于Son继承自Father, 则Son会继承Father的所有属性和方法
  2. 调用方法时, 方法的查找规则: 先在当前类中查找, 当前类找不到想要的方法, 则去父类中查找, 还找不到然后继续向上查找. 一旦找到则立即执行. 如果找到最顶层还找不到, 则会抛出异常

示例代码

# 创建人类
class Person: # 定义吃东西方法
def eat(self):
print("吃窝窝头。。") # 定义睡觉方法
def sleep(self):
print("睡着啦。。") # 创建学生类
class Student(Person): # 子类新增方法:学习
def study(self):
print("学生学习啦。。。把你爸乐坏了。。。。。") # 创建父类对象,访问父类的方法
zhangsan = Person();
zhangsan.eat()
zhangsan.sleep() # 创建子类对象,访问父类的方法和子类的方法
ergou = Student();
ergou.eat() # 访问父类的方法
ergou.sleep() # 访问父类的方法
ergou.study() # 访问子类的新增方法

3.3.2 继承中的__init__()的调用规则

如果子类没有手动__init__()方法, 则 python 自动调用子类的__init__()的时候, 也会自动的调用基类的__init()__方法.

class Father:
def __init__(self):
print("基类的 init ") # Son继承 Father 类
class Son(Father):
def speak(self):
pass s = Son()


如果子类手动添加了__init__(), 则 python 不会再自动的去调用基类的__init__()

class Father:
def __init__(self):
print("基类的 init ") # Son继承 Father 类
class Son(Father):
def __init__(self):
print("子类的 init ") def speak(self):
pass s = Son()


如果想通过基类初始化一些数据, 则必须显示的调用这个方法, 调用语法是:

基类名.__init__(self, 参数...)

class Father:
def __init__(self, name):
print("基类的 init ")
self.name = name def speak(self):
print("我是父类中的 speak 方法" + self.name) # Son继承 Father 类
class Son(Father):
def __init__(self, name, age):
# name 属性的初始化应该交给基类去完成, 手动调用基类的方法. 一般放在首行
Father.__init__(self, name) # 调动指定类的方法, 并手动绑定这个方法的 self
print("子类的 init ")
self.age = age s = Son("李四", 20)
s.speak()
print(s.name)
print(s.age)


3.4方法的重写(override)

3.4.1重写的概念

我们已经了解了调用方法时候的查找规则, 先在子类中查找, 子类查找不到再去父类中查找.

如果父类的方法不满足子类的需求, 利用这个查找规则, 我们就可以在子类中添加一个与父类的一样的方法, 那么以后就会直接执行子类的方法, 而不会再去父类中查找.

这就叫方法的覆写.(override)

>重写,就是子类将父类已有的方法重新实现。

父类封装的方法,不能满足子类的需求,子类可以重写父类的方法。在调用时,调用的是重写的方法,而不会调用父类封装的方法。

3.4.2重写父类方法的两种情况

  1. 覆盖父类的方法

    父类的方法实现和子类的方法实现,完全不同,子类可以重新编写父类的方法实现。

    具体的实现方式,就相当于在子类中定义了一个和父类同名的方法并且实现

  2. 对父类方法进行扩展

    子类的方法实现中包含父类的方法实现。(也就是说,父类原本封装的方法实现是子类方法的一部分)。

    在子类中重写父类的方法

    在需要的位置使用super().父类方法来调用父类的方法

    代码其他的位置针对子类的需求,编写子类特有的代码实现。

如果在覆写的方法中, 子类还需要执行父类的方法, 则可以手动调用父类的方法:

父类名.方法(self, 参数...)


class Father:
def __init__(self, name):
self.name = name def speak(self):
print("我是父类中的 speak 方法" + self.name) # Son继承 Father 类
class Son(Father):
def __init__(self, name, age):
Father.__init__(self, name)
self.age = age # 子类中覆写了父类的方法
def speak(self):
Father.speak(self)
print("我是子类的 speak 方法" + self.name + " 年龄:" + str(self.age)) s = Son("李四", 20)
s.speak()

3.4.3关于super

在Python中super是一个特殊的类(Python 3.x以后出现)

super()就是使用super类创建出来的对象

最常使用的场景就是在重写父类方法时,调用在父类中封装的方法实现

3.5、父类的私有属性和方法

  • 子类对象不能在自己的方法内部,直接访问父类的私有属性或私有方法
  • 子类对象可以通过父类的共有方法间接访问到私有属性或私有方法

私有属性和方法是对象的隐私,不对外公开,外界以及子类都不能直接访问

私有属性和方法通常用于做一些内部的事情

3.6、多继承

3.6.1多继承的概念

多继承:子类可以拥有多个父类,并且具有所有父类的属性和方法

​ 比如:孩子会继承自己的父亲和母亲的特性

3.6.2多继承的语法

class 子类名(父类名1, 父类名2...):
pass

示例代码:

# 父类A
class A: def test1(self): print("A类中的test1方法。。") # 父类B
class B: def test2(self): print("B类中的test2方法。。") # 子类C同时继承A和B
class C(A,B): pass # 创建C对象
c1 = C()
c1.test1()
c1.test2()

3.6.3多继承的注意事项

提问:如果不同的父类中存在同名的方法,子类对象在调用方法时,会调用哪一个父类中的方法呢?

开发时,应该尽量避免这种容易产生混淆的情况。如果父类之间存在同名的属性或者方法,应该尽量避免使用多继承

3.6.4 Python中的 MRO (方法搜索顺序)[扩展]

python中针对类提供了一个内置属性,___mro__可以查看方法搜索顺序

MRO是method resolution order,主要用于在多继承时判断方法,属性的调用路径

print(C.__mro__)

输出结果:

(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
  • 在搜索方法时,是按照__mro_-的输出结果从左至右的顺序查找
  • 如果当前类中找到方法,就直接执行,不再搜索
  • 如果没有找到,就查找下一个类中是否有对应的方法,如果找到,就直接执行,不再搜索
  • 如果找到最后一个雷,还没有对应的方法,程序报错

3.6.5 python 中的上帝类型

python 中有个类比较特殊, 所有的类都直接和间接的继承自这个类.

这个类就是:object. 他是所有类的基类.

如果一个类没有显示的去继承一个类, 则这个类默认就继承object, 也可以去显示的继承这个类.

class Student(object):
pass

3.6.6 新式类和旧式(经典)类[扩展]

object是python为所有对象提供的基类,提供有一些内置的属性和方法,可以使用

dir函数查看

新式类:以object为基类的类,推荐使用

经典类:不以object为基类的类,不推荐使用

  • 在python 3.x中定义类时,如果没有指定父类,会默认使用object作为该类的父类。所以python 3.x中定义的类都是新式类

  • 在python 2.x中定义类时,如果没有指定父类,则不会以object作为父类

    新式类和经典类在多继承时,会影响到方法的搜索顺序

提示:为了保证编写的代码能够同时在python 2.x 和python 3.x 运行,在定义类的时候,如果没有父类,建议统一继承自object

class 类名(object):
pass

四、面向对象三大特性-多态性(Polymorphism)

4.1多态性的概念

  • 封装性,根据职责将属性和方法封装到一个抽象的类中

    ​ 定义类的准则

  • 继承性,实现代码的重用,相同的代码不需要重复的编

    ​ 设计类的技巧

    ​ 子类针对自己特有的书需求,编写特定的代码

  • 多态性,不同的子类对象,调用相同的父类方法,产生不同的执行结果

    ​ 多态可以增加代码的灵活性

    ​ 以继承和重写父类方法为前提

    ​ 是调用方法的技巧,不会影响到类的内部设计

示例代码:

"""
多态性:
继承和重写为前提,创建不同的对象执行的具体方法不同
"""
class Father(object): def __init__(self, name):
print('父类的init方法')
self.name = name def say(self):
print('父类的say方法' + self.name) # Son类继承于Father类,python中是类继承于类的
class Son(Father): def __init__(self, name, age): Father.__init__(self, name)
self.age = age
print('子类的init方法') def say(self):
Father.say(self)
print('子类的say方法:' + self.name + ',' + str(self.age)) # 以下程序会体现出多态性 def mytest(obj):
obj.say() f1 = Father("张爸爸")
mytest(f1) print("---------------")
f2 = Son("小头儿子",5)
mytest(f2)

4.2属性和方法查找顺序

多态性(多态绑定)是在有继承背景情况下使用的一种特性.

是指在不考虑实例背景的情况下使用实例

多态的理论根据是属性和方法的查找过程. 只要使用obj.attr的方式使用属性和方法, 则查找顺序一定是: 对象本身, 类定义, 基类定义...

关于先查找对象本身的说明: 因为 python 是一门动态语言, 允许我们在代码执行的过程中去动态的给对象添加属性和方法, 所以先从对象本身查找.


class Father:
def __init__(self, name):
self.name = name def speak(self):
print("我是父类中的 speak 方法" + self.name) # Son继承 Father 类
class Son(Father):
def __init__(self, name, age):
Father.__init__(self, name)
self.age = age def speak(self):
Father.speak(self)
print("我是子类的 speak 方法" + self.name + " 年龄:" + str(self.age)) def foo():
print("我是动态添加上去的...") s = Son("李四", 20)
s.speak = foo
s.speak()


4.3 鸭子类型

python 的多态有的时候很多人把它称之为鸭子类型

鸭子类型是指: 看起来像鸭子, 叫起来像鸭子, 走起来像鸭子, 那么它既是鸭子, 你就可以把它当鸭子来用.

换成编程语言的说法就是: 对象属性和方法的时候完成时和类型分开的.

class A:
def speak(self):
print("a 类中的方法") class B:
def speak(self):
print("b 类中的方法") def foo(obj):
obj.speak() a = A()
b = B() foo(a)
foo(b)

说明:

  1. foo接受一个对象, 只要这个对象中有speak()方法, 就可以正常执行, 我们并不关注他的类型
  2. A, B这两个类没有任何的关系, 但是他们都有speak方法, 所以传递过去都没有任何的问题.
  3. 这就是鸭子模型, 只要你看起来有speak就可以了

五、其他

5.1 特殊属性__slot__

5.1.1动态添加属性的问题

通过前面的学习中我们知道, 由于 python 的动态语言的特性, 我们可以动态的给对象添加属性和方法.

但是这种方式添加的属性和方法, 只在当前对象上有用, 在其他对象上是没用.

class A:
pass a1 = A()
a1.name = "李四" #给 a1 对象添加一个属性
print(a1.name) a2 = A()
print(a2.name) # a2中没有 name 属性, 所以抛异常


5.1.2 __slot__的基本使用

添加属性和方法最好直接在类中添加, 这样所有的对象都可以拥有了.

如果我想避免把某些属性直接添加到实例对象上, 可以使用一个特殊属性:__slot__类实现.

__slot__定义一个元组, 则元组内的属性名允许在实例对象上直接添加, 其他的都不允许.

class A:
__slots__ = ("name", ) a1 = A()
a1.name = "李四" # 给 a1 对象添加一个属性 name 属性是允许的
print(a1.name)
a1.age = 20 # age 不允许, 所以抛异常
print(a1.age)

注意:

  1. 我们的__init__()中添加属性是在self上添加的, 其实也是直接在对象上添加, 所以没有在元组中的属性名, 也是不允许的.
  2. 对于我们直接在类中添加方法是没有任何的影响的.
class A:
__slots__ = ("name",) def __init__(self):
self.age = 30 # 也是不允许的 a = A()


5.1.3 继承中的__slot__

__slot__只对当前类有用, 对他的子类不起作用. 所以子类也要有自己的__slot__

class A:
__slots__ = ("name",) def __init__(self):
self.age = 30 # 也是不允许的 class B:
def __init__(self):
self.age = 30 b = B()
print(b.age)


5.1.4 __slot__对性能上的提升

一些人把__slot__作为一种安全的特性来实现, 然后实际上他对内存和执行速度上的性能优化才是最重要的.

不使用__slot__, python 使用字典的方式去存储实例数据的, 如果一个程序使用大量的实例, 测内存占用和执行效率都会影响比较大.

使用__slot__后, python 存储实例数据的时候, 不再使用字典, 而是使用一种更加高效的基于数组的数据结构. 可以显著减少内存占用和执行时间.

5.2 实例的测试类型

任何一个类都可以做为类型!

创建类的实例时, 该实例的类型是这个类本身, 如果有继承存在, 则父类型也是这个实例的类型.

有些情况下, 我们需要先测试实例的类型然后再写相应的代码.


python 支持 2 种测试方法:

5.2.1 内置函数:type(实例)

class A:
pass class B(A):
pass class C:
pass a = A()
b = B()
c = C() print(type(a))
print(type(b))
print(type(c))

说明:

type返回的是这个实例的所属类的类对象.

补充一下:

其实我们经常接触到的有两种对象:1. 实例对象 2. 类对象

类对象就是: 表示类本身的那个对象!


5.2.2 内置函数:isinstance(实例, 类型)

class A:
pass class B(A):
pass class C:
pass a = A()
b = B()
c = C() print(isinstance(a, A)) # True
print(isinstance(b, B)) # True
print(isinstance(b, A)) # True 继承关系
print(isinstance(c, C)) # True
print(isinstance(c, A)) # False

说明:

  1. 这个函数返回的是布尔值, 使用起来方便, 所以以后测试类型建议用这个函数
  2. 这个函数继承关系也可以测试出来. bB类创建出来的, B继承自A, 所以b也算是类A的实例.
  3. 对一个实例也可以同时测试多个类型, 有一个满足就返回True, isinstance(实例, (类 a, 类 b, ...))). 需要把多个类封装到一个tuple中.
print(isinstance(c, (A, B, C)))     # True

5.2.3 类与类的关系: issubclass(类1, 类2)

用来测试类1是不是类2的子类.

class A:
pass class B(A):
pass class C:
pass print(issubclass(B, A)) # True
print(issubclass(C, A)) # False
print(issubclass(A, B)) # False
print(issubclass(A, object)) # True
print(issubclass(C, (object, A))) # True 第二个参数也是可以 class 组成的元组

Python第七章-面向对象高级的更多相关文章

  1. Python第七章-面向对象

    面向对象编程基础 一.面向对象概念 1.1 什么是面向过程 ​ 就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了. ​ 生活中的的例子举例. 1.2 ...

  2. java 第七章 面向对象高级特性

    一.类的继承 (一)继承的含义 1.在Java中定义一个类时,让该类通过关键字extends继承一个已有的类,这就是类的继承(泛化). 2.被继承的类称为父类(超类,基类),新的类称为子类(派生类). ...

  3. 简学Python第七章__class面向对象高级用法与反射

    Python第七章__class面向对象高级用法与反射 欢迎加入Linux_Python学习群  群号:478616847 目录: Python中关于oop的常用术语 类的特殊方法 元类 反射 一.P ...

  4. <automate the boring stuff with python>---第七章 正则实例&正则贪心&匹配电话号码和邮箱

    第七章先通过字符串查找电话号码,比较了是否使用正则表达式程序的差异,明显正则写法更为简洁.易扩展.模式:3 个数字,一个短横线,3个数字,一个短横线,再是4 个数字.例如:415-555-4242 i ...

  5. Python第六章 面向对象

    第六章 面向对象 1.面向对象初了解 ​ 面向对象的优点: ​ 1.对相似功能的函数,同一个业务下的函数进行归类,分类 ​ 2.类是一个公共的模板,对象就是从具体的模板中实例化出来的,得到对象就得到一 ...

  6. 流畅的python第七章函数装饰器和闭包学习记录

    本章讨论的话题 python如何计算装饰器句法 python如何判断变量是不是局部的(通过函数内部是否给变量赋值过来判断是否是局部变量) 闭包存在的原因和工作原理(闭包是一种函数,它会保留定义函数时存 ...

  7. Python学习笔记捌——面向对象高级编程

    __slots__特殊变量的使用: 由于Python是动态语言,允许先编写类,然后在创建实例的时候添加属性或者方法:而__slots__特殊变量就是,限制往类里添加属性的: 在创建类的时候,使用__s ...

  8. Python第七章(北理国家精品课 嵩天等)

    7.1文件的使用 1.1文本类型 文本文件:由单一特定编码组成的文件,如.txt 二进制文件:如.png,.avi 1.2文件的打开和关闭 打开-操作-关闭 <变量名> = open(&l ...

  9. python第七章:常用模块--小白博客

    yagmail模块 python标准库中发送电子邮件的模块比较复杂,因此,有许多开原的库提供了更加易用的接口来发送电子邮件,其中yagmail是一个使用比较广泛的开原项目,yagmail底层依然使用了 ...

随机推荐

  1. 利用matplotlib进行数据可视化

    matplotlib是python中的一个画图库,继承了matlib(从名字上也看得出来)的优点和语法,所以对于熟悉matlib的用户来说是十分友好的. pylab和pyplot 关于pylab和py ...

  2. .NET Core C#目录

    .NET Core技术开发指南 简介 本系列教程是一份关于微软.NET Core技术栈的全面的教程,其中涉及了C#.Typescript.Angular.Redis等一系列的教程.其中教程中通常会含有 ...

  3. 修改gridfilters.js源码,往后台多传递一个参数,并设置NumericFilter、StringFilter默认提示信息

    创作不易,转载请注明出处!!! 效果 修改:ext-extend.js源码 在最后面添加3行,重写方法 代码拷贝区 Ext.override(Ext.ux.grid.GridFilters, { me ...

  4. 从HTML标签开始

    开始这一切吧! 没错,你没看错,我将从HTML标签开始我的整个系列文章.很基础吧?但是每个前端人都是从最简单的HTML标签开始的,都是从一个<html></html>开始整个前 ...

  5. H5页面通用头部设置

    见到很多人写H5页面都不设置头部,不忍直视,于是整理一篇文章,不定期更新,为了让自己显得专业一点,也为了方便自己复制粘贴 一般来说必须设置项 <!-- 页面编码 --> <meta ...

  6. 使用HBuilder开发移动APP:ajax调用接口数据

    既然要做APP,与接口交互式少不了的,除非只是想做一个纯静态的APP.所以html5+的环境准备好后,我最先开始研究的就是如何与接口交互. 使用HBuilder新建示例教程后,里面会有一个ajax(网 ...

  7. PxCook+photoshop实现傻瓜式切图(推荐小白使用)

    确定需求 刚入门前端的小伙伴经过一个阶段的学习,已经准备小试牛刀了.但看到设计师给出的psd图,又头疼了,天啊撸,怎么办,我不会切图啊.今天我就带领小白学习傻瓜式切图.包学包会.( ̄▽ ̄)" ...

  8. 17 Spring Data JPA的常用接口分析

    思考 在客户的案例中,我们发现在自定义的CustomerDao中,并没有提供任何方法就可以使用其中的很多方法,那么这些方法究竟是怎么来的呢?答案很简单,对于我们自定义的Dao接口,由于继承了JpaRe ...

  9. Flutter Form表单控件超全总结

    注意:无特殊说明,Flutter版本及Dart版本如下: Flutter版本: 1.12.13+hotfix.5 Dart版本: 2.7.0 Form.FormField.TextFormField是 ...

  10. Kaggle 题目 nu-cs6220-assignment-1

    Kaggle题目 nu-cs6220-assignment-1 题目地址如下: https://www.kaggle.com/c/nu-cs6220-assignment-1/overview 这是个 ...