简体   繁体   English

获取实例变量的类

[英]Get class of instance variable

I try to get the class of an instance variable, I think that is very simple, but at the moment I can not figure out that. 我尝试获取一个实例变量的类,我认为这很简单,但是目前我不知道这一点。

class A():
  def __init__(self):
    self.a = 1

class B():
  def __init__(self):
    self.b = A()

def getClassOfVariable(abc):
  print(abc)

getClassOfVariable(B().b)
<__main__.A object at 0x7f4b2652ac18>

For example I have a function where I pass B().b as argument (whyever) to a function and in this function I need the class of the variable where is it defined, so class B() is what I want in the function. 例如,我有一个函数,其中将B()。b作为参数(无论如何)传递给函数,在此函数中,我需要定义变量的类,因此,类B()是我想要的函数。 What I know is only that in the function getClassOfVariable I get only classes like B. 我所知道的只是,在函数getClassOfVariable中,我仅获得诸如B之类的类。

Thanks for helping! 感谢您的帮助! :) :)

You can't do that. 你不能那样做。

In Python, variables are just names for values. 在Python中,变量只是值的名称。 A value can have many names, for example 60 might be called seconds_per_minute , minutes_per_hour , or even speed_limit_mph , and these names obviously have nothing to do with each other. 值可以有许多名字,例如60可能被称为seconds_per_minuteminutes_per_hour ,甚至speed_limit_mph ,而这些名字显然没有任何关系彼此。 A value can also have no name at all, for example print(60) doesn't give 60 any name. 值也可以完全没有名称,例如print(60)不会给出60任何名称。

An important point to remember is that when you call a function, your arguments are passed by assignment . 要记住的重要一点是,在调用函数时,参数是通过Assignment传递的 That is, the function's parameters become new names for the values that you passed in. So the called function has no idea what name you use for the object you passed, it just knows its own name for that object. 也就是说,函数的参数将成为您传递的值的新名称。因此,被调用函数不知道为传递的对象使用了什么名称,它只知道该对象的名称。

In this case, the object itself doesn't know what class it was created in. You know it, because you know the name of the object (it's B().b ). 在这种情况下,对象本身不知道在哪个类中创建对象。您知道它是因为知道对象的名称(它是B().b )。 But the name of the object is not passed to the called function, so getClassOfVariable has no way of determining which class your A object was created in. 但是对象的名称没有传递给被调用的函数,因此getClassOfVariable无法确定创建A对象的类。

So, how to work around this limitation? 那么,如何解决此限制? The simplest route is to provide this information to your A object in its constructor, by passing type(self) (or self.__class__ , for Python 2.x classic classes) as an argument to A() and handling it in the A.__init__() method, like this: 最简单的方法是通过将type(self) (或对于Python 2.x经典类为self.__class__ )作为A()的参数传递给A对象,并在A该信息,从而在其构造函数中将此信息提供给A对象A.__init__()方法,如下所示:

class A():
  def __init__(self, owner=None):
    self.a = 1
    self.owner = owner

class B():
  def __init__(self):
    self.b = A(type(self))

You can then inspect the B().b.owner attribute to find out which class created your A object. 然后,您可以检查B().b.owner属性,以找出哪个类创建了您的A对象。 However, if you create a subclass of B , then type(self) will be that subclass and not B . 但是,如果创建B的子类,则type(self)将是该子类,而不是B If you still need to get B in that case, then you should pass B instead of type(self) . 如果在这种情况下仍需要获取B ,则应传递B而不是type(self)

You could use a descriptor for the attribute. 您可以为属性使用描述符。 In the descriptor's __set__ method, add an attribute to its value that can be inspected inside the function. 在描述符的__set__方法中,向其值添加一个属性,该属性可以在函数内部进行检查。

from weakref import WeakKeyDictionary

class A:
    def __init__(self):
        self.a = 1

class X:
    """A descriptor that knows where it was defined"""
    def __init__(self, default):
        self.default = default
        self.data = WeakKeyDictionary()

    def __get__(self, instance, owner):
        # we get here when someone calls x.d, and d is an X instance
        # instance = x
        # owner = type(x)
        return self.data.get(instance, self.default)

    def __set__(self, instance, value):
        # we get here when someone calls x.d = val, and d is an X instance
        # add an attribute to the value and assign the instance
        #value.defining_class = instance
        value.defining_class = instance.__class__
        self.data[instance] = value

class B:
    b = X(None) 
    def __init__(self):
        self.b = A()

def getClassOfVariable(abc):
    print(f'abc: {abc}')
    print(f'defining_class: {abc.defining_class}')

getClassOfVariable(B().b)

Result: 结果:

abc: <__main__.A object at 0x.....>
defining_class: <class '__main__.B'>

I adapted this descriptor from Python Descriptors Demystified which I always refer to when writing a descriptor. 我从Python描述符Demystified中改编了这个描述符,编写描述符时总是引用它。

Caveat: Although this works, this feels like a hack and certainly hasn't been tested for pitfalls. 警告:尽管可以,但是这感觉像是一种破解,当然还没有经过陷阱的测试。 In this example an instance of A has had an attribute added that says it was defined in B ; 在这个例子中, A的实例添加了一个属性, 表示它是在B中定义的; if that instance gets passed around a bit it might lose its context and upon introspection that added attribute might seem strange indeed. 如果该实例经过了一些传递,则可能会丢失其上下文,并且在内省时,添加的属性确实确实看起来很奇怪。 -but for this simple example it seems OK. -但对于这个简单的例子,似乎还可以。 Maybe downvotes with comments, or even edits will elucidate. 也许会对评论投反对票,甚至可以阐明编辑内容。 It seems too easy to just add an attribute and maybe there should be some protection involved. 仅添加属性似乎太容易了,也许应该涉及一些保护。 Or maybe value.defining_class should just be the string instance.__class__ - edited to that effect 或者也许value.defining_class应该只是字符串instance.__class__ value.defining_class编辑为该效果

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM