python-3.x 对于 Package 类,除了使用'__getattr__()'方法之外,还有什么方法可以替代?

nukf8bse  于 2023-01-14  发布在  Python
关注(0)|答案(1)|浏览(146)

假设我有两个类:
1.名为Swimmer的类
1.名为Person的类
对于我的特定应用程序,我们可以***NOT***让SwimmerPerson继承,尽管我们需要类似继承的东西。
代替类继承,每个Swimmer将具有Person类的示例作为成员变量。

class Swimmer:

    def __init__(self, person):  
        self._person = person 

    def __getattr__(self, attrname:str):
        try:
            attr = getattr(self._person)
            return attr  
        except AttributeError:
            raise AttributeError

Person类具有以下类方法:

  • kneel()
  • crawl()
  • walk()
  • lean_over()
  • x1米11米1x

Swimmer类具有与Person类相同的所有方法,外加一些附加方法:

  • run()
  • swim()
  • dive()
  • throw_ball()

对于跪、爬、走和躺,Swimmer应该是Person类的透明 Package 器
我想写这样的东西:

swimmer_instance = SwimmerClass(person_instance)

我写了一个__getattr__()方法。
但是,我遇到了许多头痛的__getattr__()
首先,每当我输入Swimmer属性的名称时,我的计算机就会在Person类的示例中搜索该属性。通常,修复这样的拼写错误很容易。但是,使用__getattr__()方法,跟踪问题变得很困难。
我怎样才能避免这个问题?
也许一个选择是创建Swimmer类的一个子类,在这个子类中有一个方法,这个方法的名字是拼写错误的__getattr__,但是,我对这个想法不是很确定;请告诉我。

class _Swimmer:

    def __init__(self, person):  
        self._person = person 

    def run(self):
        # SHOULD NOT LOOK FOR `oops` inside of self._person!
        self.oops # there is no attribute named `oops`
        return "I ran"

    def swim(self):
        # SHOULD NOT LOOK FOR `oops` inside of self._person!
        self.oops
        return "I swam"

    def dive(self):
        # SHOULD NOT LOOK FOR `oops` inside of self._person!
        self.oops   
        return "I dove"

    def _getattrimp(self, attrname:str):
        # MISSPELLING OF `__getattr__`
        try:
            attr = getattr(self._person)
            return attr  
        except AttributeError:
            raise AttributeError  

class Swimmer(_Swimmer):
    def __getattr__(self, attrname:str):
        attr = self._getattrimp(attrname)
        return attr

真的,对我来说,重要的是我们***不要***查看self._person内部的任何内容,除了以下内容:

  • Kneel()
  • Crawl()
  • x1米30英寸1x
  • Lean()
  • LayDown()

解必须比SwimmersPersons更一般。

我们如何编写一个函数,它接受任何类作为输入,并弹出一个与输入类同名的方法的类?

我们可以通过写入person_attributes = dir(Person)来获得Person属性的列表。
动态创建Swimmer的子类并将Person作为输入是否合适?

class Person:  
    def kneel(self, *args, **kwargs):
        return "I KNEELED"

    def crawl(self, *args, **kwargs):
        return "I crawled"

    def walk(self, *args, **kwargs):
        return "I WALKED"

    def lean_over(self, *args, **kwargs):
        return "I leaned over"

################################################################

import functools

class TransparentMethod:
    def __init__(self, mthd):  
        self._mthd = mthd 

    @classmethod
    def make_transparent_method(cls, old_method):
        new_method = cls(old_method)
        new_method = functools.wraps(old_method)
        return new_method  

    def __call__(self, *args, **kwargs):
        ret_val = self._mthd(*args, **kwargs)   
        return ret_val  

###############################################################

attributes = dict.fromkeys(dir(Person))

for attr_name in attributes.keys():
    old_attr = getattr(Person, attr_name)
    new_attr = TransparentMethod.make_transparent_method(old_attr)

name       = "_Swimmer"
bases      = (object, )

_Swimmer = type(name, bases, attributes) 
  
class Swimmer(_Swimmer):
    pass
avwztpqn

avwztpqn1#

如果我没理解错的话,您需要一个将两个类合并为一个类的函数。
我做这件事的方法是创建一个空容器类,然后循环遍历传递给函数的每个类,使用setattr设置容器类的新属性。我不得不将__class____dict__属性列入黑名单,因为Python不允许更改这些属性。注意,这个函数将覆盖以前添加的方法,比如__init__()方法。所以最后用构造函数传递类。我还添加了一个name可选参数来设置类的__name__属性,以便于调试。
我在下面的combineClasses函数中实现了这一点。我还提供了一个例子。在这个例子中,我创建了一个基本的Person类和一个_Swimmer类。我在这两个类上调用了combineClasses,并将结果类存储为Swimmer,因此它可以很好地作为一个 Package 类调用。

def combineClasses(*args, name='container'):
    class container():
        pass

    reserved = ['__class__', '__dict__']
    for arg in args:
        for method in dir(arg):
            if method not in reserved:
                setattr(container, method, getattr(arg, method))
    container.__name__ = name
    return container

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

    def sayHi(self):
        print(f'Hi, I am {self.name}')

class _Swimmer:
    def swim(self):
        print('I am swimming')

Swimmer = combineClasses(_Swimmer, Person, name='Swimmer')

bob = Swimmer('Bob')
bob.swim()
bob.sayHi()
print(bob.name)

相关问题