有没有办法创建一个不污染其实例的属性名称空间的Python类方法?

时间:2017-01-24 16:24:10

标签: python python-2.7 oop

我想提供一个可以在Python 2.7类对象上使用的方法,但不会污染其实例的属性名称空间。有没有办法做到这一点?

select t1.*
from tblItemsOrdered t1
inner join (
    select t1.itemNumber, max(t1.PONumber) as max_PONumber
    from tblItemsOrdered t1
    inner join (
        SELECT itemNumber, Max(OrderDate) as Max_OrderDate
        FROM tblItemsOrdered
        GROUP BY itemNumber
    ) t2 on t1.itemNumber = t2.itemNumber
    and t1.OrderDate = t2.Max_OrderDate
    group by t1.itemNumber
) t2 on t1.itemNumber = t2.itemNumber
and t1.PONumber = t2.max_PONumber;

4 个答案:

答案 0 :(得分:4)

ugh不在命名空间中:

>>> foo.__dict__
{}

但属性查找的规则会回退到缺少名称的实例类型。您可以覆盖Foo.__getattribute__以阻止此操作。

class Foo(object):
    @classmethod
    def ugh(cls):
        return 33

    def __getattribute__(self, name):
        if name == 'ugh':
            raise AttributeError("Access to class method 'ugh' block from instance")
        return super(Foo,self).__getattribute__(name)

这会产生:

>>> foo = Foo()
>>> foo.ugh()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "tmp.py", line 8, in __getattribute__
    raise AttributeError("Access to class method 'ugh' block from instance")
AttributeError: Access to class method 'ugh' block from instance
>>> Foo.ugh()
33

您必须使用__getattribute__,这是在任何属性访问时无条件调用,而不是__getattr__,只有在正常查找(包括检查类型的命名空间)失败后才会调用它。{/ p >

答案 1 :(得分:4)

您可以继承classmethod描述符:

class classonly(classmethod):
    def __get__(self, obj, type):
        if obj: raise AttributeError
        return super(classonly, self).__get__(obj, type)

这就是它的表现:

class C(object):
    @classonly
    def foo(cls):
        return 42
>>> C.foo()
42
>>> c=C()
>>> c.foo()
AttributeError

这样去掉了描述符调用(相反,它是由__getattribute__的默认实现调用的):

>>> C.__dict__['foo'].__get__(None, C)
<bound method C.foo of <class '__main__.C'>>
>>> C.__dict__['foo'].__get__(c, type(c))
AttributeError

必读:Data Model — Implementing DescriptorsDescriptor HowTo Guide

答案 2 :(得分:2)

是的,您可以在元类中创建方法。

class FooMeta(type):
    # No @classmethod here
    def ugh(cls):
        return 33

class Foo(object):
    __metaclass__ = FooMeta

Foo.ugh()  # returns 33
Foo().ugh()  # AttributeError

请注意,元类是一种强大功能,如果不必要,不鼓励使用它们。特别是,如果父类具有不同的元类,则多重继承需要特别小心。

答案 3 :(得分:1)

Python有quasi-private variables使用名称修改来减少意外访问。形式为__name的方法和对象变量将转换为_ClassName__name。 Python在编译类的方法时会自动更改名称,但不会更改子类的名称。

我可以在类

中使用私有方法
>>> class A(object):
...     def __private(self):
...         print('boo')
...     def hello(self):
...         self.__private()
... 
>>> 
>>> A().hello()
boo

但不在课外

>>> A().__private()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute '__private'
>>> 

或在子类中

>>> class B(A):
...     def hello2(self):
...         self.__private()
... 
>>> 
>>> B().hello()
boo
>>> B().hello2()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in hello2
AttributeError: 'B' object has no attribute '_B__private'