开发者

Python: class static member pointing to itself? [duplicate]

开发者 https://www.devze.com 2023-04-01 07:41 出处:网络
This question already has answers here: Closed 11 years ago. Possible Duplicate: Can I get a reference to the 'owner' class during the init method of a descriptor?
This question already has answers here: Closed 11 years ago.

Possible Duplicate:

Can I get a reference to the 'owner' class during the init method of a descriptor?

Code is worth a thousand words:

>>> class ShortRib(object):
>>>     def __init__(self, owner):
>>>         self.owner = owner
>>> 
>>>     ... some more methods and stuff ...
>>> 
>>> 
>>> class Cow(object):
>>>     shortRib = ShortRib(self)
>>> 
>>> 
>>> class BrownCow(Cow):
>>>     pass
>>> 
>>> BrownCow.shortRib.owner
<class '__main__.BrownCow'>

This doesn't work, though i wish it would. Basically, I want each class to have some static/class variables (i'm not sure which it is in this case?) but need each of those guys to know who (which class) it belongs to. Unfortunately, I can't "get" at the class in the body of the class declaration. Of course, I could always do this using a decorator:

>>> def vars(**kwargs):
>>>     def wrap(cls):    
>>>         for k, w in kwargs.items():
>>>             setattr(cls, k, w(cls))
>>>         return cls
>>>     return wrap
>>> 
>>> @vars(shortRib=lambda cls: ShortR开发者_运维技巧ib(cls)
>>> class BrownCow(Cow):
>>>     ...
>>>
>>> BrownCow.shortRib.owner

which would work. Another way would to have a class decorator that goes through all the shortRibs and similar static variables and sets their owner after the class declaration is complete. However, this seems like an incredibly roundabout and unintuitive way of doing what should be a pretty simple operation: having the static/class members of a class know who they belong to.

Is there a "proper" way of doing this?

Clarification:

I want these members to belong to the class, not to the instances. I'm trying to go for a almost-purely-functional style, using classes only for inheritance of shared behavior, and not creating instances of them at all. Instances would tend to give my functions access to arbitrary instance data shared across all functions, which would break the pure-functioness I am trying for. I could just use empty instances which I don't touch, but I think using pure classes would be cleaner.


You can easily do this in __new__:

class ShortRib(object):
    def __init__(self, owner):
        self.owner = owner

class Cow(object):
    shortRib = None
    def __new__(cls, *args, **kwargs):
        if cls.shortRib == None:
            cls.shortRib = ShortRib(cls)
        return super(Cow, cls).__new__(cls, *args, **kwargs)

Cow()
Cow.shortRib.owner

Or even __init__, if you don't mind referencing self.__class___.

You can also do it with a metaclass:

class ShortRib(object):
    def __init__(self, owner):
        self.owner = owner

class MetaCow(type):
    def __new__(cls, name, base, attrs):
        attrs['shortRib'] = ShortRib(cls)
        return super(MetaCow, cls).__new__(cls, name, base, attrs)

class Cow(object):
    __metaclass__ = MetaCow

Cow.shortRib.owner


Why not let the instances of the Cow class have shortRibs, instead of the class itself?:

class ShortRib(object):
    def __init__(self,owner):
        self.owner=owner

class Cow(object):
    def __init__(self):
        self.shortRib=ShortRib(self)

class BrownCow(Cow):
    pass

print(BrownCow().shortRib.owner)
# <__main__.BrownCow object at 0xb76a8d6c>

(Otherwise, you'll need a class decorator or metaclass -- as you've already mentioned. But simple is better than complex, so why not choose simple?)


By the way, if you really do want to use classes instead of instances:

class ShortRib(object):
    def __init__(self, owner):
        self.owner = owner

class MetaCow(type):
    def __init__(cls, name, base, attrs):
        super(MetaCow, cls).__init__(name, base, attrs)
        cls.shortRib = ShortRib(cls)

class Cow(object):
    __metaclass__ = MetaCow

class BrownCow(Cow):
    pass

print(Cow.shortRib.owner)
# <class '__main__.Cow'>

print(BrownCow.shortRib.owner)
# <class '__main__.BrownCow'>

Using

class MetaCow(type):
    def __new__(cls, name, base, attrs):

is incorrect. The signature for type.__new__ is

class MetaCow(type):
    def __new__(meta, name, base, attrs):

Since you want to modify the attributes of cls, not meta, use the MetaCow.__init__ not MetaCow__new__.


Two methods to to do what you want:

  • You can override the __getattr__ method in any class to return anything you desire when you ask for the value of an attribute.
  • You can use a property, which has a getter that returns the object you want it to return.

Both __getattr__ methods and properties are inherited.

0

精彩评论

暂无评论...
验证码 换一张
取 消