html网站免费下载,建设工程合同索赔的原因有哪些,只能用域名访问WordPress,搜索引擎是网站提供的搜索服务吗Python编程-面向对象基础与入门到实践一书的内容拓展 通过编程#xff0c;模拟现实生活中的事物编程#xff0c;叫做面向对象编程#xff0c;此过程也叫做实例化编程 简单类的创建
class Test():def __init__ (self,id):self.id iddef print_id(self):print(self.id)这里建…Python编程-面向对象基础与入门到实践一书的内容拓展 通过编程模拟现实生活中的事物编程叫做面向对象编程此过程也叫做实例化编程 简单类的创建
class Test():def __init__ (self,id):self.id iddef print_id(self):print(self.id)这里建立了一个名为test的类其中有两个函数__init__与print_id,有一个数据成员id
__init__函数
__init__是一种特殊方法用于创建类时的初始化其中带有两个参数self与id,其中__init__初始化类对象时将参数全部自动传递给self无需我们手动传参,self相当于为每个对象划定了一个用于存放数据成员的位置保证每个对象的数据成员独立且不受干扰需要注意的是**self必须放置在最前面**而后面的id就是我们需要传递的参数并且它的数量是任意的需要多少个参数就写多少个
成员函数访问数据
在一个类中的成员函数使用对应对象的数据成员时必须要使用self获取对应的数据成员如self.id
熟悉c的同学应该看出来了这和c的构造函数是类似的
拓展思维
既然成员是函数虽然类中叫方法那么能否使用关键字实参默认值与不定参数呢当然是可以的后文实验源码将会写到
__init__的使用
我们先看如下代码
class Base():def fun(self):self.a 1self.data 2def print_all(self):print(self.id, self.data)op Base()
op.print_all()我们定义了上述代码通过运行我们会发现这几行代码是没有办法运行的解释器会丢出以下错误 可以看到解释器提示我们缺少了对应的属性原因就是因为我们没有使用__init__来创建对应的self数据类中并没有存储我们的id与data但是没有该方法代码能不能跑呢答案是可以如下的特殊情况
class Base():def fun(self,x,y):return x,yop Base()
print(op.fun(1,2))可以看到运行是正常的但是我们进行类创建时最好加上__init__,不然实例化将失去意义
此处注意一个细节建立无参类的对象时需要加上(),例如 op Base()
创建与访问对象
class Test():def __init__ (self,id_):self.id id_self.age 16def print_id(self):print(self.id)a Test(11)
a.print_id()
a.id 12
print(a.id)
print(a.age)我们的__init__函数中传入了一个id_,所以传入了一个参数11,而我们要访问对应对象的数据或函数成员则需要.运算符,同理要修改某一成员时也需要用.运算符操作并且我们还可以为对象指定默认参数如上述代码中的self.age 16
子类继承 通常一个大类下可能有多个有差异的子类此时则需要继承操作我们注意到前面的Test的对象后面有一个括号在未进行继承时该括号可以省略 无参构造的继承
class Base():def __init__(self):self.id 1self.data 2def print_all(self):print(self.id, self.data)class Dome(Base):def __init__(self):super().__init__()self.a 3def print_all(self):print(self.id, self.data, self.a)object Dome()
object.print_all()如上代码中的无参数类继承这里需要提出几个关键点
在C中在继承时无参数基类是可以省略派生类与基类的构造但是python不能够省略派生类的super().__init__()也不能省略它是用来链接基类与派生类的省略后将无法从基类继承
对于第二点有以下情况当我们不使用基类继承成员时能否省略super().__init__()呢我们运行以下代码
class Base():def __init__(self):print(yes) # 我们加入了基类构造提示self.id 1self.data 2def print_all(self):print(self.id, self.data)class Dome(Base):def __init__(self):# super().__init__() # 将之注释掉self.a 3def print_all(self):print(self.a)object Dome()
object.print_all()通过上述代码运行结果可知此代码并没有进行继承操作仅仅只是输出了a的值即class Dome(Base)失去意义如果我们取消注释那么它又将正常继承
有参构造的继承
class Base():def __init__(self, id, data):self.id idself.data datadef print_all(self):print(self.id, self.data)class Dome(Base):def __init__(self, id, data, a):super().__init__(id, data)self.a adef print_all(self):print(self.id, self.data, self.a)object Dome(1, 2, 3)
object.print_all()如上述代码我们在子类Dome的括号内填入基类的的名字Dome中的第一个__init__用于初始化传入派生类的值super函数用于连接基类与派生类其后跟随的__init__用于向基类传递参数并且不加self作为实参调用基类的__init__并且在为基类构造时派生类的构造函数参数数量至少要大于或等于基类参数的数量否则将构建失败
重写基类成员
有时候我们需要对于派生类与基类的不同之处做出不同的行为但是为了保证代码的可读性我们要派生类调用同名函数于是我们有以下操作
class Base():def __init__ (self,id_):self.id id_def print_id(self):print(self.id)class Dome(Base):def __init__ (self,id_):super().__init__(id_)self.a 12def print_id(self):print(self.a)object Dome(11)
object.print_id()运行上述代码使用与基类中同名的函数得到子类中a的值
在子类中调用基类方法
class Base():def __init__ (self,id_):self.id id_def print_id(self):print(self.id)class Dome(Base):def __init__ (self,id_):super().__init__(id_)self.a 12def print_id(self):super().print_id()object Dome(11)
object.print_id()运行上述代码使用与基类中同名的函数得到基类中id的值
多继承的super参数处理
class BaseClass:def __init__(self, base_param):self.base_param base_paramprint(BaseClass constructor with base_param:, self.base_param)class Mixin1(BaseClass):def __init__(self, mixin1_param, **kwargs):super().__init__(**kwargs) # 调用父类的构造函数self.mixin1_param mixin1_paramprint(Mixin1 constructor with mixin1_param:, self.mixin1_param)class Mixin2(BaseClass):def __init__(self, mixin2_param, **kwargs):super().__init__(**kwargs) # 调用父类的构造函数self.mixin2_param mixin2_paramprint(Mixin2 constructor with mixin2_param:, self.mixin2_param)class MyClass(Mixin1, Mixin2):def __init__(self, base_param, mixin1_param, mixin2_param):super().__init__(base_parambase_param, mixin1_parammixin1_param, mixin2_parammixin2_param)print(MyClass constructor)# 创建实例
obj MyClass(base_paramBaseParam, mixin1_paramMixin1Param, mixin2_paramMixin2Param)
在这个例子中每个类的构造函数都接收一些参数并使用 super().__init__(**kwargs) 来调用父类的构造函数。在 MyClass 中通过使用 super() 来确保调用了 Mixin1 和 Mixin2 的构造函数并传递了适当的参数。
类的嵌套
总所周知python中套娃是非常普遍的通常情况下我们在构建一个实例时实例的属性是非常复杂的我们为了简化代码需要为某些特定属性建立一个类
class build:def __init__(self):self.time 1998def print_time(self):print(self.time)class Base:def __init__ (self,id_):self.id id_self.build build()def print_id(self):print(self.id)ob Base(22)
ob.build.print_time()如上我们为Base类建立了一个嵌套的子类build用于存储建立的时间但是访问time时时我们需要注意要通过Base对象去访问build中的成员print_time
类的访问权限
Python中对类中数据的访问权限并没有C那样严格可以暂时认为只有私有与公有两种权限先暂时这样理解后文将细说
公有权限
class Test:def __init__(self,a):self.a adef print_(self):print(self.a)object Test(22)
print(object.a)
object.a 33
print(object.a)如上定义一个简单的类然后访问并且修改它可以看到修改成功即按上述代码进行编写代码所有数据都是公有的外界可以修改
私有权限
class Test:def __init__(self,a):self.__a adef print_(self):print(self.__a)ob Test(22)
print(ob.__a)先看如上错误代码我们运行后可以发现会抛出如下错误 它会提示我们Test类中没有这个属性原来我们在成员前加上__后解释器对数据成员进行了一个类似于重命名的操作不同版本的解释的方式也不同如果我们要强行访问也可以想办法找到对应解释器的重构规则进行访问一般这类成员我们通过成员方法进行访问
class Test:def __init__(self,a):self.__a adef print_(self):print(self.__a)ob Test(22)
ob.print_()需要注意的是
类似于__init__这类前后带有双下划线的在python中是特殊的变量可以直接访问从上面可知python中的权限实际上是没有限制的只要你有对应的访问方式和C类似python的方法和C的函数一样是可以作为私有成员的如下套娃代码
class Test:def __init__(self,a):self.__a adef __print_(self):print(self.__a)def printf(self):self.__print_()ob Test(22)
ob.printf()保护权限
python中实际上是没有保护权限的但是有一种约定俗成的规定即在变量前加 _,这类成员实际上仍然是公有的但是约定为保护成员
class Test:def __init__(self,a):self._a adef print_(self):print(self._a)object Test(22)
print(object._a)
object.a 33
print(object._a)通过上述讲解我们可以将继承进行拓展即在继承时实际上是继承了所有成员但是由于我们不知道对应变量的变量名而变得难以访问对应成员
单类模块使用
和函数一样python也支持将类装进一个模块我们建立一个Test模块进行使用
# test.py
class Test:def __init__(self,a):self._a adef print_(self):print(self._a)这个模块包含了一个Test类其中有一个数据成员_a和一个函数print_
使用该模块可以通过如下引入from [模块文件名] import [对应类名]
则引入方式为 from test import Test
多类模块的引入
通常在构建项目时会建立多个类的模块可能会包含多个同等地位的类子类嵌套或继承此时引入方式和上述仍然一致
# test.py
class Test_one:def __init__(self,a):self._a adef print_(self):print(self._a)class Test_two:def __init__(self,a):self._a adef print_(self):print(self._a)如上建立同等地位的类我们的访问方式没有太多变化
from test import Test_one
from test import Test_two访问带有子类嵌套的类模块
# test.py
class Test_one:def __init__(self, x, y):self.a xself.b Test_two(y)def print_(self):print(self.a)class Test_two:def __init__(self, x):self.a xdef print_(self):print(self.a)定义类如上接下来我们进行访问
from test import Test_oneobject Test_one(22, 33)
print(object.a, object.b.a)我们注意到运行是正常的即python在引入带子类的类Test_one后初始化其对象时会自动创建其子类但是并没有自动为文件引入模块中的子类即如下操作是错误的
from test import Test_oneobject Test_two(22)访问带有继承类模块
# test.py
class Base():def __init__(self, id, data):self.id idself.data datadef print_all(self):print(self.id, self.data)class Dome(Base):def __init__(self, id, data, a):super().__init__(id, data)self.data dataself.a adef print_all(self):print(self.id, self.data, self.a)建立如上模块进行以下操作
from test import Domeobject Dome(1, 2, 3)
object.print_all()正常运行并且访问带有继承类模块时导入其派生类不会自动导入基类
还有一点类模块和函数一样也是可以取别名的就像以下操作
from test import Dome as dobject d(1, 2, 3)
object.print_all()其他导入情况
我们经常会遇到下述情况
使用同一模块中的所有类使用同一模块中的两个或两个以上的类
这方面和函数类似我们依次介绍
使用同一模块中的所有类
from test import *此操作将取出该模块中所有类并且不使用.运算符操作
格式from [模块名] import *
import test此操作导入了整个模块需要使用.运算符操作
格式import [模块名]
类与函数混合模块的导入
在python中可以将函数与类放在同一模块下如下
# test.py
class Base():def __init__(self, id, data):self.id idself.data datadef print_all(self):print(self.id, self.data)class Dome(Base):def __init__(self, id, data, a):super().__init__(id, data)self.data dataself.a adef print_all(self):print(self.id, self.data, self.a)def hello_world():print((hello World).title())但是我们使用时仍然是一致的
from test import *object Dome(1, 2, 3)
object.print_all()hello_world()实验源码
# Chicken.py
class Person:def __init__(self, name, time, *show): # 不定参数self.name nameself.time timedef print_all(self):print(self.name, self.time)class PersonShow(Person):def __init__(self, name, time, *show):super().__init__(namename, timetime) # 关键字实参self.showList []for i in range(0, len(show)):self.showList.append(show[i])def print_all(self):byte_str bytes.fromhex(e894a1e5be90e59da4)string byte_str.decode(utf-8)print(我是练习时长str(self.time)的个人练习生str(self.name))print(喜欢, self.showList)if self.name string:print(鸡 你 太 美)print(喜欢的话 请多多为我投票吧)from Chicken import *if __name__ __main__ :player PersonShow(蔡徐坤,两年半,唱,跳,RAP,篮球)player.print_all()所有类的超类object
在Python中所有的类都直接或间接地继承自object类类似于Java中的Object类。不过在Python 3中一般不需要显式继承object因为所有的类默认就是新式类。与Java的Object类类似Python中的object类也提供了一些通用的方法这些方法可以在自定义类中使用或者覆盖
__str__()方法 类似于Java中的toString()方法它返回对象的字符串表示形式。
def __str__(self):return This is a custom object__eq__()方法 用于比较两个对象是否相等。默认的实现是比较对象的身份标识identity即是否指向同一内存地址。可以根据实际需要覆盖该方法。
def __eq__(self, other):if isinstance(other, MyClass):return self.some_value other.some_valuereturn False__hash__()方法 返回对象的哈希码值。与Java中的hashCode()类似用于在散列表等数据结构中使用。
def __hash__(self):return hash(self.some_value)__repr__()方法 返回对象的“官方”字符串表示通常是一个可以用来重建对象的表达式。
def __repr__(self):return fMyClass({self.some_value})这些方法在Python中的使用与Java中的Object类的方法类似但是命名方式略有不同。在Python中双下划线__表示特殊方法也称为魔法方法或魔术方法用于实现类的特殊行为。
注意事项和建议与Java类似 __eq__()和__hash__()一致性 如果两个对象通过__eq__()方法相等那么它们的__hash__()值应该相等以确保在使用散列表等数据结构时能够正确地工作。 __str__()和__repr__()可读性 类似于Java中的toString()方法这两个方法的实现应该返回清晰、简洁且可读性强的字符串。
魔术方法
你可能注意到了上述出现的所有方法均以两个短横线开始或结束这便是python中的魔术方法它们大多数都来自object类下面是一些常见的魔术方法参考表格
魔术方法描述__init__(self, ...)初始化对象在创建对象时调用__del__(self)删除对象时调用__str__(self)返回对象的字符串表示__repr__(self)返回对象的“官方”字符串表示用于开发和调试__len__(self)返回对象的长度使用内置的len()函数时调用__getitem__(self, key)定义获取元素的行为例如obj[key]__setitem__(self, key, value)定义设置元素的行为例如obj[key] value__delitem__(self, key)定义删除元素的行为例如del obj[key]__iter__(self)定义迭代器的行为使对象可迭代__next__(self)定义迭代器的next方法返回下一个迭代值__contains__(self, item)定义成员测试行为例如item in obj__call__(self, ...)实例对象可调用类似函数调用的行为__eq__(self, other)定义相等比较的行为例如obj other__ne__(self, other)定义不相等比较的行为例如obj ! other__lt__(self, other)定义小于比较的行为例如obj other__le__(self, other)定义小于等于比较的行为例如obj other__gt__(self, other)定义大于比较的行为例如obj other__ge__(self, other)定义大于等于比较的行为例如obj other__add__(self, other)定义加法行为例如obj other__sub__(self, other)定义减法行为例如obj - other__mul__(self, other)定义乘法行为例如obj * other__truediv__(self, other)定义真除法行为例如obj / other__floordiv__(self, other)定义整除法行为例如obj // other__mod__(self, other)定义取模行为例如obj % other__pow__(self, other[, modulo])定义幂运算行为例如obj ** other__enter__(self)在进入with语句块时调用用于资源的初始化和分配__exit__(self, exc_type, exc_value, traceback)在离开with语句块时调用用于资源的释放和清理__setattr__(self, name, value)在设置属性时调用例如obj.attr value__getattr__(self, name)在获取不存在的属性时调用例如obj.nonexistent_attr
类属性使用
在Python中类属性是属于类而不是类的实例的属性。它们是在类定义中声明的变量而不是在类的实例中创建的。所有属于类的实例共享相同的类属性。
class CarClass:# 类属性num_wheels: int 4def __init__(self, make, model) - None:# 实例属性self.make makeself.model modelif __name__ __main__:# 创建两个 Car 实例car_one: CarClass CarClass(Toyota, Camry)car_two: CarClass CarClass(Honda, Accord)# 访问实例属性print(car_one.make) # 输出: Toyotaprint(car_two.model) # 输出: Accord# 访问类属性使用类名或实例都可以print(CarClass.num_wheels) # 输出: 4print(car_one.num_wheels) # 输出: 4print(car_two.num_wheels) # 输出: 4# 修改类属性注意这会影响所有实例CarClass.num_wheels 6# 检查修改后的类属性print(CarClass.num_wheels) # 输出: 6print(car_one.num_wheels) # 输出: 6print(car_two.num_wheels) # 输出: 6
需要注意的是类属性不会被实例化给每个对象而是被所有该类的实例所共享。当你创建一个类属性时它属于类本身而不是类的实例。所有通过该类创建的实例都可以访问和共享相同的类属性。
在Python中实例在访问属性时首先查找实例本身是否有该属性如果没有它会继续查找类的属性。这就是为什么实例可以访问类属性的原因。
实例属性遮蔽
接下来考虑以下问题
我们在 CarClass.num_wheels 6 前增加一行代码 car_one.num_wheels 233此时运行代码将会的出什么结果呢 当你运行 car_one.num_wheels 233时它会创建一个新的实例属性 num_wheels而不是修改类属性。这是因为在 Python 中如果你为实例赋值一个属性它会在实例上创建一个同名的属性而不会影响到类属性。这就是实例属性遮蔽
self引用实例对象
在 Python 中self 是一个惯例用于表示对象实例本身。它是在类的方法中作为第一个参数传递的但在调用该方法时不需要显式传递。self 提供了一种引用对象实例属性和方法的方式
但是self 的命名并不是强制的你可以使用其他名称但 self 是一个广泛接受的约定因此建议在大多数情况下使用它不推荐自己定义应使用self或团队公司的约定。如以下不推荐的自定义示例
class TestClass:def __init__(my_self, value):my_self.value valuedef printf(my_self):print(my_self.value)obj TestClass(233)
obj.printf()