基类中派生类的范围-python中的继承 - python

我知道通过继承基类。基类中的所有功能也可以在派生类中访问。但是它是如何工作的,这意味着可以在基类中访问子类中定义的函数。

我用一个例子尝试了上面。而且效果很好。但是那怎么可能。我无法理解工作背后的逻辑。

class fish:

    def color(self):
        # _colour is a property of the child class. How can base class access this?
        return self._colour  


class catfish(fish):

    _colour = "Blue Cat fish"

    def speed(self):
        return "Around 100mph"

    def agility(self):
        return "Low on the agility"

class tunafish(fish):

    _colour = "Yellow Tuna fish"

    def speed(self):
        return "Around 290mph"

    def agility(self):
        return "High on the agility"

catfish_obj = catfish()
tunafish_obj = tunafish()

print(catfish_obj.color())
print(tunafish_obj.color())

我知道实例是通过自我传递的,但是从逻辑上讲,子类的详细信息应该不能在基类中访问,对吗?

参考方案

您正在访问实例而不是类的属性。您的self引用绝不是fish类的实例,只能是两个派生类之一的实例,而这些派生类将设置_colour属性。

如果您自己创建了fish()的实例,则会出现属性错误,因为该实例将没有设置属性。

您可能会认为,在基类中,self成为基类的实例。事实并非如此。

而是直接在实例上及其实例的类和基类上查找实例的属性。因此,self._colour会查看实例,type(instance)type(instance).__mro__中的所有其他对象,即“方法解析顺序”,它以线性顺序设置层次结构中的所有类。

您可以打印出对象的type()

>>> class fish:
...     def color(self):
...         print(type(self))
...         return self._colour
...
# your other class definitions
>>> print(catfish_obj.color())
<class '__main__.catfish'>
Blue Cat fish
>>> print(tunafish_obj.color())
<class '__main__.tunafish'>
Yellow Tuna fish

self引用是派生类的实例,传递给继承的方法。因此,self._colour首先将查看直接在self上设置的属性,然后在type(self)上找到_colour

也许这将有助于了解Python方法的工作方式。方法只是函数的薄包装,是在实例上查找属性时创建的:

>>> tunafish_obj.color  # access the method but not calling it
<bound method fish.color of <__main__.tunafish object at 0x110ba5278>>
>>> tunafish.color      # same attribute name, but on the class
<function fish.color at 0x110ba3510>
>>> tunafish.color.__get__(tunafish_obj, tunafish)  # what tunafish_obj.color actually does
<bound method fish.color of <__main__.tunafish object at 0x110ba5278>>
>>> tunafish_obj.color.__self__   # methods have attributes like __self__
<__main__.tunafish object at 0x110ba5278>
>>> tunafish_obj.color.__func__   # and __func__. Recognise the numbers?
<function fish.color at 0x110ba3510>

仔细查看我访问的对象的名称,以及在函数上调用__get__方法时会发生什么。当您访问实例上的某些属性时,Python使用称为绑定的过程。当您以这种方式访问​​属性并使用__get__方法指向一个对象时,该对象称为描述符,然后调用__get__将对象绑定到您在对象上看到的内容。请参见descriptor howto。

在实例上访问color会生成一个绑定方法对象,但是对象的描述告诉我们它来自fish,它被称为实例引用的* bound method fish.color。在类上访问相同的名称将为我们提供fish.color函数,我可以手动将其绑定以再次创建方法。

最后,该方法具有属性__self__(它是原始实例)和__func__(它是原始函数)。神奇的是,当您调用绑定方法时,方法对象仅调用__func__(__self__, ....),因此将绑定的实例传入。

继承该函数(在fish类上找到,所以在fish.color上)时,该函数仍将传递派生类的实例,并且仍然具有派生类拥有的所有内容。

Python非常动态,而且非常灵活。您可以采用任何旧函数并将其放在类上,并且可以将其绑定到方法中。或者,您可以采用任何未绑定的函数,然后手动传递具有正确属性的对象,这样就可以正常工作。真的,Python不在乎。因此,您可以传入一个新的,独立类型的对象,并且仍然可以使用fish.color函数:

>>> fish.color  # original, unbound function on the base class
<function fish.color at 0x110ba3510>
>>> class FakeFish:
...     _colour = 'Fake!'
...
>>> fish.color(FakeFish)  # passing in a class! Uh-oh?
<class 'type'>
'Fake!'

因此,即使传入与fish层次结构完全无关但具有预期属性的类对象,仍然可以使用。

对于大多数Python代码来说,如果它走路像鸭子一样,嘎嘎叫起来像鸭子,那么代码会将它接受为鸭子。称为duck typing。

Python 3运算符>>打印到文件 - python

我有以下Python代码编写项目的依赖文件。它可以在Python 2.x上正常工作,但是在使用Python 3进行测试时会报告错误。depend = None if not nmake: depend = open(".depend", "a") dependmak = open(".depend.mak&#…

Python:对于长时间运行的进程,通过还是休眠? - python

我正在编写一个队列处理应用程序,该应用程序使用线程等待和响应要发送到该应用程序的队列消息。对于应用程序的主要部分,只需要保持活动状态即可。对于像这样的代码示例:而True: 通过要么而True: time.sleep(1)哪一个对系统的影响最小?除了保持python应用运行外,什么都不做的首选方式是什么? 参考方案 我可以想象time.sleep()会减少系…

Python:无符号32位按位算术 - python

试图回答另一篇有关其解决方案涉及IP地址和网络掩码的文章时,我陷入了普通的按位算法。在Python中,是否存在一种标准的方式来进行按位AND,OR,XOR,NOT运算,假设输入是“32位”(可能是负数)整数或long,并且结果必须是[[ 0,2 ** 32]?换句话说,我需要一个与无符号长整数之间的C按位运算有效的Python对应物。编辑:具体问题是这样的:…

>> Python中的运算符 - python

>>运算符做什么?例如,以下操作10 >> 1 = 5有什么作用? 参考方案 它是右移运算符,将所有位“右移”一次。二进制10是1010移到右边变成0101这是5

Python:如何从字节中提取特定位? - python

我有一条消息,显示为14 09 00 79 3d 00 23 27。我可以通过调用message[4]从此消息中提取每个字节,例如,这将给我3d。如何从该字节中提取单个8位?例如,如何将24-27位作为单个消息?只需28位? 参考方案 要回答问题的第二部分,您可以使用按位运算来获取特定的位值# getting your message as int i = …