创建对象后更改其类型(Python 中的类型转换)

2024-04-06

在我的项目中,我生成一个对象obj类型的CubicObject。在运行时,应该允许 GUI 设置更改类型obj to Tofu or Box(然后返回),取决于用户想要做什么以及他认为该对象最好由什么来表示。那么用户应该受益于相应类中实现的特定算法。我正在寻找这种行为的良好实现。我玩过下面的代码,它改变了__class__属性,但我确信这是不好的风格。

class CubicObject(object):
    name = 'Baseclass'

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


class Tofu(CubicObject):
    name = 'Class A'

    def eat(self):
        print("I've eaten a volume of %s. " % (self.sidelength**3))


class Box(CubicObject):
    name = 'Class B'

    def paint(self):
        print("I painted a surface of %s. " % (self.sidelength**2 * 6))

# user only knows the object is vaguely cubic
obj = CubicObject(sidelength=1.0)
# user thinks the object is a Box
obj.__class__ = Box
obj.paint()
# user changes mind and thinks its a piece of Tofu
obj.__class__ = Tofu
obj.eat()
obj.paint()  # generates an error as it should, since we cannot paint Tofu

我的两个问题是:

  • 类有哪些属性A被转移到对象“obj” 当我改变它的时候__class__属性?什么函数被称为
    以及更新了哪些属性,或者 obj 是如何发生的 将其名称更改为 A 之一?
  • 还有哪些其他更干净的方法可以实现我想要的行为?如果 必要时我可以毁掉这个物体obj并重新创建另一个, 但在这种情况下,我想以通用的方式这样做(比如obj = RoundObject(subclasstype='Tofu')因为其他部分 代码)。

根本问题是我允许用户在子类中实现自己的函数CubicObject并且在程序运行时应该能够在这些子类之间进行切换。


A 类的哪些属性被传递给对象 'obj' 当我改变它的时候class属性?调用了什么函数以及 更新了哪些属性,或者 obj 是如何发生的 将其名称更改为 A 之一?

所有实例分配的属性都会被保留 - 也就是说,Python 对象通常有一个__dict__记录所有实例属性的属性 - 被保留。并且对象的类有效地更改为分配的类。 (Python 运行时禁止__class__具有不同内存布局的对象的分配)。也就是说:新类上的所有方法和类属性都可用于该实例,并且前一个类的方法或类属性都不存在,就好像该对象是在这个新类中创建的一样。 赋值不会触发任何副作用(如:不调用特殊方法) 因此,对于你正在制作的东西来说,它是“有效的”。

还有哪些其他更干净的方法可以实现我想要的行为?如果 必要时,我可以销毁对象 obj 并重新创建另一个对象, 但在这种情况下,我想以通用方式执行此操作(例如 obj = RoundObject(subclasstype='Tofu') 因为代码的其他部分)。

是的,正如您所指出的,这不是最好的做事方式。 你可以拥有一个类层次结构,其中包含你需要的不同方法,这些方法将你的对象作为属性 - 并且根据你在做什么,你在这个外部层次结构中创建一个新对象 - 并保持你的核心对象及其属性不变。这被称为适配器模式 https://en.wikipedia.org/wiki/Adapter_pattern.

class CubicObject(object):
    name = 'Baseclass'

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


class BaseMethods(object):
    def __init__(self, related):
         self.related = related

class Tofu(BaseMethods):
    name = 'Class A'

    def eat(self):
        print("I've eaten a volume of %s. " % (self.related.sidelength**3))


class Box(BaseMethods):
    name = 'Class B'

    def paint(self):
        print("I painted a surface of %s. " % (self.related.sidelength**2 * 6))

# user only knows the object is vaguely cubic
obj = CubicObject(sidelength=1.0)
# user thinks the object is a Box
box  = Box(obj)
box.paint()

# user changes mind and thinks its a piece of Tofu
tofu = Tofu(obj)

tofu.eat()
# or simply:
Tofu(obj).eat()

您可以在自己的手动类上滚动它,或者使用众所周知且经过测试的库来实现部分流程自动化的功能。一个这样的库是zope.interface https://docs.zope.org/zope.interface/,这允许您使用适配器模式编写庞大而复杂的系统。因此,您可以拥有数百种不同类型的对象 - 您可以将它们标记为具有“Cubic”接口,只要它们具有side_length属性。然后你可以有数十个类用以下方法做“立方体”的事情side_length属性 - 的zope.interface设施将允许您将这数十个类中的任何一个与具有 Cubic 接口的任何对象一起使用,只需调用所需方法的接口并将原始对象作为参数传递即可。

But zope.interfaces可能有点难以掌握,因为在近二十年的使用中,根据需要完成的文档很差(并且在某些时候,人们诉诸使用 XML 文件来声明接口和适配器 - 只需跳过任何处理 XML 的文档),所以对于较小的项目,您可以像上面那样手动滚动它。

我当前的实现已经使用了委托对象,但它是 不切实际,因为它隐藏了 API 中所有有趣的功能 我想在该委托对象中提供(我通常复制 委托对象的所有功能,但这可以理解地令人困惑 人们)。

由于您的实际使用示例很大,因此确实是学习和使用的案例zope.interface- 但是如果您想允许多个用户访问,则可以使用完整的接口/注册表/适配器系统的另一种解决方法Cube上的方法Tofu和其他的是实施BaseMethods我有高于魔法的课程__getattr__Python 方法允许您以透明的方式检索引用对象的方法和属性,无需重写:

class BaseMethods(object):
    def __init__(self, related):
         self.related = related

    def __getattr__(self, attr):
        return getattr(self.related, attr)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

创建对象后更改其类型(Python 中的类型转换) 的相关文章

随机推荐

  • 属性的访问器实现

    是否有一些文档说明编译器如何自动生成属性的访问器 当编写自定义访问器 覆盖合成的访问器 时 最好了解原始实现 特别是要查看具有不同 弱 强 保留 复制等 属性的属性的访问器的不同实现 是否有一些文档说明编译器如何自动生成属性的访问器 编译器
  • 从 openstreetmap 获取城市边界

    我正在开发一个网站 我需要根据用户输入获取某个区域的所有边界 例如 用户想知道名为 x 的城市的边界 我应该如何从 openstreetmap 获取它 我听说过 xapi 和 osmosis 但在任何地方都找不到任何例子 谢谢 我在这里尝试
  • 使用media3库时添加MediaItem导致错误

    我正在使用最新的Android Media3库 但是我在使用它时发现了一个问题 我创建了一个媒体会话服务 然后得到MediaController中的Activity 然后当我尝试调用媒体控制器并添加一些 MediaItem 时 发生错误 j
  • Python/PyODBC 通过 IP 与可信连接连接到 SQL Server 2008 DB

    如果有人问这个问题 我提前道歉 尽管我发现了类似的问题 但我找不到正确的答案 我正在尝试通过使用可信连接的 IP 端口来连接到 SQL Server 2008 DB 另外一点复杂性是 数据库位于美国境外 通常我们通过 Citrix 登录 登
  • 告诉编译器泛型返回类型不借用任何对参数的引用?

    tldr gt 给定一个接受通用回调参数并返回关联类型的特征函数 编译器会抱怨关联类型可能从回调函数借用参数 有没有办法告诉编译器事实并非如此 细节 我计划实现一个接受回调参数的特征函数 并希望强制该特征函数的实现实际调用该回调 我通过让回
  • 保证文件关闭

    我有一个类 在构造函数中创建一个文件对象 该类还实现了 finish 方法作为其接口的一部分 在该方法中我关闭了文件对象 问题是 如果我在此之前遇到异常 文件将不会被关闭 相关类还有许多使用文件对象的其他方法 我需要将所有这些包装在一个最后
  • REST API 资源命名约定 - 用户或用户(复数)

    长版 对于某些人 包括我自己 来说 构建 REST API 过程中最痛苦 最令人头疼的部分之一是确定每个资源及其随附端点的名称 当然 这取决于个人喜好 有些事情是受到社区鼓励的 例如 大多数人 包括我 都会将他们的资源名称复数 GET no
  • 如何从日期时间获取时间跨度

    设想 第三方网络服务退货datetime在两个单独的字段中 即日期和时间 我需要一种连接成单个字段的方法 e g startDate 24 06 2012 startTime 1 01 1970 1 00 00 AM Expected re
  • 编辑距离矩阵

    我正在尝试构建一个程序 该程序接受两个字符串并为它们填充编辑距离矩阵 让我困惑的是 对于第二个字符串输入 它跳过了第二个输入 我尝试使用 getch 清除缓冲区 但没有成功 我也尝试过切换到 scanf 但这也导致了一些崩溃 请帮助 Cod
  • 张量流联合训练和评估期间的 MSE 误差不同

    我正在联合张量流中实现回归模型 我从本教程中使用的 keras 简单模型开始 https www tensorflow org tutorials keras regression https www tensorflow org tuto
  • Spring @Transactional 未创建所需的事务

    好吧 我终于屈服于同行压力并开始在我的网络应用程序中使用 Spring 所以我试图让交易处理的东西发挥作用 但我似乎无法做到这一点 我的 Spring 配置如下所示
  • 如何消除 TextBlock 中 Run 之间的空白?

    我有以下 XAML
  • 带有合并行的 ASP.net 网格分页

    我目前正在使用 GridView 来显示表格数据 我需要合并第一列中具有相同值的单元格 目前我的代码在PreRender事件来设置RowSpan对我来说是财产 而且运作良好 问题是我无法使用分页 因为页面将在第一个字段相等的部分的中间分割
  • 发布到 Azure 失败,出现 500 内部服务器错误

    我在 Windows Azure 上有一个云服务 我创建了一个 Asp net WebAPI 项目并发布到云服务 在我将 Visual Studio 更新到 4 并将 azure SDK 2 2 更新到 2 6 之前 该项目从 Visual
  • 如何以编程方式访问 Mathematica 8 中有关“Graph”对象的信息?

    我正在尝试访问某个范围内的信息GraphMathematica 8 中的对象 出于某种原因 Part命令似乎不起作用 myGraph是我想要访问的对象 下面的第一行显示 myGraph 其他人的作用是检查它 myGraph myGraph
  • 堆叠模式在关闭时滚动主页[重复]

    这个问题在这里已经有答案了 使用 Bootstrap 3 3 1 我无需任何额外的脚本即可获得堆叠模态 如在 Bootstrap 站点中复制粘贴模态模板并将其中的许多模态模板制作在同一页面中 问题是 每当顶部 最高 模态关闭时 滚动焦点就会
  • 如何获取数据表中选定的表格单元格值

    我正在使用 jquery 2 0 3 min js bootstrap min js jquery ui 1 10 3 min js DataTables 1 9 4 和 tabletools datatables net blog Twi
  • 如何通过 YouTube 直播 API 更改我的活动使用的流?

    所以我一直在寻找一种从 YouTube 获取 16 位流名称的方法 我终于通过这行代码找到了它 gt streamName returnedStream getCdn getIngestionInfo getStreamName 流名称只是
  • org.springframework.web.servlet.PageNotFound - 未找到带有 URI 的 HTTP 请求的映射

    我参考了很多帖子 但仍然无法解决这个问题 我尝试将此 css 文件夹放入 WEB INF 和视图文件夹中 但样式仍然没有反映在视图页面中 这是我的 servlet context xml
  • 创建对象后更改其类型(Python 中的类型转换)

    在我的项目中 我生成一个对象obj类型的CubicObject 在运行时 应该允许 GUI 设置更改类型obj to Tofu or Box 然后返回 取决于用户想要做什么以及他认为该对象最好由什么来表示 那么用户应该受益于相应类中实现的特